vlambda博客
学习文章列表

分布式基础-负载均衡

前言

我理解要分布式系统,无非两个原因数据和计算,单机系统无法保存这么大的数据量,所以要分布式系统来保存; 计算嘛,就是说单机计算无法达到性能要求,比如双十一一台机器肯定处理不过来,所以需要后台一系列复杂的分布式系统来解决。

前面有聊过一篇关于分布式存储的,就是讲数据如何划分到不同的机器上,这一篇也类似,说到底是将计算分布到不同的机器上。

一 负载均衡

负载均衡,这里面的负载可以是数据,也可以是请求,如果是数据,就是原来的数据分片存储,也就是将一堆数据如何均衡地保存到各个分布式节点上;更多时候讲负载均衡是将计算的负载均衡,将请求处理或计算均衡到不同的节点上去。只所以这样分,请求是类似于 Nginx 分发 HTTP 请求,后台的应用程序是启动的独立的服务,处理结果立刻返回;而计算,比如说我们常见的 spark 运行任务,将任务分派到不同的节点上,这里还利用了数据本地性原理,搬迁数据不如搬迁程序,将程序发到各个节点上执行,执行结果往往是保存本地或发 kafka 或者通过管道传递给下游系统。同时注意,负载均衡不完全是指性能的均衡,有时候还要考虑业务均衡,不同的任务分片算法目标不一样;负载均衡也不无完全只有分布式系统才有负载均衡,相同的业务同时开启两个以及以上的服务节点都可以做均衡,这些节点并不一定要组成分布式系统。

常见的有三类负载均衡:DNS 负载均衡,软件负载均衡,硬件负载均衡;还有按照负载均衡所属层次来分,又分为四层负载均衡,七层负载均衡。

1.1 DNS 负载均衡

DNS 负载均衡比较简单是依赖于 DNS 服务器来实现的,DNS 服务器配置一个域名对应多个 IP,DNS 根据一定的负载均衡算法来实现负载均衡,具体如下示意图:

优点

  1. 简单,将负载均衡的任务交给 DNS 服务器,应用服务器不用做任何调整。
  2. DNS 服务器可以根据用户位置来返回就近的地址,加快访问速度。

缺点

  1. DNS 是分级存储的,每级都可能缓存 A 纪录,如果一个服务器下线,即使修改 A 纪录,DNS 服务器要等待缓存失效还需要一段时间,在这段时间内访问都会失败。
  2. DNS 服务器对后台的服务器无感知,无法确定后台服务器的压力情况,通过简单的就近原则或轮询策略,有可能会造成压力大的服务器压力越来越大。
  3. 扩展性比较差,无法根据业务特点做负载均衡。

1.2 硬件负载均衡

硬件负载均衡是一个单独的硬件,常见的 F5 系列,A10 系列等,功能强大,但是也非常贵,价格从十多万到几十万,如下图:优点

  1. 功能强大,支持协议层数多,均衡算法多,还支持各种加密等。
  2. 性能好,支持并发能力在 100 万以上,在 200 万到 800 万左右,看下上面 98 万的 F5 的部分性能指标:

    每秒 L7 请求数:1M 每秒 L4 连接数:400K 每秒 L4 HTTP 请求数:7M 最大 L4 并发连接数:24M L4 吞吐量:40Gbps L7 吞吐量:18Gbps 最大软件压缩:10Gbps

缺点

  1. 缺点贵。
  2. 如果不支持的功能,就无法扩展实现。

1.3 软件负载均衡

主流有三种软件负载均衡(LVS,Nginx,HAproxy)。LVS 是 Linux virtual Server 简称, 1998 年 5 月由章文嵩博士发起的自由软件项目,现在博士本人在滴滴任高级副总裁。

LVS原理

LVS 的原理是通过链来实现,过程如下简单描述下:

  1. 客户端通过访问虚拟 IP,首先到达 PREROUTING 链。
  2. 内核发现是本机地址后,数据包发送给 INPUT 链,IPVS 工作在 INPUT 链上,如果数据包的目标地址和端口没在规则中,数据包经过 INPUT 链送到用户空间;
  3. 如果在规则中,则根据规则将目标地址改成真实的服务器地址,将报文发送到 POSTROUTING 链中
  4. 经由 POSTROUTING 链发送到后端的应用服务器。
  5. 响应时候,将源 ip 经由这个服务器(DirectorServer)改成 VIP 返回给客户端。

优点

  1. 性能好,可以达到 80 万/s,对内存和资源消耗低。
  2. 稳定性,可靠性高,自身有热备方案 Keepalived。
  3. 工作在四层上,性能好,几乎所有的协议都可用。

