redis定时同步到数据库的方案| 青训营

414 阅读3分钟
redis定时同步pb方案

在本次青训营项目中功能,由于点赞使用redis存储提高效率,需要设置定时任务将redis中数据同步到pb。该笔记记录了该过程中的细节思考,主要考虑的有两点:如何读取redis中所有记录、如何完成定时任务对数据库的更新。

(1)读取redis中所有记录
  • 问题描述: 在对 redis 点赞记录定时同步任务中,我们需要得到 redis 中的所有点赞记录 hash,并将其中新增的数据同步到 mysql。

    • 基础版本中使用 redis 中的 keys 方法来扫描所有 key 得到点赞记录。但是 keys 指令做的是全量扫描,会在 Redis 中阻塞所有其他操作,直到它完成为止。如果 Redis 中存储了大量的键,这个指令可能会导致 Redis 在一段时间内无响应。此外,keys 指令会一次性返回所有匹配的键,占用大量内存。
  • 优化方案: 改为使用 scan 方法来进行分段增量迭代扫描,相比之下 scan 指令是一个基于游标的迭代器,可以逐步返回匹配的键,而不会阻塞其他 Redis 操作。此外,scan 指令可以在迭代过程中返回键的子集,从而减少了在一次操作中返回大量键所带来的内存占用问题。

(2)定时任务的数据库更新
  • 问题描述: 在扫描redis获取全部数据后,需要将数据写入mysql。而数据的写入操作都在同一张表内,因此我们考虑尽可能的减少数据库的IO以提高性能。

    • 基础版本中会遍历每一条 redis 中的数据进行判断,如果某条在数据库中存在则执行更新操作,如果不存在则执行插入操作。但每次判断并写入会在同步的这段时间内带来大量数据库IO。
  • 优化方案: 使用 redis 存储数据并定时同步 mysql 的一个好处如是可以降低用户访问延迟并防止用户直接写数据库;而另一个好处则体现在数据库更新中,由于 redis 中一次存储很多条操作同一数据库表的数据,我们可以执行批量插入操作来减少数据库IO。

    • 方案细节如下:

      • 定时任务触发时,使用 Hscan 方法扫描 redis hash 结构的 key 得到所有的点赞记录;
      • 遍历每一个点赞记录,如果在 mysql 中存在则直接进行update,如果不存在则将该条记录并向后拼接到一个批量插入字符串上;
      • 遍历完 redis 中的点赞记录后,该字符串中的所有数据则为要插入数据,将其拼接为sql语句执行 mysql 的批量 insert,用一次 IO 完成插入。

image.png