半步多 玄玉的博客

小结扩容方案与负载均衡和吞吐量延迟

2024-04-21
玄玉

扩容方案

常见的几个名词释义:

  • DNS轮询:通过在 DNS-server 上对一个域名设置多个 IP 解析,来扩充 web-server 性能及实施负载均衡的技术
  • Nginx:一个高性能的 web-server 和实施反向代理的软件
  • Keepalived:一款用来检测服务状态存活性的软件,常用来做高可用
  • F5:一个高性能、高可用、负载均衡的硬件设备
  • LVS:Linux Virtual Server,使用集群技术,实现在 linux 操作系统层面的一个高性能、高可用、负载均衡服务器

简易方案DNS轮询

多部署几个 web-server,然后在 DNS-server 层面将域名每次解析到不同的 IP

优点:

  1. 零成本:在 DNS-server 上多配几个 IP 即可,功能也不收费
  2. 部署简单:多部署几个 web-server 即可,原系统架构不需要做任何改造
  3. 负载均衡:变成了多机,但负载基本是均衡的

缺点:

  1. 非高可用:DNS-server 只负责域名解析 IP,这个 IP 对应的服务是否可用,它是不保证的
  2. 扩容非实时:DNS解析有一个生效周期
  3. 暴露了太多的外网 IP

简易方案Nginx

利用高性能的 Nginx 来做反向代理,Nginx 将请求分发给后端多个 web-server

优点:

  1. DNS-server 不需要动
  2. 负载均衡:通过 Nginx 来保证
  3. 只暴露一个外网IP:Nginx 到 Tomcat 之间使用内网访问
  4. 扩容实时:Nginx 内部可控,随时增加 web-server 随时实时扩容
  5. 能够保证站点层的可用性:任何一台 tomcat 挂了,Nginx 可以将流量迁移到其他 tomcat

缺点:

  1. 反向代理层成了单点,非高可用:tomcat 挂了不影响服务,Nginx 挂了影响到服务了

高可用方案Keepalived

两台 Nginx 组成一个集群,分别部署上 Keepalived,设置成相同的虚 IP,保证 Nginx 的高可用

当一台 Nginx 挂了,Keepalived 能够探测到,并将流量自动迁移到另一台 Nginx 上,整个过程对调用方透明

优点:

  1. 解决了高可用的问题

缺点:

  1. 资源利用率只有 50%
  2. Nginx 仍然是接入单点,如果接入吞吐量超过 Nginx 的性能上限怎么办?

ScaleUp方案LVS/F5

Nginx 毕竟是软件,性能比 tomcat 好,但总有个上限,超出了上限,还是扛不住

LVS 就不一样了,它实施在操作系统层面

F5 的性能又更好了,它实施在硬件层面

它们性能都比 Nginx 好很多,所以通过 LVS 来扩展多个 Nginx,通过 Keepalived 保证可用性

99.9999% 的公司到这一步基本就能解决接入层高可用、扩展性、负载均衡的问题

ScaleOut方案DNS轮询

如果请求量超过 LVS / F5 的上限,怎么办?

这时,水平扩展,才是解决性能问题的根本方案:能够通过加机器扩充性能的方案才具备最好的扩展性

终点又是起点:还是得通过 DNS 轮询来进行扩容

  1. 通过 DNS 轮询来线性扩展入口 LVS 层的性能
  2. 通过 Keepalived 来保证高可用
  3. 通过 LVS 来扩展多个 Nginx
  4. 通过 Nginx 来做负载均衡

负载均衡

负载均衡,主要用于解决单机负载能力的局限性。

问题是你的应用真的到了单机的负载上限了吗?未必!

很多人不知道如何推断瓶颈,如何解决问题,就开始盲目的增加机器,似乎只要能加机器,性能就都不是问题

我们看以下场景

一个数据库服务器上跑两个数据库,并且在生产环境中,这两个数据库所带来的负载是差不多的

通过工具监测发现是硬盘的IO遇到了瓶颈,怎么办?

很多人马上想到:加一台服务器,配置读写分离,或者同步复制,把两个数据库分别用单独的服务器跑等等方案

其实这个问题很简单,既然瓶颈在 IO,那就解决 IO 问题:加一块硬盘

两个数据库的数据分别放在不同的硬盘上就行了,有些场景下增加内存也可以降低磁盘 IO,也能很简单的解决问题

还有索引:通常有索引和没索引(或者索引不当)造成的性能差别是相当大的,这显然不能通过增加机器来解决

另一个场景:文件下载服务器,它的瓶颈通常体现在单机的网络吞吐能力上,而单机网络吞吐能力又取决于网卡的吞吐能力

总不能因为网卡的问题又要加机器(其实一个机器是可以加多个网卡的)

吞吐量延迟

很多人都曾认为:高吞吐量(throughput)就意味着低延迟(latency),高延迟就意味着吞吐量变小

这种观点是错的:举例如下(我们把网络发送数据包比喻成去 ATM 取钱)

每个人从开始使用 ATM 到取钱结束整个过程要一分钟,所以这里的延迟是 60 秒,吞吐量自然是 1/60 人/秒

现在银行升级了 ATM 操作系统,每个人只要 30 秒就能取完款,那么延迟是 30 秒,吞吐量就是 1/30 人/秒

别慌,看下面!

现在银行在这里增加一台 ATM 机,一共两台了,这样一分钟可以让 4 个人取完钱,虽然你排队取钱时还是要花 30 秒

但是延迟没有变,可吞吐量增大了。

可见:吞吐量可以不用通过减小延迟来提高

接着,银行为了改进服务又做出一个决定:每个取完钱的客户必须在旁边填写一个调查问卷,用时也是 30 秒

那么,现在你去取钱的话,从开始使用 ATM 到完成调查问卷离开的时间,又是 60 秒了

换句话说,延迟是 60 秒,而吞吐量根本没变。一分钟之内还是可以进来 4 个人

可见:延迟增加了,而吞吐量没有变

由此可见:

吞吐量,测量的是整个银行(整个系统)的处理效率

而延迟,测量的是每个客户(每个应用程序)感受到的时间长短

是两个完全不同的概念

系统不光要尽量让吞吐量大,还要让每个请求的延迟尽量小,这是两个不同的目标


相关文章

Content