系统高可用
1. 什么是高可用?可用性的判断标准是啥?
高可用描述的是一个系统在大部分时间都是可用的,可以为我们提供服务的。高可用代表系统即使在发生硬件故障或者系统升级的时候,服务仍然是可用的。
1.1 可用性的判断标准是啥?
一般情况下,我们使用多少个 9 来评判一个系统的可用性,比如 99.9999% 就是代表该系统在所有的运行时间中只有 0.0001% 的时间是不可用的,这样的系统就是非常非常高可用的了!当然,也会有系统如果可用性不太好的话,可能连 9 都上不了。
除此之外,系统的可用性还可以用某功能的失败次数与总的请求次数之比来衡量,比如对网站请求 1000 次,其中有 10 次请求失败,那么可用性就是 99%。
2. 哪些情况会导致系统不可用?
- 硬件故障,比如服务器坏掉。
- 并发量/用户请求量激增导致整个服务宕掉或者部分服务不可用。
- 代码问题导致程序挂掉。
- 网站架构某个重要的角色比如 Nginx 或者数据库突然不可用。
…
3. 有哪些提高系统可用性的方法?
3.1 注重代码质量,定时Review代码
3.2 使用集群,减少单点故障
先拿常用的 Redis 举个例子!我们如何保证我们的 Redis 缓存高可用呢?答案就是使用集群,避免单点故障。当我们使用一个 Redis 实例作为缓存的时候,这个 Redis 实例挂了之后,整个缓存服务可能就挂了。使用了集群之后,即使一台 Redis 实例挂了,不到一秒就会有另外一台 Redis 实例顶上。
3.3 限流
流量控制(flow control),其原理是监控应用流量的 QPS 或并发线程数等指标,当达到指定的阈值时对流量进行控制,以避免被瞬时的流量高峰冲垮,从而保障应用的高可用性。——来自 alibaba-Sentinel 的 wiki。
3.4 使用缓存
如果我们的系统属于并发量比较高的话,如果我们单纯使用数据库的话,当大量请求直接落到数据库可能数据库就会直接挂掉。使用缓存缓存热点数据,因为缓存存储在内存中,所以速度相当地快!
3.5 异步调用
可以使用消息队列,消息队列可以通过异步处理提高系统性能(削峰、减少响应所需时间)并且可以降低系统耦合性
3.6 超时和重试机制设置
一旦用户请求超过某个时间的得不到响应,就抛出异常。这个是非常重要的,很多线上系统故障都是因为没有进行超时设置或者超时设置的方式不对导致的。我们在读取第三方服务的时候,尤其适合设置超时和重试机制。一般我们使用一些 RPC 框架的时候,这些框架都自带的超时重试的配置。如果不进行超时设置可能会导致请求响应速度慢,甚至导致请求堆积进而让系统无法再处理请求。重试的次数一般设为 3 次,再多次的重试没有好处,反而会加重服务器压力(部分场景使用失败重试机制会不太适合)。
3.7 熔断机制
熔断机制说的是系统自动收集所依赖服务的资源使用情况和性能指标,当所依赖的服务恶化或者调用失败次数达到某个阈值的时候就迅速失败,让当前系统立即切换依赖其他备用服务。 比较常用的流量控制和熔断降级框架是 Netflix 的 Hystrix 和 alibaba 的 Sentinel。
4. QPS和TPS
4.1 QPS(每秒查询率)
是一台服务器每秒能够响应的查询次数(数据库中的每秒执行查询sql的次数),显然,这个不够全面,不能描述增删改,所以,不建议用qps来作为系统性能指标。
4.2 TPS(事务/秒)
一个事务是指客户端向服务器发起请求,服务器做出响应的过程。发送请求开始计时,收到响应结束计时,以此来计算相应的时间和完成事务的个数。
具体的事务定义,可以是一个接口、多个接口、一个业务流程等等。以单接口定义为事务举例,每个事务包括了如下3个过程
a.向服务器发请求
b.服务器自己的内部处理(包含应用服务器、数据库服务器等)
c.服务器返回结果给客户端
如果每秒能够完成N次这三个过程,tps就是N;
如果多个接口定义为一个事务,那么,会重复执行abc,完成一次这几个请求,算做一个tps。
4.3 区别
如果是对一个查询接口压测,且这个接口内部不会再去请求其它接口,那么 TPS = QPS,否则,TPS ≠ QPS。
4.4 峰值 QPS和机器计算公式
原理:每天80%的访问集中在20%的请求中,这20%的时间叫做峰值时间。
公式:(总PV数 * 80%)/ (每天的秒数 * 20%)= 峰值时间每秒请求数(QPS)
机器:峰值时间每秒QPS / 单台机器的QPS = 需要的机器数量
举例:每天300w PV的单台机器上,这台机器需要多少QPS?
(3000000 * 0.8) / (86400 * 0.2) =139(QPS)
如果一台机器的QPS是58,需要多少台机器?
139/58≈3
4.4 提升QPS的方法
QPS= 并发数/平均响应时间
4.4.1 增加并发数
- 增加处理接口的线程数,和服务器性能匹配的线程数
- 调用链路上的各个服务尽量不要单点,不要让其中某一点成为瓶颈
4.4.2 减少平均响应时间
- 流量消峰。放行适当的流量,处理的不了的请求直接返回错误或者提示
- 优化程序
5. 限流
5.1 固定窗口计数器算法
固定窗口其实就是时间窗口。固定窗口计数器算法 规定了我们单位时间处理的请求数量。
假如我们规定系统中某个接口 1 分钟只能访问 33 次的话,使用固定窗口计数器算法的实现思路如下:
给定一个变量 counter 来记录当前接口处理的请求数量,初始值为 0(代表接口当前 1 分钟内还未处理请求)。
1 分钟之内每处理一个请求之后就将 counter+1 ,当 counter=33 之后(也就是说在这 1 分钟内接口已经被访问 33 次的话),后续的请求就会被全部拒绝。
等到 1 分钟结束后,将 counter 重置 0,重新开始计数。
这种限流算法无法保证限流速率,因而无法保证突然激增的流量。
就比如说我们限制某个接口 1 分钟只能访问 100次,前 59s 这个接口 1 个请求没有接收,后 1s 突然接收了 100 个请求;然后接着又来了100的请求;在当前场景下,这 200个请求在 2s 内是没办法被处理的,系统直接就被瞬时的大量请求给击垮了。
5.2 滑动窗口计数器算法
滑动窗口计数器算法 算的上是固定窗口计数器算法的升级版。
我们遍历过去一分钟内每个独立区间,也就是每10秒内的计数器的计数总数,这个总和当然就是过去一分钟内全部的请求数量了。
每经过10秒,我们需要将整个计数器区间往右移动一格。
5.3 令牌桶
一个固定大小的容器(令牌桶),系统以恒定的速率向令牌桶中放入令牌,如果客户端发来请求,就需要先从令牌桶中拿到一个令牌,才能正常请求,这时候令牌桶中就少了一个令牌,当令牌桶满了的时候,在向令牌桶生成令牌的时候,令牌会被舍弃。
请求速度大于令牌生成速度,那么令牌被拿完后,后续再进来的请求会被限流;
请求速度等于令牌生成速度,正常处理;
请求速度小于令牌生成速度,正常处理;
优点:可以短时间内大量请求,因为桶里有令牌。
5.4 漏桶
我们可以把发请求的动作比作成注水到桶中,我们处理请求的过程可以比喻为漏桶漏水。我们往桶中以任意速率流入水,以一定速率流出水。当水超过桶流量则丢弃,因为桶容量是不变的,保证了整体的速率。
如果想要实现这个算法的话也很简单,准备一个队列用来保存请求,然后我们定期从队列中拿请求来执行就好了(和消息队列削峰/限流的思想是一样的)。
当请求速度大于漏桶流出速度,也就是请求量大于服务最大处理能力,触发限流策略。
当请求速度小于漏桶流出速度,也就是服务处理能力大于等于请求量,正常执行。
缺点:当系统短时间内有突发的大量请求,漏桶算法处理不了。
文章来源:https://snailclimb.gitee.io/javaguide/#/docs/high-availability/high-availability-system-design?id=_7%e4%bd%bf%e7%94%a8%e7%bc%93%e5%ad%98
QPS和TPS来源:https://www.bilibili.com/video/BV17R4y1M74u/?spm_id_from=333.337.search-card.all.click&vd_source=b901ef0e9ed712b24882863596eab0ca
https://blog.csdn.net/weixin_42483745/article/details/123953857
限流:https://www.bilibili.com/video/BV1AT4y167iA/?spm_id_from=333.337.search-card.all.click&vd_source=b901ef0e9ed712b24882863596eab0ca
https://snailclimb.gitee.io/javaguide/#/docs/high-availability/limit-request?id=%e4%bb%a4%e7%89%8c%e6%a1%b6%e7%ae%97%e6%b3%95
https://www.bilibili.com/video/BV1ZY4y1w7e7/?spm_id_from=333.788&vd_source=b901ef0e9ed712b24882863596eab0ca