使用 mysql 存储 10 亿的用户数据,用户表的设计是 (bigint user_id, bigint phone, varchar email)
查询分为两类 case:
目前方案:使用 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
daimaosix 2020-02-29 01:28:00 +08:00 via iPhone 2
直接上 TiDB,都不用做分库分表,100%兼容 MySQL,就像不曾离开 MySQL
|
2
akira 2020-02-29 01:40:01 +08:00
10 亿... 是国内的哪家大厂么。。
|
3
peyppicp 2020-02-29 01:45:23 +08:00 via iPhone
email,phone 分别存在两个分片库里,分别关联对应的 uid。比较操蛋的就是新用户进来的时候要双一写了。
|
4
luxinxin 2020-02-29 01:48:44 +08:00 via iPhone
其他还好,但感觉登陆并不是啥热数据,不需要 redis 缓存
|
5
luckylo 2020-02-29 07:22:26 +08:00 via Android
@akira 用户数量能过亿行业就那么些。
传统行业的运营商+银行 +某些垄断行业。这些基本上是 Oracle ,就算不是,也基本跟 mysql 没啥关系。然后就是互联网的那几个大厂 |
7
opengps 2020-02-29 07:59:10 +08:00 via Android
登录名缓存下来,值为数据库的路由标识
|
8
neoblackcap 2020-02-29 10:08:29 +08:00
同 @peyppicp 的解决方法,采取非规约化的方法对数据库进行处理,分别以 phone, email 为主键(cluster key)建表,关联 user_id。
问题还是在于用户注册时就变得需要一次性写三个表。不过这个不算是大问题,哪怕是后面进行分布式事务,这个性能也是可以接受的。 |
9
pabno OP |
12
ifconfig 2020-02-29 11:14:41 +08:00
请问下,直接用分区不行么,为什么要分表
|
13
encro 2020-02-29 11:48:07 +08:00
应该没有更好的方案,如果通过号码查询的频率高,应该采用 kv 内存存储吧。
没有试过 kv 和数据库 hash 索引,10 亿数量级性能会差别多少。 楼主花半天做一个实验给我们看看? 到达这数量级,就是一个尝试验证改良的过程。 |
14
lovelife1994 2020-02-29 11:58:46 +08:00
@neoblackcap 如果登录数据不是热点数据,在有一级缓存的前提下,是不是单表做分区,在查询列上建 non-clustered 的覆盖索引就行了,这样能避免分库的带来的路由,双写和分布式事务的问题。感觉需要根据当前数据规模和预估增长的到的规模做下压测做取舍。如果 phone 和 email 都是可变更的,还要考虑分区,分表,分库间数据迁移怎么做。
|
15
neoblackcap 2020-02-29 12:25:56 +08:00
@lovelife1994 我提的那边理论上只要开发支持(分布式事务,查询变更),你说的几点都解决了。无论是 phone, email 的可变更,还是查询的性能。我说的主要是 Cassandra 的解决方案。
不过如同你所说,分布式方案肯定是有其他问题,路由,分布式事务。要结合生产环境取舍(压测)。这样的问题的确可以算是真正架构师的活了。 |
16
neoblackcap 2020-02-29 12:29:47 +08:00
@ifconfig 分区还是单机,分表就可以多节点了
|
17
justRua 2020-02-29 12:44:23 +08:00
es 存一份用于搜索,mysql 里做分表分库,现公司是这么做的,不过用户数据是千万级,没上亿
|
18
cabing 2020-02-29 13:00:31 +08:00
如果是单纯的用户表应该不会涉及到跨表事务吧。
一般的设计,登录相对应该是不频繁。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 查询了。 |
19
dragonsunmoon 2020-02-29 13:21:00 +08:00
全球接近 80 亿的人, 地球上每 8 个人,就有一个人是你们系统的用户,牛逼,呵呵
|
20
dragonsunmoon 2020-02-29 13:22:03 +08:00
哦, 才注意到, 是设备,😅
|
21
dragonsunmoon 2020-02-29 13:24:43 +08:00
不过设备也很牛逼呀, 假设单个设备的成本是 10.00 元, 光设备他妈的也要 100 亿元. 还不算分发,部署,运维,网络通讯费,后台带宽服务费, 后台服务器,存储等费用. 这个系统真弄下来, 耗费巨大呀
|
22
brucefu 2020-02-29 14:27:13 +08:00
这些数据分表就可以了啊,为嘛要分库
|
23
brucefu 2020-02-29 14:30:38 +08:00
@dragonsunmoon 注册的多,活跃的少
|
24
mreasonyang 2020-02-29 18:18:46 +08:00 via iPhone
@dragonsunmoon 这个很常见啊,又不是自然人
|
26
mysunshinedreams 2020-02-29 19:57:29 +08:00
@dragonsunmoon 其实你理解的太绝对了,举个例子,一台手机,可能对应几十个设备 ID,因为用户存在各种各样的复原的操作,举个实际的例子,亚马逊对 Kindle 设备的管理,如果你经常重做系统的话,就会发现它们的识别策略是每一次都会识别为一个新的设备。
|
27
dragonsunmoon 2020-02-29 22:58:27 +08:00 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 应用服务的负载均衡, 微服务,集群,数据容灾备份等等. 更别说, 处理海量数据所需要的云计算的云主机,带宽,存储等资源, 需要的也是流水般的费用呀. 但是, 对于一个初创公司的初创项目, 压根就不需要考虑海量数据问题. 因为初期压根就不会遇到海量数据带来的问题. 不要提前过渡设计. 一开始也不要把问题给复杂化. 不要试图做一个完美的系统. 不要考虑你几乎不会遇到的问题. |
28
dragonsunmoon 2020-02-29 23:38:18 +08:00
@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 亿个设备, 是会产生海量数据问题的. 而海量数据问题的性质, 复杂度, 解决方法, 已经超过表设计这个问题范畴了. 初期,不要考虑海量数据问题. 因为, 很大概率上, 公司都不能撑到有那么多的用户量 /设备量. 如果真的遇到了海量数据问题, 那么恭喜你们! 你们项目,你们的事业已经成功一大半了. |
31
pabno OP @dragonsunmoon 我们海外和国内都有业务,设备数还是比较大的。其实现在这些数据都有落地在我们的大数据平台,现在是想整合这些 id 做营销,最主要是生成一个统一的 ID。据反馈 19 年 Q4 以来的设备数就已经有 2 亿了,这还是 18 年底被谷歌点名后设备数大幅度下降后的
老板的事业是挺成功的,我只能争取努力努力,帮老板再买一辆玛莎拉蒂 |
32
dusu 2020-03-01 03:48:57 +08:00 via iPhone
光从性能角度来说
一级热数据进 redis (取最近登录多少天) 二级进 pika 或 ssdb 这类 kvdb (取最常登录多少次) 三级命中走 mysql 分表查询 无论存还是查 100 亿都问题不大 |
33
staticor 2020-03-01 08:20:36 +08:00
少了描述背景, 会带来更多的问题
有种 X/Y problem 的味道 |
34
cabing 2020-03-01 11:53:10 +08:00
|
35
sagaxu 2020-03-01 11:54:09 +08:00 via Android 1
去年就有两亿设备,业务遍布全球,这样的公司没有架构师也没有 dba ?难道是触宝么
|
36
mysunshinedreams 2020-03-01 12:35:11 +08:00
@dragonsunmoon 你忽略了黄牛,黄牛的设备并不一定是真实设备,但是他们能弄出庞大的设备群体,举个例子,X 团,一些低价促销活动,会有很多黄牛再抢,他们用的就不是真实的设备。
|
37
watsy0007 2020-03-01 15:36:45 +08:00
分区就可以了吧. 查询压力有多大
|