朋友遇到一个面试题,微信朋友圈怎么设计? - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
请不要在回答技术问题时复制粘贴 AI 生成的内容
UserNameisNull
V2EX    程序员

朋友遇到一个面试题,微信朋友圈怎么设计?

  •  1
     
  • &nsp; UserNameisNull 2021-04-23 17:00:48 +08:00 9128 次点击
    这是一个创建于 1700 天前的主题,其中的信息可能已经有所发展或是发生改变。
    假设微信朋友圈的
    读 QPS 100w
    写 QPS 10w
    每个用户最多 400 个朋友,
    发朋友圈和刷朋友圈该怎么设计?
    数据怎么存储?
    求大佬解答。
    第 1 条附言    2021-04-23 22:34:28 +08:00
    抖音技术 leader 。
    写扩散,400 * 10w = 4000w 被否决
    读扩散的话 100w qps,redis 扛不住为由否决。。。。。。。
    除了 redis,还有什么高并发解决方案呢?
    第 2 条附言    2021-04-23 22:35:30 +08:00
    收藏的人好多啊
    30 条回复    2021-04-28 16:45:51 +08:00
    THESDZ
        1
    THESDZ  
       2021-04-23 17:04:23 +08:00
    查阅 feed 流
    brader
        2
    brader  
       2021-04-23 17:09:47 +08:00
    这种面试不就是在空手套白狼?白嫖人家的高并发设计架构
    hejw19970413
        3
    hejw19970413  
       2021-04-23 17:11:13 +08:00
    我感觉 面试想问 数据表和缓存怎么设计,可以参考评论系统。
    ch2
        4
    ch2  
       2021-04-23 17:13:07 +08:00   2
    这种有时间先后顺序的 timeline,就是用 redis 的 list(双向链表)专门为每个人保存一个缓存
    如果关注者数量不多,就采用采用 push 模式,否则采用 pull 模式
    push 模式是一个人发了朋友圈往他朋友们的 timeline 里同步,删除了就全删掉
    点赞也是先临时修改对应的链表结点,再定期落到关系数据库里
    PiersSoCool
        5
    PiersSoCool  
       2021-04-23 17:45:30 +08:00
    空手套白狼倒是也没那么浮夸,这种就算你说了,如果对方没做过,也做不了
    mlcq
        6
    mlcq  
       2021-04-23 17:47:22 +08:00
    这个好像之前有个帖子讨论过,读扩散与写扩散
    p2pCoder
        7
    p2pCoder  
       2021-04-23 17:48:29 +08:00
    feed 流系统设计
    有很多博客系统性讲这个
    zhuzhibin
        8
    zhuzhibin  
       2021-04-23 20:58:13 +08:00 via iPhone
    发发帖子老哥们
    binux
        9
    binux  
       2021-04-24 00:12:03 +08:00 via Android
    读写又不是单机实时的,4000w 怎么了?
    nicebird
        10
    nicebird  
       2021-04-24 00:17:15 +08:00
    才 400 好友,写扩散就行了
    iseki
        12
    iseki  
       2021-04-24 00:38:32 +08:00
    写扩散吧,读扩散更吓人,按他这么算,读扩散不得 400*100w = 40000w ? 每秒 4 亿?

    感觉还是从优化的方向想办法,不是每个人都有 400 朋友,更不是每个人都每秒不停刷刷刷
    securityCoding
        13
    securityCoding  
       2021-04-24 00:55:17 +08:00
    t/768603

    并发写:分库分表+mq 异步没什么扛不住的
    并发读:一个集群扛不住那就多集群,做好 uid 分片策略
    cassyfar
        14
    cassyfar  
       2021-04-24 05:58:44 +08:00
    100w qps 为啥 redis 扛不住了?我们组也是 100w 读 qps 。用的 redis 。至少 3 个 9 uptime 。我怀疑面试官水平不行吧,估计都没接触过百万 qps 服务。
    cassyfar
        15
    cassyfar  
       2021-04-24 06:00:13 +08:00
    读扩扇( pull )没啥毛病
    xuanbg
        16
    xuanbg  
       2021-04-24 08:15:22 +08:00
    时间线索引,这量级不单独建一个和内容分离的索引表是不可能的
    ifhwhlwpto
        17
    ifhwhlwpto  
       2021-04-24 10:05:44 +08:00   1
    发朋友圈的时候给每个朋友发一条消息
    刷朋友圈的时候从手机本地读缓存的消息
    把用户的手机用来做缓存,并把问题转化为了如何实现一个高并发的 IM
    hejw19970413
        18
    hejw19970413  
       2021-04-24 10:11:55 +08:00
    你就算是 100w 的请求量,其中有好多都是重复拉取相同的数据吧, 那么就是用 redis + memacache 做多级缓存,利用 kafka 来做消息的队列 ,可以利用 kafka 不同的主题概念,将用户的行为做不同的主题投放,如果一台 Kafka 扛不住这些,那么用不同的 kafka 做不同的主题,起个 job 服务来消费这些消息 ,memacache 可以做内容的缓存,redis 可以做内容消息的索引缓存。根据不同的用户的用户量进行轻重隔离,例如朋友多的用户和朋友少的用户做不同的集群处理。如果有用户很频繁的拉取,可以在你的客户端都拉取限制,然后将这种更新频繁的用户做为热点处理,把缓存的级别提升,做到内存缓存。然后如果用户的拉的内容相同,利用单飞让这些相同的内容,全部命中一个点。 然后你这些服务启动链路追踪 ,调优系统调用的性能。
    samun
        19
    samun  
       2021-04-24 12:28:46 +08:00
    朋友圈内容可以设置查看权限的 这个怎么搞
    leimao
        20
    leimao  
       2021-04-24 12:37:33 +08:00
    完全不知道
    pkupyx
        21
    pkupyx  
       2021-04-24 13:21:09 08:00
    先得聊聊什么叫 redis 扛不住,你给的方案难道是主备?
    UserNameisNull
        22
    UserNameisNull  
    OP
       2021-04-24 16:34:37 +08:00
    @ifhwhlwpto 和我想法一样
    6ufq0VLZn0DDkL80
        23
    6ufq0VLZn0DDkL80  
       2021-04-25 13:29:16 +08:00
    你可以反问一下他,抖音是怎么做的
    ZhaoHuiLiu
        24
    ZhaoHuiLiu  
       2021-04-25 14:59:34 +08:00
    假设微信朋友圈的
    读 QPS 100w
    写 QPS 10w
    每个用户最多 400 个朋友,

    这里读每秒 100 万此,写每秒 10 万次。
    按照要求来算,无论是 SQL 还是 NOSQL 单台机器都完成不了任务。
    只能按照分布式方式,把数据拆散储存。

    创建一个 users 二进制文件,储存所有用户信息。
    创建一个 friends 二进制文件,储存了所有朋友关联信息。
    创建一个 user_friends 二进制文件,储存了关联用户和朋友的信息。

    此时分布式文件系统储存了以下 3 个文件。
    /users.db
    /friends.db
    /user_friends.db

    发朋友圈信息,把数据写到 /message/用户名 /sent.db 这个文件中。
    再从 user_friends.db 读取 400 个朋友的用户名,再分别更新文件 /message/用户名 /received.db 文件。
    这个读取更新操作是自动完成的,当用户读取朋友圈的时候,会根据上次更新时间来判断是否更新,比如上次更新在 1-3 分钟内,根据负载来判断是否更新,负载很高的情况下,并且上次更新少于 3 分钟就不更新。
    如果少于 3 分钟,就立即更新信息。更新方式就是读取 400 个朋友用户名,然后再分别读取 /message/用户名 /sent.db 文件,以当前日期为准读取,比如今天是 2020-1-1 日,就读这一天的,然后聚集 400 个朋友的 2020-1-1 这天的信息,根据时间戳来排序。

    由于上面采用的是分布式文件系统储存方式,读写压力完全根据有多少台服务器来判定,所以理论上不存在读写限制。

    想完成上面操作,推荐用 C++ 或者 Go 语言,上面需求并不复杂。
    ZhaoHuiLiu
        25
    ZhaoHuiLiu  
       2021-04-25 15:02:07 +08:00
    上面只是说了个大概实现,实际可以进行更详细的拆分,不过拆分越细,整体工程就越复杂,我从简设计的。
    ginjedoad
        26
    ginjedoad  
       2021-04-25 21:25:13 +08:00
    这不就是我去腾讯面试的时候的题目吗?
    ansyx
        27
    ansyx  
       2021-04-26 18:45:51 +08:00
    @PiersSoCool 小哥连云港人吗,我有个连云港人在上海的老乡群,可以加一下哈,我的 wechat:ansyxo
    UserNameisNull
        28
    UserNameisNull  
    OP
       2021-04-27 11:21:10 +08:00
    @ansyx 你是怎么知道他是连云港的?
    pkupyx
        29
    pkupyx  
       2021-04-28 03:25:43 +08:00   1
    没做过这么大量级的,瞎想了想

    1.先定义下要持久化的表:朋友圈:moment,用户的跟随者:user_follower,用户跟随了谁:user_followee
    用户:user (无关,外部服务)

    2.moment(user_id,data...)表
    moment 表 10W QPS 写,一天按 10W 秒算,每天新增 100 亿,每年新增 4W 亿。这个量级需要同时做 sharding 和冷热库了。然后热库存最近一年的,剩下全同步给冷库,应该是够用的。
    热库:一年需要存 4W 亿,按单表 1KW 算(其实 SSD 了可以多点),需要 40W 个表,2^19=524288 。按照实体机每台 32 个库,每个库 32 个表分,需要 512 台 mysql 实体机,还可以。
    冷库:复制一个同规模的集群,随时同步超过一年的数据。正常业务的冷查询不会很多,做好冷库的防刷是另外一个话题。这边要计算下磁盘够不够用,按照一条 moment 2KB 来算,冷库设计存 10 年,需要存 40W 亿( 40T ) * 2KB = 80PB,平均每台 160TB,现在密集写的服务器等级的 SSD 主要是 3.84TB 的? girigiri 够。热库除以 10,16TB 一台物理机,肯定够用了。
    sharding 维度:按按发布用户 id 吧,my_moment_ids 的查询直接命中了。

    3.follower(user_id,follower_id) & followee(user_id,followee_id)表
    user_follower 和 user_followee 是等价量级的,可以认为都是热数据。这个增量还比较可控,每人 400 个好友,按 1W 亿规模计算,上面那个方案够用。两个库分别按 user_id 做 sharding,一个对应我关注的用户列表,一个对应关注我的用户列表,写关系时候同步写 2 个表,主要是方便查方便写缓存。

    4.发布&查询朋友圈
    增加缓存:moment 实体,user_follower_ids,user_followee_ids 的缓存,我发的朋友圈的 id 索引 my_moment_ids(user_id->[{my_moment_id,time},...]),重点是我看的朋友圈的 id 关系索引 mix_moment_ids(user_id->[{followee_moment_id,time},...]):
    全量写到 my_moment_idx 缓存,好办。
    读 moment 实体,这块甚至能做到 99%命中缓存。

    维护 mix_moment_ids:
    全量写:如果 mix_moment_ids 要全量写全量存,量级是 moment 表量级的 400 倍,每年要新增 1600 万亿( 1.6P )条数据,按上面的计算,就算放宽 sharding 到单表 1 亿,也需要一个上万台的 mysql 集群,估计 GG 。全量写扩散到 redis 不丢弃,每条关系按 10 字节算,一年 16PB,集群内存估计一个月也存不下,GG 。

    部分写:
    mix_moment_ids 只写前 100 条的 ID,按 100 亿(10G)用户每条 10 字节计算,10TB 数据,redis 集群内存富裕。总之这里策略合适抗住 95%的 mix_moment_idx 查询,剩下 5W 读 qps 需要计算。命中不够就多缓存点,100TB 的 redis 集群还是有的。全量写到 mix_moment_ids 前 100 条的话,写操作先需要读 my_follower_ids,再写到对应人的 mix_moment_ids,集群需要 4KW 的写 QPS,理论上可以做得到。。。吧?不行就只写热点用户。

    剩余 5Wqps 变成了读扩散:这里包含没命中缓存的和冷用户,需要取 user_followee_ids,再取 400 个我关注的人的 my_moment_ids 按时间聚合,这样变成 2KW 读 QPS,95%打到 redis 集群上,剩下 100Wqps 命中 mysql 集群的 moment 表,全热库的话每台 2KQPS,够了。这块应该有很大的做各种 trick 优化的空间。

    纸上谈兵的话就是这样了,欢迎做过这个量级的来指点迷津
    ---
    感谢头条群友逆天之剑半夜讨论启发
    ansyx
        30
    ansyx  
       2021-04-28 16:45:51 +08:00
    @UserNameisNull 我是用 V2EX 搜索时候,看到的一个关于上海还有连云港帖子的留言,具体内容我忘了
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     3228 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 28ms UTC 04:41 PVG 12:41 LAX 20:41 JFK 23:41
    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