初识分库分表

1. 为什么要分库分表? 什么场景下需要分库分表?

单表数据上亿,查询性能下降;

解决大数据存储,提高访问性能;

超大容量问题

性能问题:单一数据库,服务器的CPU、磁盘、内存、IO都有极限

如何去做

垂直切分、水平切分

垂直切分

1. 垂直分库:按模块分库,每个功能模块按照业务领域区分,解决表过多的问题

关联度低的不同表存储在不同的数据库

2. 垂直分表:解决单表列过多的问题

水平切分

单表数据量过大,影响查询性能;解决办法:大数据表拆分成小表

mysql单表性能在500W-1000W,超过1000W性能降低

2. 分库分表原理

拆分策略

  • 范围切分:按照日期、userId等,如userId 19999的记录分到第一个库,1000020000的分到第二个库,以此类推
  • 根据数值驱魔:一般采用hash取模mod的切分方式,后期分片集群扩容时,需要迁移旧的数据(使用一致性hash算法能较好的避免这个问题)

垂直拆分(er分片)

拆分带来的问题

  1. 跨库join问题:拆分时键的问题,对原业务的sql数据进行统计,合理选择;后续尽量避免join查询

    • 设计时考虑到应用层的join问题
    • 在服务层去做调用
    • 全局表:字典、省市区
      • 数据变更比较少的基于全局应用的表
    • 做字段冗余(空间换时间)
      • 订单表: 商家id,冗余商家名称,商家名称变更--定时任务、任务通知对订单表的商家名称进行更新
  2. 跨分片数据排序分页:在应用层做拼接(不推荐)

  3. 唯一主键问题:用自增id做主键

    解决方案

    • UUID 性能比较低;
    • 用算法生成主键:snowflake、MongoDB、zookeeper、数据库全局唯一表
  4. 分布式事务问题:多个数据库表之间保证原子性(2PC),只要达到最终一致性即可

分库分表最难的在于业务的复杂度

3. 应用

如何权衡当前公司的存储需要优化

  1. 提前规划,提前防范(主键问题解决、join问题)
  2. 当前数据单表超过1000W,每天的增长量持续上升
1551610230219.png

最佳实践

订单号索引表

根据用户编号进行哈希分库分表,可以满足创建订单和通过用户编号维度进行查询操作的需求,但是根据统计,按订单号进行查询的占比达到80%以上,所以需要解决通过订单号进行订单的CURD等操作,所以需要建立订单号索引表。

订单号索引表是用于用户编号与订单号的对应关系表,根据订单号进行哈希取模,放到分库里面。根据订单号进行查询时,先查出订单号对应的用户编号,再根据用户编号取模查询去对应的库查询订单数据。

订单号与用户编号的关系在创建订单后是不会更改的,为了进一步提高性能,引入缓存,把订单号与用户编号的关系存放到缓存里面,减少查表操作,提升性能,索引不命中时再去查表,并把查询结果更新到缓存中。

参考

数据库分库分表思路

推荐阅读更多精彩内容