写点什么

一文读懂什么是 Nginx?它能否实现 IM 的负载均衡?

作者:JackJiang
  • 2025-02-07
    江苏
  • 本文字数:6932 字

    阅读完需:约 23 分钟

一文读懂什么是Nginx?它能否实现IM的负载均衡?

1、引言

Nginx(及其衍生产品)是目前被大量使用的服务端反向代理和负载均衡方案,从某种意义上来讲,Nginx 几乎是低成本、高负载 Web 服务端代名词。

如此深入人心的 Nginx,很多人也想当然的认为,在 IM 或消息推送等场景下是否也能使用 Nginx 来解决负载均衡问题?

另外,即时通讯网的论坛和QQ群里也经常有人问起,Nginx 是否能支持 TCP、UDP、WebSocket 的负载均衡?

带着上面的疑问,我们来开始本文的学习吧!

2、知识准备

《TCP/IP 详解 - 第 11 章·UDP:用户数据报协议》

《TCP/IP 详解 - 第 17 章·TCP:传输控制协议》

《TCP/IP 详解 - 第 18 章·TCP 连接的建立与终止》

《TCP/IP 详解 - 第 21 章·TCP 的超时与重传》

《通俗易懂-深入理解 TCP 协议(上):理论基础》

《网络编程懒人入门(三):快速理解 TCP 协议一篇就够》

《新手快速入门:WebSocket 简明教程》

《WebSocket 详解(一):初步认识 WebSocket 技术》

《快速理解高性能 HTTP 服务端的负载均衡技术原理》

《腾讯资深架构师干货总结:一文读懂大型分布式系统设计的方方面面》

《一篇读懂分布式架构下的负载均衡技术:分类、原理、算法、常见方案等》

《新手入门:零基础理解大型分布式架构的演进历史、技术原理、最佳实践》

《通俗易懂:基于集群的移动端 IM 接入层负载均衡方案分享》

3、Nginx 的产生

没有听过Nginx?那么一定听过它的"同行"Apache吧!Nginx 同 Apache 一样都是一种 WEB 服务器。基于 REST 架构风格,以统一资源描述符(Uniform Resources Identifier)URI 或者统一资源定位符(Uniform Resources Locator)URL 作为沟通依据,通过 HTTP 协议提供各种网络服务。

然而,这些服务器在设计之初受到当时环境的局限,例如当时的用户规模,网络带宽,产品特点等局限并且各自的定位和发展都不尽相同。这也使得各个 WEB 服务器有着各自鲜明的特点。

Apache 的发展时期很长,而且是毫无争议的世界第一大服务器。它有着很多优点:稳定、开源、跨平台等等。它出现的时间太长了,它兴起的年代,互联网产业远远比不上现在。所以它被设计为一个重量级的。它不支持高并发的服务器。在 Apache 上运行数以万计的并发访问,会导致服务器消耗大量内存。操作系统对其进行进程或线程间的切换也消耗了大量的 CPU 资源,导致 HTTP 请求的平均响应速度降低。

这些都决定了 Apache 不可能成为高性能 WEB 服务器,轻量级高并发服务器 Nginx 就应运而生了。

俄罗斯的工程师 Igor Sysoev,他在为 Rambler Media 工作期间,使用 C 语言开发了 Nginx。Nginx 作为 WEB 服务器一直为 Rambler Media 提供出色而又稳定的服务。

▲ Igor Sysoev,Nginx 的创始人

然后呢,Igor Sysoev 将 Nginx 代码开源,并且赋予自由软件许可证。

由于以下原因:

  • 1)Nginx 使用基于事件驱动架构,使得其可以支持数以百万级别的 TCP 连接;

  • 2)高度的模块化和自由软件许可证使得第三方模块层出不穷(这是个开源的时代啊~);

  • 3)Nginx 是一个跨平台服务器,可以运行在 Linux,Windows,FreeBSD,Solaris,AIX,Mac OS 等操作系统上;

  • 4)这些优秀的设计带来的是极大的稳定性。

所以,Nginx 火了!

4、Nginx 最常见的用途、用法、使用场景

4.1 概述

