10 亿用户数据分库分表设计 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
请不要在回答技术问题时复制粘贴 AI 生成的内容
pabno

10 亿用户数据分库分表设计

  •  
  •   pabno 2020 年 2 月 28 日 8585 次点击
    这是一个创建于 2245 天前的主题,其中的信息可能已经有所发展或是发生改变。

    使用 mysql 存储 10 亿的用户数据,用户表的设计是 (bigint user_id, bigint phone, varchar email)

    查询分为两类 case:

    1. 用户登陆,可能会使用 phone 登陆,也可能使用 email 登陆
    2. 登陆后操作用户数据

    目前方案:使用 user_id >> 32 % 2 分库,user_id >> 22 % 20 分表。user_id 由雪花算法生成

    针对 case 2,直接用 user_id 取模就很容易定位到具体到库和表,但是 case 2 需要使用 email 或者 phone 反查 user_id. 暂时想到的就是在对 email,phone 分别进行分库分表再做查询,然后将数据缓存到 redis 中。当用户使用 phone 或者 email 进行登陆时,先查询缓存中有没有数据,没有再计算相应当分片库和分片表进行查询

    不知道还有没有什么比较好的方案

    第 1 条附言    2020 年 3 月 1 日
    原本只是想为了简化说明问题,但是没想到适得其反。我们真实的业务场景是:每个 Android 设备可能存在很多类型的 ID,比如国外从 google play 下载的应用可以拿到 gaid,国内的没有 ga,就只能拿到 android。一共有 5 个这样的 ID 类型,一个设备可能同时拿到多个类型的 id. 我们就是为了要把这些 ID 整合起来,生成一个我们的 ID,然后基于这个 ID 做一些运营。其实就是一个很简单的场景,只要同一个用户的数据落到同一个库上,就不会有分布式事务问题,而且数据一致性要求比较低
    37 条回复    2020-03-01 15:36:45 +08:00
    daimaosix
        1
    daimaosix  
       2020 年 2 月 29 日 ia iPhone   2
    直接上 TiDB,都不用做分库分表,100%兼容 MySQL,就像不曾离开 MySQL
    akira
        2
    akira  
       2020 年 2 月 29 日
    10 亿... 是国内的哪家大厂么。。
    peyppicp
        3
    peyppicp  
       2020 年 2 月 29 日 via iPhone
    email,phone 分别存在两个分片库里,分别关联对应的 uid。比较操蛋的就是新用户进来的时候要双一写了。
    luxinxin
        4
    luxinxin  
       2020 年 2 月 29 日 via iPhone
    其他还好,但感觉登陆并不是啥热数据,不需要 redis 缓存
    luckylo
        5
    luckylo  
       2020 年 2 月 29 日 via Android
    @akira 用户数量能过亿行业就那么些。
    传统行业的运营商+银行 +某些垄断行业。这些基本上是 Oracle ,就算不是,也基本跟 mysql 没啥关系。然后就是互联网的那几个大厂
    mikulch
        6
    mikulch  
       2020 年 2 月 29 日 via iPhone
    @peyppicp 你这个操作相当于数据异构啦,那不上 es 加列数据库了
    opengps
        7
    opengps  
       2020 年 2 月 29 日 via Android
    登录名缓存下来,值为数据库的路由标识
    neoblackcap
        8
    neoblackcap  
       2020 年 2 月 29 日
    同 @peyppicp 的解决方法,采取非规约化的方法对数据库进行处理,分别以 phone, email 为主键(cluster key)建表,关联 user_id。
    问题还是在于用户注册时就变得需要一次性写三个表。不过这个不算是大问题,哪怕是后面进行分布式事务,这个性能也是可以接受的。
    pabno
        9
    pabno  
    OP
       2020 年 2 月 29 日
    @luckylo
    @akira
    这个只是我类比过来当一个场景,为了方便说明问题。实际上是 10 亿设备(国内外都有业务),但是不同设备可能会有各种不同当 id,比如 gaid,androidid,imeiid
    pabno
        10
    pabno  
    OP
       2020 年 2 月 29 日
    @luxinxin 这个确实是
    pabno
        11
    pabno  
    OP
       2020 年 2 月 29 日
    @opengps 想过这个问题,但最终还是需要持久化下来。不然很久没有登陆后重新登陆没有命中缓存就找不到路由标识了
    ifconfig
        12
    ifconfig  
       2020 年 2 月 29 日
    请问下,直接用分区不行么,为什么要分表
    encro
        13
    encro  
       2020 年 2 月 29 日
    应该没有更好的方案,如果通过号码查询的频率高,应该采用 kv 内存存储吧。
    没有试过 kv 和数据库 hash 索引,10 亿数量级性能会差别多少。
    楼主花半天做一个实验给我们看看?

    到达这数量级,就是一个尝试验证改良的过程。
    lovelife1994
        14
    lovelife1994  
       2020 年 2 月 29 日
    @neoblackcap 如果登录数据不是热点数据,在有一级缓存的前提下,是不是单表做分区,在查询列上建 non-clustered 的覆盖索引就行了,这样能避免分库的带来的路由,双写和分布式事务的问题。感觉需要根据当前数据规模和预估增长的到的规模做下压测做取舍。如果 phone 和 email 都是可变更的,还要考虑分区,分表,分库间数据迁移怎么做。
    neoblackcap
        15
    neoblackcap  
       2020 年 2 月 29 日
    @lovelife1994 我提的那边理论上只要开发支持(分布式事务,查询变更),你说的几点都解决了。无论是 phone, email 的可变更,还是查询的性能。我说的主要是 Cassandra 的解决方案。
    不过如同你所说,分布式方案肯定是有其他问题,路由,分布式事务。要结合生产环境取舍(压测)。这样的问题的确可以算是真正架构师的活了。
    neoblackcap
        16
    neoblackcap  
       2020 年 2 月 29 日
    @ifconfig 分区还是单机,分表就可以多节点了
    justRua
        17
    justRua  
       2020 年 2 月 29 日
    es 存一份用于搜索,mysql 里做分表分库,现公司是这么做的,不过用户数据是千万级,没上亿
    cabing
        18
    cabing  
       2020 年 2 月 29 日
    如果是单纯的用户表应该不会涉及到跨表事务吧。
    一般的设计,登录相对应该是不频繁。case1 经常使用,case2 不那么频繁


    说一个简单的方案:

    针对 cace2 可以通过分布式的 kv(持久化)系统去存储,做备份就行,数据的变更,可以通过消息队列去更新。

    此外还有针对活跃用户,还需要定期比对 case1 中的和 kv 系统中的数据。

    kv 系统,可以考虑小米的 Pegasus,也可以找个类似的 kv 系统,也可以自己根据 rocksdb 撸一个。

    如果 kv 系统只是存储 uid 的,

    10 亿数据,如果只是存储 email=>(uid) phOne=>(uid)

    256 * 1000000000/1024/1024/1024 = 238G,其实存储数据量不是特别多。


    此方案只是通过一次 email 或者 phone 寻址到 uid,后续的流程还是走到 uid 查询了。
    dragonsunmoon
        19
    dragonsunmoon  
       2020 年 2 月 29 日
    全球接近 80 亿的人, 地球上每 8 个人,就有一个人是你们系统的用户,牛逼,呵呵
    dragonsunmoon
        20
    dragonsunmoon  
       2020 年 2 月 29 日
    哦, 才注意到, 是设备,
    dragonsunmoon
        21
    dragonsunmoon  
       2020 年 2 月 29 日
    不过设备也很牛逼呀, 假设单个设备的成本是 10.00 元, 光设备他妈的也要 100 亿元. 还不算分发,部署,运维,网络通讯费,后台带宽服务费, 后台服务器,存储等费用. 这个系统真弄下来, 耗费巨大呀
    brucefu
        22
    brucefu  
       2020 年 2 月 29 日
    这些数据分表就可以了啊,为嘛要分库
    brucefu
        23
    brucefu  
       2020 年 2 月 29 日
    @dragonsnmoon 注册的多,活跃的少
    mreasonyang
        24
    mreasonyang  
       2020 年 2 月 29 日 via iPhone
    @dragonsunmoon 这个很常见啊,又不是自然人
    GDC
        25
    GDC  
       2020 年 2 月 29 日   1
    @akira 用户 10 亿的大厂不需要来 V2 问这样的问题…
    mysunshinedreams
        26
    mysunshinedreams  
       2020 年 2 月 29 日
    @dragonsunmoon 其实你理解的太绝对了,举个例子,一台手机,可能对应几十个设备 ID,因为用户存在各种各样的复原的操作,举个实际的例子,亚马逊对 Kindle 设备的管理,如果你经常重做系统的话,就会发现它们的识别策略是每一次都会识别为一个新的设备。
    dragonsunmoon
        27
    dragonsunmoon  
       2020 年 2 月 29 日   2
    @pabno 不好意思,我的回复是稍微带着点调侃的味道,先对你说声 sorry
    虽然是带着点调侃的话,可是我想说一下技术外的问题. 先从"10 亿用户"这个数量来说. 题主在问题里给出的表设计描述: 用户表的设计是 (bigint user_id, bigint phone, varchar email). 用户是以手机和电子邮箱为用户标识的.
    @mysunshinedreams 但从表的字段来说,注册的对象背后是手机号码和邮箱这种身份标识资源, 与具体设备无关.不存在一个手机对应几十个设备 ID, 因为关注的是 phone 和 email
    因为现在是移动互联网,所以普通用户使用邮箱注册的毕竟是少数,我们先假设 10%的用户是使用邮箱注册,另外 90%使用手机注册. 抛开 1 亿个邮箱注册的用户, 剩下 9 亿个手机号码. 再假设人均 2 个号码(实际生活里, 绝大多数"正常用户"只会使用一个手机号码, 并且,人均 2 个号码这个数值其实已经给得很高了,这里是为了方便计算, 如果调低了,只会让计算出来的真实注册用户数更多).

    回到之前的描述, 假设人均 2 个号码都注册了, 那么使用手机号码注册的人数也有 4.5 亿. (还没有把使用 email 来注册的用户算进来). 4.5 亿个用户, 大家能理解这是个什么概念吗?
    如果题主所在的公司是一个小公司或者初创公司. 我认为 10 亿用户 数,根本就是个伪命题. 因为, 很大程度上, 等系统上线后, 能不能撑到 100 万的注册用户数, 都是个未知数. 所以担心一个几乎根本不可能发生的问题, 没有必要.
    如果题主所在的公司, 依旧有一定的规模. 有超过 100 万的注册用户, 我觉得这个公司也应该有钱请个资深的架构师来解决这个问题(重构系统), 就像 @GDC 所说的,应该也不会来 V2 问这样的问题了.
    这让我想起来多少年前业界的一个笑谈. 一帮人创业, 先用 ruby on rails 开发出产品原型, 上线. 然后融到资, 接着再招聘另外一帮 java 的人, 把 ruby 写的系统再重构到 java 上. (Twitter 还真就是这样的)

    @pabno 我觉得, 你现在所处的公司应该是个初创企业(我猜的, 如果我猜错了话,这些回复内容就当做废话随便看看吧) 你其实你现在根本就不需要担心 10 亿用户这个问题. 因为到 10 亿用户, 整个系统面临的不仅仅是用户登录查询的问题. 10 亿用户, 假设 10%的的活跃用户, 那就是 1 亿的活跃用户. 这些用户在你们系统里的行为活动, 会产出大量的数据. 这已经不单单是一个用户表设计的问题了.
    量变引起质变, 海量用户数据的处理,会引申出一系列的问题, 单机数据库在性能(tps/qps), 容量上不够. 需要分布式数据库, 按照业务领域进行垂直分隔, 按照数据进行水平拆分. 分库,分表,数据归档. 引入 no sql 的数据库在应用层建立索引服务, 媒体数据的海量存储, 加速访问的 cdn. Api 应用服务的负载均衡, 微服务,集群,数据容灾备份等等. 更别说, 处理海量数据所需要的云计算的云主机,带宽,存储等资源, 需要的也是流水般的费用呀.

    但是, 对于一个初创公司的初创项目, 压根就不需要考虑海量数据问题. 因为初期压根就不会遇到海量数据带来的问题.
    不要提前过渡设计. 一开始也不要把问题给复杂化. 不要试图做一个完美的系统. 不要考虑你几乎不会遇到的问题.
    dragonsunmoon
        28
    dragonsunmoon  
       2020 年 2 月 29 日
    @pabno 我才留意到你在后面的回复里, 指出是以用户表设计来当做类比场景的.
    但是, 即便以设备数来说, 10 亿个设备数也是很大的数字. 考虑到 @mysunshinedreams 所说的, 对应几十个设备 ID 的情况, 会有,但是不会是普遍情况, 对应几十个设备 ID 的情况占比应该很小的. 所以我们粗略的给定一个设备的 ID 重复产生系数, 假设为 2, 那么也有 5 亿的设备. 这个设备数量已经很高了. 5 亿设备中, 假设有 1 亿个活跃设备, 每天产生 10 条数据. 每条数据假设为 1KB (因为不清楚业务类型,不清楚实际情况,这个值可能高, 也可能低了, 暂时先用这个值来描述问题), 一年产生的纯数据容量(数据进入到数据库后, 还会有索引等, 所以实际需要的存储容量只会比这更高) 约为: 100,000,000 * 10 条 * 1 KB / 1024 / 1024 / 1024 * 365 天 = 339.93 TB

    所以, 真有 5 亿个设备, 是会产生海量数据问题的. 而海量数据问题的性质, 复杂度, 解决方法, 已经超过表设计这个问题范畴了.

    初期,不要考虑海量数据问题. 因为, 很大概率上, 公司都不能撑到有那么多的用户量 /设备量.
    如果真的遇到了海量数据问题, 那么恭喜你们! 你们项目,你们的事业已经成功一大半了.
    pabno
        29
    pabno  
    OP
       2020 年 3 月 1 日
    @justRua 有考虑过这个方案,不过太贵了
    pabno
        30
    pabno  
    OP
       2020 年 3 月 1 日
    @cabing 原来也想着映射关系方 redis 做持久化的,但是一个设备可能一两个礼拜才会做一次登陆
    pabno
        31
    pabno  
    OP
       2020 年 3 月 1 日   1
    @dragonsunmoon 我们海外和国内都有业务,设备数还是比较大的。其实现在这些数据都有落地在我们的大数据平台,现在是想整合这些 id 做营销,最主要是生成一个统一的 ID。据反馈 19 年 Q4 以来的设备数就已经有 2 亿了,这还是 18 年底被谷歌点名后设备数大幅度下降后的

    老板的事业是挺成功的,我只能争取努力努力,帮老板再买一辆玛莎拉蒂
    dusu
        32
    dusu  
       2020 年 3 月 1 日 via iPhone
    光从性能角度来说

    一级热数据进 redis (取最近登录多少天)

    二级进 pika 或 ssdb 这类 kvdb (取最常登录多少次)

    三级命中走 mysql 分表查询

    无论存还是查 100 亿都问题不大
    staticor
        33
    staticor  
       2020 年 3 月 1 日
    少了描述背景, 会带来更多的问题

    有种 X/Y problem 的味道
    cabing
        34
    cabing  
       2020 年 3 月 1 日
    @pabno

    如果觉得 redis 成本高。

    持久化方案不一定非得放内存。

    ssd+lru(内存)


    ssd 1T 也不贵。内存不用太大,lru 就行。
    sagaxu
        35
    sagaxu  
       2020 年 3 月 1 日 via Android   1
    去年就有两亿设备,业务遍布全球,这样的公司没有架构师也没有 dba ?难道是触宝么
    mysunshinedreams
        36
    mysunshinedreams  
       2020 年 3 月 1 日
    @dragonsunmoon 你忽略了黄牛,黄牛的设备并不一定是真实设备,但是他们能弄出庞大的设备群体,举个例子,X 团,一些低价促销活动,会有很多黄牛再抢,他们用的就不是真实的设备。
    watsy0007
        37
    watsy0007  
       2020 年 3 月 1 日
    分区就可以了吧. 查询压力有多大
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     3325 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 75ms UTC 11:14 PVG 19:14 LAX 04:14 JFK 07:14
    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