系统设计之负载均衡

系统设计之负载均衡

针对分布式系统横向扩展,通常使用集群,可以使web应用服务器集群,也可以

将负载(访问请求)“均衡”地分配到多个处理节点,这样可以减少单个处理节点的请求量,提升整体系统的性能。

  • DNS负载均衡
  • 代理类的负载均衡
  • 客户端的负载均衡

DNS 负载均衡

A记录, 将特定的主机名映射到对应主机的IP地址上。

域名配置多个A记录,每次域名解析请求都会根据对应的负载均衡算法计算出一个不同的IP地址并返回,这样A记录中配置多个服务器就可以构成一个集群,并可以实现负载均衡

优点:

省去了网站管理维护负载均衡服务器的麻烦,技术实现比较灵活、方便,简单易行,成本低,使用于大多数TCP/IP应用。

DNS可以支持基于地理位置的域名解析,会将域名解析成距离用户地理最近的一个服务器地址,这样就可以加速用户访问,改善性能。

缺点:

DNS是多级解析的,每一级DNS都可能缓存A记录,当某台服务器下线之后,即使修改了A记录,要使其生效也需要较长的时间,这段时间,DNS仍然会将域名解析到已下线的服务器上,最终导致用户访问失败。

不能够按服务器的处理能力来分配负载。DNS负载均衡采用的是简单的轮询算法,不能区分服务器之间的差异,不能反映服务器当前运行状态,所以负载均衡效果并不是太好。

异地多活

灾备,持续可用。

常用两地三中心,数据中心A,数据中心B位于同城,用户访问随机访问到A或B。A和B同步数据复制,保持consistency。由于同步复制,对数据中心距离有要求,需要两个数据中心必须在同城,或者距离很近的另一城市。异地备份通过异步,正常情况下不对外提供服务。

对于数据一致性要求不高的情况,多地的数据中心同步,并且均提供对外服务。可用DNS作为一级负载均衡到不同数据中心,数据中心再使用二级负载均衡器。


代理类的负载均衡

  • HAProxy
  • LVS ( Linux Virtual Server )
  • nginx

HAProxy

HAProxy 支持两种代理模式 TCP(四层)和HTTP(七层)

HAProxy 跟 LVS 类似,本身就只是一款负载均衡软件;单纯从效率上来讲 HAProxy 会比 Nginx 有更出色的负载均衡速度,在并发处理上也是优于 Nginx 的。

HAProxy 支持 TCP 协议的负载均衡转发,可以对 MySQL 读进行负载均衡,对后端的 MySQL 节点进行检测和负载均衡,大家可以用 LVS+Keepalived 对 MySQL 主从做负载均衡。

LVS

LVS 是四层(传输层)负载均衡,要通过报文中的目标地址和端口,效率高。因为是在传输层,因此几乎可以针对所有应用场景做负载均衡,http,数据库流量等等。。。

缺点:不能针对url做更为细致的分发,无法探测后端服务示范存活

(OSI 网络模型把整个网络分成了七层,自下而上分别是物理层、数据链路层、网络层、传输层、会话层、表示层和应用层)

Nginx

七层(应用层)的负载均衡,适用于http,以反向代理的方式进行负载均衡。

(反向代理:接受公网的请求,nginx将请求转发到内部网络的服务器,将服务器得到的结果返回;内部网络的服务器不暴露给公网访问)

优点:配置灵活,可以感知后端健康状态。

缺点:性能低于四层负载均衡。

如何探测服务节点可用

阿里开源nginx_upstream_check_module

定期地探测后端服务的一个指定的接口,然后根据返回的状态码来判断服务是否还存活。当探测不存活的次数达到一定阈值时,就自动将这个后端服务从负载均衡服务器中摘除。

upstream server { 
server 192.168.1.1:8080;
server 192.168.1.2:8080;
check interval=3000 rise=2 fall=5 timeout=1000 type=http default_down=true;//检测间隔为3秒,检测超时时间是1秒,使用http协议。如果连续失败次数达到5次就认为服务不可用;如果连续成功次数达到2次,则认为服务可用。后端服务刚启动时状态是不可用的
check_http_send "GET /health_check HTTP/1.0\r\n\r\n"; //检测URL
check_http_expect_alive http_2xx; //检测返回状态码为200时认为检测成功}

负载均衡策略:

Round robin

轮询,nginx的默认负载均衡策略。例如三台服务器A、B、C,请求依次分发到A、B、C。

Weighted_Round_Robin

轮询的策略可以做到将请求尽量平均地分配到所有服务节点上,但是,它没有考虑服务节点的具体配置情况。比如,你有三个服务节点,其中一个服务节点的配置是 8 核 8G,另外两个节点的配置是 4 核 4G,那么如果使用轮询的方式来平均分配请求的话,8 核 8G 的节点分到的请求数量和 4 核 4G 的一样多,就不能发挥性能上的优势

加权轮询, 如下配置

upstream backend {
server 172.168.0.1 weight=8;
server 172.168.0.2 weight=1;
server 172.168.0.3 weight=1;
}

IP_hash

对IP进行hash,某个IP来的请求会分配到固定的节点

Least Connection

选择连接数最少的服务器节点优先负载

第三方

url_hash是nginx的第三方模块, 按访问url的hash结果来分配请求,使每个url定向到同一个后端服务器

fail,按后端服务器的响应时间来分配请求,响应时间短的优先分配。

LVS + Nginx

可以使用LVS+nginx 做负载均衡,LVS在入口处承担大流量的分发,Nginx 要部署在业务服务器之前做更细维度的请求分发。


客户端负载均衡

针对微服务,尤其是RPC调用,通常服务节点存储在注册中心中(服务发现),代理类的负载均衡很难结合服务注册中心获取完整、最新的节点列表。

客户端可以从注册中心获取最新的节点列表,根据一定策略选取合适的节点,发送请求。

Screen Shot 2020-10-14 at 11.04.57 PM

eg:Spring Cloud的 ribbon的weightedResponseTimeRule 是使用响应时间给每个服务节点计算一个权重,然后依据这个权重,来给调用方分配服务节点。


Reference

https://zhuanlan.zhihu.com/p/76918261

Screen Shot 2020-10-15 at 4.07.56 PM