分库分表归纳总结

原文地址 mp.weixin.qq.com

为什么要分库分表?

随着业务的发展,单库单表难以满足我们对性能的要求,在分库之前,可能我们经历了sql调优、索引优化、数据库参数优化、读写分离、使用分布式缓存来降低我们数据库的压力。但是随着业务再一步扩大,以上的方法可能就不适用了;基本上就以下几种情况

  • IO瓶颈

  • 并发量过大,查询磁盘次数过大,特别是缓存命中率很低的时候更严重(分库)

  • 表太大,一次查询磁盘操作过多(分库、或分表,单表容量控制在2000万以内,根据业务增长预估提前规划)

  • 进出数据比较多,网络IO较大 (分库)

  • 数据库参数未优化,比如可以开启组提交来降低IO操作

  • 缓存设置过小也会

  • CPU瓶颈

  • 大SQL查询导致cpu彪高,单独从库,或者走大数据

  • 函数操作,特别是聚合、排序、分组、关联查询,能在程序中处理最好在程序中处理

  • 未走索引,优化sql,或者添加索引

  • 存储瓶颈

  • 比如阿里单实例最大3TB,业务数据过多无法存储(分库)

  • 一般不建议单实例存储太多的数据,存储数据多,代表着表多,表多了磁盘寻址也是个性能损耗

  • 连接数瓶颈

  • 并发量过大,链接数不够用(分库)

  • 死锁导致堆积,也会带来cpu瓶颈(实时监控与治理)

  • 慢查询,导致连接消耗也会带来cpu瓶颈

我还遇到一个因微服务拆分带来的分库需求,由单体拆出去以后多个项目共用一个数据库,多源写导致数据操作难以控制。

我们为什么需要分库分表

在分库分表之前,就需要考虑为什么需要拆分。我们做一件事,肯定是有充分理由的。所以得想好分库分表的理由是什么。我们现在就从两个维度去思考它,为什么要分库?为什么要分表?

1.1 为什么要分库

如果业务量剧增,数据库可能会出现性能瓶颈,这时候我们就需要考虑拆分数据库。从这两方面来看:

  • 磁盘存储

业务量剧增,MySQL单机磁盘容量会撑爆,拆成多个数据库,磁盘使用率大大降低。

  • 并发连接支撑

我们知道数据库连接数是有限的。在高并发的场景下,大量请求访问数据库,MySQL单机是扛不住的!高并发场景下,会出现too many connections报错。

当前非常火的微服务架构出现,就是为了应对高并发。它把订单、用户、商品等不同模块,拆分成多个应用,并且把单个数据库也拆分成多个不同功能模块的数据库(订单库、用户库、商品库),以分担读写压力。

1.2 为什么要分表

假如你的单表数据量非常大,存储和查询的性能就会遇到瓶颈了,如果你做了很多优化之后还是无法提升效率的时候,就需要考虑做分表了。一般千万级别数据量,就需要分表。

这是因为即使SQL命中了索引,如果表的数据量超过一千万的话,查询也是会明显变慢的。这是因为索引一般是B+树结构,数据千万级别的话,B+树的高度会增高,查询就变慢啦。MySQL的B+树的高度怎么计算的呢?跟大家复习一下:

InnoDB存储引擎最小储存单元是页,一页大小就是16k。B+树叶子存的是数据,内部节点存的是键值+指针。索引组织表通过非叶子节点的二分查找法以及指针确定数据在哪个页中,进而再去数据页中找到需要的数据,B+树结构图如下:

图片

假设B+树的高度为2的话,即有一个根结点和若干个叶子结点。这棵B+树的存放总记录数为=根结点指针数*单个叶子节点记录行数。

如果一行记录的数据大小为1k,那么单个叶子节点可以存的记录数 =16k/1k =16. 非叶子节点内存放多少指针呢?我们假设主键ID为bigint类型,长度为8字节(面试官问你int类型,一个int就是32位,4字节),而指针大小在InnoDB源码中设置为6字节,所以就是 8+6=14 字节,16k/14B =16*1024B/14B = 1170

因此,一棵高度为2的B+树,能存放1170 * 16=18720条这样的数据记录。同理一棵高度为3的B+树,能存放1170 *1170 *16 =21902400,大概可以存放两千万左右的记录。B+树高度一般为1-3层,如果B+到了4层,查询的时候会多查磁盘的次数,SQL就会变慢。

因此单表数据量太大,SQL查询会变慢,所以就需要考虑分表啦。