简而言之,Nginx 是:

  • 1)自由的、开源的、高性能的 HTTP 服务器和反向代理服务器;

  • 2)也是一个 IMAP、POP3、SMTP 代理服务器;

  • 3)可以作为一个 HTTP 服务器进行网站的发布处理;

  • 4)可以作为反向代理进行负载均衡的实现。

4.2 什么是代理?

说到代理,首先我们要明确一个概念,所谓代理就是一个代表、一个渠道。

此时就涉及到两个角色,一个是被代理角色,一个是目标角色,被代理角色通过这个代理访问目标角色完成一些任务的过程称为代理操作过程;如同生活中的专卖店~客人到 adidas 专卖店买了一双鞋,这个专卖店就是代理,被代理角色就是 adidas 厂家,目标角色就是用户。

4.3 什么是正向代理?

说反向代理之前,我们先看看正向代理,正向代理也是大家最常接触的到的代理模式,我们会从两个方面来说关于正向代理的处理模式,分别从软件方面和生活方面来解释一下什么叫正向代理。

在如今的网络环境下,我们如果由于技术需要要去访问国外的某些网站,此时你会发现位于国外的某网站我们通过浏览器是没有办法访问的,此时大家可能都会用一个操作 FQ 进行访问,FQ 的方式主要是找到一个可以访问国外网站的代理服务器,我们将请求发送给代理服务器,代理服务器去访问国外的网站,然后将访问到的数据传递给我们!

上述这样的代理模式称为正向代理:

  • 1)正向代理最大的特点是客户端非常明确要访问的服务器地址;

  • 2)服务器只清楚请求来自哪个代理服务器,而不清楚来自哪个具体的客户端;

  • 3)正向代理模式屏蔽或者隐藏了真实客户端信息。

来看个示意图(我把客户端和正向代理框在一块,同属于一个环境,后面我有介绍):

客户端必须设置正向代理服务器,当然前提是要知道正向代理服务器的 IP 地址,还有代理程序的端口。

如下图所示:

总结来说:正向代理,"它代理的是客户端,代客户端发出请求",是一个位于客户端和原始服务器(origin server)之间的服务器,为了从原始服务器取得内容,客户端向代理发送一个请求并指定目标(原始服务器),然后代理向原始服务器转交请求并将获得的内容返回给客户端。客户端必须要进行一些特别的设置才能使用正向代理。

正向代理的用途:

  • 1)访问原来无法访问的资源,如 Google;

  • 2) 可以做缓存,加速访问资源;

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

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

4.4 什么是反向代理?

明白了什么是正向代理,我们继续看关于反向代理的处理方式。

举例如我大天朝的某宝网站,每天同时连接到网站的访问人数已经爆表,单个服务器远远不能满足人民日益增长的购买欲望了,此时就出现了一个大家耳熟能详的名词:分布式部署。

所谓分布式部署,也就是通过部署多台服务器来解决访问人数限制的问题。某宝网站中大部分功能也是直接使用 Nginx 进行反向代理实现的,并且通过封装 Nginx 和其他的组件之后起了个高大上的名字:Tengine,有兴趣的童鞋可以访问 Tengine 的官网查看具体的信息:http://tengine.taobao.org/

那么反向代理具体是通过什么样的方式实现的分布式的集群操作呢,我们先看一个示意图(我把服务器和反向代理框在一块,同属于一个环境,后面我有介绍),如下图所示。

通过上述的图解大家就可以看清楚了:多个客户端给服务器发送的请求,Nginx 服务器接收到之后,按照一定的规则分发给了后端的业务处理服务器进行处理了。此时~请求的来源也就是客户端是明确的,但是请求具体由哪台服务器处理的并不明确了,Nginx 扮演的就是一个反向代理角色。

客户端是无感知代理的存在的,反向代理对外都是透明的,访问者并不知道自己访问的是一个代理。因为客户端不需要任何配置就可以访问。

反向代理,"它代理的是服务端,代服务端接收请求",主要用于服务器集群分布式部署的情况下,反向代理隐藏了服务器的信息。

反向代理的作用:

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

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

典型的项目场景:

