V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
puritania
V2EX  ›  程序员

微博的用户关系数据库应该如何设计?

  •  
  •   puritania · 2018-01-18 15:58:11 +08:00 · 5481 次点击
    这是一个创建于 2497 天前的主题,其中的信息可能已经有所发展或是发生改变。

    疑问在于用什么维度做数据库、表拆分,这种数据极不平均,大 R 几千万粉丝,普通人几百粉丝,按传统 uid 这种做 hash 行不通,应该如何设计呢?

    第 1 条附言  ·  2018-01-18 18:41:21 +08:00
    刚才看了一下 大 v 的粉丝列表只给看 5 页
    第 2 条附言  ·  2018-01-18 19:22:15 +08:00
    http://www.infoq.com/cn/articles/weibo-relation-service-with-redis
    找到了一篇文章,具体解决方案没说
    33 条回复    2018-01-19 09:45:13 +08:00
    WeaPoon
        1
    WeaPoon  
       2018-01-18 16:19:07 +08:00
    等大佬回答,排队学习.
    xAx
        2
    xAx  
       2018-01-18 16:21:50 +08:00
    具体是怎么实现不清楚。
    但这类场景,如果是用关系型数据库,那么不管哪种解决方案,思路都差不多。
    用代理层对业务屏蔽数据库细节。
    数据库上可能把大 V 和普通用户分库或分表。这怎么分都是无所谓。
    分库分表不一定非 uid 什么的,随便哪个字段都行,是不是 vip,是不是政企,注册时间,活跃度...都可以用作分库分表的依据。
    甚至可以把不同用户的数据散布在不同的数据中心。

    业务含意的逻辑分完后,还可以进行数据库底层的物理分。

    其实重点是怎么做汇总查。
    很多项目都处理不好分表分库时的汇总查,所以喜欢搞微批系统,以批量出非实时统计结果
    puritania
        3
    puritania  
    OP
       2018-01-18 16:37:04 +08:00
    @xAx 数据库上可能把大 V 和普通用户分库或分表。这怎么分都是无所谓。
    你直接就把我的问题无所谓了。。
    puritania
        4
    puritania  
    OP
       2018-01-18 16:47:39 +08:00
    @xAx 然后为什么说要按 uid 分,就是为了降低查询的复杂度,按你说的随便哪个字段那代理层可能需要查无数个数据库、表才能获得我到我的粉丝列表。
    xwhxbg
        5
    xwhxbg  
       2018-01-18 16:53:19 +08:00
    如果把用户关系看做有向图,似乎可以通过图的疏密来分区,查找可能是两步,先从分区键查分区,再用 uid 查具体哪个用户
    以上全是 YY 的哈,没做过这个量级的
    kimchan
        6
    kimchan  
       2018-01-18 17:08:43 +08:00
    排队学习+1
    jzds001
        7
    jzds001  
       2018-01-18 17:28:59 +08:00
    排队学习+1
    grimpil
        8
    grimpil  
       2018-01-18 17:30:30 +08:00 via Android
    排队围观,暂时学不了这种高科技
    chenyj
        9
    chenyj  
       2018-01-18 17:32:15 +08:00
    好奇观摩
    jy02534655
        10
    jy02534655  
       2018-01-18 17:35:16 +08:00
    排队学习+1
    clino
        11
    clino  
       2018-01-18 17:43:19 +08:00
    "大 R 几千万粉丝,普通人几百粉丝"
    我现想的抛个砖,我想虽然这里面大 V 有好多粉丝,但是并没有需要有地方能把这些粉丝都显示出来,所以我只要保证前多少个粉丝(比如 500)能快速查询出来就可以了,多的另外的表来存放,这样是不是相当于把大 V 和普通人分开了.

    而一个用户 fo 的人一般不会太多,这部分也冗余地存放起来

    我觉得比较难的部分是快速过滤出某些用户的微博,比如我 fo 的所有用户的微博,各种 tag 的用户的列表,要能看这些列表的微博,这部分我觉得要做到高效挺难的...不知道怎么做的
    puritania
        12
    puritania  
    OP
       2018-01-18 17:49:01 +08:00
    @clino 你说的 feed 数据每个人都有自己的 feed 列表,一般都是推拉结合来做的。
    clino
        13
    clino  
       2018-01-18 17:55:26 +08:00
    @puritania #12 你是说每个人的 feed 都是自己一份? 那比如我有 20 个用户分组,那么每个组的 feed 是从前面这份全的 feed 和分组信息关联查询出来的?
    puritania
        14
    puritania  
    OP
       2018-01-18 18:00:49 +08:00
    @clino 那肯定,没有必要为了分组多冗余数据。
    clino
        15
    clino  
       2018-01-18 18:08:45 +08:00
    @puritania #14 如果每个人的 feed 都自己一份,那就是说比如说有 1 千万粉丝的大 V 发一条,就要给这些粉丝的 feed 增加一条记录,就要一下增加 1 千万条这样吗?
    fcten
        16
    fcten  
       2018-01-18 18:12:55 +08:00
    用户的关注关系是一个访问极端频繁的数据,是必然要缓存在内存里的。所以即使需要用关系型数据库做持久化,在设计上也不必太考虑性能的问题。
    估计会针对大 V 和非活跃用户做一些特殊处理。
    rogwan
        17
    rogwan  
       2018-01-18 18:22:05 +08:00 via Android   ❤️ 1
    以前微博的技术 yang 分享过,就是推拉结合。具体谁推谁拉算法肯定是一直在变的,根据用户的活跃情况调整。
    puritania
        18
    puritania  
    OP
       2018-01-18 18:34:01 +08:00 via iPhone
    @clino 所以说是推拉结合的 可以考虑只给再现用户推 部在线用户 上线时拉取
    puritania
        19
    puritania  
    OP
       2018-01-18 18:35:52 +08:00
    @fcten 问题就是特殊处理应该如何处理。。
    puritania
        20
    puritania  
    OP
       2018-01-18 18:38:35 +08:00
    @clino feed 也是很难的设计
    Universe
        21
    Universe  
       2018-01-18 18:47:15 +08:00 via Android
    不止一种数据库,关系型数据库和图数据库混用,这个是图数据库的经典例子了,相关的讨论非常多
    klxq15
        22
    klxq15  
       2018-01-18 18:49:54 +08:00 via Android
    我尝试用过 dgraph 图数据库,但是性能什么的没测试过
    fcten
        23
    fcten  
       2018-01-18 18:51:42 +08:00
    @puritania 我不是说数据库特殊处理,我是说缓存特殊处理。
    这种数据用 NoSQL 存储,根本没有分库分表的问题。用关系型数据库存储,必然达不到性能要求,必然要上缓存。数据库进行特殊处理,恐怕收益非常有限。
    puritania
        24
    puritania  
    OP
       2018-01-18 19:00:08 +08:00
    @fcten 数据库肯定是要有完整数据的,缓存的话每个大 v 几千万的粉丝都缓存感觉不太现实吧。
    1ku
        25
    1ku  
       2018-01-18 19:03:28 +08:00
    等会,我去泡好茶,搬好凳子...瓜子零食已到位,好了,开始吧!
    Kilerd
        26
    Kilerd  
       2018-01-18 19:09:19 +08:00
    排队学习
    Immortal
        27
    Immortal  
       2018-01-18 19:09:35 +08:00
    微博应该大量用了 redis 以前有技术分析的文章 找一下网上应该有不少 大 B 百万关注那种都是特殊处理了 单独使用一个实例 或者 啥的,和普通用户分开了 还有就是前面大佬说的推拉结合
    fcten
        28
    fcten  
       2018-01-18 19:15:56 +08:00
    @puritania 几千万粉丝其实数据量并不大。对于微博来说,上 TB 的内存集群都没啥问题吧。
    owenliang
        29
    owenliang  
       2018-01-18 19:33:33 +08:00 via Android
    不要用条数轮性能,知道 log based 存储吗 越大的批量写入收益越高。

    当你性能不行的时候,想想批量两个字。
    Zzde
        30
    Zzde  
       2018-01-18 20:08:37 +08:00
    排队学习
    puritania
        31
    puritania  
    OP
       2018-01-18 20:30:45 +08:00
    @owenliang 不明白你什么意思 数据库存储结构跟批量写入有什么关系
    owenliang
        32
    owenliang  
       2018-01-18 20:50:55 +08:00 via Android
    @puritania 大家一般认为 feed 流就是拷贝千万次,实际上对于 hbase 这种日志存储来说,批量提交 1m 的 batch 可能包含数万条 feed 关系,这是大家觉得不可思议最本质的一个问题。

    就像有人疑惑弹幕服务器如何承载百万人在线一样,认为 1 条弹幕要推送 100 万次,不可思议。其实大家没想过,完全可以攒几秒秒再批量推送下去,瓶颈转移到带宽而不是 cpu。

    只是告诉你两个字,批量。
    bsidb
        33
    bsidb  
       2018-01-19 09:45:13 +08:00   ❤️ 2
    微博的技术大拿在网上有技术分享 PPT,应该还能搜到。
    我印象中,当时的 PPT 是这样说的(约至少 2 年前),如果说的有问题,还请拍砖:
    1. 微博信息数据(即微博的具体内容等)是存储在关系型数据库中的。使用标准的分库分表技术就能水平扩展。
    2. 微博的关系数据(即 Follow 关系)和 Feed 流数据,我记得没有细说。但是每个用户是会维护自己的 Feed 流,这个 Feed 流应该只保存了微博 ID 编号,不保存具体微博内容。等用户浏览自己的 Feed 流的时候,再从关系数据库中取出微博内容,并将网页返回给用户。
    3. 微博的通知数据(你有 XX 新粉丝,有 XX 新回复,有 XX 新点赞等信息),因为体积不大而且经常变动,是保存在 Redis 中。

    当一个用户发了一条新微博之后,后续的更新动作一般是推拉结合:
    1. 对于普通用户(粉丝数小于某个值)的微博更新,用“推”的方式比较划算。当一个用户更新微博后,把新微博的 ID 信息写入他的粉丝的 Feed 流存储之中。
    2. 对于大 V 用户(粉丝数大于某个值)的微博更新,用“拉”的方式比较划算。当大 V 更新微博后,并不会将新微博 ID 推送到粉丝的 Feed 流。而是在粉丝查看自己的 Feed 流的时候,现场去查询其关注的大 V 的最新动态,并加入 Feed 流。这种“拉”的好处是减少了大 V 更新微博时的一系列数据库操作代价,而且大 V 微博的时效性很强,能很好地进行热缓存。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   5534 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 28ms · UTC 03:38 · PVG 11:38 · LAX 19:38 · JFK 22:38
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.