单个数据库遇到的问题
- 单库用户请求量过大导致的数据库连接不足
- 单库数据量太大,单库所在服务器的磁盘空间有限,单库上的操作IO有瓶颈
- 单表数据量太大导致的性能瓶颈。查询,插入,更新操作都会变慢
什么是分库分表
- 分库:从单个数据库拆分成多个数据库的过程,也就是将数据分散到多个数据库中去。
- 分表:从单张表拆分成多张表的过程,将数据散落到多张表中去。
为什么要分库分表
- 提升性能
- 增加可用性
如何分库分表
切分方案 | 解决的问题 |
---|---|
只分库不分表 | 数据库读写QPS过高,数据库连接数不足 |
只分表不分库 | 解决单表数据量过大,存储性能遇到瓶颈 |
既分库又分表 | 解决连接数、磁盘容量、操作IO有上限以及单表存储性能瓶颈 |
如何选择我们自己的切分方案
真实案例-1
如果需要分表,那么分多少张表合适
Xspace客服平台系统来服务会员,该系统是为了解决会员的咨询诉求,目前主要以同步的离线工单数据作为我们的数据源来构建自己的数据。
假设,每一笔离线工单都会产生一笔会员的咨询问题(我们简称:问题单),如果:
- 在线渠道:每天产生 3w 笔聊天会话,假设,其中50%的会话会生成一笔离线工单,那么每天可生成 3w * 50% = 1.5w 笔/天
- 热线渠道:每天产生 2.5w 通电话,假设,其中80%的电话都会产生一笔工单,那么每天可生成 2.5w * 80% = 2w 笔/天;
- 离线渠道:假设离线渠道每天直接生成 3w 笔;
合计共 1.5w + 2w + 3w = 6.5w 笔/天
考虑到以后可能要继续覆盖的新的业务场景,需要提前预留部分扩展空间,这里我们假设为每天产生 8w 笔问题单。
除问题单外,还有另外2张常用的业务表:用户操作日志表、用户提交的表单数据表。
其中,每笔问题单都会产生多条用户操作日志,根据历史统计数据来可以看到,平均每个问题单大约会产生8条操作日志,我们预留一部分空间,假设每个问题单平均产生约10条用户操作日志。
如果系统设计使用年限5年,那么问题单数据量大约 = 5年 365天/年 8w/天 = 1.46亿,那么估算出的表数量如下:
- 问题单需要:1.46亿/500w = 29.2 张表,我们就按 32 张表来切分;
- 操作日志需要 :32 * 10 = 320 张表,我们就按 32 *16 = 512 张表来切分。
如果需要分库,那么分多少库合适
分库的时候除了要考虑平时的业务峰值读写QPS外,还要考虑到诸如双11大促期间可能达到的峰值,需要提前做好预估。根据我们的实际业务场景,问题单的数据查询来源主要来自于阿里客服小蜜首页。因此,可以根据历史QPS、RT等数据评估,假设我们只需要3500数据库连接数,如果单库可以承担最高1000个数据库连接,那么我们就可以拆分成4个库。
真实案例-2
如何分库
我之前待过一家公司,我们团队是做游戏运营的,我们公司提供平台,游戏厂商接入我们平台,推广他们的游戏。
游戏玩家通过我们平台登录,成功之后跳转到游戏厂商的指定游戏页面,该玩家就能正常玩游戏了,还可以充值游戏币。
这就需要建立我们的账号体系和游戏厂商的账号的映射关系,游戏玩家通过登录我们平台的游戏账号,成功之后转换成游戏厂商自己平台的账号。
这里有两个问题:
- 每个游戏厂商的接入方式可能都不一样,账号体系映射关系也有差异。
- 用户都从我们平台登录,成功之后跳转到游戏厂商的游戏页面。当时有N个游戏厂商接入了,活跃的游戏玩家比较多,登录接口的并发量不容小觑。
为了解决这两个问题,我们当时采用的方案是:分库。即针对每一个游戏都单独建一个数据库,数据库中的表结构允许存在差异。
我们当时没有进一步分表,是因为当时考虑每种游戏的用户量,还没到大到离谱的地步。不像王者荣耀这种现象级的游戏,有上亿的玩家。
其中有个比较关键的地方是:登录接口中需要传入游戏id字段,通过该字段,系统就知道要操作哪个库,因为库名中就包含了游戏id的信息。
如何分表
还是在那家游戏平台公司,我们还有另外一个业务就是:金钻会员。
说白了就是打造了一套跟游戏相关的会员体系,为了保持用户的活跃度,开通会员有很多福利,比如:送游戏币、充值有折扣、积分兑换、抽奖、专属客服等等。
在这套会员体系当中,有个非常重要的功能就是:积分。
用户有很多种途径可以获取积分,比如:签到、充值、玩游戏、抽奖、推广、参加活动等等。
积分用什么用途呢?
退换实物礼物
兑换游戏币
抽奖
说了这么多,其实就是想说,一个用户一天当中,获取积分或消费积分都可能有很多次,那么,一个用户一天就可能会产生几十条记录。
如果用户多了的话,积分相关的数据量其实挺惊人的。
我们当时考虑了,水平方向的数据量可能会很大,但是用户并发量并不大,不像登录接口那样。
所以采用的方案是:分表。
当时使用一个积分数据库就够了,但是分了128张表。然后根据用户id,进行hash除以128取模。
需要特别注意的是,分表的数量最好是2的幂次方,方便以后扩容。