system desing 系统设计(十一): 评论comment功能设计

  1、互联网服务重要的功能之一就是评论了,从电商到社交,从短视频到长视频,无一例外都有评论功能!如果是一些流量小的站点(average QPS只有几到十几那种),每天有几千条评论已经很多了,一年也就新增million级别的数据,就这点数据量,webserver可以直接从数据库DB读写,也可以在数据库做索引,反正流量都很小,整个系统没必要搞那么复杂,以减低后期运维的成本!但是对于MAU 有hundrends million级别的大厂来说,就要注意了:系统能不能抗住大流量? 以 Read:1000 RPS、Write:100 RPS 、 latency<=500ms为例:

  •    每年新增comments:100*3600*24*365=3.15billion
  •    假设每条评论150byte,每年新增3.15billion*150 = 440GB的数据;这还只是评论,还有其他字段,比如作者、时间、点赞/踩、回复等,加起来就更多了!

   从数据量看,建议选择nosql数据库,比如mongoDB,因为高并发,扩展性也要好很多!另外,为了加快数据的查询速度,把latency做到500ms以内:

  •    在nosql数据库中根据不同的value建index
  •    或则用Elastic search建索引

   综合考虑:还是在Elastic search建索引!原因:ES成熟的高,还可以建全文索引【比如用key查找comment】,建完索引后数据的膨胀度比nosql低!综合上面的考虑,整体数据流设计:

    

   client对comment的操作无非就这么几个:post comment,读comment、读context评论区,删除自己的comment,除了post comment是write option,其他3都涉及到查询检索,考虑到latency的要求,现在把这两类操作分成两条线:

  •  先看看查询检索这一路: 既然是查询,并且根据假定的Read:1000 RPS测算,建议用redis做cache,加速读取的时间;如果redis没有,就继续去最终的database+Elastic search检索和读取数据,具体怎么读要结合table的data model,后续介绍!
  •  再看看post comment这一线,以Write: 100 RPS测算
    • 上述是average RPS,peak RPS 以3倍计算,就是300。如果直接write into database,估计扛不住【database还要支持另外3个查询读取的操作了,这是又当爹又当妈的】,所以用kafka来削锋
    • 用户发表comment后,延迟几秒钟再看到自己的comment也能忍受,所以用kafka导致的latency是能接受的
    •  kafka里面的comment被API indexer接收后,同时push到database和Elastic search;进入database是为了长久保存,进入Elastic search是为了把关键的列用来建索引,加速查询!
    • 为了处理用户的读写请求,这里有两个service:API server和API indexer,为啥要分两个了?read的RPS远比write大,如果走一条线,万一某个环节崩溃,整个服务都宕机了;如果分成两条线,互相松耦合decoupling,互不影响读和写,后续出了问题也容易排查,降低运维的成本!

 2、(1)4个操作的rest接口设计如下:

        

   由于comment本身的字段属性可能变化,所以这部分以json形式返回!对应的,接口函数可以这样写了:

       

  (2)接口啥都设计好了,就剩下数据表的设计了!需要考虑的核心因素:

  • 表的字段:各种id(author、comment、ctx等)、内容、点赞/踩、comment的回复,这些字段都是要占用存储空间的等
  • 表和表的关系:星形?雪花形状?

   上述表的设计,直接影响到了数据的读写效率!

  • 如果全都放一个表:有些comment很小众和冷门,没有回复和点赞,那这两个字段岂不是空着浪费空间了?【当然,如果说磁盘够大,不差这点钱就当我没说】
  • 如果分开放几个表,像下面这种:读取的时候还要根据commendId和replyTo做join,加大latency!

     

    所以comment表设计如下:因为replyTo只是部分comment有,部分没有,所以这列不要了,剩下的4列肯定都是有数据的!

          

      连replyTo都没了,怎么知道comment是不是回复了?看看上面的设计思路,用户post comment是不是还通过kafka写入Elastic search建索引了么?这里不是还有replyTo的数据么?所以此时查询时就需要database+Elastic search配合联动了,流程如下:

          

    这时就体现了nosql+es的优势了:

  •    Elastic search建invert index时,value只取部分用得到的,借此控制数据膨胀的体积
  •    Elastic search和nosql都是KV形式的,根据K查找V很快,满足latency的需求!

  (3)点赞和踩,有如下特点:

  •  对于同一条comment,点赞和踩是互斥的,不能又点赞又踩
  •     数据跟新可以延迟,没那么强的实时性要求
  •     同一个author,对同一条comment,只能有1次的点赞或踩!

    

   如果设计成这样,怎么才能知道宋江的comment有没有被其他人重复赞过了?梁山一共才108好汉,除了宋江只剩107位了, 怎么有234个赞了?肯定是有重复的,所以数据库upvote个downvote的时候肯定是要检查是否重复的,这时的表模型又该怎么设计了?如下:

  

   既然在点赞时要检查以前是否已经点赞,自然是要把每个用户的点赞单独记录的,查询的时候流程如下:

  

   还是es和nosql的配合:因为都是KV形式的,查询的速度会很快!

 

参考:

1、https://www.bilibili.com/video/BV1Za411Y7rz?p=162&vd_source=241a5bcb1c13e6828e519dd1f78f35b2   评论系统设计 comment system

posted @ 2022-08-24 17:12  第七子007  阅读(844)  评论(0编辑  收藏  举报