分库分表设计方案总结
1、分库分表使用场景及设计方案 或 链接2
场景:有时数据库可能既面临着高并发访问的压力,又需要面对海量数据的存储问题,这时需要对数据库既采用分表策略,又采用分库策略,以便同时扩展系统的并发处理能力,以及提升单表的查询性能,这就是所谓的分库分表。
分库分表的策略比前面的仅分库或者仅分表的策略要更为复杂,一种分库分表的路由策略如下:
1. 中间变量 = user_id % (分库数量 * 每个库的表数量) 2. 库 = 取整数 (中间变量 / 每个库的表数量) 3. 表 = 中间变量 % 每个库的表数量
同样采用user_id作为路由字段,首先使用user_id 对库数量*每个库表的数量取模,得到一个中间变量;然后使用中间变量除以每个库表的数量,取整,便得到对应的库;而中间变量对每个库表的数量取模,即得到对应的表。
分库分表策略详细过程如下:
假设将原来的单库单表order拆分成256个库,每个库包含1024个表,那么按照前面所提到的路由策略,对于user_id=262145 的访问,路由的计算过程如下:
中间变量 = 262145 % (256 * 1024) = 1 库 = 取整 (1/1024) = 0 表 = 1 % 1024 = 1
这就意味着,对于user_id=262145 的订单记录的查询和修改,将被路由到第0个库的第1个order_1表中执行。
2、大数据如何分库分表
根据您提供的文本,以下是对“使用uid取模运算进行分库分表”方案的总结:
方案概述
该方案是业界常用的订单数据分库分表方法,核心是以用户ID(uid)作为分片键进行取模运算,将数据均匀分散到多个数据库和表中。
具体实现规则
1. 库定位:使用用户ID末尾4位数字 Mod 32(即除以32取余数)。余数范围0-31,对应32个库,例如 `order_db_0` 到 `order_db_31`。
2. 表定位:分两步计算:
* 先将用户ID末尾4位数字 Dev 32(即除以32后向下取整)。
* 再将得到的整数 Mod 32(除以32取余数)。余数范围0-31,对应每个库内的32张表,例如 `order_tb_0` 到 `order_tb_31`。
3. 数据规模:按此规则(32库 × 32表),可建立总计1024张表。通过控制单表数据量(如1千万至5千万行),系统可支撑海量数据。
优点
* 实现简单:在程序层面进行取模运算即可,开发便捷。
* 数据分布均匀:通过取模能使数据相对均匀地分散到各个库和表,有助于避免单个库成为性能瓶颈。
* 查询效率高(针对用户维度):由于同一用户的所有订单通过其固定ID计算后,总会落在同一个库的同一张表中,因此查询指定用户的所有订单时,无需跨库或跨表查询,性能高。
缺点
* 扩容复杂:当需要增加数据库节点(扩容)时,原有的取模规则会发生变化,需要进行数据迁移,操作繁琐。
* 最佳实践:为减少迁移量,扩容通常以倍数形式进行(例如从8库扩至16库,再至32库)。
* 数据可能分布不均:虽然取模能使数据整体分散,但无法避免因业务差异导致的数据倾斜。例如,某些用户(或其ID段)下单量极大,其所有订单仍会集中到同一张表,可能导致该单表数据量过早达到上限。
总结与权衡
该方案是一种在实现复杂性、查询性能与可扩展性之间取得平衡的实用选择。它用相对简单的逻辑解决了用户维度查询的核心痛点,虽然存在扩容麻烦和数据潜在倾斜的问题,但其优势在多数业务场景下更为突出,因此被广泛采用。业界通常的应对策略是接受其缺点,优先满足当前业务性能需求,待未来数据量真正达到瓶颈时,再考虑更复杂的解决方案。
3、大众点评订单系统分库分表实践
唯一ID方案:时间戳+用户标识码+随机数。好处:自带分库规则,这里的用户标识码即为用户ID的后四位,在查询的场景下,只需要订单号就可以匹配到相应的库表而无需用户ID,只取四位是希望订单号尽可能的短一些,并且评估下来四位已经足够。
可排序,因为时间戳在最前面。
采用Mod来切分。
数据水平切分后我们希望是一劳永逸或者是易于水平扩展的,所以推荐采用mod 2^n这种一致性Hash。
以统一订单库为例,我们分库分表的方案是32*32的,即通过UserId后四位mod 32分到32个库中,同时再将UserId后四位Div 32 Mod 32将每个库分为32个表,共计分为1024张表。
线上部署情况为8个集群(主从),每个集群4个库。
场景一:数据库性能达到瓶颈
方法一
按照现有规则不变,可以直接扩展到32个数据库集群。
方法二
如果32个集群也无法满足需求,那么将分库分表规则调整为(32*2^n)*(32/2^n),可以达到最多1024个集群。
4、如果面试官让你设计美团外卖的分库分表架构,就该这么说!
用户端:根据用户id的hash值对数据库的数量进行取模找到对应的数据库->根据用户id的hash值除以对表的数量,然后在对表的数量进行取模即可找到对应的表
单独为商家B端设计了一套表(C端和B端是独立的):在下单的时候把队友的订单号发送到MQ里,商家可以去消费这个MQ,然后根据订单号获取订单信息,然后再把订单信息插入到商户的数据库表当中。商户的 路由策略 和用户的 路由策略 是一样的。
5、订单表每天新增500w数据,分库分表如何设计?
1.1天500万,那么1年就是18亿,我们按照2年的增量来算就是大概40亿
2.在预留一些空间,按照50亿来算
3.那么需要使用32个库,每个库32张表,那么一共就是1024张表,每个表存500万数据
4.使用orderId(订单id)当做分片键,使用一致性hash算法来分配,要插入到那个数据库的那个表中
5.当订单的数据超过了2年,那么使用冷热分离的方案或者使用tidb在线扩容数据库来解决
6.热库数据保留一年,1年以后迁移到冷库,冷库保存2年,2年后,进行数据归档
6、【架构设计】高并发订单系统分库分表方案
一、分片策略选择(核心决策)
1. 按用户ID分片
适用场景:用户维度的查询频繁(如查询个人订单列表、分页展示)。
实现方式:
分库:user_id % 64 路由到64个库(预留扩容空间)。 分表:每个库内按user_id % 1024 分1024张表,单表控制在千万级数据量。
优点:同一用户数据集中存储,避免跨分片查询。
缺点:超级买家可能导致数据倾斜(如某用户订单量极大)。
优化:冷热分离,3个月内热数据存MySQL,历史数据归档至HBase/ES。
2. 按订单号分片
适用场景:需均匀分散写入压力,避免热点。
实现方式:
基因分片法:订单号末尾嵌入用户ID哈希值(如订单号=时间戳+用户ID后4位+随机数),直接根据订单号定位库表。
分库分表:hash(order_id) % (库数量×表数量) 计算中间变量,再拆解库表序号。
优点:数据分布均匀,支持高并发写入。
缺点:按用户ID查询需跨分片,需额外设计索引表。
3. 按时间分片
适用场景:时间范围查询为主(如统计月度订单)。
实现方式:按月分库(orders_202301),库内再按用户ID或订单号分表。
缺点:新表写入热点,历史数据查询需跨库。
优化:结合哈希后缀分散写入(如订单号添加随机数)。
二、全局ID生成方案
- 雪花算法(Snowflake):
64位结构:1符号位 + 41位时间戳 + 10位机器ID + 12位序列号。
问题:时钟回拨需通过NTP同步或本地缓存解决。
- 号段模式:
从数据库批量获取ID段(如每次分配1000个ID),减少DB压力。
- 嵌入分片信息:
在订单号头部添加分库分表路由码(如库序号+表序号),实现无索引直接查询。
三、跨分片查询解决方案
- 索引表机制:
建订单号→用户ID映射表,异步写入MQ更新,分库分表后按订单号取模分片。
查询时先查索引表获取用户ID,再路由到对应分片。
- 数据冗余:
多写异构:订单同时写入买家库(按user_id分片)和卖家库(按shop_id分片),通过MQ同步数据。
字段冗余:订单表冗余商家名称、用户名称等高频字段,避免JOIN查询。
- 聚合查询:
复杂统计(如全平台销售额)通过ETL同步至ES或Hive离线分析。
四、热点问题处理
- 秒杀订单:
独立分片:秒杀订单单独分配至特定分库,避免影响常规订单。
本地缓存+Redis预减库存,DB层异步落单。
- 数据倾斜:
冷热分离:3个月内热数据存高性能库,历史数据转冷存储。
动态扩容:按倍数扩容(如8库→16库),减少数据迁移量。
posted on 2025-12-26 15:03 wenbin_ouyang 阅读(3) 评论(0) 收藏 举报
浙公网安备 33010602011771号