目录标题
前言
年轻的时候看到文章说到百万并发总是感慨万千,虽然很多文章都是标题上有两个字,但是也不妨碍我对这些的憧憬,到底怎么样才能扛百万并发呀?这系统该多么牛逼呀
但是接触多了高并发的系统,再系统学习这方面知识后 ,你就会发现 : 百万并发确实牛皮,但是也没有那么神秘。虽然有不少技术点,但是思路其实不难。
- 核心要点 :不论多大的流量,其最终的目的都是对流量进行分流,即负载均衡。
- 文章效果 :能对流量分发和负载均衡有一个全面的理解,但是细节方法的使用无法提供
高并发的应对方案:分而治之
- 高并发一定不是单台或者少量服务器扛得住的
高并发分到每台服务器上面并不会有海量的流量 - 高并发场景永远不会把服务器负载拉到顶峰
所以,高并发的核心是-负载均衡
宏观架构
- S1 : DNS 的特殊性 (Anycast)使得流量会自动流入最近得 DNS 集群,也是最重要得一层分流
- S2 : 由 DNS 下发到 LVS 负载中
- S3 : LVS 的流量瓶颈远大于更下游的负载均衡服务器 (Nginx),在这里再次进行一对多的下发
- S4 : 可以由 Nginx 下发到更下层的 SpringGateway ,也可以直接有 OpenResty / Kong 下发到实际的服务
- S5 : 如果是下发到 Spring Gateway ,则会再次分流一次
补充
- Nginx 代表的是一系列业务型的复杂均衡服务器,包括基础类型的 Nginx 或者带有更多复杂功能的 OpenResty / Kong
- 如果使用 OpenResty ,在一定程度上可以满足绝大多数业务,可以考虑不要 SpringGateway (毕竟Gateway的性能真的不算高),通过定制(当然要更复杂)实现自己的业务
所以,高并发的基础是DNS
细节解读
第一层 :DNS
DNS 是一切流量的起点,没有DNS的特殊特性,流量分发就会陷入单台性能无限拔高的死循环。
哪怕流量底层被分发的稀碎,在最开始就是实打实的百万流量,正常公司能用到的服务器里面,没有哪台能扛得住一次性这么大的流量,哪怕什么都不做。
那么 DNS 是怎么做到的呢 ?Anycast
Anycast 是什么 ?
Anycast(任播)是一种网络寻址和路由策略
,它允许多个服务器在全球范围内共享相同的IP地址
,并通过路由协议将用户请求路由到最近或最佳的服务器
。
可以回忆一下 DNS 的配置方式,小时候拨号上网的时候,往往需要把 DNS 配置到网络连接里面,才能保证网络的稳定,那个时候我们会配置2个IP ,一个主地址,一个备用地址。
而 Anycast 的特性就保证了最开始的流量
,不会压在一台DNS上面
,想想也是,全球 DNS根 IPV4 也就 13 台
DNS 里面配置多个 IP 映射
过了第一步,不同区域的人确实可以在不同的 DNS 服务器中找到对应域名映射的 IP 地址,但是其实每一台 DNS 里面配置的映射都是一样的,那么如果全部配置一个 IP ,那台 IP 对应的服务器还是会承受过大的压力。
由此引发了 DNS 第二个特性 : DNS 里面允许配置多个 IP 地址
。
通过DNS多 IP 地址映射从而让一个域名可以通过负载均衡的方式分发到合适的服务IP上
至此 DNS 完成了流量的第一次分流,基于这种方式,我们第一次将大量的流量按照区域相对均衡的分发到了不同的服务器上
DNS 分发 IP 的案例
- 以掘金为例,查询其 DNS 就能看到多个 IP 映射
- chrome://net-internals/#dns
第二层 : LVS 负载
在第二层我们可以通过 LVS 虚拟服务器对流量再次分流,LVS 现在已经集成到 Linux 系统中,并且技术已经完全成熟。 通过 LVS 负载配合 Linux 集群可以轻松的实现一个高性能,高可用的服务器集群。
VIP 是什么 ?
- VIP代表
Virtual IP
,也称为虚拟IP地址 - 用于接收来自客户端的请求,然后将这些请求转发到实际的后端服务器
- VIP 不会实际存在于任何物理服务器上,只用来代表整个集群
PS :这一点是不是特别像 DNS,脱离了抽象的个体就能够很方便的扩展集群。
主要流程是什么 ?
LVS 有多种路由均衡策略 ,从流程上说 LVS 主要流程如下 :
- S1 : 客户端发起请求,
请求到达 LVS 负载均衡器的虚拟 IP 地址
- S2 : LVS 通过
预定的均衡调度算法
计算出 可用转发的服务器
- S3 : 通过
路由模式
将客户端请求路由到被选中的后端服务器
- S4 : 后端服务器处理请求并且依次向上回传数据
支持的路由模式
- LVS-NAT : 将请求报文中的目标IP地址与目标端口修改,来实现报文的传送
- LVS-DR : 请求报文重新封装一个MAC首部进行转发,源MAC是DIP所在的接口的MAC,目标MAC是某挑选出的RS的RIP所在接口的MAC地址;源IP/PORT,以及目标IP/PORT均保持不变
- LVS-Tun :在原有的IP报文外再次封装多一层IP首部,内部IP首部(源地址为CIP,目标IIP为VIP),外层IP首部(源地址为DIP,目标IP为RIP)
这一块不细说太多,更细节的东西可以看看这一篇文档 : zhuanlan.zhihu.com/p/425662554
第三层 : Nginx
Nginx 应该是程序员接触最多的非Java体系的负载均衡器了 ,Nginx 功能太多了,包括不限定于 : Web 服务器,负载均衡,反向代理, Request二次操作等等。
用一个简单的 Demo 来说大概是这样 :
xml
http {
// 负载均衡路由的地址
upstream backend {
server backend1.example.com;
server backend2.example.com;
server backend3.example.com;
}
// 请求的域名
server {
listen 80;
server_name your_domain.com;
// 对路径进行代理
location / {
proxy_pass http://backend;
}
}
}
负载均衡里面既可以是域名,当然也可以是IP,只不过配置IP不太实用
一般情况下这里的域名都是企业自定义DNS里面再内部进行解析,属于内部操作,不会再绕一圈了
Nginx 支持的负载均衡模式
负载均衡算法 | 描述 |
---|---|
轮询(Round Robin) | 默认算法,将请求按顺序分发到后端服务器 |
加权轮询(Weighted Round Robin) | 基于权重分发请求,权重高的服务器获得更多请求 |
IP哈希(IP Hash) | 根据客户端IP地址将请求路由到后端服务器 |
最少连接(Least Connections) | 将请求发送到当前连接数最少的服务器 |
URL哈希(URL Hash) | 根据URL将请求分发到后端服务器,适用于缓存 |
基于URI的负载均衡 | 根据URI路径将请求分发到不同的后端服务器 |
随机(Random) | 随机选择一个后端服务器来处理请求 |
第四层 : Gateway Application
第四层就是我们常用的 SpringGateway 或者 Zuul ,当然这一层对负载均衡的能力就没那么强了。
这一层主要的工作是对请求的二次处理,例如安全认证,全链路ID这种。
但是由于实际处理耗时还是在应用服务端, 网关处理的运算很少,所以一台网关服务器把流量分发到少量的计算服务器里面是一点问题都没有的。
不过在这个模型里面,我们把它看成负载均衡的终点,也就是终端。
PS :SpringGateway 性能属实不高,主要为了实现纯Java的网关方案,按照这些年的了解,能到5000 QPS已经很牛了,日常业务2-3K的负载
并发上限
七层模型或多或少都听说过 ,它具有以下的几层 :
OSI 层次 | 名称 | 功能 | 协议和示例 |
---|---|---|---|
第七层 | 应用层 (Application) | 提供应用程序服务 | HTTP, FTP, SMTP |
第六层 | 表示层 (Presentation) | 数据格式转换和加密 | SSL/TLS, JPEG, MPEG |
第五层 | 会话层 (Session) | 建立、管理和终止会话 | NetBIOS, RPC |
第四层 | 传输层 (Transport) | 端到端数据传输 | TCP, UDP |
第三层 | 网络层 (Network) | 路由和数据包传输 | IP, ICMP, OSPF |
第二层 | 数据链路层 (Data Link) | 数据帧传输和物理寻址 | Ethernet, PPP |
第一层 | 物理层 (Physical) | 物理介质和比特流传输 | Ethernet, USB, DSL |
从理论上说,越接近一层的数据处理越单纯,效率越高。
- DNS 将Anycast IP 地址宣告到互联网的 BGP 路由表中 , 通过该路由表进行最近路由。不参与层数。
- LVS : 可以部署在第四层,通过检查TCP ,UDP 信息将请求进行路由 , 也可以部署在第七层,通过 HTTP 协议内容进行分发。
- Nginx : Nginx 通常情况下则会部署在第七层,直接通过处理HTTP请求进行负载均衡
从QPS来估计:
- LVS : 50万以下对它毫无压力 ,所以基本上不考虑性能问题
- Nginx / OpenResty : 对于日常业务,一般认为 10W 是比较靠谱的数据
- SpringGateway : 5000 就顶天了,3000 都比较优秀了,不需要文档,见得多了
更多方案
逐层分发是分流最常见的玩法,在这个环节中还有很多的扩展,比如
- OPFS 协议 : 开放式最短路径优先 ,更利于高效的负载均衡
- F5 是一个硬件级的负载均衡方案,性能也是非常出众的
- LBS : 阿里系的负载均衡,等同于 LVS
业务扩展
从域名角度如何承受更大的流量
很多公司都在把一个臃肿的集团划分为多个分公司进行自治,从而减少了整个体系的压力。同样一个庞大的操作系统也可以通过这种方式进行处理。
最简单的案例,之前看的CDN的处理方式中 ,CDN 的域名路径和动态请求的访问路径就不是同一个。
在这个思路基础上,我们可以对不同的服务体系进行划分,例如支付,订单,会员等等,他们通常在微服务体系里面归属不同的 Module ,本身耦合性不强,同样可以通过不同的域名进行访问,对流量进行合理的分流。
从业务的角度看如何分流大的流量
仔细观察双十一的活动,就会发现双十一从一天的集中活动变成持续半个月的长期活动,虽然当天的活动量会更大,但是基本上提前半个月就预热了。
这其实也是一种刻意的分流方式,之前看过一篇文章,每年双十一流量都会更高,就导致要求的并发需求越来越高,哪怕再多的服务器,也给整体运维带来了很大的难度。
所以如果能把流量引导在其他的时间段上,同样可以极大减少峰值。
总结
一味的拉高流量峰值会消耗大量的硬件资源,哪怕自动缩容也会在闲时浪费大量算力,将流量从业务层面和时间维度进行分流比优化系统能带来更大的收益