通常情况下,我们在实际项目操作时,正向代理和反向代理很有可能会存在在一个应用场景中,正向代理代理客户端的请求去访问目标服务器,目标服务器是一个反向单利服务器,反向代理了多台真实的业务处理服务器。

具体的拓扑图如下:

4.5 正向代理和反向代理的区别

截了一张图来说明正向代理和反向代理二者之间的区别,如下图。

图解如下:

  • 1)在正向代理中,Proxy 和 Client 同属于一个 LAN(图中方框内),隐藏了客户端信息;

  • 2)在反向代理中,Proxy 和 Server 同属于一个 LAN(图中方框内),隐藏了服务端信息。

实际上,Proxy 在两种代理中做的事情都是替服务器代为收发请求和响应,不过从结构上看正好左右互换了一下,所以把后出现的那种代理方式称为反向代理了。

4.6 Nginx 的负载均衡技术

我们已经明确了所谓代理服务器的概念,那么接下来,Nginx 扮演了反向代理服务器的角色,它是以依据什么样的规则进行请求分发的呢?不用的项目应用场景,分发的规则是否可以控制呢?

这里提到的客户端发送的、Nginx 反向代理服务器接收到的请求数量,就是我们说的负载量。

请求数量按照一定的规则进行分发到不同的服务器处理的规则,就是一种均衡规则。

所以~将服务器接收到的请求按照规则分发的过程,称为负载均衡。

负载均衡在实际项目操作过程中,有硬件负载均衡和软件负载均衡两种,硬件负载均衡也称为硬负载,如 F5 负载均衡,相对造价昂贵成本较高,但是数据的稳定性安全性等等有非常好的保障,如中国移动中国联通这样的公司才会选择硬负载进行操作;更多的公司考虑到成本原因,会选择使用软件负载均衡,软件负载均衡是利用现有的技术结合主机硬件实现的一种消息队列分发机制。

Nginx 支持的负载均衡调度算法方式如下:

  • 1)weight 轮询(默认,常用):接收到的请求按照权重分配到不同的后端服务器,即使在使用过程中,某一台后端服务器宕机,Nginx 会自动将该服务器剔除出队列,请求受理情况不会受到任何影响。 这种方式下,可以给不同的后端服务器设置一个权重值(weight),用于调整不同的服务器上请求的分配率;权重数据越大,被分配到请求的几率越大;该权重值,主要是针对实际工作环境中不同的后端服务器硬件配置进行调整的。

  • 2)ip_hash(常用):每个请求按照发起客户端的 ip 的 hash 结果进行匹配,这样的算法下一个固定 ip 地址的客户端总会访问到同一个后端服务器,这也在一定程度上解决了集群部署环境下 session 共享的问题。

  • 3)fair:智能调整调度算法,动态的根据后端服务器的请求处理到响应的时间进行均衡分配,响应时间短处理效率高的服务器分配到请求的概率高,响应时间长处理效率低的服务器分配到的请求少;结合了前两者的优点的一种调度算法。但是需要注意的是 Nginx 默认不支持 fair 算法,如果要使用这种调度算法,请安装 upstream_fair 模块。

  • 4)url_hash:按照访问的 url 的 hash 结果分配请求,每个请求的 url 会指向后端固定的某个服务器,可以在 Nginx 作为静态服务器的情况下提高缓存效率。同样要注意 Nginx 默认不支持这种调度算法,要使用的话需要安装 Nginx 的 hash 软件包。

5、Nginx 对 TCP、UDP、WebSocket 的负载均衡支持

5.1 概述

准确地说,对于熟悉 Nginx 的使用者来讲,上面的章节所介绍的内容都是针对 Nginx 最擅长的 Http 协议来讲的,这也是 Nginx 最为成功的应用场景。随着 Nginx 的不断升级和进化,开发者们对于 Nginx 能支持更为底层的 TCP、UDP 以及 HTML5 里才出现的 WebSocket 协议颇为期待,好在这一切已经成真!

Nginx 从 1.3 版开始支持 WebSocket 协议的反向代理(负载均衡),从 1.9.0 版本开始支持 TCP 协议反向代理(负载均衡),从 1.9.13 开始支持 UDP 协议反向代理(负载均衡)。

