当前位置:首页 > 问答 > 正文

用Redis怎么快速存储和统计文章阅读量那些事儿,简单又高效的方案分享

直接用Redis来存文章阅读量,这事儿特别简单,核心就是两个命令:INCRHINCRBY,你不用想得太复杂,我一步步跟你说。

最基本的方法:一个键对应一篇文章

这是最直白的想法,每篇文章给一个唯一的键(Key),article:read:count:12345,这里的 12345 就是文章的ID,每次有人阅读这篇文章,你就执行一句命令:

INCR article:read:count:12345

这个 INCR 命令很棒,它做了两件事:把键对应的值增加1;如果这个键本来不存在,它会自动创建并把值设为1,你什么都不用操心,一句命令就搞定了读取和增加,要查看阅读量呢?再用一个 GET article:read:count:12345 就行了。 (来源:基于Redis官方对INCR命令的通用用法描述)

这种方法好处是简单到没朋友,但有个小问题,如果你的文章数量非常多,比如有10万篇,那么就会有10万个这样的键散落在Redis里,虽然Redis处理起来也没啥压力,但当我们想批量获取一批文章的阅读量时,就得一个个去查,稍微有点麻烦。

更省空间、适合批量操作的方法:用哈希表(Hash)

为了解决上面说的问题,可以用Redis的哈希表结构,思路是把一批文章的阅读量放在一起。

比如说,你可以按文章发布的日期来分组,今天是2023年10月27日,你就可以创建一个叫 article:read:count:20231027 的哈希表,在这个哈希表里,每个字段(Field)是文章的ID(12345),对应的值(Value)就是这篇文章当天的阅读量。

增加阅读量的命令就变成了:

HINCRBY article:read:count:20231027 12345 1

意思是,在名为 article:read:count:20231027 的哈希表里,给字段 12345 的值增加1。 (来源:基于Redis官方对HINCRBY命令的通用用法描述)

这样做有什么好处呢? 第一,节省内存,Redis在存储很多小键值对时,用一个哈希表把它们包起来,比让它们各自为政要更节省空间。 第二,方便统计,如果你想获取今天所有文章的阅读量概况,直接用 HGETALL article:read:count:20231027 命令,就能一次性拿到这天所有文章的阅读量数据,非常利于做每日统计。

应对高并发阅读和性能考虑

你可能担心,万一有一篇爆款文章,瞬间几万人点击,INCR 命令会不会把Redis搞垮?这个基本可以放心,Redis是单线程处理命令的,意味着每个命令都是原子操作。INCRHINCRBY 在执行时绝对不会出现混乱,即使十万人同时发令,Redis也会排好队,一个接一个安全地增加数值,最终结果绝对是准确的。

为了追求极致的性能,你可以考虑一种“先内存累加,再定时写入Redis”的招数,就是在你的应用服务器内存里,用一个Map之类的结构,先把阅读量增加累积起来,比如每累积10次阅读,或者每隔5秒钟,才向Redis发送一次 INCRBY article:read:count:12345 10 这样的命令,把累积的量一次性加上去,这样就把对Redis的写入频率降低了成百上千倍,大大减轻了Redis的压力。 (来源:这是一种常见的、基于应用层聚合的通用性能优化思路)

但这样做有个缺点:阅读量更新会有短暂的延迟(比如几秒钟),并且如果应用服务器突然重启,内存里还没来及同步到Redis的数据就会丢失,除非你对性能要求极高,且能接受轻微的数据延迟和极小概率的丢失,否则直接用 INCR 是最简单稳妥的。

关于数据持久化的问题

用Redis存阅读量,很多人会问:“如果Redis服务器重启了,数据会不会丢?” 这取决于你的Redis配置,Redis本身可以把数据持久化到硬盘上,有两种主要方式:

  1. RDB(快照):隔一段时间把内存里的数据拍个照存到硬盘,如果中途宕机,可能会丢失最后一次快照到宕机之间的数据(比如几分钟的数据)。
  2. AOF(日志):把每一个写命令都记录到日志文件里,这样即使宕机,重启后重新执行一遍日志里的命令,几乎可以恢复所有数据(最多丢失1秒的数据)。 (来源:基于Redis官方关于持久化的通用介绍)

对于阅读量这种数据,丢失几分钟甚至一小部分,通常是可以接受的,所以用RDB模式就足够了,它在性能和数据安全之间取得了很好的平衡,如果你要求绝对不能丢,可以开启AOF模式,但这会稍微影响一点写入性能。

总结一下

用Redis快速存储和统计文章阅读量,真的不难:

  • 起步阶段,直接用 INCR article:read:count:{文章ID},简单粗暴效果好。
  • 文章量大了,考虑用哈希表 HINCRBY article:read:count:{日期} {文章ID} 1 来分组管理,省内存且利于批量查询。
  • 担心性能?Redis自身的原子操作足以应对绝大多数高并发场景,极端情况下,可以在应用层做批量聚合,但会牺牲一点实时性。
  • 怕数据丢失?配置好Redis的RDB或AOF持久化策略,就能根据你的需求保证数据安全。

这套方案的好处是开发速度快,性能高,基本能满足绝大多数网站和App对阅读量统计的需求。

用Redis怎么快速存储和统计文章阅读量那些事儿,简单又高效的方案分享