0. Keywords
Keywords: 缓存抗读写、数据库扩展(列扩展+行扩展)、批量操作、计数系统与业务系统分离、业务拓展性、读写效率
1. 一些概念
QPS:并发量 / 平均响应时间。即每秒的响应请求数,也是最大吞吐能力。
2. 思路考虑
Redis 做缓存层,数据固化落到 DB 上。核心数据设计:
- mysql:t_count(msg_id, parise_count)
- redis(k-v): key: msg_id; value: praise_count
物理机依托 mysql 和 redis,水平拓展不是问题。
3. 计数系统的难点与优化
3.1 真实业务场景
记数系统的难点在于:业务拓展性,以及读写效率。
业务拓展性:体现在下面这张图中,一个消息中,除了点赞数,还有评论、转发、阅读数。
效率:一个页面中,有很多条消息(只能在代码中循环每一条消息)。
3.2 一种不算完美的解决方案
Redis 的 k-v 设计上,k 的生成规则可以使用:msg_id:业务flag
的格式。比如对于第一条消息的阅读数,它的 key 就是:1:read
;对于评论数:1:comment
。
在针对指定消息查询的时候,需要对 redis 发起多次 RPC 调用。浪费次数。
Mysql 的设计上,常见就是「列扩展」。如下所示:
MySQL记录
但是当新增属性时,需要新增一列,比如转发数量。随着需要统计的数据量种类增加,要不断扩展表的列,效率低下,容易出现「宽表」。
3.3 比较好的方案
针对 Redis,能做的就是降低单独消息的 RPC 调用次数,减少 Redis 访问次数。可以将 count 的计数,放在同一个 value 中。如下所示:
Redis记录
针对 Mysql,可以使用「行扩展」来解决列扩展问题,表结构设计如下:
MySQL记录
3.4 读写效率问题
对于计数系统来说,读的次数远远大于写的次数。因此,影响读写效率的主要是读操作。对于 redis 的 valu 结构优化来说,写的话需要 2 次 RPC,读的话仅需 1 次,使用写效率换读效率。
3.5 削峰填谷
对于热门微博,点赞数和评论数都是非常夸张的。此时,单纯用redis抗,也会影响在此redis上的其它业务数据的读写效率。
对于超过一定点赞阈值的微博,可以将其写入到「消息队列」,进行「异步消费」。