缺点

  1. 伸缩能力一般,Director 本身可能就成为系统瓶颈。
  2. 不能完全判断节点故障。

1.4 Nginx 负载均衡

Nginx 支持四层和七层负载均衡,可以支持 HTTP/EMAIL 等。优点:

  1. 搭建比较简单,维护和部署都很简单。
  2. 便宜,开源产品,不需要购买单独硬件。
  3. 可以根据后台服务器的情况做灵活调整,可以自己开发相关插件。比如可以把请求发到连接最少的服务上,可以根据响应时间有限分配。
# 简单轮询
upstream  dalaoyang-server {
       server    localhost:10001;
       server    localhost:10002;
}

#带权重的轮询
upstream  dalaoyang-server {
       server    localhost:10001 weight=1;
       server    localhost:10002 weight=2;
}
#ip hash
upstream  dalaoyang-server {
       ip_hash;
       server    localhost:10001 weight=1;
       server    localhost:10002 weight=2;
}
#最少连接
upstream  dalaoyang-server {
       least_conn;
       server    localhost:10001 weight=1;
       server    localhost:10002 weight=2;
}
#响应时间最短优先
upstream  dalaoyang-server {
       server    localhost:10001 weight=1;
       server    localhost:10002 weight=2;
       fair;
}
  1. 可以支持各种算法,比如简单轮询,根据权重轮询,可以结合 ip 做 hash 轮询。

缺点:

  1. 性能相对于硬件负载均衡和LVS差了些。

二 负载均衡中的算法

2.1 轮询算法

轮询算法是最简单的算法,每个请求过来之后按照服务器的顺序轮着发,这样是最均衡的了,但是这种均衡类似于大锅饭,不是真正的均衡,如果按照哈希算法来讲的话,我觉得是第 N 个请求对服务器总数取模,这种简单的算法;

不同的服务器可能性能不一样,所以就有了带权重的轮询算法,如上面 Nginx 配置,可以根据机器的性能不同设置不同的轮询算法,最简单的带权重的轮询算法,我们可以将一个性能好的服务器划分为多个性能差的虚拟服务器,然后再用轮询算法进行轮询即可。

优点:

  1. 算法比较简单,性能比较高,在同构机器环境下,负载很均衡。

缺点:

  1. 如果请求需要的资源不同,比如一个请求更消耗 CPU,另外一个更需要内存,简单轮询不利于任务的运行。
  2. 由于采用轮询算法,同一个客户端发起两次请求不一定由相同的机器处理,那就会造成缓存失效等问题。

此算法适应于请求所需的资源比较接近场景,最好机器也是同构的机器。Nginx 里面使用各种改进的轮询策略进行负载均衡。

2.2 哈希和一致性哈希策略

为防止缓存失效,我们希望一个客户端的请求落到一台服务器处理。我们可以使用以前说的带负载的哈希算法和一致性哈希算法,设置合理的话,负载会很均衡,而且相同的客户端发起的请求落到同一个服务器处理,缓存不会失效。

如果没有采用一致性哈希算法,每次一台机器发生故障后,大量请求会重新定位到不同的机器上,缓存一样失效,可能会造成一些机器的压力过大问题。

缺点还有同样没有根据任务的资源使用情况来分配机器。

2.3 随机策略

请求过来之后,随机挑选存活服务器进行任务的派发。好处是简单,缺点更多,首先每次相同的客户端不一定到达相同的服务器端,不利于缓存数据;没有考虑到服务器的性能差异问题;同样对任务的种类也没有区分。

2.4 资源调度

负载均衡无法是将资源分配给任务,前几种策略没有多细致地关注后台节点的资源实时使用情况,可能会造成闲的很闲,忙的很忙的情况。所以就有了资源调度框架,像 yarn,mesos 等资源管理框架,通过收集节点的资源占用情况,再根据任务特点,比如是消耗 cpu 还是消耗内存,更合理地精细化地调度任务,这也算一种负载均衡策略,由于比较复杂,有空聊聊吧。

三 古诗词欣赏

 狱中题壁
      [清代] [谭嗣同]

望门投止思张俭,忍死须臾待杜根。
我自横刀向天笑,去留肝胆两昆仑。(版本一)

望门投趾怜张俭,直谏陈书愧杜根。
手掷欧刀仰天笑,留将公罪后人论。(版本二)

今天是 9.18 , 今日中国是否可以令先辈们有所宽慰;不过美国对中国的公司的打压是一个接着一个,我辈还当自强!