求教各位彦祖,点赞系统设计的最佳实践? - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
请不要在回答技术问题时复制粘贴 AI 生成的内容
GreatEscape
V2EX    程序员

求教各位彦祖,点赞系统设计的最佳实践?

  •  
  •   GreatEscape 2021-07-27 10:57:48 +08:00 4355 次点击
    这是一个创建于 1617 天前的主题,其中的信息可能已经有所发展或是发生改变。

    我们有一个类知乎的服务,日活 500 万左右;用户可以对文章进行点赞,但是用户只有在文章详情页才可以进行点赞相关的查询和操作,QPS 也不高,所以直接走数据库查询也没有太大性能问题。 最近产品提出将点赞按钮前置到文章列表中的需求,我们每次分页会查询 50 篇文章的信息,肯定不能直接走数据库了。 目前我初步想法是将用户点赞数据放到 Redis 位图中,考虑到用户点赞其实是个相对低频的操作,点赞、取消点赞都直接操作 Redis,异步刷新到 DB,这样牺牲了部分可靠性,比如 Redis 挂了导致用户操作没有同步到 DB 、或者 Redis 操作成功,但是 DB 操作失败如何处理,还要考虑如异步调用乱序如何处理。 所以想请教下各位 V2er,这类点赞系统的设计有没有一些最佳实践?比如走 ES 或 Mongo?

    19 条回复    2021-07-29 10:41:59 +08:00
    love2020
        1
    love2020  
       2021-07-27 11:06:09 +08:00
    25 次点击,没人回答你的问题。 [也许 Redis 真的没那么容易挂。。]
    securityCoding
        2
    securityCoding  
       2021-07-27 11:08:04 +08:00
    redis-》进程内缓存-》 DB,完全能扛得住
    GreatEscape
        3
    GreatEscape  
    OP
       2021-07-27 11:14:02 +08:00
    服了,发出来怎么换行等格式全没了。。。
    bnrwnjyw
        4
    bnrwnjyw  
       2021-07-27 11:22:30 +08:00
    @GreatEscape markdown 要换两行
    no1xsyzy
        5
    no1xsyzy  
       2021-07-27 11:34:13 +08:00
    我猜测将「文章被点赞总数」一并进行存储再添加[用户,文章]联合索引即可满足性能需求。
    最佳实践应是图数据库

    ps.
    markdown 换两行 = 分 <p>
    空两格换一行 = <br>
    hahasong
        6
    hahasong  
       2021-07-27 12:00:43 +08:00
    各家主流的做法是,点赞 /取消 界面 UI 实时反馈(与请求无关),然后上报一次事件。你可以把事件记在队列里。然后匀速消费,统计点赞数和记日志。你不记操作日志,点赞人进去怎么看到自己是点了还是没点


    也可以简化做,不用队列,直接请求接口,但是 WAF 做下限流就行,大不了太多了返回 “操作频繁,请稍后再试”
    xuanbg
        8
    xuanbg  
       2021-07-27 12:16:55 +08:00
    分页查询怎么就不能直接查表了? left join 点赞记录表就好了嘛
    tedcon
        9
    tedcon  
       2021-07-27 15:07:53 +08:00
    点赞的数量 也就是读操作可以放到缓存。写操作先入 db 然后同步到缓存。这不是常规操作吗?
    GreatEscape
        10
    GreatEscape  
    OP
       2021-07-27 16:17:56 +08:00
    @xuanbg 看 QPS 的,我们之前点赞列表直接联表查,有次做活动,直接引导用户跳转到自己的点赞列表,联表查就差点查挂了。
    bthulu
        11
    bthulu  
       2021-07-28 09:02:47 +08:00
    写入浏览器本地数据库就行了, 每次用户登录或退出登录的时候, 随登录或退出登录接口传到后端存入数据库即可
    GreatEscape
        12
    GreatEscape  
    OP
       2021-07-28 09:59:45 +08:00
    @tedcon 重点不在于点赞数量,而是用户对该文章的点赞状态,写 DB 同步到缓存会导致用户快速操作时出现缓存不一致的问题。
    waibunleung
        13
    waibunleung  
       2021-07-28 10:43:52 +08:00
    像上面 @hahasong 说的,先界面 UI 实时响应,然后前端 /客户端先把用户点赞过的内容先缓存起来,后端用队列来将点赞数据落地到 DB 。请求用户点赞状态 /计数的时候,返回结果带上一个版本号,前端通过版本号来对比来决定是否+1 或者替换掉服务端的数据,这样是否可以?

    点赞这种东西,不需要强一致性的,只需要保持最终一致就好了。至于数据丢失,肯定会有的,CAP 理论,看你们怎么取舍而已。保证 BASE 可用就好了。个人理解,欢迎友好交流~
    a719031256
        14
    a719031256  
       2021-07-28 13:58:10 +08:00
    我到觉得你先做出来再谈优化,楼主给我的感觉跟我现在带的同事好像,东西没做就想这想那
    4BVL25L90W260T9U
        15
    4BVL25L90W260T9U  
       2021-07-28 14:11:42 +08:00
    我真是特别讨厌叫人「彦祖」这种提问方式,不是每个人都喜欢明星的
    tedcon
        16
    tedcon  
       2021-07-28 16:17:47 +08:00
    @GreatEscape 这个就需要前端控制啊 不管是点赞还是其他操作。前端肯定要有个 state=pending 然后等待 response,成功了才将点赞+1,pending 的时候无法再次点赞。
    shadowfish0
        17
    shadowfish0  
       2021-07-29 01:11:08 +08:00   1
    @ospider 这只是个梗吧,意思和喊帅哥差不多
    ljzxloaf
        18
    ljzxloaf  
       2021-07-29 10:10:08 +08:00
    先更新计数(建议用可持久化的 kv 数据库如 etcd,redis 是用来做缓存的),具体请求先写到消息队列,异步更新到数据库。还有评论啊点赞啊这些东西都是要做频率控制的
    ljzxloaf
        19
    ljzxloaf  
       2021-07-29 10:41:59 +08:00
    @ljzxloaf #18 etcd 好像没有相关的 api,还是用 redis 吧。。注意下可用性
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     1138 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 25ms UTC 17:56 PVG 01:56 LAX 09:56 JFK 12:56
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86