文章原创于公众号:程序猿周先森。本平台不定时更新,喜欢我的文章,欢迎关注我的微信公众号。

之前其实写过一篇文章具体介绍过:最基础的Nginx教学,当时有提到过Nginx有一个重要的功能:负载均衡。所以这篇文章主要讲讲Nginx如何实现反向代理以及在Nginx中负载均衡的参数使用。

一、代理

正向代理

正向代理也是大家最常接触的到的代理模式,那究竟什么是正向代理呢?我们都知道Google在国内是无法正常访问的,但是某些时候我们由于技术问题需要去访问Google时,我们会先找到一个可以访问Google的代理服务器,我们将请求发送到代理服务器,代理服务器去访问Google,然后将访问到的数据返回给我们,这样的过程就是正向代理。

正向代理的特点

正向代理最大的特点是客户端需要明确知道要访问的服务器地址,Google服务器只清楚请求来自哪个代理服务器,而不清楚来自哪个具体的客户端,正向代理可以隐藏真实客户端的具体信息。

客户端必须设置正向代理服务器,而且需要知道正向代理服务器的IP地址以及代理程序的端口。一句话来概括就是正向代理代理的是客户端,是一个位于客户端和Google服务器之间的服务器,为了从Google服务器取得数据,客户端向代理服务器发送一个请求并指定目标(Google服务器),然后代理向原始服务器转交请求并将获得的数据返回给客户端。

正向代理的使用:

  • 访问国外无法访问的网站

  • 做缓存,加速访问资源

  • 对客户端访问授权,上网进行认证

  • 代理可以记录用户访问记录(上网行为管理),对外隐藏用户信息

反向代理

说完了什么是正向代理,我们接下来看看什么叫做反向代理,如果我们网站每日访问量达到某个上限,单个服务器远远不能符合我们日常需求,这时候我们首先会想到分布式部署。通过部署多台服务器来解决访问人数限制的问题,然后我们功能其实大部分都是通过Nginx反向代理来实现的。我们可以看下图:

反向代理的特点

我们可以清楚的看到,多个客户端给服务器发送的请求,Nginx服务器接收到请求以后,按照一定的规则转发到不同的服务器进行业务逻辑处理。此时请求来源于哪个客户端是确定的,但是请求由哪台服务器处理的并不明确,Nginx扮演的就是一个反向代理角色。可以这样来理解,反向代理对外都是透明的,访问者并不知道自己访问的是一个代理。反向代理代理的是服务端,主要用于服务器集群分布式部署的情况下,反向代理隐藏了服务器的信息。

反向代理的使用:

  • 保证内网的安全,通常将反向代理作为公网访问地址,Web服务器是内网

  • 负载均衡,通过反向代理服务器来优化网站的负载

正向代理与反向代理区别

  • 在正向代理中,隐藏了请求来源的客户端信息;

  • 在反向代理中,隐藏了请求具体处理的服务端信息;

服务端中我们最常使用的反向代理的工具就是Nginx。

二、基本架构

Nginx在启动后以daemon的方式在后台运行,会有一个master进程和多个worker进程:

  1. Nginx 在启动后,会有一个 master 进程和多个相互独立的 worker 进程。
  2. 接收来自外界的信号,向各worker进程发送信号,每个进程都有可能来处理这个连接。
  3. master 进程能监控 worker 进程的运行状态,当 worker 进程退出后(异常情况下),会自动启动新的 worker 进程。

master进程:主要用来管理worker进程,包含:

  1. 接收来自外界的信号
  2. 向各worker进程发送信号
  3. 监控worker进程的运行状态
  4. 当worker进程异常退出后,会自动重新启动新的worker进程。

worker进程:处理基本的网络事件了。多个worker进程之间是对等的,他们同等竞争来自客户端的请求,各进程互相之间是独立的。一个请求只能在一个worker进程中处理,一个worker进程,不可能处理其它进程的请求。worker进程的个数是可以设置的,一般我们会设置与机器cpu核数一致,或者直接设置参数worker_processes auto;

Nginx基本架构如下:

我们可以输入nginx -s reload来重启Nginx,nginx -s stop来停止Nginx的运行,执行这些命令时其实会启动一个新的Nginx进程,而新的Nginx进程在解析到reload参数后,其实就可以知道用户执行这个命令是控制Nginx重新加载配置文件,于是向master进程发送信号。master进程接到信号会先重新加载配置文件,然后启动新的worker进程并向所有旧worker进程发送信号提示老进程可以停止运行了。新的worker启动成功后就开始接收新的请求,而旧worker在收到来自master的信号后停止接收新的请求,在未处理完的请求处理完成后进程就会退出。所以说使用nginx -s reload命令重启Nginx的时候服务是不中断的。

三、Nginx处理客户端请求方式

