网站首页 > 精选教程 正文
设定一个场景,假如一个商品接口在某段时间突然上升,会怎么办?
生活中的例子来说,假设冰墩墩在当天晚上上热搜之后,迅速有十几万人去淘宝下单购买,此时并没有做好对该商品的缓存预热以及准备,如何操作?
对于这个问题,在电商高并发系统中,对接口的保护一般采用:缓存、限流、降级 来操作。
假设该接口已经接受过风控的处理,过滤掉一半的机器人脚本请求,剩下都是人为的下单请求。
服务限流
限流 主要的目的是通过对并发访问/请求进行限速,或者对一个时间窗口内的请求进行限速,一旦达到限制速率则可以拒绝服务、排队或等待、降级等处理。
限流算法
1. 漏斗算法
漏桶算法 是当请求到达时直接放入漏桶,如果当前容量已达到上限(限流值),则进行丢弃或其他策略(触发限流策略)。漏桶以固定的速率(根据服务吞吐量)进行释放访问请求(即请求通过),直到漏桶为空。
漏斗算法的思想就是,不管你来多少请求,我的接口消费速度一定是小于等于流出速率的阈值的。
可以基于消息队列来实现。
2. 令牌桶算法
令牌桶算法 是程序以v(v = 时间周期 / 限流值)的速度向令牌桶中增加令牌,直到令牌桶满,请求到达时向令牌桶请求令牌,如果获取成功则通过请求,如果获取失败触发限流策略。
令牌桶算法和漏斗算法的思想差别在于,前者可以允许突发请求的发生。
3. 滑窗算法
滑窗算法 是将一个时间周期分为N个小周期,分别记录每个小周期内访问次数,并且根据时间滑动删除过期的小周期。
如下图所示,假设时间周期为1分钟,将1分钟再分为2个小周期,统计每个小周期的访问数量,则可以看到,第一个时间周期内,访问数量为75,第二个时间周期内,访问数量为100,如果一个时间周期内所有的小周期总和超过100的话,则会触发限流策略。
Sentinel的实现 和 TCP滑窗。
接入层限流
Nginx限流
Nginx 限流采用的是漏桶算法。
它可以根据客户端特征,限制其访问频率,客户端特征主要指 IP、UserAgent等。使用 IP 比 UserAgent 更可靠,因为 IP 无法造假,UserAgent 可随意伪造。
limit_req模块基于IP:
http://nginx.org/en/docs/http/ngx_http_limit_req_module.html
tgngine:
http://tengine.taobao.org/document_cn/http_limit_req_cn.html
本地接口限流
Semaphore
Java 并发库 的 Semaphore 可以很轻松完成信号量控制,Semaphore 可以控制某个资源可被同时访问的个数,通过 acquire() 获取一个许可,如果没有就等待,而 release() 释放一个许可。
假如我们对外提供一个服务接口,允许最大并发数为40,我们可以这样:
private final Semaphore permit = new Semaphore(40, true);
public void process(){
try{
permit.acquire();
//TODO 处理业务逻辑
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
permit.release();
}
}
具体的 Semaphore 实现参考源码。
分布式接口限流
使用消息队列
不管是用MQ中间件,或是Redis的List实现的消息队列,都可以作为一个 缓冲队列 来使用。思想就是基于漏斗算法。
当对于一个接口请求达到一定阈值时,就可以启用消息队列来进行接口数据的缓冲,并根据服务的吞吐量来消费数据。
服务降级
在接口做好风控的前提下,发现了接口请求的并发量迅速上升,我们可以启用兜底方案,进行服务降级。
一般服务降级应该用来对一些 不重要 或 不紧急 的服务或任务进行服务的 延迟使用 或 暂停使用。
降级方案
停止边缘业务
比如淘宝双11前,就不可以查询三个月前的订单,对边缘业务进行降级,保证核心业务的高可用。
拒绝请求
在接口请求并发量大于阈值,或是接口出现大量失败请求等等突发情况,可以拒绝一些访问请求。
拒绝策略
- 随机拒绝:随机拒绝超过阈值的请求 。
- 拒绝旧请求:按照请求的时间,优先拒绝更早收到的请求。
- 拒绝非核心请求:根据系统业务设置核心请求清单,将非核心清单内的请求拒绝掉。
恢复方案
在实现服务降级之后,对于突增流量我们可以继续注册多个消费者服务来应对并发量,之后我们再对一些服务器进行慢加载。
降级具体实现参考其他文章。
数据缓存
在接口做好风控的前提下,发现了接口请求的并发量迅速上升,我们可以分以下几个操作执行:
- 对访问请求使用分布式锁进行阻塞。
- 在这个短时间中,我们可以将对应操作行的热点数据,缓存在缓存中间件中。
- 放行请求后,让所有请求优先操作缓存数据。
- 再将操作的结果通过消息队列发送给消费接口慢慢消费。
缓存问题
假设我们操作的是一个库存接口,此时数据库中只有100个库存。
那假如此时我们将一条数据放入缓存中,如果所有的请求都来访问这个缓存,那它还是被打挂,我们该怎么操作?
读写分离
第一种想法,读写分离。
使用Redis的哨兵集群模式来进行主从复制的读写分离操作。读的操作肯定大于写操作,等库存被消费到0时,读操作直接快速失败。
负载均衡
第二种想法,负载均衡。
在缓存数据后,如果所有请求都来缓存中操作这个库存,不管是加悲观锁还是乐观锁,并发率都很低,此时我们可以对这个库存进行拆分。
我们可以参照 ConcurrentHashMap 中的 counterCells 变量的设计思想,将100个库存拆分到10个缓存服务中,每个缓存服务有10个缓存,然后我们再对请求进行负载均衡到各个缓存服务上。
但是这种方式会有问题,如果大部分用户被hash到同一个缓存上,导致其他缓存没有被消费,却返回没有库存,这是不合理的。
page cache
第三种想法,page cache。
大部分软件架构其实都用到了这种方法,比如linux内核的硬盘写入、mysql的刷盘等等,即将短时间内的写操作聚合结果写入,所有的写操作在缓存内完成。
原文链接:https://mp.weixin.qq.com/s/IgzxUYJcU3Z5f2RTIz87TQ
猜你喜欢
- 2024-11-06 信号量限流,高并发场景不得不说的秘密
- 2024-11-06 面试卡在多线程?那就分享几道Java多线程高频面试题,面试不用愁
- 2024-11-06 Java并发系列之Semaphore源码分析
- 2024-11-06 Java多线程与并发 java的并发,多线程,线程模型
- 2024-11-06 66.java并发编程之Semaphore和CountDownLatch使用
- 2024-11-06 Java基础笔试练习(十五) java基础知识试题
- 2024-11-06 72道Java线程面试题,这些面试官必问
- 2024-11-06 Java并发基础-锁详细分析(可重入锁、读写锁、信号量等)
- 2024-11-06 Java并发工具:CountDownLatch CyclicBarrier Semaphore快速掌握
- 2024-11-06 死磕 java同步系列之Semaphore源码解析
你 发表评论:
欢迎- 04-11Java面试“字符串三兄弟”String、StringBuilder、StringBuffer
- 04-11Java中你知道几种从字符串中找指定的字符的数量
- 04-11探秘Java面试中问的最多的String、StringBuffer、StringBuilder
- 04-11Python字符串详解与示例(python字符串的常见操作)
- 04-11java正则-取出指定字符串之间的内容
- 04-11String s1 = new String("abc");这句话创建了几个字符串对象?
- 04-11java判断字符串中是否包含某个字符
- 04-11关于java开发中正确的发牌逻辑编写规范
- 最近发表
-
- Java面试“字符串三兄弟”String、StringBuilder、StringBuffer
- Java中你知道几种从字符串中找指定的字符的数量
- 探秘Java面试中问的最多的String、StringBuffer、StringBuilder
- Python字符串详解与示例(python字符串的常见操作)
- java正则-取出指定字符串之间的内容
- String s1 = new String("abc");这句话创建了几个字符串对象?
- java判断字符串中是否包含某个字符
- 关于java开发中正确的发牌逻辑编写规范
- windows、linux如何后台运行jar(并且显示进程名)
- 腾讯大佬私人收藏,GitHub上最受欢迎的100个JAVA库,值得学习
- 标签列表
-
- nginx反向代理 (57)
- nginx日志 (56)
- nginx限制ip访问 (62)
- mac安装nginx (55)
- java和mysql (59)
- java中final (62)
- win10安装java (72)
- java启动参数 (64)
- java链表反转 (64)
- 字符串反转java (72)
- java逻辑运算符 (59)
- java 请求url (65)
- java信号量 (57)
- java定义枚举 (59)
- java字符串压缩 (56)
- java中的反射 (59)
- java 三维数组 (55)
- java插入排序 (68)
- java线程的状态 (62)
- java异步调用 (55)
- java中的异常处理 (62)
- java锁机制 (54)
- java静态内部类 (55)
- java怎么添加图片 (60)
- java 权限框架 (55)
本文暂时没有评论,来添加一个吧(●'◡'●)