技术同学都知道,当表数据超过一定量级,我们就需要通过分表来解决单表的性能瓶颈问题;当数据库负载超过一定水平线,我们就需要通过分库来解决单库的连接数、性能负载的瓶颈问题。
本文主要阐述在同时满足以下业务场景:
分表分库存储需要对分表数量不同的表进行同事务操作这些表的分库分表策略依赖的Sharding业务ID一致等情况下,让这些不同数量级表,在同一个业务ID的事务操作路由到同一分库中的方案,省去解决垮库事务的烦恼。
二 案例1 背景假设有2个数据库实例,需要保存商家订单明细和汇总2张表的数据,这2张表的 分库分表策略都用shop_id取模策略,按单表数据500w的原则进行分表分库:
(1)shop_order_detail 商家订单明细表,日均数据6000w
(2)shop_order_stat 商家订单统计表,日均数据2000w
配置完成后生成的库表:
然后我们要做这么一件事情:在同一个事务中,新增用户订单明细成功后,更新用户订单统计数据:
2 问题此时,我要处理一笔 user_id = 3 的订单数据:
如图,执行新增shop_order_detail表操作的时候,操作被路由到了DB0中;执行更新shop_order_stat表操作的时候,操作被路由到了DB1。这时候 这两个操作跨库了,无法在同一个事务中执行, 流程异常中断。
如果用TDDL组件的话就会报这样的错:
### Cause: ERR-CODE: [TDDL-4603][ERR_ACCROSS_DB_TRANSACTION] Transaction accross db is not supported in current transaction policy三 解决方案
解决多表跨库事务的方案有很多,本文阐述的是如下解决方案:
将shop_order_stat作为shop_order_detail的映射基础表,调整shop_order_detail的分表策略,让shop_order_detail和shop_order_stat的数据都路由到同一个库中。但该方案的前提是目标表的表数量是映射基础表表数量的N倍数。比如shop_order_stat的总表数量是4,shop_order_detail的总表数量是12,故shop_order_detail的总表数是shop_order_stat总表数的3倍。
shop_order_detail新分表分库策略的推导思路如下:
1 调整分库策略首先,我们看shop_id在0~11范围内,用shop_id % 4分库分表策略shop_order_stat的sharding分布图:
用shop_id % 12分库分表策略shop_order_detail的sharding分布图:
图中看出,两张表都是根据shop_id做sharding,但现有同一个shop_id有可能会被路由到不同的库中,导致跨库操作。
此时,我只需要把shop_order_detail的分库策略调整为跟shop_order_stat一致,保证同一个shop_id能路由到同一个DB分片中就能解决这个问题。调整后的sharding分布图:
但调整完分库策略后,原本的表映射策略就失效了:
原本的shop_id = 5数据可以通过shop % 12 = 5的取模策略映射到DB0的shop_order_detail_05表上。调整完分库策略后,shop_id = 9被路由到了DB0中,通过shop % 12 = 9的取模策略会映射到shop_order_detail_09这张表上,但shop_order_detail_09这张表不在DB0中,所以操作失败了。
这时候,我们需要调整分表策略,把shop_id = 9的数据既映射到DB0中的shop_order_detail_05表中。
2 分区取模策略首先,以shop_order_stat的单库表数量2作为分块大小,总表数量4作为分区大小,对shop_id=[0~11]进行分区操作,并且将shop_id根据分块大小取模:
当前分库数量为2,shop_order_stat的单库表数量为6,计算出跨库步长=分库下标*单库表数量:
根据分区下标和分块大小,计算出分区步长=分区下标*分块大小,最后根据分块取模数+跨库步长+分区步长就能定位到最终的分表下标了:
这样就完成了把shop_id = 9的数据既映射到DB0中的shop_order_detail_05表中的工作。
四 计算公式分表下标路由策略计算公式:
分表下标 = 业务ID取模 % 分块大小 + 业务ID取模 / 分块大小 单库表数量 + 业务ID取模 / 分区大小 分块大小业务ID取模 = 业务ID % 总表数量分区大小 = 目标映射表的总表数量分块大小 = 目标映射表的单库表数量以上面的案例为例,调整shop_order_detail的分库分表路由策略:
(1)shop_order_stat 商家订单统计表
(2)shop_order_detail 商家订单明细表
TDDL sharding-rule配置代码示例:
Java代码示例:
long shopId = 9; int dbs = 2; int tables = 12; int oneDbTables = 6; int partitionSize = 4; int blockSize = 2; int sharding = (int) (shopId % tables); // 目标分库 int dbIndex = (int) (shopId % partitionSize / dbs); // 目标分表 int tableIndex = sharding % blockSize + sharding % partitionSize / blockSize * oneDbTables + sharding / partitionSize * blockSize;五 结尾
我是本地生活外卖商家运营研发团队中的一员,在实际业务场景的设计中遇到了多表事务分库内闭环的问题,没有找到适合的案例参考,才孵化出这个解决方案。
目前该方案已经在落地上线,有相同业务场景需求的同学可直接套用计算公式既可,欢迎大家交流沟通。
免费领取电子书
《阿里巴巴大数据及 AI 实战》
本书将深度剖析淘宝、高德、友盟+、1688、优酷、阿里妈妈、阿里影业大数据实战场景,是 2020 不容错过的企业大数据实战手册。
扫码加阿里妹好友,回复“阿里ai”获取吧~(英文字母小写,若扫码无效,可直接添加alimei4、alimei5、alimei6、alimei7)
【编者的话】本文作者利用自己云原生工程师的优势,分享了他对2021年及之后的云...
1. 接口描述 接口请求域名: cvm.tencentcloudapi.com 。 本接口 (ResetInstance...
TOP云 (west.cn)8月14日消息,本期的sedo 域名交易 榜共有63个 域名 超2000美...
云计算服务正在以前所未有的速度在各行各业快速普及,成为IT应用的最主流实现形...
步入2月,美股新一轮财报季渐入高潮。 本周二,包括阿里巴巴、亚马逊、谷歌在内...
据IDC评述网(idcps.com)报道,ntldstats.com最新数据显示,截止至2016年3月31...
本文转载自公众号读芯术(ID:AI_Discovery) 下面这个模型在一项图像识别竞赛中经...
Cloud-init是开源的云初始化程序,能够对新创建弹性云服务器中指定的自定义信息...
每年618是年中购物节,每到这一天,大家都会进入网购模式,疯狂的买买买。618购...
操作场景 本节操作介绍在Windows和Linux环境中使用SSH密钥对方式远程登录Linux云...