每日 3000万订单,如何分库分表?( 三 )


文章插图
 
五、分库分表产生的问题
分库分表能够解决性能瓶颈问题,但是分库分表不是银弹,它同样也会带来一些问题:
 

调试和维护难度 分布式事务 分布式事务 跨库关联/分页/排序
 
5.1 定位和维护难度
单库单表,可以很直观在表中查看数据,分库分表后,需要先根据 key 找到库和表,这样在一定意义上增加了开发人员定位问题的难度,再因为库和表的增多,维护难度自然也上去了(公司有 DBA 可以交给他们) 。
5.2 分布式 ID
单库单表,可以直接使用表自增主键保证全局唯一性,分库分表后,需要自己维护全局唯一的 ID,常用的算法有:UUID、号段模式(数据库生成全局 ID)、雪花算法 。
UUID 优点:
 
性能非常高,本地生成,没有网络消耗;
 
UUID 缺点:
 
不易于存储:UUID 太长,16 字节 128 位,通常以 36 长度的字符串表示,很多场景不适用; 信息不安全:基于 mac 地址生成 UUID 的算法可能会造成 MAC 地址泄露,这个漏洞曾被用于寻找梅丽莎病毒的制作者位置; ID 作为主键时在特定的环境会存在一些问题,比如做 DB 主键的场景下,UUID 就非常不适用 。
 
号段模式优点:
 
可以每次获取一个 ID,也可以每次获取一批 ID; 简单,利用现有数据库系统的功能实现; ID 单调自增,可以实现对 ID 要求特殊的业务;
 
号段模式缺点:
 
强依赖发号 DB 的性能,可能有单点问题;
 
雪花算法优点:
 
毫秒数在高位,自增序列在低位,整个 ID 都是趋势递增的 。不依赖数据库等第三方系统,以服务的方式部署,稳定性更高,生成 ID 的性能也是非常高的 。可以根据自身业务特性分配 bit 位,非常灵活 。
 
雪花算法缺点:
 
强依赖机器时钟,如果机器时钟回拨,会导致重复或者服务不可用,不过发生的概率比较小;
 
总结
对于公司内部没有分布式 ID 相关实现的,可以使用或借鉴 美团开源的 Leaf ( https://github.com/Meituan-Dianping/Leaf ) ,该框架提供了雪花算法和号段模式两种方案 。
5.3 分布式事务
单库单表可以直接使用本地事务来保障数据的正确性,分库分表之后可能就需要引入分布式事务的问题,解决方案有两种:
 
业务划分的时候规避分布式事务; 使用专业的的分布式框架,比如阿里开源的 Seata ( https://seata.io/zh-cn/ );
 
5.4 跨库关联/分页/排序
单库单表可以直接使用 MySQL limit 特性实现分页,分库分表后,可能会出现分页问题,解决方案有三种:
 
选择合适的分表字段,规避绝大部分高频查询场景出现跨库; 使用专业的分布式框架,比如开源框架:ElasticSearch ( https://github.com/elastic/elasticsearch ); 业务代码中分别查询,然后组装数据;
六、分库分表工具 
分库分表工具主要有 2 种模式:客户端模式 和 代理模式
6.1 客户端模式
客户端模式是指在客户端实现直连数据库,客户端通常是通过一些封装好的 jar 来实现,如下图所示:
每日 3000万订单,如何分库分表?

文章插图
 
常见的开源中间件有:Apache 的 Sharding-JDBC、淘宝的 TDDL、美图的 Zebra 。
6.2 代理模式
代理模式是指需要单独部署服务,客户端连接代理服务,由代理服务再和数据库交互,如下图所示:
每日 3000万订单,如何分库分表?

文章插图
 
常见的开源中间件有:Apache 的 Sharding-Proxy、阿里的 cobar、国产的 MyCat、360 的 Atlas 。
另外还有 google 的 vitess,它是基于 zookeeper,通过 RPC 方式进行数据管理 。
6.3 总结
两种方案的核心思想都是类似的,都是将分库分表的逻辑进行抽象封装,业务无需关注分库分表的实现细节,只需按照规则进行简单的配置和开发,就能正常的使用分库分表 。
两者各有优劣,客户端模式比较轻量,性能也会比较好;代理模式,客户端无需维护服务,但是需要部署额外的代理服务器,代理服务器的稳定性和性能等都需要保障 。


推荐阅读