高并发系统设计 --基于MySQL构建评论系统

阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6

如何用MySQL来实现评论系统

为什么我不用mongodb

  1. 社区成熟度不如MySQLredis
  2. 需要学习的东西很多迁移扩容片建集群
  3. redis > mongodb

架构设计

使用MySQL进行存储的话就必须要用到Redis来做缓存后台admin需要接通ES来进行查询comment-service通过异步来进行写Redis和MySQL评论数据MySQL和ES通过Canal进行binlog同步。

缓存模式

首先我们需要预读我们读第一页的时候也需要把第二页的内容加载出来。读第二页的时候我们预先读第三页这样可以避免大量的cache miss。

但是这里有一个致命的问题就是当缓存抖动的时候会触发大量的cache rebuild因为我们使用了预加载容易造成OOM(内存溢出)。因此我们需要使用消息队列来进行逻辑异步化对于当前请求只返回MySQL中的部分数据即可。

写的逻辑

至于写的操作我们要穿透到存储层因此最好使用消息队列异步削峰。例如我的评论发布出去了用户过100ms才看到评论这是无所谓的。

存储设计

comment_subject表

idint主键
obj_idint对象id
obj_typeint对象类型
member_idint作者id
countint评论总数
root_countint跟评总数
all_countint评论+回复总数
stateint状态 0正常 1隐藏
attrsint属性 0置顶 1不置顶
create_time+update_timedatatime创建时间修改时间

obj_id+obj_type把评论系统设计成中台。 一般是指搭建一个灵活快速应对变化的架构快速实现前端提的需求避免重复建设达到提高工作效率目的。

obj_id+obj_type形成了一个业务键比如微博发帖发视频你可以发视频你也可以发文章评论系统设计成中台。

comment_index

idint主键id
obj_idint对象id
obj_typeint对象类型
member_idint发表者id
rootint根评论id不为0是回复评论
parentint父评论id为0是root评论
floorint评论楼层
countint评论总数
root_countint根评论总数
likeint点赞数
hateint点踩数
stateint状态0正常1隐藏
attrsint属性
create_timedatetime创建时间
update_timedatetime修改时间

parent父评论id其实就是记录是否是回复评论。

comment_content表

comment_idint主键
at_member_idsvarchar对象id
ipint对象类型
platformint发表者id
devicevarchar跟评论id不为0是回复评论
messagevarchar评论内容
metavarchar评论元数据背景字体
create_timedatetime创建时间
update_timedatetime修改时间

index是索引表content是内容表。

数据写入事务更新comment_subjectcomment_indexcomment_content三张表其中content是非强制性需要一致性考虑的。因此可以先写入content之后事务更新其他表。即便content更新成功后续失败仅仅存在一条ghost数据。

数据读取基于obj_id + obj_typecomment_index表找到评论列表where root=0 order by floor。之后根据comment_index的id字段捞出comment_content的评论内容。对于二级的子楼层where parent/root in(id...)

为什么要把index和content分成两个表

comment_index评论楼层的索引表实际并不包含内容。comment_content评论内容的表包含评论的具体内容。其中comment_index的id字段和comment_content是1对1的关系这里面包含了几种设计思想。

  • 表都有主键comment_content没有id是为了减少一次二级索引查找直接基于主键检索同时comment_id在写入要尽可能的顺序自增。
  • 索引内容分离方便mysql_datapage缓存更多的row如果和content耦合会导致更大的IO。长远来看content信息可以直接使用KV storage存储。

缓存设计

comment_subject_cache【string】

keystringoid_type
valueintsubject marshal string
expireduration24h

comment_index_cache【sorted set】

keystringcache keyoid_type_sort其中sort为排序方式0楼层1回复数量
memberintcomment_id评论id
scoredouble楼层号回复数量排序得分
expireduration8h

comment_content_cache

keystringcomment_id
valueintcontent
expireduration24h

comment_subject_cache对应主题的缓存value使用protobuf序列化的方式存入这样调用rpc的时候速度可以更块一点。

comment_index_cache使用redis sorted set进行索引的缓存索引即数据的组织顺序而非数据内容。通过预加载少量数据通过增量加载的方式逐渐预热填充缓存而redis sorted set skiplist的实现可以做到O(logN) + O(M)的时间复杂度效率很高

sorted set是要增量追加的因此必须判定key存在才能zadd

comment_content_cache对应评论内容数据使用protobuf序列化的方式存入。

增量加载(目标表仅更新源数据表中变化的内容)+lazy加载(延迟加载种将资源标识为非阻塞非关键资源并仅在需要时加载它们的策略)

可用性设计

其实就是各种缓存问题消息队列消息等问题。

如果这个key是热点的key的话可以使用本地缓存+分布式缓存。

那么如何统计是否是热点呢

这里我们就移步到我们的下一篇文章了谢谢大家。

阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6
标签: mysql