96秒100亿!如何抗住双11高并发流量?
今年双?11 全民购物狂欢节进入第十一个年头,1 分 36 秒,交易额冲到?100?亿?!比?2018 年快了近 30?秒,比 2017 年快了近 1 分半!这个速度再次刷新天猫双 11?成交总额破?100 亿的纪录。

服务等级协议
我们常说的 N 个 9,就是对 SLA 的一个描述。SLA 全称是 Service Level Agreement,翻译为服务水平协议,也称服务等级协议,它表明了公有云提供服务的等级以及质量。
例如阿里云对外承诺的就是一个服务周期内集群服务可用性不低于 99.99%,如果低于这个标准,云服务公司就需要赔偿客户的损失。
做到 4 个 9 够好了吗
对互联网公司来说,SLA 就是网站或者 API 服务可用性的一个保证。
9 越多代表全年服务可用时间越长服务更可靠,4 个 9 的服务可用性,听起来已经很高了,但对于实际的业务场景,这个值可能并不够。
我们来做一个简单的计算,假设一个核心链路依赖 20 个服务,强依赖同时没有配置任何降级,并且这 20 个服务的可用性达到 4 个 9,也就是 99.99%。

微服务的雪崩效应

限流降级怎么做
缓存以及队列等手段,增加系统的容量。限流和降级则是关心在到达系统瓶颈时系统的响应,更看重稳定性。
限流和降级
超时降级
失败次数降级
故障降级

熔断隔离
如果不对服务资源做隔离,一旦一个服务出现了问题,整个系统的稳定性都会受到影响!服务隔离的目的就是避免服务之间相互影响。

何处隔离:一次服务调用,涉及到的是服务提供方和调用方,我们所指的资源,也是两方的服务器等资源,服务隔离通常可以从提供方和调用方两个方面入手。
隔离什么:广义的服务隔离,不仅包括服务器资源,还包括数据库分库,缓存,索引等,这里我们只关注服务层面的隔离。
降级和熔断的区别
熔断,一般是停止服务:典型的就是股市的熔断,如果大盘不受控制,直接休市,不提供服务,是保护大盘的一种方式。
降级,通常是有备用方案:从北京到济南,下雨导致航班延误,我可以乘坐高铁,如果高铁票买不到,也可以乘坐汽车或者开车过去。
两者的区别:降级一般是主动的,有预见性的,熔断通常是被动的,服务 A 降级以后,一般会有服务 B 来代替,而熔断通常是针对核心链路的处理。
常用限流算法设计
计数器法
这时候判断,如果计数器的值小于限流值,并且与上一次请求的时间间隔还在一分钟内,允许请求通过,否则拒绝请求,如果超出了时间间隔,要将计数器清零。
public?class?CounterLimiter?{
????//初始时间
????private?static?long?startTime?=?System.currentTimeMillis();
????//初始计数值
????private?static?final?AtomicInteger?ZERO?=?new?AtomicInteger(0);
????//时间窗口限制
????private?static?final?long?interval?=?10000;
????//限制通过请求
????private?static?int?limit?=?100;
????//请求计数
????private?AtomicInteger?requestCount?=?ZERO;
????//获取限流
????public?boolean?tryAcquire()?{
????????long?now?=?System.currentTimeMillis();
????????//在时间窗口内
????????if?(now?< ?startTime?+?interval)?{
????????????//判断是否超过最大请求
????????????if?(requestCount.get()?< ?limit)?{
????????????????requestCount.incrementAndGet();
????????????????return?true;
????????????}
????????????return?false;
????????}?else?{
????????????//超时重置
????????????startTime?=?now;
????????????requestCount?=?ZERO;
????????????return?true;
????????}
????}
}
漏桶算法
漏桶算法的示意图如下:

这里简单实现一下,也可以使用 Guava 的 SmoothWarmingUp 类,可以更好的控制漏桶算法:
public?class?LeakyLimiter?{
????//桶的容量
????private?int?capacity;
????//漏水速度
????private?int?ratePerMillSecond;
????//水量
????private?double?water;
????//上次漏水时间
????private?long?lastLeakTime;
????public?LeakyLimiter(int?capacity,?int?ratePerMillSecond)?{
????????this.capacity?=?capacity;
????????this.ratePerMillSecond?=?ratePerMillSecond;
????????this.water?=?0;
????}
????//获取限流
????public?boolean?tryAcquire()?{
????????//执行漏水,更新剩余水量
????????refresh();
????????//尝试加水,水满则拒绝
????????if?(water?+?1?>?capacity)?{
????????????return?false;
????????}
????????water?=?water?+?1;
????????return?true;
????}
????private?void?refresh()?{
????????//当前时间
????????long?currentTime?=?System.currentTimeMillis();
????????if?(currentTime?>?lastLeakTime)?{
????????????//距上次漏水的时间间隔
????????????long?millisSinceLastLeak?=?currentTime?-?lastLeakTime;
????????????long?leaks?=?millisSinceLastLeak?*?ratePerMillSecond;
????????????//允许漏水
????????????if?(leaks?>?0)?{
????????????????//已经漏光
????????????????if?(water?< =?leaks)?{
????????????????????water?=?0;
????????????????}?else?{
????????????????????water?=?water?-?leaks;
????????????????}
????????????????this.lastLeakTime?=?currentTime;
????????????}
????????}
????}
}
令牌桶算法
如果令牌不被消耗,或者被消耗的速度小于产生的速度,令牌就会不断地增多,直到把桶填满。后面再产生的令牌就会从桶中溢出。

最后桶中可以保存的最大令牌数永远不会超过桶的大小,每当一个请求过来时,就会尝试从桶里移除一个令牌,如果没有令牌的话,请求无法通过。
public?class?TokenBucketLimiter?{
????private?long?capacity;
????private?long?windowTimeInSeconds;
????long?lastRefillTimeStamp;
????long?refillCountPerSecond;
????long?availableTokens;
????public?TokenBucketLimiter(long?capacity,?long?windowTimeInSeconds)?{
????????this.capacity?=?capacity;
????????this.windowTimeInSeconds?=?windowTimeInSeconds;
????????lastRefillTimeStamp?=?System.currentTimeMillis();
????????refillCountPerSecond?=?capacity?/?windowTimeInSeconds;
????????availableTokens?=?0;
????}
????public?long?getAvailableTokens()?{
????????return?this.availableTokens;
????}
????public?boolean?tryAcquire()?{
????????//更新令牌桶
????????refill();
????????if?(availableTokens?>?0)?{
????????????--availableTokens;
????????????return?true;
????????}?else?{
????????????return?false;
????????}
????}
????private?void?refill()?{
????????long?now?=?System.currentTimeMillis();
????????if?(now?>?lastRefillTimeStamp)?{
????????????long?elapsedTime?=?now?-?lastRefillTimeStamp;
????????????int?tokensToBeAdded?=?(int)?((elapsedTime?/?1000)?*?refillCountPerSecond);
????????????if?(tokensToBeAdded?>?0)?{
????????????????availableTokens?=?Math.min(capacity,?availableTokens?+?tokensToBeAdded);
????????????????lastRefillTimeStamp?=?now;
????????????}
????????}
????}
}
漏桶和令牌桶的比较
使用 RateLimiter 实现限流

RateLimter 提供的 API 可以直接应用,其中 acquire 会阻塞,类似 JUC 的信号量 Semphore,tryAcquire 方法则是非阻塞的:
public?class?RateLimiterTest?{
????public?static?void?main(String[]?args)?throws?InterruptedException?{
????????//允许10个,permitsPerSecond
????????RateLimiter?limiter?=?RateLimiter.create(10);
????????for(int?i=1;i< 20;i++){
????????????if?(limiter.tryAcquire(1)){
????????????????System.out.println("第"+i+"次请求成功");
????????????}else{
????????????????System.out.println("第"+i+"次请求拒绝");
????????????}
????????}
????}
}
总结
作者:邴越
简介:某电商平台架构师,曾任阿里巴巴中台资深开发工程师,云栖社区专家,关注分布式系统和高可用架构。
编辑:陶家龙、孙淑娟
出处:https://www.cnblogs.com/binyue/p/11596763.html

精彩文章推荐:
关注公众号:拾黑(shiheibook)了解更多
[广告]赞助链接:
四季很好,只要有你,文娱排行榜:https://www.yaopaiming.com/
让资讯触达的更精准有趣:https://www.0xu.cn/
关注网络尖刀微信公众号随时掌握互联网精彩
- 1 确保“十五五”开好局起好步 7904482
- 2 员工“踢了一脚” 救了老板一命 7808142
- 3 故宫下雪了 7713709
- 4 2026年经济工作要这么干 7618379
- 5 村支书卖小米被小米法务投诉下架 7523845
- 6 女子买千元羽绒服穿1天变吸油服 7425848
- 7 凭煮蛋涨粉350万 “蛋神”回应爆红 7329710
- 8 不提“雪” 怎么描写雪很大 7234965
- 9 日本极右翼分子对美国“开火”了 7142477
- 10 中央经济工作会议释放哪些重要信号 7040675







51CTO技术栈
