朋友圈的系统设计思考

乐云一
  • 设计
  • 设计
About 1724 wordsAbout 6 min

微信朋友圈的设计

B站刷到经常看的事故区UP 极海Channelopen in new window 的视频,https://www.bilibili.com/video/BV1kC411h7V9/?spm_id_from=333.999.0.0&vd_source=08af8467d86ee3cf7b802fe0f136c2d7 ;

其中有一个系统设计问题,如何实现微信朋友圈功能

基于一个开发人的素养,第一时间想了自己对于博客评论功能的那一套设计,基本功能实现没问题。

不过关于微信的点赞只有看能认识人,再结合微信的并发。

这个问题,可以很有趣的探讨;

有什么功能

发布+评论+点赞

用户A发布朋友圈之后,其好友用户B可以看到并且进行点赞和评论;

存在用户C,如果是共同好友,那么用户C可以双向看到用户B在用户A的朋友圈下的记录。

用户A可设置仅用户B查看,或禁止用户C观看。

总结来说就是:

  • 仅好友之间可见,好友只能看到好友
  • 黑名单功能
  • 好友新发朋友圈提醒
  • 删除评论、取消点赞

问题

如果有充足的时间去思考朋友圈是怎么完成的,很多人可以娓娓道来;

但是如果这个问题突然打向毫无准备的你,阁下该如何应对;

常规的评论系统的表设计:

  • 用户表,存储用户基本信息
  • 文章表,文章存储
  • 文章评论表,文章关联及评论的父子级关联

相比于传统的博客类型的文章-评论系统,朋友圈有自己的独特功能是:

  • 点赞,评论,过滤掉非好友用户
  • 大数据量并发的读多写少数据
  • 黑名单用户不可见

因此朋友圈的实现核心解决这三个,剩下的就是基本的文章-评论功能了

实现

仅好友用户可见

首先要说一个细节,在微信朋友圈中,你看到的好友并非好友的微信名,而是他的备注。

因此可以很容易得知,朋友圈下的所有好友信息都是通过传递id,页面翻译或者由后台联表翻译我设置好友的备注名。

有两个方案:

  1. Mysql 设计一张文章-用户关联表

    这里需要强调,为什么不适用一个字段存储用户点赞人:减少文章表的IO压力,因为要知道文章表作为一个主表会冗余多少字段是未知的,虽然微信好友有5000的上线,只需一个简单的json字段就能存住。但是这会为后续的拓展以及性能造成不可控的影响;

    使用mysql的话就是简单的联表查询然后DB了,需要注重的也只是索引的设计。因为本身是动态的数据不存在缓存,都是实时的查询读取。

    不过用户ID以及文章ID一般都是UUID类的主键设计,对比整形的查询性能多少存在差异;

  2. MongDB,文档关联

    使用文档:

    {
        "id":"1", //主键id
        "articleId":"1", //文章id
        "type":1, //类型,点赞,评论
        "content":"", 
        "userId":2, 
        "author":9, //作者
        "fatherId":1001,//父节点id
        "timestamp":1711807849
    }
    

    也可以:

    {
        "articleId":"1",//主键id
        "userId":1, //发布人
        "content":"今天心情很好", //内容
        "resource":["",""], //媒体资源
        "like":["1","2"],//点赞人
        "InvolvingUser":["1","2"],//涉及用户
        "timestamp":1711807849
    }
    

前者是标准的关联关系,和mysql一样通过业务去关联查询然后过滤;

后者则是将评论于该朋友圈的涉及人员划分开来:

  1. 查询该朋友圈,拿到涉及人员
  2. 将涉及人员根据当前用户的好友列表进行过滤
  3. 仅查询我好友的评论

不过严谨的说,也需要关联、过滤什么的,可以直接拿当前用户的好友列表当前查询条件去查询评论😃。

这里需要探寻的是为什么使用MongDb:

  • 一是对比Mysql,在这里会频繁的查询,新增,修改还是非关系型数据库,采取文档对象存储的方式更适合文章对象
  • 二是性能考虑,因为不管使用哪种存储都是会直接进行Db操作的,没有缓存兜底。所以为何不使用直接内存读写性能更强大的mongdb呢

读多写少

因为是一个非常标准的查询-新增模式的功能,所以大数据量的读多写少也可以看成一个普通的CRUD功能;

并发?抱歉,因为不涉及金额、订单等等问题只需要最终一致,并且评论时间,点赞时间全然是由时间戳控制,所以完全可以交给数据库自带的乐观锁机制处理;

查询慢?那就减少联表数量,比方说好友列表的用户id可以采用缓存或页面传输;

最后强调的是读多写少,在我的观念中使用Mysql进行存储是比较差的思路。MongDb文档内存模型,你值得拥有;

黑名单

这里也有一个使用细节,朋友圈发布一篇文章时设置某人不可见 之后再将其可见,好友最终会可见;

因此和仅好友可见一样:

  • 通过关联表设计不可见或者可见好友表
  • 通过一个字段去控制

朋友圈提醒

即右下角未读的红点;

首先关于APP端如何检测登录用户有无朋友圈未读,只有两种选择:

  1. 接入mq中间件,通过消息发布订阅模式让app监控当前用户的消息仓库
  2. app轮询调用接口,查询未读状态

前者如果应用本身就接入了消息中间件那么可以采用,但只为了未读而去引入重体量的中间件不可取。

后者则是需要后台着重维护未读及未读数量的缓存信息

总结

简简单单的唠嗑看了视频后的简单思考,最终下来感觉自己想的很乱。

总有一种,真的这么简单就能做出微信朋友圈?但是又一时找不出真正的技术难点所在;

可惜的是没有尽量也没有开发过微信朋友圈这种体量的博客-评论的业务,思维限制在了过去自己开发自己网站时简单的文章-评论设计中;

后续有涉及,再开一篇文章回顾。

Last update:
Contributors: LeYunone
Comments
  • Latest
  • Oldest
  • Hottest
Powered by Waline v2.14.7