当前位置: 首页 > 后端技术 > Node.js

循序渐进深入理解Nginx

时间:2023-04-03 10:31:55 Node.js

文章最初发表于公众号:程序员周先森。本平台不定期更新,喜欢我的文章,请关注我的微信公众号。其实之前写过一篇文章详细介绍过:最基础的Nginx教学。当时提到Nginx有一个重要的功能:负载均衡。所以这篇文章主要讲一下Nginx是如何实现反向代理的,以及Nginx中负载均衡参数的使用。一、Proxy正向代理正向代理也是大家最常接触到的代理模型,那么正向代理到底是什么?我们都知道谷歌在国内是不能正常访问的,但是有时候我们因为技术问题需要访问谷歌的时候,我们会先找一个可以访问谷歌的代理服务器,我们将请求发送到代理服务器,代理服务器会访问谷歌,然后将访问的数据返回给我们,这个过程就是一个正向代理。正向代理的特点正向代理最大的特点就是客户端需要知道要访问的服务器地址。Google服务器只知道请求来自哪个代理服务器,而不知道具体是哪个客户端。正向代理可以隐藏真正的客户端特定信息。?客户端必须设置一个正向代理服务器,需要知道正向代理服务器的IP地址和代理程序的端口。一句话,forwardproxy代理就是客户端,是客户端和谷歌服务器之间的一个服务器。为了从谷歌服务器获取数据,客户端向代理服务器发送请求并指定目标(谷歌服务器)。然后代理将请求转发给源服务器,并将获得的数据返回给客户端。正向代理的使用:访问国外无法访问的网站进行缓存,加速访问资源,授权客户端访问,在互联网上进行认证。代理可以记录用户访问记录(上网行为管理),对外界隐藏用户信息。对于代理,我们来看看什么叫反向代理。如果我们网站每天的访问量达到一定的限度,单台服务器是远远不能满足我们日常需求的。这个时候我们首先会想到分布式部署。通过部署多台服务器来解决限制访问量的问题,其实我们的大部分功能都是通过Nginx反向代理来实现的。我们可以看下图:反向代理的特点我们可以清楚的看到,多个客户端向服务器发送请求。Nginx服务器收到请求后,按照一定的规则转发给不同的服务器进行业务逻辑处理。这个时候确定了请求来自哪个客户端,但是并不清楚请求是由哪个服务器处理的。Nginx扮演着反向代理的角色。可以这样理解,反向代理对外是透明的,访问者不知道自己访问的是一个代理。反向代理代理就是服务器,主要用于服务器集群分布式部署的情况。反向代理隐藏了服务器的信息。反向代理的使用:为了保证内网的安全,通常使用反向代理作为公网访问地址,web服务器作为内网的负载均衡,反向代理服务器用来优化负载网站。正向代理和反向代理的区别在于,在正向代理中,隐藏了请求源的客户端信息;在反向代理中,隐藏了请求具体处理的服务器信息;我们在服务器端最常用的反向代理工具是Nginx。2、基本结构Nginx启动后以daemon的形式在后台运行,会有一个master进程和多个worker进程:Nginx启动后会有一个master进程和多个独立的worker进程。接收外界的信号,发送信号给每个worker进程,每个进程都可能处理这个连接。master进程可以监控worker进程的运行状态,当worker进程退出时(异常情况下),会自动启动一个新的worker进程。Master进程:主要用来管理worker进程,包括:接收外界的信号,向各个worker进程发送信号,监控worker进程的运行状态。当worker进程异常退出时,会自动重启一个新的worker进程。工作进程:处理基本的网络事件。多个工作进程是对等的,它们平等地竞争来自客户端的请求,并且每个进程相互独立。一个请求只能在一个worker进程中处理,一个worker进程不能处理来自其他进程的请求。可以设置工作进程的数量。一般我们会设置成与机器的CPU核数一致,或者直接设置参数worker_processesauto;Nginx的基本结构如下:我们可以输入nginx-sreload来重启Nginx,nginx-sstop来停止Nginx的运行。当执行这些命令时,实际上会启动一个新的Nginx进程。新的Nginx进程解析reload参数后,其实可以知道用户执行这条命令是为了控制Nginx重新加载配置文件,于是向master进程发送信号。当master进程收到信号后,会先重新加载配置文件,然后启动一个新的worker进程,并向所有老的worker进程发送一个信号,表示老进程可以停止运行了。新的worker启动成功后开始接收新的请求,而老的worker在收到master的信号后停止接收新的请求,处理完未处理的请求后进程退出。所以在使用nginx-sreload命令重启Nginx时,服务不会中断。3、Nginx处理客户端请求的方式刚才提到了每个worker进程都是从master进程中分支出来的,所以在master进程中需要先建立要监听的socket,然后再分支出多个worker进程。当建立新连接时,所有工作进程的listenfd事件都将变得可读。为确保只有一个进程处理连接,需要设置互斥量。所有worker进程都需要抢到mutex,抢到mutex的worker进程注册listenfdRead事件,在listenfdread事件中调用accept接受连接。Nginx监听80端口,当有客户端连接请求过来时,每个worker进程都会抢到mutex并注册listenfdread事件。当一个worker进程接受连接后,开始处理获取数据的请求,然后将数据返回给客户端,然后断开连接,一个请求到此结束。一个请求完全由工作进程处理,并且只在一个工作进程中处理。我将在下面发布一个简单的配置:server{listen80;server_nameaaa.comwww.aaa.com;}server{listen80;server_nameaaa.cnwww.aaa.cn;}server{listen80;server_nameaaa.orgwww.aaa.org;}当收到来自客户端的http请求时,Nginx会根据请求头的Host字段来判断该请求应该被哪个服务器处理。如果Host字段的值与服务器不匹配或者请求中没有Host字段,Nginx将发送默认服务器将请求路由到该端口。如果不显示默认服务器,则默认服务器为第一个配置。当然,我们也可以使用default_server参数来指定默认服务器。server{listen80default_server;server_nameaaa.comwww.aaa.com;}这里需要注意:配置默认服务器监听的端口号,而不是服务器名。4、Nginx实现高并发Nginx内部采用异步非阻塞的方式处理请求,使用epoll和大量的底层代码优化。它可以同时处理数千个请求。异步非阻塞:每次有请求进来,都会有一个worker进程去处理。但不是整个过程,到什么程度?处理可能发生阻塞的地方,比如将请求转发给后端服务器,等待请求返回。被处理的worker在发送请求后会注册一个事件:“如果上游返回,则执行下一个工作”。这个时候,如果有别的请求进来,他又可以快速的按这种方式处理。一旦后台服务器返回,就会触发这个事件,worker进程会接管请求然后执行。Nginx使用一个master进程和多个woker进程。master进程主要负责收集和分发请求。每当请求到来时,master拉起一个worker进程来处理请求。同时master进程还负责监控woker的状态,保证高可靠性。woker进程一般设置为与CPU核数一致。Nginx的woker进程同时处理的请求数只受内存限制,可以同时处理多个请求。Nginx异步非阻塞的工作方式可以利用进程的空闲等待时间,少数几个进程就可以解决大量的并发问题。Nginx中以epoll为例。当事件没有准备好时,将其放入epoll。当事件就绪后,Nginx就会进行读写。当读写返回EAGAIN时,会再次加入epoll。这样,只要一个事件准备好了,Nginx就可以处理它,只有当所有事件都没有准备好时,它才会在epoll中等待。这样就实现了所谓的并发处理请求,但是线程只有一个,所以当然只能同时处理一个请求,也就是不断地在请求之间切换。与多线程相比,Nginx单线程机制的优点是不需要创建线程。每个请求占用的内存也很少。没有上下文切换。事件处理非常轻量级。再多的并发也不会造成不必要的资源浪费。5、Nginx负载均衡算法和参数权重轮询(默认):接收到的请求,按照请求顺序,一一分配给不同的后端服务器。如果一个服务器在使用过程中宕机,Nginx会自动将该服务器从队列中移除,不会以任何方式影响请求的接受。这样就可以为不同的后端服务器设置一个权重值。权重数据越大,服务器将分配给请求的概率就越大。ip_hash:每个请求根据发起客户端IP的哈希结果进行匹配。使用此算法,具有固定IP地址的客户端将始终访问同一台后端服务器。公平:智能调整调度算法,根据后端服务器的请求响应时间动态均衡分配。响应时间短、处理效率高的服务器被分配请求的概率高,响应时间长、处理效率低的服务器被分配的请求少。url_hash:根据访问的url的哈希结果分配请求。每个请求的url都会指向后端固定的服务器,这样可以提高Nginx作为静态服务器时的缓存效率。以上是四种最基本的算法。我们也可以通过改变参数来配置负载均衡:upstreamlocalhost{ip_hash;服务器127.0.0.1:9090宕机;服务器127.0.0.1:8080权重=2;服务器127.0.0.1:6060;server127.0.0.1:7070backup;}down表示当前服务器停止参与负载。weight默认为1,weight越大,负载的权重越大。backup是指当所有其他非备份机器都宕机或忙时,请求备份机器。所以这台机器会是压力最小的。欢迎关注我的简介公众号:程序员周先森