Skip to content
raymond-zhao edited this page Aug 16, 2020 · 3 revisions

为什么需要 Nginx?

在传统的 Web 项目中,并发量小,用户量小,用户可以直接访问 Tomcat 服务器,然后 Tomcat 服务器返回消息给用户。在面临高并发时,需要进行负载均衡,也就是多准备一些 Tomcat 服务器,当用户访问时可以将请求转发到合适的 Tomcat 服务器上,但是在上传图片时,下次再发起请求可能换了台服务器就找不到上次上传的图片了。所以为了解决这种问题,需要一个 HTTP Server 存储的资源(HTML 文件、图片文件等等)。

Tomcat 是应用服务器 Application Server,通常作为 JSP/Servlet 程序的容器。

Nginx 是 HTTP Server,关心的是 HTTP 协议层面的传输与访问,所以在 Nginx 中可以看到代理,负载均衡等功能。客户端通过 HTTP Server 访问服务器上。

Nginx 模块

Nginx 模块

反向代理

其实所有的代理都是充当着中间代理人的角色,问题就在于,中间人代表的到底是谁的利益。在请求的过程中涉及三个角色,客户端(Client)、代理服务器(Proxy)、服务器(Server)。Proxy 在夹缝中生存,必须倒向一方才行。

代表广大人民群众(Clients)的时候就是正面的,否则就是反面的。

  • 正向代理:代理与客户端在一个局域网中,隐藏客户端,假装自己是客户端,对 Server 透明。
  • 反向代理:代理与服务器在一个局域网中,隐藏服务端,假装自己是服务端,对 Client 透明。
    • 反向代理(Reverse Proxy)实际运行方式是以代理服务器来接受来自 internet 的连接请求,然后将请求转发给内部网络上的服务器,并将从服务器上得到的结果返回给 internet 上请求连接的客户端,此时代理服务器对外就表现为一个服务器。
    • 可以保证内网的安全
    • 可以实现负载均衡,优化网络负载。

正向代理

反向代理

知乎上这篇文章回答的不错,尤其是慕课网的那份回答。

负载均衡

主要还是为了实现高并发,在以往的小型项目中,用户量小,并发量小时,一台服务器可能就勉强够用了,但是现在项目越来越大,也越来越偏向微服务架构,每个服务都需要许多台机器来提供支持。这个时候就需要实现负载均衡,而 Nginx 又比较适合在高并发的场景下工作,它作为反向代理,可以接受大量 Client 的请求,然后进行任务分发(指派服务器)。

  • 负载均衡的目的就是为了减轻单个服务节点的压力,避免 Web 响应过慢,避免出现宕机。

Nginx 负载均衡策略

内置有三种:轮询、加权、IP 绑定

  • 轮询:每个请求按时间顺序逐一分配到不同的后端服务器,如果后端某个服务器宕机,能自动剔除故障系统。
upstream backserver { 
	server 192.168.0.12; 
	server 192.168.0.13; 
}
  • 加权 weight:指定轮询几率,weight和访问比率成正比,用于后端服务器性能不均的情况。
upstream backserver { 
    server 192.168.0.14 weight=8; 
    server 192.168.0.15 weight=10; 
} 
  • IP 绑定 ip_hash:每个请求按访问 ip 的 hash 结果分配,每个访客固定访问一个后端服务器,可以解决 session 共享的问题。
upstream backserver { 
	ip_hash; 
    server 192.168.0.12:88; 
    server 192.168.0.13:80; 
} 

第三方插件两种:fair、url_hash

  • fair:需要安装 upstream_fair 模块。可以根据页面大小和加载时间只能地进行负载均衡,响应时间短的优先分配。
upstream backserver { 
    server server1; 
    server server2; 
    fair; 
} 
  • url_hash:需要安装 nginx 的 hash 软件包。利用 url 的 hash 结果分配,使每个 url 定向到同一台后端服务器。
upstream backserver { 
    server squid1:3128; 
    server squid2:3128; 
    hash $request_uri; 
    hash_method crc32; 
} 

动静分离

什么是动静分离?