从原理上说,Nginx 对于 UDP 或 TCP 的反向代理(负载均衡)是一致的,而 WebSocket 协议实际是就是 TCP 协议的应用层协议,因此本节我们将介绍 Nginx 对 TCP 协议反向代理(负载均衡)的支持。

Nginx 对于经典的 HTTP 协议,也就是我们通常所说的“七层负载均衡”,它实际上工作在第七层“应用层”。而对于更为底层的 TCP 协议来说,负载均衡就是我们通常所说的“四层负载均衡”,工作在“网络层”和“传输层”。例如,LVS(Linux Virtual Server,Linux 虚拟服务)和 F5(一种硬件负载均衡设备),也是属于“四层负载均衡”。

5.2 TCP 负载均衡的执行原理

当 Nginx 从监听端口收到一个新的客户端链接时,立刻执行路由调度算法,获得指定需要连接的服务 IP,然后创建一个新的上游连接,连接到指定服务器。

TCP 负载均衡支持 Nginx 原有的调度算法,包括 Round Robin(默认,轮询调度),哈希(选择一致)等。同时,调度信息数据也会和健壮性检测模块一起协作,为每个连接选择适当的目标上游服务器。如果使用 Hash 负载均衡的调度方法,你可以使用 $remote_addr(客户端 IP)来达成简单持久化会话(同一个客户端 IP 的连接,总是落到同一个服务 server 上)。

和其他 upstream 模块一样,TCP 的 stream 模块也支持自定义负载均和的转发权重(配置“weight=2”),还有 backup 和 down 的参数,用于踢掉失效的上游服务器。max_conns 参数可以限制一台服务器的 TCP 连接数量,根据服务器的容量来设置恰当的配置数值,尤其在高并发的场景下,可以达到过载保护的目的。

Nginx 监控客户端连接和上游连接,一旦接收到数据,则 Nginx 会立刻读取并且推送到上游连接,不会做 TCP 连接内的数据检测。Nginx 维护一份内存缓冲区,用于客户端和上游数据的写入。如果客户端或者服务端传输了量很大的数据,缓冲区会适当增加内存的大小。



当 Nginx 收到任意一方的关闭连接通知,或者 TCP 连接被闲置超过了 proxy_timeout 配置的时间,连接将会被关闭。对于 TCP 长连接,我们更应该选择适当的 proxy_timeout 的时间,同时,关注监听 socke 的 so_keepalive 参数,防止过早地断开连接。

5.3 服务健壮性监控

TCP 负载均衡模块支持内置健壮性检测,一台上游服务器如果拒绝 TCP 连接超过 proxy_connect_timeout 配置的时间,将会被认为已经失效。在这种情况下,Nginx 立刻尝试连接 upstream 组内的另一台正常的服务器。连接失败信息将会记录到 Nginx 的错误日志中。

如果一台服务器,反复失败(超过了 max_fails 或者 fail_timeout 配置的参数),Nginx 也会踢掉这台服务器。服务器被踢掉 60 秒后,Nginx 会偶尔尝试重连它,检测它是否恢复正常。如果服务器恢复正常,Nginx 将它加回到 upstream 组内,缓慢加大连接请求的比例。

之所“缓慢加大”,因为通常一个服务都有“热点数据”,也就是说,80%以上甚至更多的请求,实际都会被阻挡在“热点数据缓存”中,真正执行处理的请求只有很少的一部分。在机器刚刚启动的时候,“热点数据缓存”实际上还没有建立,这个时候爆发性地转发大量请求过来,很可能导致机器无法“承受”而再次挂掉。以 mysql 为例子,我们的 mysql 查询,通常 95%以上都是落在了内存 cache 中,真正执行查询的并不多。

其实,无论是单台机器或者一个集群,在高并发请求场景下,重启或者切换,都存在这个风险。

解决的途径主要是两种:

  • 1)请求逐步增加,从少到多,逐步积累热点数据,最终达到正常服务状态;

  • 2)提前准备好“常用”的数据,主动对服务做“预热”,预热完成之后,再开放服务器的访问。

