高可用(一)

思维导图

在这里插入图片描述



一、高可用系统设计

1.概述

系统大部分时间是可用的,即能为我们提供服务,即使在发生硬件故障或升级时。

1.1 判断
(1)按时间

99.9999%可用:有0.0001%时间不可用

(2)按次数

成功次数与总请求次数之比
99%可用:网站请求100次,其中99次成功(也即1次失败)

1.2 导致不可用的情况

  • (1)黑客攻击

  • (2)硬件故障,比如服务器坏掉。

  • (3)并发量/用户请求量激增导致整个服务宕掉或者部分不可用

  • (4)代码中原因导致内存泄漏或者其他问题导致程序挂掉

  • (5)网站架构某个重要组件如Nginx或者数据库突然不可用

  • (6)自然灾害或者人为破坏



2.提高可用性方法

2.1 注重代码质量,测试严格把关

最重要,包括常见的内存泄露、循环依赖等会大量损害系统可用性

提高代码神器:

  • Sonarqube

  • Alibaba 开源的 Java 诊断工具 Arthas

  • 阿里巴巴 Java 代码规范(Alibaba Java Code Guidelines)

  • IDEA 自带的代码分析等工具

2.2 使用集群减少单点故障

2.3 限流

流量控制

原理: 监控应用流量的QPS、并发线程数等,当达到指定阈值时对流量进行控制,已避免被瞬时的流量高峰冲垮。

2.4 超时和重试机制设置

一旦用户请求超各某个时间得不到响应就抛出异常

(1)若未设置超时,导致请求响应速度慢,甚至导致请求堆积进而导致系统无法再处理请求

(2)超时设置方式不正确

(3)不适合重试或者重试次数过多(一般设为3次)

2.5 熔断机制

系统自动收集所依赖服务的资源使用情况或性能指标,当所依赖的服务恶化或者失败调用失败次数达到某个阈值时就迅速失败,并让当前系统立即切换依赖其他备用服务。

常用熔断降级框架是Netflix 的 Hystrix 和 alibaba 的 Sentinel。

2.6 异步调用

用户请求完成使用异步调用就能立即返回结果,具体处理后续再做。

除了异步调用,还可以使用消息队列

2.7 使用缓存

并发量高时大量请求直接请求数据库可能会使数据库挂掉,使用缓存则可以避免。

2.8 其他

  • 核心应用和服务优先使用更好的硬件

  • 监控系统资源使用情况增加报警设置

  • 注意备份,必要时候回滚

  • 灰度发布
    每次只发布服务集群中若干机器,若无问题继续发布其他机器,若有问题则回滚已发布的机器

  • 定期检查、更换、升级硬件





二、服务限流

1.概念

对请求的速率进行限制,避免瞬时的大量请求击垮系统。

2.算法

2.1 固定窗口计数器法

规定了我们单位时间处理的请求数量。

固定窗口其实就是时间窗口。

(1)示例

1分钟只能访问60次:

  • 设定当前接口处理的请求数量counter,初始值为0

  • 1分钟内每处理一个请求counter+1,当counter=60之后就拒绝后面全部的请求

  • 等到1分钟钟之后将counter重置0,重新开始计数。

(2)缺点
  • 无法保证限流速率,因而无法保证突然激增的流量

  • 如:某个接口1分钟内只能访问1000次,该接口的QPS是500,前59s这个接口1个请求都没有接收,后1s突然接收了1000个请求,系统直接就被瞬时的大量请求给击垮了

在这里插入图片描述

2.2 滑动窗口计数器法

在固定窗口计数器算法上把时间按一定比例分片。

(1)示例

1分钟只能访问60次:

  • 把1分钟分为60个窗口

  • 每隔1秒移动一次,每个窗口1s只能处理不大于60请求数/60窗口数=1个请求数的请求

  • 如果当前窗口的请求计数总和超过限制数量的话,就不再处理其他请求

  • 当滑动窗口的格子划分的越多,滑动窗口的滚动就越平滑,限流的统计就会越准确

在这里插入图片描述

2.3 漏桶算法

准备一个队列用来保存请求,然后定期从队列中拿请求来执行(类似消息队列削峰/限流)

在这里插入图片描述

2.4 令牌桶算法

  • 请求在被处理前需要从桶里拿到一个令牌,请求处理完将这个令牌丢弃(删除)

  • 我们根据限流大小,按照一定的速率往桶里添加令牌。

  • 如果桶装满了,就不能继续往里面继续添加令牌了。

在这里插入图片描述


3.单机限流

针对单体架构应用

2.1 RateLimiter