动静分离就是动态文件与静态文件的分离。动静分离让动态网站里的动态网页根据一定规则把不变的资源和经常变的资源区分开来,动静资源做好拆分以后,就可以根据静态资源的特点将其做缓存操作,这就是网站静态化处理的核心思路。

  • 静态资源:用户多次访问这个资源,资源的源代码几乎不会改变(HTML、CSS、JS、Images)。
  • 动态资源:用户多次访问这个资源,资源的源代码很可能会发生改变(JSP)。

为什么要用动静分离?

  • 将网站静态资源(HTML,JavaScript,CSS,Images 等文件)与后台应用分开部署,提高用户访问静态代码的速度,降低对后台应用访问,减轻后台服务的压力。这里需要将静态资源放到 nginx 中,动态资源转发到 tomcat 服务器中。

使用方法

将静态资源上传到 nginx 服务器指定目录下,然后通过 location 对请求url进行匹配。

location /static/ {
    root /usr/local/var/www;
}

如何保证 nginx 的高可用性?

当上游服务器出现故障或者是没有及时响应的话,应该直接轮训到下一台服务器,保证服务器的高可用。

server {
    listen       80;
    server_name  www.raymond-zhao.top;
    location / {
        # 指定上游服务器负载均衡服务器
        proxy_pass http://backServer;
        # nginx与上游服务器(真实访问的服务器)超时时间 后端服务器连接的超时时间_发起握手等候响应超时时间
        proxy_connect_timeout 1s;
        # nginx发送给上游服务器(真实访问的服务器)超时时间
        proxy_send_timeout 1s;
        # nginx接受上游服务器(真实访问的服务器)超时时间
        proxy_read_timeout 1s;
        index  index.html index.htm;
    }
}

限流算法

漏桶算法

漏桶算法(Leaky Bucket)的主要目的是控制数据注入到网络的速率,平滑网络上的突发流量。

漏桶可以看作是一个带有常量服务时间的单服务器队列,如果漏桶(包缓存)溢出,那么数据包会被丢弃。 在网络中,漏桶算法可以控制端口的流量输出速率

如图所示,把请求比作是水,水来了都先放进桶里,并以限定的速度出水,当水来得过猛而出水不够快时就会导致水直接溢出,即拒绝服务。

可以看出,漏桶算法可以很好的控制流量的访问速度,一旦超过该速度就拒绝服务。

漏桶算法

令牌桶算法

令牌桶算法用来控制发送到网络上的数据的数目,并允许突发数据的发送。

令牌桶算法的原理:系统会以一个恒定的速度往桶里放入令牌,而如果请求需要被处理,则需要先从桶里获取一个令牌,当桶里没有令牌可取时,则拒绝服务。如果令牌消耗速率小于生产令牌的速度,令牌就会一直产生直至装满整个令牌桶。

令牌桶算法

从原理上看,令牌桶算法和漏桶算法是相反的,一个“进水”,一个是“漏水”。

Google 的 Guava 包中的 RateLimiter 类就是令牌桶算法的解决方案。

比较

漏桶算法与令牌桶算法的区别在于

  • 漏桶算法能够强行限制数据的传输速率。
  • 令牌桶算法能够在限制数据的平均传输速率的同时还允许某种程度的突发传输。

在某些情况下,漏桶算法不能够有效地使用网络资源,因为漏桶的漏出速率是固定的,所以即使网络中没有发生拥塞,漏桶算法也不能使某一个单独的数据流达到端口速率。

因此,漏桶算法对于存在突发特性的流量来说缺乏效率。而令牌桶算法则能够满足这些具有突发特性的流量。通常,漏桶算法与令牌桶算法结合起来为网络流量提供更高效的控制。

Nginx 如何限流?

在开发高并发系统时有三把利器用来保护系统:缓存、降级和限流

  • 缓存:目的是提升系统访问速度和增大系统处理容量。

  • 降级:当服务器压力剧增的情况时,根据当前业务情况及流量对一些服务和页面有策略的降级,以此释放服务器资源以保证核心任务的正常运行

  • 限流:通过对并发访问/请求进行限速,或者对一个时间窗口内的请求进行限速来保护系统,一旦达到限制速率则可以拒绝服务、排队或等待、降级等处理。

Nginx 的事件处理机制

nginx基于epoll模型事件驱动流程详解

扩展阅读

Nginx 从入门到实践,万字详解!