麒麟v10 上部署 TiDB v5.1.2 生产环境优化实践
700
2023-06-03
浅谈订单重构之 MySQL 分库分表实战篇
一、背景
发布上篇文章浅谈订单重构之路之后,有很多小伙伴想知道,分库分表具体是如何实现的。那么这篇文章具体介绍下,分库分表实战。
二、目标
本文将完成如下目标:
* 分表数量: 256 分库数量: 4
* 以用户ID(user_id) 为数据库分片Key
* 最后测试订单创建,更新,删除, 单订单号查询,根据user_id查询列表操作。
架构图:
表结构如下:
CREATE TABLE `order_XXX` ( `order_id` bigint(20) unsigned NOT NULL, `user_id` int(11) DEFAULT '0' COMMENT '订单id', `status` int(11) DEFAULT '0' COMMENT '订单状态', `booking_date` datetime DEFAULT NULL, `create_time` datetime DEFAULT NULL, `update_time` datetime DEFAULT NULL, PRIMARY KEY (`order_id`), KEY `idx_user_id` (`user_id`), KEY `idx_bdate` (`booking_date`), KEY `idx_ctime` (`create_time`), KEY `idx_utime` (`update_time`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
注: 000<= XXX <= 255, 本文重点在于分库分表实践, 只保留具有代表性字段,其它场景可以在此基础上做改进。
全局唯一ID设计
要求:1.全局唯一 2:粗略有序 3:可反解出库编号
1bit + 39bit时间差 + 8bit机器号 + 8bit用户编号(库号) + 8bit自增序列
订单号组成项保留字段毫秒级时间差机器数用户编号(表编号)自增序列
所占字节(单位bit) 1 39 8 8 8
单机最大QPS: 256000 使用寿命: 17年
订单号生成规则说明详见 浅谈分布式唯一Id生成器之最佳实践
三、环境准备
1. 基本信息
2. 数据库环境准备
3. 建库 & 导入分表
* 在mysql master实例分别建库
172.30.1.21( o rder_db_ 1) , 172.30.1.22( order_db_2) ,
172.30.1.23( ord er_db_3) , 172.30.1.24( order_db_4 )
* 依次导入建表SQL 命令为
mysql -uroot -pbytearch -h172.30.1.21 order_db_1 四、配置&实践 1. pom文件 2. 常量配置 3. yml 配置 4主4从数据库配置, 这里仅测试默认使用root用户密码,生产环境不建议使用root用户。 4. 分库分表策略 1). 根据order_id为shardKey分库分表策略 2). 根据user_id 为shardKey分库分表策略 5. dao层编写 1). OrderPartitionByIdDao 6. 单元测试 @SpringBootTest(classes = {Application.class}) @RunWith(SpringJUnit4ClassRunner.class) public class ShardingTest { @Autowired OrderPartitionByIdDao orderPartitionByIdDao; @Autowired OrderPartitionByUserIdDao orderPartitionByUserIdDao; @Test public void testCreateOrderRandom() { for (int i = 0; i < 20; i++) { int userId = ThreadLocalRandom.current().nextInt(1000,1000000); OrderEntity orderEntity = new OrderEntity(); orderEntity.setOrderId(SeqIdUtil.nextId(userId % ShardingStrategyConstant.SHARDING_TABLE_NUM)); orderEntity.setStatus(1); orderEntity.setUserId(userId); orderEntity.setCreateTime(new Date()); orderEntity.setUpdateTime(new Date()); orderEntity.setBookingDate(new Date()); int ret = orderPartitionByIdDao.insertOrder(orderEntity); Assert.assertEquals(1, ret); } } @Test public void testOrderAll() { //insert int userId = ThreadLocalRandom.current().nextInt(1000,1000000); OrderEntity orderEntity = new OrderEntity(); orderEntity.setOrderId(SeqIdUtil.nextId(userId % ShardingStrategyConstant.SHARDING_TABLE_NUM)); orderEntity.setStatus(1); orderEntity.setUserId(userId); orderEntity.setCreateTime(new Date()); orderEntity.setUpdateTime(new Date()); orderEntity.setBookingDate(new Date()); int i = orderPartitionByIdDao.insertOrder(orderEntity); Assert.assertEquals(1, i); //get from master OrderEntity orderInfo = orderPartitionByIdDao.getOrderByIdFromMaster(orderEntity.getOrderId()); Assert.assertNotNull(orderInfo); Assert.assertEquals(orderInfo.getOrderId(), orderEntity.getOrderId()); //get from slave OrderEntity slaveOrderInfo = orderPartitionByIdDao.getOrderById(orderEntity.getOrderId()); Assert.assertNotNull(slaveOrderInfo); //update OrderEntity updateEntity = new OrderEntity(); updateEntity.setOrderId(orderInfo.getOrderId()); updateEntity.setStatus(2); updateEntity.setUpdateTime(new Date()); int affectRows = orderPartitionByIdDao.updateOrderByOrderId(updateEntity); Assert.assertTrue( affectRows > 0); } @Test public void testGetListByUserId() { int userId = ThreadLocalRandom.current().nextInt(1000,1000000); for (int i = 0; i < 5; i++) { OrderEntity orderEntity = new OrderEntity(); orderEntity.setOrderId(SeqIdUtil.nextId(userId % ShardingStrategyConstant.SHARDING_TABLE_NUM)); orderEntity.setStatus(1); orderEntity.setUserId(userId); orderEntity.setCreateTime(new Date()); orderEntity.setUpdateTime(new Date()); orderEntity.setBookingDate(new Date()); orderPartitionByIdDao.insertOrder(orderEntity); } try { //防止主从延迟引起的校验错误 Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } List 大功告成: 五、总结 本篇主要介绍Java版使用Mango框架实现Mysql分库分表实战,分库分表中间件也可以使用类似于ShardingJDBC,或者自研。 以上分库分表数量仅供演示参考,实际工作中分表数量、分库数量、是根据公司实际业务数据增长速度, 高峰期QPS,物理机器配置等等因素计算。
版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。