2.1.2 概述
  • Google Guava 自带的限流工具类 ,不仅有令牌桶算法(平滑突发限流)实现,还有平滑预热限流算法实现。

  • 平华突发限流就是按照指定的速率放令牌到桶里

  • 平滑预热限流则会有一段预热时间,预热时间之内,速率会逐渐提升到配置的速率

2.1.3 代码实现
(1)引入依赖
<dependency>
    <groupId>com.google.guava</groupId>
    <artifactId>guava</artifactId>
    <version>31.0.1-jre</version>
</dependency>
(2)RateLimiter平滑突发限流的Demo
import com.google.common.util.concurrent.RateLimiter;

public class RateLimiterDemo {

    public static void main(String[] args) {
        // 1s 放 5 个令牌到桶里也就是 0.2s 放 1个令牌到桶里
        RateLimiter rateLimiter = RateLimiter.create(5);
        for (int i = 0; i < 10; i++) {
            double sleepingTime = rateLimiter.acquire(1);
            System.out.printf("get 1 tokens: %ss%n", sleepingTime);
        }
    }
}

输出:

get 1 tokens: 0.0s
get 1 tokens: 0.188413s
get 1 tokens: 0.197811s
get 1 tokens: 0.198316s
get 1 tokens: 0.19864s
get 1 tokens: 0.199363s
get 1 tokens: 0.193997s
get 1 tokens: 0.199623s
get 1 tokens: 0.199357s
get 1 tokens: 0.195676s
(3)RateLimiter平滑预热限流的Demo
import com.google.common.util.concurrent.RateLimiter;
import java.util.concurrent.TimeUnit;


public class RateLimiterDemo {

    public static void main(String[] args) {
        // 1s 放 5 个令牌到桶里也就是 0.2s 放 1个令牌到桶里
        // 预热时间为3s,也就说刚开始的 3s 内发牌速率会逐渐提升到 0.2s 放 1 个令牌到桶里
        RateLimiter rateLimiter = RateLimiter.create(5, 3, TimeUnit.SECONDS);
        for (int i = 0; i < 20; i++) {
            double sleepingTime = rateLimiter.acquire(1);
            System.out.printf("get 1 tokens: %sds%n", sleepingTime);
        }
    }
}

输出:

get 1 tokens: 0.0s
get 1 tokens: 0.561919s
get 1 tokens: 0.516931s
get 1 tokens: 0.463798s
get 1 tokens: 0.41286s
get 1 tokens: 0.356172s
get 1 tokens: 0.300489s
get 1 tokens: 0.252545s
get 1 tokens: 0.203996s
get 1 tokens: 0.198359s

Guava 地址:
https://github.com/google/guava

2.2 Bucket4j 与Resilience4j

2.2.1 Bucket4j

Bucket4j基于令牌/漏桶算法不错的限流库

  • RateLimiter简单开箱即用,单机场景下实用

  • Bucket4j限流功能更全面,支持单机限流、分布式限流,还可以集成监控,搭配Prometheus 和 Grafana 使用。

Bucket4j 地址:
https://github.com/vladimir-bukhtoyarov/bucket4j

2.2.1 Bucket4j
  • 轻量级容错组件,Spring官方和Netflix推荐使用做限流熔断,SpringCloud Gateway 基于它实现。

  • 提供限流、熔断、负载保护、自动重试等保障系统高可用开箱即用的功能

  • 生态很好,很多网关都是用它做限流熔断

Resilience4j 地址:
https://github.com/resilience4j/resilience4j


3.分布式限流

针对分布式、微服务应用架构应用

3.1 常见方案

(1)借助中间件/架构限流

如:用Sentinel、Redis来实现对应的限流逻辑

(2) 网关层限流

网关层限流通常也要用中间件/框架:

  • 如SpringCloud Gateway 的分布式限流实现RedisRateLimiter基于Redis+Lua来实现

  • 如SpringCloud Gateway还可以整合Sentinel来做限流

见我另一篇文章:
SpringCloud之Sentinel

(3) Redis+Lua方式

优点:

  • 减少网络开销
    利用Lua脚本提交批量Redis命令到Redis服务器一次性执行批量

  • 原子性
    一段Lua脚本执行中不会有其他脚本或者Redis命令同时执行

项目实现:
Apache网关项目ShenYu的RateLimiter限流插件基于Redis+Lua实现了令牌桶算法/并发令牌桶算法/漏桶算法/滑动窗口算法。

ShenYu 地址:
https://github.com/apache/incubator-shenyu

备注:
网上也有很多现成的优秀的Redis+Lua限流脚本




一篇跳转—高可用(二)


本篇文章主要参考链接如下:

参考链接1-JavaGuide


持续更新中…

随心所往,看见未来。Follow your heart,see light!

欢迎点赞、关注、留言,一起学习、交流!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值