刚才有讲到过每个worker进程都是从master进程分支的,所以在master进程里面需要先建立好需要监听的socket然后再分支出多个worker进程。所有worker进程listenfd事件会在新连接时变成可读,为保证只有一个进程处理该连接,所以需要设置互斥锁,所有worker进程需要抢互斥锁,抢到互斥锁的work进程注册listenfd读事件,在listenfd读事件里调用accept接受该连接。当Nginx监听80端口时,一个客户端的连接请求过来的时候,每个worker进程都会去抢互斥锁注册listenfd读事件。当一个worker进程在accept这个连接之后,就开始处理请求获取数据,再将数据返回给客户端,然后断开连接,到这里一个请求结束。

一个请求,完全由worker进程来处理,而且只在一个worker进程中处理。

我下面贴一个简单的配置:

server {
listen 80;
server_name aaa.com www.aaa.com;
}

server {
listen 80;
server_name aaa.cn www.aaa.cn;
}

server {
listen 80;
server_name aaa.org www.aaa.org;
}

当接收到客户端http请求,Nginx根据请求头的Host字段决定请求应该由哪一台服务器处理,如果Host字段的值没有匹配的服务器或者请求中没有Host字段,Nginx会将请求路由至这个端口的默认服务器。没有显示配置默认服务器,则默认服务器则为第一个配置。当然我们还可以使用default_server参数指定默认服务器。

server {
listen 80 default_server;
server_name aaa.com www.aaa.com;
}

这里需要注意一下:配置默认服务器是监听端口号,而不是服务器名称。

四、Nginx实现高并发

Nginx内部采用了异步非阻塞的方式处理请求,使用了epoll和大量的底层代码优化。可以同时处理成千上万个请求的。

异步非阻塞:每进来一个request,会有一个worker进程去处理。但不是全程的处理,处理到什么程度呢?处理到可能发生阻塞的地方,比如向后端服务器转发request,并等待请求返回。这个处理的worke会在发送完请求后注册一个事件:“如果upstream返回了,再进行执行接下来的工作”。此时,如果再有request 进来,他就可以很快再按这种方式处理。而一旦后端服务器返回了,就会触发这个事件,worker进程会来接手request接着往下执行。

而Nginx采用一个master进程,多个woker进程的模式。master进程主要负责收集、分发请求。每当一个请求过来时,master就拉起一个worker进程负责处理这个请求。同时master进程也负责监控woker的状态,保证高可靠性,woker进程一般设置为跟cpu核心数一致。Nginx的woker进程在同一时间可以处理的请求数只受内存限制,可以处理多个请求。Nginx 的异步非阻塞工作方式可以把当中的进程空闲等待时间利用起来,因此表现为少数几个进程就解决了大量的并发问题。

Nginx中以epoll为例子,当事件没准备好时,放到epoll里面,事件准备好了,Nginx就去读写,当读写返回EAGAIN时,就将它再次加入到epoll里面。这样,只要有事件准备好了,Nginx就可以去处理它,只有当所有事件都没准备好时,才在epoll里面等着。这样便实现了所谓的并发处理请求,但是线程只有一个,所以同时能处理的请求当然只有一个了,只是在请求间进行不断地切换而已。

Nginx单线程机制与多线程相比优势:

  • 在于不需要创建线程。
  • 每个请求占用的内存也很少。
  • 没有上下文切换。
  • 事件处理非常的轻量级。
  • 并发数再多也不会导致无谓的资源浪费。

五、Nginx负载均衡的算法及参数

  • weight轮询(默认):接收到的请求按照请求顺序逐一分配到不同的后端服务器,如果在使用过程中,某一台服务器宕机,Nginx会自动将该服务器剔除出队列,请求受理情况不会受到任何影响。这种方式下,可以给不同的后端服务器设置一个权重值,权重数据越大,服务器被分配到请求的几率越大。

  • ip_hash:每个请求按照发起客户端的ip的hash结果进行匹配,这样的算法下一个固定ip地址的客户端总会访问到同一个后端服务器。

  • fair:智能调整调度算法,动态的根据后端服务器的请求响应时间进行均衡分配,响应时间短处理效率高的服务器分配到请求的概率高,响应时间长处理效率低的服务器分配到的请求少。

  • url_hash:按照访问的url的hash结果分配请求,每个请求的url会指向后端固定的某个服务器,可以在Nginx作为静态服务器的情况下提高缓存效率。

上面是最基本的4种算法,我们还可以通过改变参数来自行配置负载均衡:

upstream localhost{
> ip_hash;
> server 127.0.0.1:9090 down;
> server 127.0.0.1:8080 weight=2;
> server 127.0.0.1:6060;
> server 127.0.0.1:7070 backup;
}

  • down表示当前的服务器停止参与负载。
  • weight默认为1,weight越大,负载的权重就越大。
  • backup表示其它所有的非backup机器down或者忙的时候,请求backup机器。所以这台机器压力会最轻。

欢迎关注我的个人公众号:程序猿周先森

