流量削峰这个概念主要来自于互联网的业务场景。例如春节火车票抢购,大量的用户需要同一时间去抢购;又例如阿里的双十一秒杀,短时间内上亿的用户涌入,瞬间流量巨大(高并发)。具体就是,300万人在凌晨0点抢购一件数量只有500件的商品,最后能购买到的只有300万人中的这500人。从业务上来说,这种秒杀活动是一种商业推广的行为,当然是希望越多人参与越好,也就是希望在抢购之前,能有越来越多的人来浏览商品。但是在到达抢购时间,用户真正开始下单的时候,承载秒杀的服务器却不希望有几百万人同时发起抢购请求,因为服务器处理资源的能力是有限的,当出现请求峰值的时候就很容易造成服务器宕机,用户无法访问的情况出现。
这就好比出行的时候存在早高峰和晚高峰的情况,为了解决高峰问题,出行有错峰限行的解决方案。同理,在线上的秒杀业务等场景,也需要类似的解决方案来解决流量峰值的问题,这就是流量削峰的由来。
实现流量削峰的方案
削峰从本质上来说,就是更多地延缓用户请求,以及层层过滤用户的访问需求,遵从【最后落地到数据库的请求数要尽量少】的原则。
1.消息队列实现削峰
要对流量进行削峰,最容易想到的解决方案就是用消息队列来缓冲瞬时流量,把同步的直接调用转换成异步的间接推送,中间通过一个队列在一端承接瞬时的流量洪峰,在另一端平滑地将消息推送出去。
消息队列中间件主要解决应用耦合、异步消息、流量削峰等问题。常用的消息队列系统有ActiveMQ、RabbitMQ、ZeroMQ、Kafka、Me'taMQ和RocketMQ等。
在这里,消息队列就像是水库一样,拦截上游的洪水,削减进入下游河道的洪峰流量,从而达到减免洪水灾害的目的。
2.流量削峰漏斗:层层削峰
解决秒杀场景还可以对请求进行分层过滤,从而过滤掉一些无效的请求。分层过滤实际上就是采用漏斗式的设计来处理请求的,从高层至底层逐步过滤掉请求和数据。
分层过滤的核心思想是通过在不同的层次尽可能地过滤掉无效的请求,比如通过CDN过滤掉大量的图片、静态资源的请求,再通过类似Redis的分布式缓存来过滤请求等,也是典型的在上游拦截读请求。
分层过滤的基本原则是要对数据进行基于时间的合理分片,过滤掉过期的失效请求;对写请求做限流保护,将超出系统承载能力的请求过滤掉;涉及到的读数据不做强一致性校验,减少因为一致性校验产生瓶颈的问题;对写数据进行强一致性校验,只保留最后的有效数据;最终,让抵达漏斗最底端(数据库)的请求成为有效请求,例如当用户真实达到订单和支付的流程是需要数据一致性的。
总结
1.对于秒杀业务这样的高并发业务场景,最基本的原则就是要将请求拦截在系统的上游,降低下游的压力。如果不在前端拦截,就很可能会造成数据库读写锁冲突,甚至导致死锁,最终还有可能出现服务宕机的结果。
2.划分好动静资源,静态资源使用CDN进行服务分发,提高访问性能。
3.充分利用缓存(Redis等),增加QPS,从而加大整个集群的吞吐量。
4.高峰流量是压垮系统的一个重要原因,所以需要Kafka等消息队列在一端承接瞬时的流量洪峰,在另一端平滑地将消息推送出去。
"心若没有栖息的地方,到哪里都像在流浪。"