数据库水平切分二三事

58沈剑到公司分享,数据量太大,怎么进行水平切分呢?这个是分享的笔记,大神的干货,记录一下,以备后用。

一、基本概念

  • 分片:解决数据量大的问题->设计路由的问题
  • 复制 + 分组:一主多从同步,保证读高可用的问题。
  • 路由规则:
    (1)范围:简单、拓展方便。但是负载问题,新数据负载高。
    (2)哈希:取模,数据均衡、请求均衡。但是扩容复杂,可能需要数据迁移。(使用最多)
    (3)路由服务:专门用来做数据路由,对调用数据端屏蔽。

二、数据库架构设计什么

  • 可用性
  • 读性能:读往往是瓶颈
  • 一致性问题:主从、缓存一致性
  • 扩展性:表扩展、水平切分、分库不支持分页

三、怎么水平切分

3.1、场景一:(单key)用户库如何拆分

3.1.1、用户库,10亿数据量

1
user(uid, uname, passwd, age, sex, create_time);

3.1.2、业务需求如下

  • (1)1%登录请求=> where uname=XXX and passwd=XXX
  • (2)99%查询请求=> where uid=XXX

根据第二个需求,我们可以很快的确定,需要按照uid进行分库,假定我们分了4个库

3.1.3、问题?那uname的查询怎么办?

  • (1)串行请求,四个库挨个访问。
  • (2)并行请求,同时访问四个库。
  • (3)uname和uid做映射关系,比如md5,但是这种方式会有冲突。
  • (4)单独对uname和uid建立索引表,或者对uname和uid做一层映射关系的缓存。

3.2、场景二:(1对多)帖子库如何拆分

3.2.1、帖子库,15亿数据量

1
tiezi(tid, uid, title, content, time);

3.2.2、业务需求如下

  • (1)查询帖子详情(90%请求)=>SELECT * FROM tiezi WHERE tid=$tid
  • (2)查询用户所有发帖(10%请求)=>SELECT * FROM tieziWHERE uid=$uid

3.2.3、问题?如何进行分库

(1)可以对tid分库,然后对tie和uid做一层映射关系,这样似乎回到了第一个场景。
(2)为了满足业务2,假设我们按照uid分4个库,那么命中哪个库是由uid的最后2个字节决定的(uid%4)。而同时为了满足业务1,我们需要把tid生成的时候,最后2字节跟uid的一样,这样就能同时满足上述2个业务了(uid和tid%4取模都在同一个库)。

3.3、场景三:(多对多)好友库如何拆分

3.3.1、好友库,1亿数据量

1
friend(uid, friend_uid, nick, memo, XXOO);

3.3.2、业务需求如下

  • (1)查询我的好友(50%请求)=> 用亍界面展示SELECT friend_uid FROM friend WHERE uid=$my_uid
  • (2)查询加我为好友的用户(50%请求)=> 用户反向通知SELECT uidFROM friend WHERE friend_uid=$my_uid

这种场景,我们需要垂直切分,uid一个库,friend_uid一个库

3.3.3、问题一?如何写入数据

  • (1)同步写入数据,依次往uid库、friend_uid库写入数据。这样会比较慢。
  • (2)异步写入数据,先写入uid库,再通过mq异步写入friend_uid库
  • (3)异步写入数据,先写入uid库,再通过binlog,读取日志的方式来写入friend_uid库。

3.3.3、问题二?数据不一致怎么处理

上述方法,分布式造成的数据冗余、数据不一致无法避免,所以需要尽快发现,尽快修护。

  • (1)写脚本,发现uid库与friend_uid库不一致再同步。缺点是数据量太大时候,每次扫描的没用数据太多。
  • (2)扫描当天修改的数据。通过扫描binlog。
  • (3)通过mq实现,uid库的修改与friend_uid库的修改都通知mq,如果出现数据不一致则进行修护。但是这样不利于系统的架构,需要的服务太多。

3.4、场景四:(多key)订单库如何拆分

3.4.1、订单库,10亿数据量

1
order(oid, buyer_id, seller_id, order_info, XXOO);

3.4.2、业务需求如下

  • (1)查询订单信息(80%请求)=>SELECT * FROM order WHERE oid=$oid
  • (2)查询我买的东东(19%请求)=>SELECT *FROM order WHERE buyer_id=$my_uid
  • (3)查询我卖出的东东(1%请求)=>SELECT *FROM order WHERE seller_id=$my_uid

3.4.3、问题?如何分库

  • (2)转化为第二和第三种场景的综合
  • (1)转化为第二种场景。oid+buyer_id分库,跟第二种业务场景一样。seller_id则根据业务进行串行查询。

四、前后台分离

后台服务可能会影响前台服务,所以后台服务架构需要跟前台分离。

  • 前台主库可以没有索引,因为只有写。从库需要索引
  • 后台同步主库数据,可以根据业务建立不同索引

五、提问环节

5.1、数据分布性,热点问题。

  • 通过uid分数据。大客户,如果大客户多,分布还是均匀。如果还是有不均匀的,直接单独处理。
文章目录
  1. 1. 一、基本概念
  2. 2. 二、数据库架构设计什么
  3. 3. 三、怎么水平切分
    1. 3.1. 3.1、场景一:(单key)用户库如何拆分
      1. 3.1.1. 3.1.1、用户库,10亿数据量
      2. 3.1.2. 3.1.2、业务需求如下
      3. 3.1.3. 3.1.3、问题?那uname的查询怎么办?
    2. 3.2. 3.2、场景二:(1对多)帖子库如何拆分
      1. 3.2.1. 3.2.1、帖子库,15亿数据量
      2. 3.2.2. 3.2.2、业务需求如下
      3. 3.2.3. 3.2.3、问题?如何进行分库
    3. 3.3. 3.3、场景三:(多对多)好友库如何拆分
      1. 3.3.1. 3.3.1、好友库,1亿数据量
      2. 3.3.2. 3.3.2、业务需求如下
      3. 3.3.3. 3.3.3、问题一?如何写入数据
      4. 3.3.4. 3.3.3、问题二?数据不一致怎么处理
    4. 3.4. 3.4、场景四:(多key)订单库如何拆分
      1. 3.4.1. 3.4.1、订单库,10亿数据量
      2. 3.4.2. 3.4.2、业务需求如下
      3. 3.4.3. 3.4.3、问题?如何分库
  4. 4. 四、前后台分离
  5. 5. 五、提问环节
    1. 5.1. 5.1、数据分布性,热点问题。
,