什么时候考虑分库分表?

对于MySQLInnoDB存储引擎的话,单表最多可以存储10亿级数据。但是的话,如果真的存储这么多,性能就会非常差。一般数据量千万级别,B+树索引高度就会到3层以上了,查询的时候会多查磁盘的次数,SQL就会变慢。

阿里巴巴的《Java开发手册》提出:

单表行数超过500万行或者单表容量超过2GB,才推荐进行分库分表。

那我们是不是等到数据量到达五百万,才开始分库分表呢?

不是这样的,我们应该提前规划分库分表,如果估算3年后,你的表都不会到达这个五百万,则不需要分库分表。

MySQL服务器如果配置更好,是不是可以超过这个500万这个量级,才考虑分库分表?

虽然配置更好,可能数据量大之后,性能还是不错,但是如果持续发展的话,还是要考虑分库分表

一般什么类型业务表需要才分库分表?

通用是一些流水表、用户表等才考虑分库分表,如果是一些配置类的表,则完全不用考虑,因为不太可能到达这个量级。

如何选择分表键

分表键,即用来分库/分表的字段,换种说法就是,你以哪个维度来分库分表的。比如你按用户ID分表、按时间分表、按地区分表,这些用户ID、时间、地区就是分表键。

一般数据库表拆分的原则,需要先找到业务的主题。比如你的数据库表是一张企业客户信息表,就可以考虑用了客户号做为分表键

为什么考虑用客户号做分表键呢?

这是因为表是基于客户信息的,所以,需要将同一个客户信息的数据,落到一个表中,避免触发全表路由

非分表键如何查询

分库分表后,有时候无法避免一些业务场景,需要通过非分表键来查询

假设一张用户表,根据userId做分表键,来分库分表。但是用户登录时,需要根据用户手机号来登陆。这时候,就需要通过手机号查询用户信息。而手机号是非分表键