渐进深入理解Nginx的更多相关文章

  1. 《深入理解Nginx》阅读与实践(一):Nginx安装配置与HelloWorld

    最近在读陶辉的<深入理解Nginx:模块开发与架构解析>,一是想跟着大牛练练阅读和编写开源代码的能力,二是想学学Nginx优秀的架构设计,三是想找一个点深入下Linux下网络编程的细节.侯 ...

  2. 《深入理解Nginx》阅读与实践(四):简单的HTTP过滤模块

    一.Nginx的HTTP过滤模块特征 一个请求可以被任意个HTTP模块处理: 在普通HTTP模块处理请求完毕并调用ngx_http_send_header()发送HTTP头部或调用ngx_http_o ...

  3. 《深入理解Nginx》阅读与实践(三):使用upstream和subrequest访问第三方服务

    本文是对陶辉<深入理解Nginx>第5章内容的梳理以及实现,代码和注释基本出自此书. 一.upstream:以向nginx服务器的请求转化为向google服务器的搜索请求为例 (一)模块框 ...

  4. 《深入理解Nginx》阅读与实践(二):配置项的使用

    前文链接:<深入理解Nginx>阅读与实践(一):Nginx安装配置与HelloWorld HelloWorld的完成意味着已经踏入了nginx的大门,虽然很振奋人心,但在编写中仍有很多疑 ...

  5. 深入理解Nginx及使用Nginx实现负载均衡

    前言: 最近在部署项目时要求实现负载均衡,有趣的是发现网上一搜全部都是以下类似的配置文件 upstream localhost{ server 127.0.0.1:8080 weight=1; ser ...

  6. 如何理解Nginx, WSGI, Flask(Django)之间的关系

    如何理解Nginx, WSGI, Flask(Django)之间的关系 值得指出的是,WSGI 是一种协议,需要区分几个相近的名词: uwsgi 同 wsgi 一样也是一种协议,uWSGI服务器正是使 ...

  7. 读书笔记之深入理解Nginx:模块开发与结构解析

    前言 我现在看书一般都是看自己能看懂的地方,看不懂就先略过,回头再看,下面就写自己看得懂的地方吧,并且把自己的理解也放到里面. 第一部分 Nginx能帮我们做什么 编译安装各个命令解释 configu ...

  8. 转载:第2章 Nginx的配置 概述《深入理解Nginx》(陶辉)

    原文:https://book.2cto.com/201304/19623.html Nginx拥有大量官方发布的模块和第三方模块,这些已有的模块可以帮助我们实现Web服务器上很多的功能.使用这些模块 ...

  9. 转载:Nginx是什么(1.1)《深入理解Nginx》(陶辉)

    原文:https://book.2cto.com/201304/19609.html 人们在了解新事物时,往往习惯通过类比来帮助自己理解事物的概貌.那么,我们在学习Nginx时也采用同样的方式,先来看 ...

随机推荐

  1. PHP危险函数总结学习

    1.PHP中代码执行的危险函数 call_user_func() 第一个参数 callback 是被调用的回调函数,其余参数是回调函数的参数. 传入call_user_func()的参数不能为引用传递 ...

  2. 02 http和https协议

    1. HTTP协议 简介 HTTP协议是Hyper Text Transfer Protocol(超文本传输协议)的缩写, 是用于从万维网(WWW:World Wide Web )服务器传输超文本到本 ...

  3. Java 最全异常讲解

    1. 导引问题 实际工作中,遇到的情况不可能是非常完美的.比如:你写的某个模块,用户输入不一定符合你的要求.你的程序要打开某个文件,这个文件可能不存在或者文件格式不对,你要读取数据库的数据,数据可能是 ...

  4. Apache—dbutils开源JDBC工具类库简介

    Apache—dbutils开源JDBC工具类库简介 一.前言 commons-dbutils 是 Apache 组织提供的一个开源 JDBC工具类库,它是对JDBC的简单封装,学习成本极低,并且使用 ...

  5. 算法与数据结构基础 - 贪心(Greedy)

    贪心基础 贪心(Greedy)常用于解决最优问题,以期通过某种策略获得一系列局部最优解.从而求得整体最优解. 贪心从局部最优角度考虑,只适用于具备无后效性的问题,即某个状态以前的过程不影响以后的状态. ...

  6. Mac OS 下包管理器 homebrew的安装

    homebrew :熟悉mac os的小伙伴们一定都知道这个包管理工具,它非常方便且好用,安装它只需要打开终端并将以下代码粘贴到终端中运行即可: /usr/bin/ruby -e "$(cu ...

  7. java四种引用及在LeakCanery中应用

    java 四种引用 Java4种引用的级别由高到低依次为: StrongReference > SoftReference > WeakReference > PhantomRefe ...

  8. codeblocks中文乱码原因及解决办法

    原因:(本地化做得不够好)默认情况下codeblocks编辑器保存源文件是保存为windows本地编码,就是WINDOWS-936字符集,即GBK:但CB的编辑器在默认编辑的时候是按照UTF-8来解析 ...

  9. 迁移桌面程序到MS Store(10)——在Windows S Mode运行

    首先简单介绍Windows 10 S Mode,Windows在该模式下,只能跑MS Store里的软件,不能通过其他方式安装.好处是安全有保障,杜绝一切国产流氓软件.就像iOS一样,APP进商店都需 ...

  10. zabbix设置钉钉报警

    1 添加机器人 在钉钉群里面添加一个机器人 会获取到一个URL: 'https://oapi.dingtalk.com/robot/send?access_token=62be1ea97b4653b8 ...