什么是“热点”
热点分为热点操作和热点数据。
所谓“热点操作”,例如大量的刷新页面、大量的添加购物车、双十一零点大量的下单等都属于此类操作。
对系统来说,这些操作可以抽象为“读请求”和“写请求”
读请求的优化空间要大一些
写请求的瓶颈一般都在存储层,优化的思路就是根据 CAP 理论做平衡
“热点数据”是用户的热点请求对应的数据。而热点数据又分为“静态热点数据”和“动态热点数据”。
- “静态热点数据”,就是能够提前预测的热点数据。例如,我们可以通过卖家报名的方式提前筛选出来,通过报名系统对这些热点商品进行打标。另外,我们还可以通过大数据分析来提前发现热点商品,比如我们分析历史成交记录、用户的购物车记录,来发现哪些商品可能更热门、更好卖,这些都是可以提前分析出来的热点。
- “动态热点数据”,就是不能被提前预测到的,系统在运行过程中临时产生的热点。例如,卖家在抖音上做了广告,然后商品一下就火了,导致它在短时间内被大量购买。
发现静态热点数据
静态热点数据可以通过商业手段,例如强制让卖家通过报名参加的方式提前把热点商品筛选出来,实现方式是通过一个运营系统,把参加活动的商品数据进行打标,然后通过一个后台系统对这些热点商品进行预处理,如提前进行缓存。但是这种通过报名提前筛选的方式也会带来新的问题,即增加卖家的使用成本,而且实时性较差,也不太灵活。
不过,除了提前报名筛选这种方式,还可以通过技术手段提前预测,例如对买家每天访问的商品进行大数据计算,然后统计出 TOP N 的商品,我们可以认为这些 TOP N 的商品就是热点商品。
发现动态热点数据
动态热点发现系统的具体实现
- 构建一个异步的系统,它可以收集交易链路上各个环节中的中间件产品的热点 Key,如 Nginx、缓存、RPC 服务框架等这些中间件(一些中间件产品本身已经有热点统计模块)。
- 建立一个热点上报和可以按照需求订阅的热点服务的下发规范,主要目的是通过交易链路上各个系统(包括详情、购物车、交易、优惠、库存、物流等)访问的时间差,把上游已经发现的热点透传给下游系统,提前做好保护。比如,对于大促高峰期,详情系统是最早知道的,在统一接入层上 Nginx 模块统计的热点 URL。
- 将上游系统收集的热点数据发送到热点服务台,然后下游系统(如交易系统)就会知道哪些商品会被频繁调用,然后做热点保护
主要是依赖前面的导购页面(包括首页、搜索页面、商品详情、购物车等)提前识别哪些商品的访问量高,通过这些系统中的中间件来收集热点数据,并记录到日志中
通过部署在每台机器上的 Agent 把日志汇总到聚合和分析集群中,然后把符合一定规则的热点数据,通过订阅分发系统再推送到相应的系统中。你可以是把热点数据填充到 Cache 中,或者直接推送到应用服务器的内存中,还可以对这些数据进行拦截,总之下游系统可以订阅这些数据,然后根据自己的需求决定如何处理这些数据。
打造热点发现系统时几点注意事项。
- 这个热点服务后台抓取热点数据日志最好采用异步方式,因为“异步”一方面便于保证通用性,另一方面又不影响业务系统和中间件产品的主流程。
- 热点服务发现和中间件自身的热点保护模块并存,每个中间件和应用还需要保护自己。热点服务台提供热点数据的收集和订阅服务,便于把各个系统的热点数据透明出来。
- 热点发现要做到接近实时(3s 内完成热点数据的发现),因为只有做到接近实时,动态发现才有意义,才能实时地对下游系统提供保护。
处理热点数据
一是优化,二是限制,三是隔离
优化热点数据最有效的办法就是缓存热点数据,如果热点数据做了动静分离,那么可以长期缓存静态数据。但是,缓存热点数据更多的是“临时”缓存,即不管是静态数据还是动态数据,都用一个队列短暂地缓存数秒钟,由于队列长度有限,可以采用 LRU 淘汰算法替换
限制更多的是一种保护机制,限制的办法也有很多,例如对被访问商品的 ID 做一致性 Hash,然后根据 Hash 做分桶,每个分桶设置一个处理队列,这样可以把热点商品限制在一个请求队列里,防止因某些热点商品占用太多的服务器资源,而使其他请求始终得不到服务器的处理资源。
秒杀系统设计的第一个原则就是将这种热点数据隔离出来,不要让 1% 的请求影响到另外的 99%,隔离出来后也更方便对这 1% 的请求做针对性的优化。
可以在下几个层次实现隔离
- 业务隔离。把秒杀做成一种营销活动,卖家要参加秒杀这种营销活动需要单独报名,从技术上来说,卖家报名后对我们来说就有了已知热点,因此可以提前做好预热。
- 系统隔离。系统隔离更多的是运行时的隔离,可以通过分组部署的方式和另外 99% 分开。秒杀可以申请单独的域名,目的也是让请求落到不同的集群中。
- 数据隔离。秒杀所调用的数据大部分都是热点数据,比如会启用单独的 Cache 集群或者 MySQL 数据库来放热点数据,目的也是不想 0.01% 的数据有机会影响 99.99% 数据。
实现隔离有很多种办法
- 按照用户来区分,给不同的用户分配不同的Cookie,在接入层,路由到不同的服务接口中
- 在接入层针对 URL 中的不同 Path来设置限流策略
- 服务层调用不同的服务接口,以及数据层通过给数据打标来区分等等这些措施