TCP 负载均衡原理上和 LVS 等是一致的,工作在更为底层,性能会高于原来 HTTP 负载均衡不少。但是,不会比 LVS 更为出色,LVS 被置于内核模块,而 Nginx 工作在用户态,而且,Nginx 相对比较重。

6、Nginx 能否实现 IM 的负载均衡?

6.1 概述

从上一节内容来看,Nginx 是可以实现 TCP、UDP、WebSocket 协议的反向代码(负载均衡)的,既然如此,那么基于 TCP、UDP 或者 WebSocket 协议的 IM 聊天系统来说,是否能通过 Nginx 直接实现 IM 的负载均衡呢?

要回答这个问题,我们首先来不同的长连接场景下,具体的数据走向情况。

为了方便叙述,以下基于 TCP、UDP 或者 WebSocket 协议实现的 socket 长连接,我们简称为 socket 长连接。

6.2 Nginx 所支持的长连接反向代理数据走向能力

对于利于 Nginx 实现的 socket 长连接,数据走向如下图所示:

如上图,即:

  • 1)客户端通过 Nginx 反向代理到一台 socket 长连接服务器;

  • 2)客户端可以与建立连接的 socket 长连接服务器进行双向通信(即客户端->socket 长连接服务器、和 socket 长连接服务器->客户端两个方向)。

简而言之,Nginx 能实现的长连接数据走向能力为:

  • 1)Client to Server 方向(简称 c2s):即客户端向长连接服务端发送数据的能力;

  • 2)Server to Client 方向(简称 s2c):即长连接服务端向客户端发送数据的能力。

6.3 IM 聊天软件需要的长连接数据走向能力

对于 IM 聊天应用来说,必须具备的数据走向能力为:

  • 1)Client to Server 方向(简称 c2s):即客户端向长连接服务端发送数据的能力;

  • 2)Server to Client 方向(简称 s2c):即长连接服务端向客户端发送数据的能力;

  • 3)Client to Client 方向(简称 c2c):即客户端向客户端发送数据的能力。

IM 聊天应用中的 3 种数据走向,对应的典型功能逻辑场景:

  • 1)Client to Server 方向(简称 c2s):通常用于客户端向 IM 长连接服务端发起指令,比如:发起加好友请求、发送一条陌生人聊天消息、发送一条群聊消息等;

  • 2)Server to Client 方向(简称 s2c):通常用于服务端主动向客户端推送指令,比如:向客户端转达加好友请求、转发陌生人聊天消息、扩散写式的发送群聊消息(给所有群成员)、系统通知等;

  • 3)Client to Client 方向(简称 c2c):即客户端向客户端发送数据的能力,比如:一条正常的好友聊天消息就是由客户端 A 发送给客户端 B(当然这不一定是 P2P 技术实现)。

6.4 结论

显然,如上节所讲,Nginx 所实现的 TCP、UDP 或者 WebSocket 协议的反向代理(负载均衡),只能实现 c2s、s2c 两种数据走向,而 IM 聊天应用中是必须需要 c2s、s2c、c2c 共 3 种消息走向。对于 c2c 这种数据走向,显然是 IM 特有的场景需求,要让 Nginx 这种通用解决方案来提供,就有点牵强了。

我们可以得出结论:我们是无法通过 Nginx 直接实现 IM 的负载均衡的。

换句话讲,如果真能通过 Nginx 直接实现 IM 的负载均衡,那 IM 的服务端在处理高并发、高吞吐时,就可以像 Http 协议一样安逸啦!(本文已同步发布于:http://www.52im.net/thread-2600-1-1.html

6.5 例外

不过,对于即时通讯网所关注的另一技术范畴——消息推送系统(或类似系统),是完全可以通过 Nginx 直接实现消息推送的负载均衡的,因为恰好消息推送系统也只需要 c2s、s2c 两种数据走向,并不需要 c2c 这种横向的数据交互。

用户头像

JackJiang

关注

还未添加个人签名 2019-08-26 加入

开源IM框架MobileIMSDK、BeautyEye的作者。

评论

发布
暂无评论
一文读懂什么是Nginx?它能否实现IM的负载均衡?_网络编程_JackJiang_InfoQ写作社区