扩容方案
常见的几个名词释义:
- DNS轮询:通过在 DNS-server 上对一个域名设置多个 IP 解析,来扩充 web-server 性能及实施负载均衡的技术
- Nginx:一个高性能的 web-server 和实施反向代理的软件
- Keepalived:一款用来检测服务状态存活性的软件,常用来做高可用
- F5:一个高性能、高可用、负载均衡的硬件设备
- LVS:Linux Virtual Server,使用集群技术,实现在 linux 操作系统层面的一个高性能、高可用、负载均衡服务器
简易方案DNS轮询
多部署几个 web-server,然后在 DNS-server 层面将域名每次解析到不同的 IP
优点:
- 零成本:在 DNS-server 上多配几个 IP 即可,功能也不收费
- 部署简单:多部署几个 web-server 即可,原系统架构不需要做任何改造
- 负载均衡:变成了多机,但负载基本是均衡的
缺点:
- 非高可用:DNS-server 只负责域名解析 IP,这个 IP 对应的服务是否可用,它是不保证的
- 扩容非实时:DNS解析有一个生效周期
- 暴露了太多的外网 IP
简易方案Nginx
利用高性能的 Nginx 来做反向代理,Nginx 将请求分发给后端多个 web-server
优点:
- DNS-server 不需要动
- 负载均衡:通过 Nginx 来保证
- 只暴露一个外网IP:Nginx 到 Tomcat 之间使用内网访问
- 扩容实时:Nginx 内部可控,随时增加 web-server 随时实时扩容
- 能够保证站点层的可用性:任何一台 tomcat 挂了,Nginx 可以将流量迁移到其他 tomcat
缺点:
- 反向代理层成了单点,非高可用:tomcat 挂了不影响服务,Nginx 挂了影响到服务了
高可用方案Keepalived
两台 Nginx 组成一个集群,分别部署上 Keepalived,设置成相同的虚 IP,保证 Nginx 的高可用
当一台 Nginx 挂了,Keepalived 能够探测到,并将流量自动迁移到另一台 Nginx 上,整个过程对调用方透明
优点:
- 解决了高可用的问题
缺点:
- 资源利用率只有 50%
- Nginx 仍然是接入单点,如果接入吞吐量超过 Nginx 的性能上限怎么办?
ScaleUp方案LVS/F5
Nginx 毕竟是软件,性能比 tomcat 好,但总有个上限,超出了上限,还是扛不住
LVS 就不一样了,它实施在操作系统层面
F5 的性能又更好了,它实施在硬件层面
它们性能都比 Nginx 好很多,所以通过 LVS 来扩展多个 Nginx,通过 Keepalived 保证可用性
99.9999% 的公司到这一步基本就能解决接入层高可用、扩展性、负载均衡的问题
ScaleOut方案DNS轮询
如果请求量超过 LVS / F5 的上限,怎么办?
这时,水平扩展,才是解决性能问题的根本方案:能够通过加机器扩充性能的方案才具备最好的扩展性
终点又是起点:还是得通过 DNS 轮询来进行扩容
- 通过 DNS 轮询来线性扩展入口 LVS 层的性能
- 通过 Keepalived 来保证高可用
- 通过 LVS 来扩展多个 Nginx
- 通过 Nginx 来做负载均衡
负载均衡
负载均衡,主要用于解决单机负载能力的局限性。
问题是你的应用真的到了单机的负载上限了吗?未必!
很多人不知道如何推断瓶颈,如何解决问题,就开始盲目的增加机器,似乎只要能加机器,性能就都不是问题
我们看以下场景
一个数据库服务器上跑两个数据库,并且在生产环境中,这两个数据库所带来的负载是差不多的
通过工具监测发现是硬盘的IO遇到了瓶颈,怎么办?
很多人马上想到:加一台服务器,配置读写分离,或者同步复制,把两个数据库分别用单独的服务器跑等等方案
其实这个问题很简单,既然瓶颈在 IO,那就解决 IO 问题:加一块硬盘
两个数据库的数据分别放在不同的硬盘上就行了,有些场景下增加内存也可以降低磁盘 IO,也能很简单的解决问题
还有索引:通常有索引和没索引(或者索引不当)造成的性能差别是相当大的,这显然不能通过增加机器来解决
另一个场景:文件下载服务器,它的瓶颈通常体现在单机的网络吞吐能力上,而单机网络吞吐能力又取决于网卡的吞吐能力
总不能因为网卡的问题又要加机器(其实一个机器是可以加多个网卡的)
吞吐量延迟
很多人都曾认为:高吞吐量(throughput)就意味着低延迟(latency),高延迟就意味着吞吐量变小
这种观点是错的:举例如下(我们把网络发送数据包 Packet 比喻成去 ATM 取钱)
每个人从开始使用 ATM 到取钱结束整个过程要一分钟,所以这里的延迟是 60s,吞吐量自然是 1/60 人/秒
现在银行升级了 ATM 操作系统,每个人只要 30s 就能取完款,那么延迟是 30s,吞吐量就是 1/30 人/秒
别慌,看下面!
银行在这里又增加一台 ATM 机,一共两台了,这样一分钟可以让 4 个人取完钱(虽然排队取钱还是要花 30s)
但是延迟没有变,可吞吐量增大了。
可见:吞吐量,可以不用通过,减小延迟,来提高
接着,银行为了改进服务又做出一个决定:每个取完钱的客户必须在旁边填写一个调查问卷,用时也是 30s
那么,现在你去取钱的话,从开始使用 ATM 到完成调查问卷离开的时间,又是 60s
换句话说,延迟是 60s,而吞吐量根本没变。一分钟之内还是可以进来 4 个人
可见:延迟增加了,而吞吐量没有变
由此可见:
吞吐量,测量的是整个银行(整个系统)的处理效率
而延迟,测量的是每个客户(每个应用程序)感受到的时间长短
是两个完全不同的概念
系统不光要让吞吐量尽可能大,还要让每个请求的延迟尽可能小,这是两个不同的目标
QPS和TPS
QPS
Queries Per Second 是每秒能够处理的查询数(它表示一台服务器,每秒响应的查询的次数)
这里的查询,通常是指对系统的一个请求,可能是 HTTP 请求、RPC 调用或数据库查询
它通常用于衡量系统的请求处理能力,其与请求直接相关,每个请求对应一个 QPS 计数
所以:QPS = 总请求数 / 测试时间(秒)
假如:10s 内处理了 1000 个 HTTP 请求,则 QPS = 1000 / 10 = 100
补充:还有一个指标叫 RPS(Requests Per Second)表示系统每秒能够处理的请求数
补充:它俩的概念非常相似,通常可以互换使用,但在某些场景下,RPS 更强调 HTTP 请求或 API 调用的数量
TPS
Transactions Per Second 是每秒能够处理的事务数(一个事务表示客户端发送请求,并收到响应的过程)
比如购物下单时,服务器收到请求后,会进行保存订单、扣减库存、确认支付等一系列操作后,响应结果给客户端
这个完整的过程,就是一次事务,TPS 则表示每秒内,可以完成多少次这样的请求
由于一个事务可能包含多个 HTTP 请求或数据库操作
因此它通常与具体的业务逻辑绑定,不同的业务事务可能有不同的复杂度
所以:TPS = 总事务数 / 测试时间(秒)
假如:10s 内完成了 500 个订单事务,则 TPS = 500 / 10 = 50
由于:一个事务(TPS)可能包含多个请求(QPS/RPS),所以:QPS = TPS × 每个事务的请求数