高并发点赞功能设计

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 真实业务场景

记数系统的难点在于:业务拓展性,以及读写效率

业务拓展性:体现在下面这张图中,一个消息中,除了点赞数,还有评论、转发、阅读数。

Untitled.png

效率:一个页面中,有很多条消息(只能在代码中循环每一条消息)。

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上的其它业务数据的读写效率。

对于超过一定点赞阈值的微博,可以将其写入到「消息队列」,进行「异步消费」。

🔗 参考链接