非分表键查询,一般有这几种方案:

  • 遍历:最粗暴的方法,就是遍历所有的表,找出符合条件的手机号记录(不建议

  • 将用户信息冗余同步到ES,同步发送到ES,然后通过ES来查询(推荐

其实还有基因法:比如非分表键可以解析出分表键出来,比如常见的,订单号生成时,可以包含客户号进去,通过订单号查询,就可以解析出客户号。但是这个场景除外,手机号似乎不适合冗余userId

数据切分

既然要分库分表,那一定会涉及到数据的切分,一般有两种模式,垂直切分,和水平切分;

垂直切分

一种是分库

  • 将不同的系统模块的表拆解到不同的库中;

  • 将同一个系统模块中根据数据量或者业务规则拆到不同的库中(程序关联性大的放在一起);

  • 将不同的租户数据拆到不同的库里(表结构一样)

举个例子:比如我们授信系统,拆成了两个库auth 和auth2

  • auth库里是用户授信记录

  • auth2库是风控相关的操作记录

一种是分表

  • 将字段特别多的表拆分为多个表;

  • 将大字段拆出(单行超过700多个字节的时候,会拆到额外的存储区域)

举个例子:

图片

还有我们在做业务的时候,也会不自觉的采用分表,比如我们的工单表和工单扩展表

水平切分(每个表的结构相同)

这个主要是解决单表数据量过大的问题,比如说,10亿的用户,单表存储不现实的吧,一般会拆成10张表;

水平拆分,一般由程序进行控制,一般有以下几种方式:

范围拆分
  • 按照id范围,比如id[11000万)一张表,id[1000万2000万)一张表,以此类推

  • 增删数据库实例方便,全量顺序查找方便

  • 按照创建时间,比如一个月或者一年一张表

  • 业务操作都得带着时间,比如查询最近一个月的账单,可以拆分出来查哪些库表

  • 交易订单、银行流水等按照时间排序的

  • 按照某个分类比如租户分表

  • 业务操作都得带租户,按租户查找方便,按租户新增库表方便

图片

优点:

  • 扩/缩容方便(增加或删除库表方便)

  • 归档方便

缺点:

  • 流量倾斜,热点数据不均衡(热点一般都是新进来的数据)

  • 某个库表压力过大

取模拆分(一般为业务主键)

note: 分表尽可能使用比较均匀的字段,同时要考虑到用户的行为习惯,比如手机号码,大部分人不会选择尾号为4的手机号,如果按尾号分,很容易出现尾号4的库表访问量少的问题,同时还有一个身份证,也存在同样的问题(x相对较少),如果必须要用这两个,建议hash以后再分

  • 如果是整数,直接进行取模,比如 id/10 路由到不同的库表中;

  • 如果是字符串,可以先hash,然后再取模(避免流量倾斜)

图片

优点:

  • 数据分散相对均匀

  • 数据库表的负载压力均衡

缺点:

  • 扩展能力差(增加库表,数据需要进行迁移)

  • 平衡难以把控,一次规划好,浪费资源,业务增量大,迁移麻烦

扩展能力差的问题,可以用一次性hash的方式来降低迁移的难度;

一致性Hash

如果用hash方式分表,前期规划不好,需要扩容二次分表,表的数量需要增加,所以hash值需要重新计算,这时候需要迁移数据了。

比如我们开始分了10张表,之后业务扩展需要,增加到20张表。那问题就来了,之前根据orderId取模10后的数据分散在了各个表中,现在需要重新对所有数据重新取模20来分配数据

为了解决这个扩容迁移问题,可以使用一致性hash思想来解决。

一致性哈希:在移除或者添加一个服务器时,能够尽可能小地改变已存在的服务请求与处理请求服务器之间的映射关系。一致性哈希解决了简单哈希算法在分布式哈希表存在的动态伸缩等问题

分库分表带来的问题

数据倾斜问题
  • 业务与倾斜要选一个平衡,比如电商类,在双十一和双十二的订单里会很大,避免不了的倾斜;

  • 数据倾斜不一定会出现热点问题;

如何避免热点问题数据倾斜(热点数据)

如果我们根据时间范围分片,某电商公司11月搞营销活动,那么大部分的数据都落在11月份的表里面了,其他分片表可能很少被查询,即数据倾斜了,有热点数据问题了。

我们可以使用range范围+ hash哈希取模结合的分表策略,简单的做法就是:

在拆分库的时候,我们可以先用range范围方案,比如订单id在0~4000万的区间,划分为订单库1;id在4000万~8000万的数据,划分到订单库2,将来要扩容时,id在8000万~1.2亿的数据,划分到订单库3。然后订单库内,再用hash取模的策略,把不同订单划分到不同的表。

图片

热点问题
  • 热点问题,通过取模或一致性hash解决
事务问题
  • 一般互联网应用中不建议使用事务,建议业务补偿,保证最终一致性;

  • 分库时,尽可能将一个事务内的操作放入到一个库,避免跨库事务;

  • 实在避免不了,还必须用事务,用分布式事务解决

  • 本地消息表

  • TCC

  • RocketMQ的事务消息

  • 事件中心

  • saga

聚合查询问题 (跨节点的order by,group by等聚合函数)
  • 一般是统计报表或数据分析,需要用到聚合函数或join,这种情况下不建议在业务系统里;

  • 如果是业务系统使用,一般会冗余一些字段,减少聚合查;

  • 一般互联网应用不建议聚合查,代码层进行组装,降低数据库的压力;

图片

  • 通过中间件将各分库的数据同步到聚合库,这个聚合库可以是hbase或者Cassandra里,也可以是oracle,当然也可以是mysql;

  • 分库以后各表的主键id建议使用分布式id,使用雪花算法yyyyMMddHHmmssSSS+机器位+内存序列,能保证数据相对有序,毫秒级的数据能落入到一个数据页中,性能损耗不大,根据实际需求,可以把自己定义机器位的大小和内存序列的大小;

跨库Join的几种解决思路:

  • 字段冗余:把需要关联的字段放入主表中,避免关联操作;比如订单表保存了卖家ID(sellerId),你把卖家名字sellerName也保存到订单表,这就不用去关联卖家表了。这是一种空间换时间的思想。

  • 全局表:比如系统中所有模块都可能会依赖到的一些基础表(即全局表),在每个数据库中均保存一份。

  • 数据抽象同步:比如A库中的a表和B库中的b表有关联,可以定时将指定的表做同步,将数据汇合聚集,生成新的表。一般可以借助ETL工具。

  • 应用层代码组装:分开多次查询,调用不同模块服务,获取到数据后,代码层进行字段计算拼装。

分页问题
  • 如果是以分区主键来查询业务,分页问题就不是问题;

  • 如果是全局查,且分页,建议使用聚合库做查询分页,操作接口再到具体的分库分表上;

  • 根据业务属性增加一层处理机制,比如审核类的,我们分页查找一般都是进行中的,审核完的,只需要精确查找就行;

  • 我们抽出一个处理中的表,在这里进行业务操作处理;

  • 处理完的一般都是精确查找,如果需要业务分析,大数据处理

  • 如果不使用聚合库,只能使用全局查找,先把符合条件的数据查到,然后在内存中聚合,然后再分页,如果数据量大,oom了,同时对于数据库的压力也不小;

分库分表后的分页几种解决思路:

  • 方案1(全局视野法):在各个数据库节点查到对应结果后,在代码端汇聚再分页。这样优点是业务无损,精准返回所需数据;缺点则是会返回过多数据,增大网络传输

比如分库分表前,你是根据创建时间排序,然后获取第2页数据。如果你是分了两个库,那你就可以每个库都根据时间排序,然后都返回2页数据,然后把两个数据库查询回来的数据汇总,再根据创建时间进行内存排序,最后再取第2页的数据。

  • 方案2(业务折衷法-禁止跳页查询):这种方案需要业务妥协一下,只有上一页和下一页,不允许跳页查询了。

这种方案,查询第一页时,是跟全局视野法一样的。但是下一页时,需要把当前最大的创建时间传过来,然后每个节点,都查询大于创建时间的一页数据,接着汇总,内存排序返回。

非分区业务查询

比如我们使用用户的uuid分表,然后我们要通过手机号mobile查用户的信息,怎么办?总不能来个全库扫描吧。那怎么办?

  • 关系映射

    当通过mobile查询的时候,先查到uuid再去具体的表里查

  • 将映射关系存储到一张索引表,通过旁路缓存查询

  • 直接永久缓存起来(需要考虑缓存失效的问题,缓存中没有怎么处理?)

  • 通过手机号生成uuid

  • 在往用户表插入数据的时候,通过一个固定方法把mobile转成uuid(需要考虑去重,极小的概率会重复)

  • 基因法(高低位存储)

  • 自己设计一个id生成器生成uuid,高位存储时间戳(20221201221126945)+3位机器位+3位内存毫秒级自增序列,

  • 低位(2~3位)存储分区规则,分区规则由mobile生成

分库分表实现或工具

  • 直接写mybatis插件自己实现

  • 通过库名和表名替换实现路由

  • TDDL(淘宝)

  • https://github.com/alibaba/tb_tddl 2012年后未更新

  • jar包的方式供应用调用,可以理解为自己实现的增强版

  • 通过规则匹配后做表名替换,然后将sql转发过去

  • Cobar中间件(阿里巴巴)

  • https://github.com/alibaba/cobar 2018年以后未更新

  • cobar是在amoeba基础上进化的版本

  • 代理方式

  • mycat 中间件

  • 基于ocbar开发的

  • http://mycatone.top/ 现在社区在推2.x的版本

  • 也是基于代理的方式,所有的规则都配置在mycat里;

  • ShardingSphere-JDBC 和ShardingSphere-Proxy

  • https://shardingsphere.apache.org

  • ShardingSphere-JDBC 仅支持java,低损耗、无中心化的工具

  • ShardingSphere-Proxy(代理)

大部分都是使用ShardingSphere-JDBC

如何评估分库数量

  • 对于MySQL来说的话,一般单库超过5千万记录,DB的压力就非常大了。所以分库数量多少,需要看单库处理记录能力。

  • 如果分库数量少,达不到分散存储和减轻DB性能压力的目的;如果分库的数量多,对于跨多个库的访问,应用程序需要访问多个库。

  • 一般是建议分4~10个库,我们公司的企业客户信息,就分了10个库。

hash分库分表在线处理方案

水平扩库

note: 如果生产上能对这个库的写拦截10秒左右最好,数据无损

中间件+程序改造

比如dts同步到kafka,然后消费kafka处理

图片

  1. 将最近一次备份库恢复;

  2. 将数据按分片规则清洗到不同的库里;

  3. 清洗完成后,回放备份时间点以后的binlog;

  4. 将binlog根据分片规则回放到不同的实例里;

  5. 确保同步是准实时;

  6. 将写入的数据缓存到分布式缓存里5分钟(确保时差内可以同步过去);

  7. 应用依次发布(新应用发布以后,老应用还在写数据,新应用优先从缓存里读);

从库机制

图片

  • 先给要分库的库挂对应数量的从库,比如要分10个库,挂10个从库

  • 同时申请10个VIP挂先挂指向主库db_user上

  • 增加路由规则,uuid%10=0的走u0.vip,其他的类似

  • 虽然路由到了不同的vip上,但是这个vip都指向了主库;

图片

分表要停服嘛?不停服怎么做?

不用停服。不停服的时候,应该怎么做呢,主要分五个步骤:

  1. 编写代理层,加个开关(控制访问新的DAO还是老的DAO,或者是都访问),灰度期间,还是访问老的DAO

  2. 发版全量后,开启双写,既在旧表新增和修改,也在新表新增和修改。日志或者临时表记下新表ID起始值,旧表中小于这个值的数据就是存量数据,这批数据就是要迁移的。

  3. 通过脚本把旧表的存量数据写入新表。

  4. 停读旧表改读新表,此时新表已经承载了所有读写业务,但是这时候不要立刻停写旧表,需要保持双写一段时间。

  5. 当读写新表一段时间之后,如果没有业务问题,就可以停写旧表啦

数据库重构迁移方案

系统重构时,需要对数据库进行数据迁移到新表,需要保证迁移过程是在线的,迁移前后数据是一致的,迁移过程是可回滚的。整体步骤:同步、双写、校验、切读、切写。方案说明
在这里插入图片描述
1.第一步,存量同步可通过Binlog增量日志进行同步,也可手工同步。

2.第二步,双写新库需要考虑在同一个事务,如果为了性能考虑,可以异步写入新库,但要注意失败数据的补偿写入。注意:如果第一步是通过Binlog同步,同步程序同时在进行数据增量写入,可以通过开关控制第二步双写启动后,关闭Binlog同步程序。

3.第三步,校验新老库数据是否一致,校验方式:

①离线回流全量校验,每天增量回流校验

②在线数据量校验,比对在线表数据总量是否一致

③在线抽取部分数据校验,随机抽取当天的部分数据,比对两边是否一致

4.第四步,切读,灰度切换,有问题随时回滚

5.第五步,切写,灰度切换,有问题随时回滚,全量切换完成后可下线旧库

双写加上第三步的校验,保证新旧库数据完全一致,所以在切换的过程中出现任何的问题,都可以将读写流量随时切换

数据校验工作是最复杂且最重要的部分,因此在未开始迁移数据之前先写好数据校验的工具或者脚本,在测试环境上测试充分之后,再开始正式的数据迁移。

分库分表步骤

根据容量(当前容量和增长量)评估分库或分表个数 -> 选key(均匀)-> 分表规则(hash或range等)-> 执行(一般双写)-> 扩容问题(尽量减少数据的移动)。

分库分表问题

1、非partition key的查询问题

基于水平分库分表,拆分策略为常用的hash法。

  1. 端上除了partition key只有一个非partition key作为条件查询

    • 映射法

    • 基因法

      注:写入时,基因法生成user_id,如图。关于xbit基因,例如要分8张表,23=8,故x取3,即3bit基因。根据user_id查询时可直接取模路由到对应的分库或分表。根据user_name查询时,先通过user_name_code生成函数生成user_name_code再对其取模路由到对应的分库或分表。id生成常用snowflake算法

  2. 端上除了partition key不止一个非partition key作为条件查询

    • 映射法

    • 冗余法
      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tG74Lprj-1677721869138)(https://images2018.cnblogs.com/blog/955136/201808/955136-20180807171456867-464776606.png)]

      注:按照order_id或buyer_id查询时路由到db_o_buyer库中,按照seller_id查询时路由到db_o_seller库中。感觉有点本末倒置!有其他好的办法吗?改变技术栈呢?

  3. 后台除了partition key还有各种非partition key组合条件查询

    • NoSQL法
    • 冗余法

2、非partition key跨库跨表分页查询问题

基于水平分库分表,拆分策略为常用的hash法。

注:用**NoSQL法**解决(ES等)。

3、扩容问题

基于水平分库分表,拆分策略为常用的hash法。

  1. 水平扩容库(升级从库法)

    注:扩容是成倍的。

  2. 水平扩容表(双写迁移法)

    第一步:(同步双写)修改应用配置和代码,加上双写,部署;
    第二步:(同步双写)将老库中的老数据复制到新库中;
    第三步:(同步双写)以老库为准校对新库中的老数据;
    第四步:(同步双写)修改应用配置和代码,去掉双写,部署;

注:双写是通用方案。

分库分表总结

  1. 分库分表,首先得知道瓶颈在哪里,然后才能合理地拆分(分库还是分表?水平还是垂直?分几个?)。且不可为了分库分表而拆分。
  2. 选key很重要,既要考虑到拆分均匀,也要考虑到非partition key的查询。
  3. 只要能满足需求,拆分规则越简单越好。

分库分表示例

示例GitHub地址:https://github.com/littlecharacter4s/study-sharding

MySQL数据库之互联网常用分库分表方案 https://www.cnblogs.com/littlecharacter/p/9342129.html

多维度查询问题介绍

在进行分库分表的时候应该有碰到一个问题,一个数据需要根据两种维度进行查询,但是我们在进行分库分表是只能根据一种维度进行。比如:用户购买了商品产生了订单,当用户非常多的时候,我们会选择订单【根据下单用户的ID进行分库分表】。但是这里面存在一个问题就是作为卖家要如何查询我卖出的所有订单呢?因为订单是根据用户id规则进行分库分表的,卖家订单查询接口物理上是无法一次查询出当前的订单的,因为客户的数据分别分布在不同的订单库或者订单表中的,有可能商家自己所有客户的订单列表,需要跨非常多的表,这个样性能是非常低效的。

解决方案

方案1:建立两个维度的订单数据库买方库和卖方库,买方数据库中的表基于用户id进行分片,卖方数据库中的表基于商家id进行分片。两个数据可以通过datax数据同步框架将买方库的数据根据商家id同步到卖方库中。通过DataX实现数据同步不是实时的,DataX是基于定时任务完成数据同步的,如果将时间间隔设置的比较小,会存在一定的cpu性能浪费。

图片

方案2:将数据基于用户id分片的数据进行汇总,然后存储在NoSql数据库中,比如elasticSearch,这样在商家进行查询的时候直接走 ElasticSearch即可。

分库分表后路由策略设计

参考:https://mp.weixin.qq.com/s/A9l55dzbzK5qN2eRzMWoow

概述

分库分表后设计到的第一个问题就是,如何选择路由key,应该如何对key进行路由。路由key应该在每个表中都存在而且唯一。路由策略应尽量保证数据能均匀进行分布。

如果是对大数据量进行归档类的业务可以选择时间作为路由key。比如按数据的创建时间作为路由key,每个月或者每个季度创建一个表。按时间作为分库分表后的路由策略可以做到数据归档,历史数据访问流量较小,流量都会打到最新的数据库表中。

也可以设计其与业务相关的路由key。这样可以保证每个数据库的资源都能很好的承担流量。


支持场景

外卖订单平台分库分表后需要支持的场景,用户的角度,需要实时查看所点外卖订单的状态,跟踪订单信息。商家需要查询订单信息,通过订单分析菜品的质量,进行商业决策。

用户Consumer = C端 商家Business = B端

图片

用户下单后订单可能会落到不同的表中,查询的时候可能需要查询多张表。

图片


路由策略

如果创建订单时随机插入到某一张表中,或者不知道插入到那张表中,查询订单的时候都需要查询所有的表才能确保查询的准确信。

如果在插入订单的时候有一定的规则,根据这个规则插入到数据库中,查询的时候也执行相应的规则到对应的表中进行查询。这样就能减少数据操作的复杂性。可以通过设计路由策略来实现,用户和商家查询数据的时候都遵循相同的路由策略。

图片

图片


用户端路由key

根据上一小节的路由策略分析,现在需要选定一个路由key。用户端让同一个用户id的数据保存到某固定的表中,所以可以选用用户id最为路由key。

在单库的情况下,用户下单,生成一个订单,把用户id作为路由key,对user_id取hash值然后对表的数量进行取模,得到对应需要路由的表,然后写入数据。

图片

多库多表的情况下需要先找到对应的库然后再找到对应的表。多库多表的路由策略:用户下达->生成订单->路由策略:根据用户id的hash值对数据库的数量进行取模找到对应的数据库->根据用户id的hash值除以对表的数量,然后在对表的数量进行取模即可找到对应的表。

图片

路由策略设计的要点是根据具体的业务业务场景设计,跟用户信息关联度比较大的作为路由key进行hash值取模


商家路由key

单独为商家B端设计了一套表(C端和B端是独立的)。

图片

用户的角度以user_id作为路由key,商户的角度以商家id作为路由key。商家是如何通过路由key路由数据的呢。游湖在下单的时候把队友的订单号发送到MQ里,商家可以去消费这个MQ,然后根据订单号获取订单信息,然后再把订单信息插入到商户的数据库表当中。商户的路由策略和用户的路由策略是一样的。

图片

用户端和商户端的完整数据流程图:

图片

新老系统数据迁移

https://chenqinghe.com/?p=170

- END -

  • 27
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值