秒杀笔记 —— 流量削峰

秒杀笔记 —— 流量削峰

秒杀业务场景,商品是有限的,请求数无论多少,最终获得商品的用户还是有限的。可是在业务的角度讲,能承载越多的人参与当然越好,但是实际下单时,秒杀请求并不是越多越好。因此可以设计一些规则,让并发请求可以延缓,甚至过滤一部分无效请求。

为什么要削峰

削峰,为什么?峰值有什么坏处?

  • 控制成本,保证质量
    服务器资源是恒等的,假设满分资源是100分,平时保证系统正常运行使用是80分,可是秒杀活动时,如果想让所有用户的请求都可以实际处理,那服务器资源可能就要做到200甚至更高分,为了控制成本同时保证应用质量,所以我们要削峰。
  • 削峰为什么存在
    • 可以让服务端处理变得更加平稳
    • 可以节省服务器资源成本

基于“请求数要尽量少”的设计原则,削峰本质上就是延缓更多用户请求的发出,减少和过滤一些无效请求。

排队

消息队列缓冲瞬时流量,同步操作转换为异步间接推送,中间通过队列在一端承接瞬时流量洪峰,另一端平滑推送消息出去。
比喻:消息队列好比“水库”,拦蓄上游洪水,削减进入下游河道的洪峰流量,达到减免洪水灾害目的。
在这里插入图片描述
但是,流量峰值持续一段时间达到消息队列的处理上限,例如本机消息积压达到存储空间上限,消息队列会被压垮,这样虽然做到了队列削峰,可是会丢弃一部分请求。
除了消息队列,类似的排队方式还有:

以上三个都有一个共同特征,把“一步操作”编程“两步操作”,增加了一步缓冲操作。

增加了访问请求路径并不符合“4要1不要”原则。确实,但是如果不增加一个缓冲,实际场景就可能会出现崩溃,导致系统宕机,在这个角度,我们需要在程序设计时综合权衡。

答题

早起秒杀并没有答题,那为什么后来增加了答题功能?有两个目的:

  • 防范秒杀器作弊
    秒杀器,作弊,如果没有答题,写脚本刷接口就行。秒杀答题截图:
    在这里插入图片描述
  • 延缓请求
    对请求流量削峰,提高系统对流量高峰的抗压力。此功能就是把峰值下单请求拉长,从1s变为2s~10s。这样,请求就会基于时间分片了。时间分片大大降低了服务器的并发压力,并且,请求具有先后顺序,靠后的请求就没有库存了,因此根本到不了实际下单的服务处理,达到真正并发写限制作用。

秒杀答题实际思路:
在这里插入图片描述
上图所示,秒杀答题逻辑分为3部分:

  • 题库生成模块
    生成题目和答案,不需要很复杂,达到能够避免秒杀器自动答题即可,目的是防刷。
  • 题库推送模块
    秒杀答题前,题目提前推送给详情系统和交易系统。题库推送主要目的是保证用户请求的题目是唯一的,目的也是防止答题作弊。
  • 题目图片生成模块
    用于题目生成图片格式,并且在图片中增加一些干扰元素。同样是防止机器自动答题,要求人才能理解题目本身的含义。这里需要注意,把图片提前推送到CDN并且进行预热,可以避免用户在答题时,由于网络拥挤导致的图片加载过慢。

答题逻辑其实很简单,用户提交的答案与题目对应答案做比较,如果通过进行一步下单逻辑,反之失败。
可以把问题和答案用下面的Key来进行MD5加密:

说明
问题Key userId + itemId + questionId + time + PK
答案Key userId + itemId + answer + PK

验证逻辑示意图:
在这里插入图片描述
注意:验证逻辑除了验证问题的答案以外,还包含用户身份的验证,例如是否已经登陆、用户的Cookie是否完整、用户是否重复频繁提交等。

除了做正确性验证,还可以对提交答案的时间做些限制,例如从开始答题到接受答案要超过1s,因为小于1s是人为操作的可能性很小,这样也能防止机器答题的情况。
答题系统的实现(待完善)

分层过滤

无论使用队列还是设置答题,都是对请求进行缓冲,也就是分层过滤,从而过滤掉一些无效请求。分层过滤其实就是采用“漏斗式”设计处理请求,如下:
在这里插入图片描述
假设请求分别经过CDN、前台读系统(如商品详情系统)、后台系统(如交易系统)和数据库这几层,那么:

  • 大部分数据和流量在用户浏览器或者CDN上获取,这一层可以拦截大部分数据的读取;
  • 经过第二层(即前台系统)时数据(包括强一致性的数据)尽量得走Cache,过滤一些无效请求;
  • 再到第三层后台系统,主要做数据的二次检验,对系统做好保护和限流,数据量和请求就会进一步减少;
  • 最后在数据层完成数据强一致性校验;

这样就像漏斗一样,尽量把数据量和请求量一层一层过滤和减少了;

分层过滤的核心思想:

  • 将动态请求的读数据缓存(Cache)在Web端(离用户最近的并且最合理的位置),过滤掉无效的数据读。
  • 读数据不做强一致性校验,减少因为一致性校验产生瓶颈的问题;
  • 写数据进行强一致性校验,只保留最后有效数据;
  • 写数据进行基于时间的合理分片,过滤掉过期的失效请求;
  • 写请求做限流保护,将超出系统承载能力的请求过滤掉;

分层家考验的目的:

系统 描述
读系统 尽量减少由于一致性校验带来的系统瓶颈,尽量将不影响性能的检查提前,如用户是否具有秒杀资格、商品状态是否正常、用户答题是否正确、秒杀是否已经结束、是否非法请求、营销等价物是否充足等;
写系统 主要对写的数据(如“库存”)做一致性检查,最后在数据库层保证数据的最终准确性(如“库存”不能为负数)

总结

削峰的三种处理方式:

  • 通过队列缓冲请求,控制请求发出;
  • 通过答题延长请求发出时间,请求发出后,承接(服务端、缓存、数据库)请求时进行控制,最后再对不符合条件的请求进行过滤;
  • 对请求进行分层过滤;

适用场景

场景
队列缓冲 更通用,适用于内部上下游系统之间调用请求不平缓的场景,由于内部系统的服务质量不允许随意丢弃请求,所以使用消息队列能起到很好的削峰和缓冲作用。
答题 秒杀或营销活动,在请求发起端控制请求速度,越到后面无效请求越多,所以配合后面介绍分层拦截方式,可进一步减少无效请求对系统资源对占用。
分层过滤 非常适合交易性的写请求,比如减库存、拼车场景,因为库存和座位是不断变化的,读的时候不需要非常准确,可以先放一些请求过去,然后真正减少时一定要做到强一致性,这样即过滤一些请求又解决了强一致性读的瓶颈。

猜你喜欢

转载自blog.csdn.net/Cy_LightBule/article/details/87984764