整个点赞服务的系统可以分为五个部分1、流量路由层(决定流量应该去往哪个机房)2、业务网关层(统一鉴权、反黑灰产等统一流量筛选)3、点赞服务(thumbup-service),提供统一的RPC接口4、点赞异步任务(thumbup-job)5、数据层(db、kv、redis)下文将重点分享下数据存储层、点赞服务层(thumbup-service)与 异步任务层(thumbup-job)的系统设计
2、三级数据存储
基本数据模型:点赞记录表:记录用户在什么时间对什么实体进行了什么类型的操作(是赞还是踩,是取消点赞还是取消点踩)等点赞计数表:记录被点赞实体的累计点赞(踩)数量①、第一层存储:DB层 - (TiDB)点赞系统中最为重要的就是点赞记录表(likes)和点赞计数表(counts),负责整体数据的持久化保存,以及提供缓存失效时的回源查询能力。点赞记录表 - likes : 每一次的点赞记录(用户Mid、被点赞的实体ID(messageID)、点赞来源、时间)等信息,并且在Mid、messageID两个维度上建立了满足业务求的联合索引。点赞数表 - counts : 以业务ID(BusinessID) 实体ID(messageID)为主键,聚合了该实体的点赞数、点踩数等信息。并且按照messageID维度建立满足业务查询的索引。由于DB采用的是分布式数据库TiDB,所以对业务上无需考虑分库分表的操作②、第二层存储缓存层Cache:点赞作为一个高流量的服务,缓存的设立肯定是必不可少的。点赞系统主要使用的是CacheAside模式。这一层缓存主要基于Redis缓存:以点赞数和用户点赞列表为例
1.点赞数
key-value = count:patten:{business_id}:{message_id} - {likes},{disLikes}
用业务ID和该业务下的实体ID作为缓存的Key,并将点赞数与点踩数拼接起来存储以及更新
2.用户点赞列表
key-value = user:likes:patten:{mid}:{business_id} - member(messageID)-score(likeTimestamp)
* 用mid与业务ID作为key,value则是一个ZSet,member为被点赞的实体ID,score为点赞的时间。当改业务下某用户有新的点赞操作的时候,被点赞的实体则会通过 zadd的方式把最新的点赞记录加入到该ZSet里面来
为了维持用户点赞列表的长度(不至于无限扩张),需要在每一次加入新的点赞记录的时候,按照固定长度裁剪用户的点赞记录缓存。该设计也就代表用户的点赞记录在缓存中是有限制长度的,超过该长度的数据请求需要回源DB查询
③、第三层存储LocalCache - 本地缓存本地缓存的建立,目的是为了应对缓存热点问题。利用最小堆算法,在可配置的时间窗口范围内,统计出访问最频繁的缓存Key,并将热Key(Value)按照业务可接受的TTL存储在本地内存中。其中热点的发现之前也有同步过:https://mp.weixin.qq.com/s/C8CI-1DDiQ4BC_LaMaeDBg④、针对TIDB海量历史数据的迁移归档迁移归档的原因(初衷),是为了减少TIDB的存储容量,节约成本的同时也多了一层存储,可以作为灾备数据。以下是在KV数据库(taishan)中点赞的数据与索引的组织形式:
1.点赞记录
1_{mid}_${business_id}_${type}_${message_id} => {origin_id}_{mtime}
2.用户点赞列表索引
2_{mid}_${business_id}_${type}_${mtime}_{message_id} => {origin_id}
3.实体维度点赞记录索引