MySQL - 分库分表产生的问题&解决方案

1. 为什么分

  1. 业务拆分,将一个大的业务拆分成多个小服务,服务之间通过RPC调用,不同服务的数据使用独立的数据库存储
  2. 应对高并发,读多写少,增加从库应对读流量,读少写多,分库分表,均衡写流量
  3. 数据隔离,C端数据和B端数据分隔,核心数据与非核心数据分隔,使其不要相互影响

2. 怎么分

在分库分表之前,数据库表的主键自增可以唯一标记一条记录,但是分库分表之后,无法使用数据库的id,因为可能造成全局的主键id重复冲突

常见的是采用一个分布式发号器实现,Twitter的Snowflake,美团的leaf等

 

在分库分表前,全局一张表,举个例子是订单表。order(id,userid,memchantId)有三个字段,订单ID,用户ID,商家ID

分库分表说的简单一些就是根据一套算法将原来单表中的数据均衡到多张表中

常见的分表算法有

  1. 区域法:根据id划分区域,例如:0-1000一个表,1001-2000一个表
  2. 哈希法:根据id哈希后取余数划分,例如:hash(id)%256==1,就存入第1号表中

互联网一般采用的是哈希法进行分库分表,因为数据更加均衡,但是不利于将来扩容迁移数据(区域法与之相反

 

3. 分表后产生的问题

3.1. 查询问题

哈希法分表后会产生一个新的问题?

在原来order表查询既有根据orderid查询,也有根据userId查询,如果只是根据orderid进行分表,通过orderid搜索没有任何问题,因为可以根据orderid的值定位到具体数据在那张表中,但是如果根据userid查询,那么无法定位表,势必得全库全表搜索一下,执行效率十分低下。

3.1.1. 映射表

新建一个表存放orderId与userid的映射关联,根据userid查询时候,先根据userid查询到orderid,然后找到所在的表,然后在这张表中执行SQL即可

问题:新增一张表后,新增一条记录,需要改2张表,而且映射表也可能分库分表。可能设置两个不同数据库之间的分布式事务问题。

3.1.2. 业务双写

同一份数据两套分表规则,两套完全一样的数据库,冗余一份数据

问题:双写复杂性,两套分库分表同样存在分布式事务问题,多存储一份数据,资源浪费

3.1.3. 异步双写

还是两套数据,两套分表规则,但是只是单写,另一个库坚挺Binlog变化去进行数据同步

问题:多存储一份数据,资源浪费,引入新的中间件,增加系统复杂度

3.1.4. 双纬度合一

把订单id和userid合并到一个纬度中,举个例子,当新产生一条订单的时候,生成订单id,此时订单的用户id是123456,那么其订单id可以根据分布式发号器生成一部分1001,然后拼接一部分的用户id生成

新订单id=1001456,红色是发号器生成,蓝色是截取用户id后3位,因为根据分表256张表,只和后3位值有关系。那么此时新的订单id就包含用户id信息和orderid信息了

此时如果调用方根据订单id查询之间根据分表规则查询即可,如果调用方根据用户id查询,那么截取用户id=123456的后3位,依然可以定位到指定数据表

 

3.2. Join问题

分库分表后Join无法使用了,针对这种情况,一般有下面几种方案解决

  1. 不在数据库层做Join,单用单表查询,在代码层做结果拼装
  2. 宽表,新建立一个表,提前把Join后的视图写入这个表,重写轻读(类似物理视图
  3. 搜索引擎ES
  4. CQRS,读写模型分离,读的模型通过监听主库变化,实现写好读模型(Join后的数据)

3.3. 分布式事务问题

分库分表后分布式事务问题可能产生,但是一般产生分布式事务可以通过产品层,代码层的流程优化解决,不一定非要使用分布式事务。

实在解决不了,可以使用,TCC,Seats,消息补偿保障最终一致性等方案解决

你可能感兴趣的:(MySQL系列,mysql,分库分表)