【七日打卡】理解缓存预热

173 阅读6分钟

缓存冷启动问题

如图所示,redis中没有数据,导致大量请求 打给了 mysql,mysql很难抗住大量的请求。

缓存预热

  1. 我们提前给redis中写入部分数据,再提供服务

    我们肯定不可能将所有数据都写入redis

    • 因为数据量过大,写入耗费时间太长了,**
    • redis内存资源有限,无法容纳全部的数据

    因此我们可以将部分热数据写入redis,而不是写入所有的数据

  2. 需要根据当天的具体访问情况,实时统计出访问频率较高的热数据(热数据统计

  3. 然后将访问频率较高的热数据写入redis中

  4. 然后将写入了热数据的redis对外提供服务,这样就不至于冷启动,直接让数据库裸奔

缓存预热方案的目的就是要让redis中尽可能包含热数据,避免mysql裸奔(扛不住高并发)。

具体方案

因为方案使用到了storm完成实时计算,所以这里罗列了关于storm的基本原理,其实也可以采用flink等实时计算基数。

storm与流计算

Storm 是一个开源的分布式实时计算框架,可以以简单、可靠的方式进行大数据流的处理。通常用于实时分析,在线机器学习、持续计算、分布式 RPC、ETL 等场景。

Storm 与 Hadoop对比

Hadoop 采用 MapReduce 处理数据,而 MapReduce 主要是对数据进行批处理,这使得 Hadoop 更适合于海量数据离线处理的场景。而 Storm 的设计目标是对数据进行实时计算,这使得其更适合实时数据分析的场景。

Storm 与 Spark Streaming对比

Spark Streaming 并不是真正意义上的流处理框架。 Spark Streaming 接收实时输入的数据流,并将数据拆分为一系列批次,然后进行微批处理。只不过 Spark Streaming 能够将数据流进行极小粒度的拆分,使得其能够得到接近于流处理的效果,但其本质上还是批处理(或微批处理)

流处理

什么是流处理

与流数据相对的是静态数据处理。

在流处理之前,数据通常存储在数据库或文件系统中,应用程序根据需要查询或计算数据,这就是传统的静态数据处理架构。Hadoop 采用 HDFS 进行数据存储,采用 MapReduce 进行数据查询或分析,这就是典型的静态数据处理架构。

而流处理则是直接对运动中数据的处理,在接收数据的同时直接计算数据。实际上,在真实世界中的大多数数据都是连续的流,如传感器数据,网站用户活动数据,金融交易数据等等 ,所有这些数据都是随着时间的推移而源源不断地产生。

接收和发送数据流并执行应用程序或分析逻辑的系统称为流处理器。流处理器的基本职责是确保数据有效流动,同时具备可扩展性和容错能力,Storm 和 Flink 就是其代表性的实现。

流处理的优点

  • 可以立即对数据做出反应:降低了数据的滞后性,使得数据更具有时效性,更能反映对未来的预期;
  • 可以处理更大的数据量:直接处理数据流,并且只保留数据中有意义的子集,然后将其传送到下一个处理单元,通过逐级过滤数据,从而降低实际需要处理的数据量;
  • 更贴近现实的数据模型:在实际的环境中,一切数据都是持续变化的,想要通过历史数据推断未来的趋势,必须保证数据的不断输入和模型的持续修正,典型的就是金融市场、股票市场,流处理能更好地处理这些场景下对数据连续性和及时性的需求;
  • 分散和分离基础设施:流式处理减少了对大型数据库的需求。每个流处理程序通过流处理框架维护了自己的数据和状态,这使其更适合于当下最流行的微服务架构。

方案讲解

本文的项目背景是一个电商详情页,通过nginx去请求后端服务,获取商品信息。

  1. nginx+lua将访问流量上报到kafka中

  2. storm从kafka中消费数据,实时统计出每个商品的访问次数,访问次数基于LRU内存数据结构的存储方案(LRUMap)

  3. 每个storm task启动的时候,基于zk分布式锁,将自己的id写入zk同一个节点中

  4. 每个storm task负责完成自己这里的热数据的统计(每隔一段时间,就遍历一下这个map,然后维护一个前3个商品的list,更新这个list)

  5. 写一个后台线程,每隔一段时间,比如1分钟,都将排名前3的热数据list,同步到zk中去,存储到当前storm task对应的一个znode中去

  6. 我们需要启动一个服务

    • 服务可能部署了很多个实例
    • 每次服务启动的时候,就会去拿到一个storm task的列表,然后根据taskid,一个一个的去尝试获取taskid对应的znode的zk分布式锁
    • 如果能获取到分布式锁的话,那么就将那个storm task对应的热数据的list取出来
    • 然后将数据从mysql中查询出来,写入缓存中,进行缓存的预热

编码实现思路

  1. 服务启动的时候,进行缓存预热(多个服务实例)

  2. 从zk中读取taskid列表

  3. 依次遍历每个taskid,尝试获取分布式锁,如果获取不到,快速报错,不要等待,因为说明已经有其他服务实例在预热了

  4. 直接尝试获取下一个taskid的分布式锁

  5. 即使获取到了分布式锁,也要检查一下这个taskid的预热状态,如果已经被预热过了,就不再预热了

  6. 执行预热操作,遍历productid列表,查询数据,然后写ehcache和redis

  7. 预热完成后,设置taskid对应的预热状态

图解

参考文章

  1. 大数据干货系列(七)--Storm总结

  2. Storm 核心概念详解

  3. Storm 1.1.0 中文文档

  4. 中华石杉—亿级流量电商详情页系统(缓存架构、高可用架构、微服务架构)