溯源项目架构优化之分库分表

447 阅读7分钟

背景

几年前参与了公司的溯源项目,数据库采用的是Mysql随着业务的增长,我们进行索引、硬盘(将机械硬盘替换为SSD硬盘)、读写分离等相关优化后,我们发现单库单单表模式的查询和存储速度还是难以满足业务需求,此时我们采用了分库分表的方案来解决此问题。

前言

关于分库分表所涉及核心内容如下:

图片.png

什么时候需要采用分库分表

互联网系统设计需要考虑三高.但是并不是项目初期我们就需要考虑分库分表,而是存在如下的问题时,我们才需要进行相关的分库分表设计。

单库数据量太大

单个服务的磁盘空间是有限制的,如果并发压力下,所有的请求都访问同一个节点,肯定会对磁盘IO造成非常大的影响。

单表数据量太大

MySQL单库数据量在5000万以内性能比较好,超过阈值后性能会随着数据量的增大而变弱。

数据库连接

数据库连接是非常稀少的资源,如果一个库里既有标签、商品、订单相关的数据,当海量用户同时操作时,数据库连接就可能成为瓶颈。

常见分库分表方法

垂直分库

垂直分库是按照系统中的不同业务进行拆分,比如拆分成订单库、标签库、商品库,把它们部署在不同的数据库服务器。

图片.png

垂直分表

垂直分表俗称的大表拆小表,将一些不常用的、数据较大或者长度较长的列拆分到另外一张表。

图片.png

溯源项目中原来的标签表有50多个字段,经过垂直分表为标签基础信息表和标签附属表。

水平分表

水平分表是在同一个数据库内,把同一个表的数据按一定规则拆到多个表中。

图片.png

水平分库

水平分库是把同一个表的数据按一定规则拆到不同的数据库中,每个库中的表结构都是一样的,且每个库可以放在不同的服务器上。

图片.png

小结

  • 垂直分表:将一个大表的字段按不常用的、数据较大或者长度较长的列原则拆分为多个表,既能使业务表结构清晰,也提升相关的性能。

  • 垂直分库:按业务耦合松紧归类,分别存放在不同的库并分布在不同服务器,从而使访问压力被多服务器负载,大大提升性能,需要解决跨库所带来的复杂问题。

  • 水平分库:把一个表的数据(按数据行)分到多个不同的库,每个库只有这个表的部分数据,这些库可以分布在不同服务器,从而使访问压力被多服务器负载,大大提升性能。需要解决跨库所带来的复杂问题。

  • 水平分表:可以把一个表的数据(按数据行)分到多个同一个数据库的多张表中,每个表只有这个表的部分数据,从而提升性能。

分库分表常用策略

Range范围

Range即范围策略划分表,我们可以将表的主键,按照从01000万的划分为一个表,10002000万划分到另外一个表,以此类推。

图片.png

优点

简单、数据均衡、扩容简单

缺点

负载不均衡,随着id的逐渐增会将最近一段时间内的数据汇集在一起,存在热点问题。

Hash取模

指定的路由key对分表总数进行取模,把数据分散到各个表中。

图片.png

优点

简单、数据均衡、负载均衡,不会存在明显的热点问题。

缺点

扩容比较困难,需要迁移数据。

Range+Hash取模混合

既然range存在热点数据问题,hash取模扩容迁移问题,我们需要将两种策略进行结合,先采用先用range范围方案将数据分配到不同的库,然后再使用hash取模的方案将数据分配到不同的表。

图片.png

分库分表引入问题

引入分库分表了带了许多问题,我们对此进行相关的优化。

事务问题

原来采用的时单数据库处理,采用分库分表后,业务拆分为多个数据库,事务变为分布式事务,关于分布式事务,我们引入分布式事务中间件来解决。

跨库john问题

原先单库的时候可以采用join直接进行关联查询,但是分库分表后,无法在进行join,需要将原先的一次查询完成的,现在需要拆分为多次查询。

集合排序问题

跨节点的count,order by,group by以及聚合函数等问题:可以分别在各个节点上得到结果后在应用程序端进行合并。

实现方案

图片.png

分库分表的实现方案,目前常用的还是MyCat与Sharding-JDBC。

Mycat

MyCat是一个开源的分布式数据库系统,是一个实现了MySQL协议的服务器,前端用户可以把它看作是一个数据库代理,用MySQL客户端工具和命令行访问,而其后端可以用MySQL原生协议与多个MySQL服务器通信,也可以用JDBC协议与大多数主流数据库服务器通信,其核心功能是分表分库,即将一个大表水平分割为N个小表,存储在后端MySQL服务器里或者其他数据库里。

核心架构

图片.png

Sharding-JDBC

定位为轻量级Java框架,在Java的JDBC层提供的额外服务。 它使用客户端直连数据库,以jar包形式提供服务,无需额外部署和依赖,可理解为增强版的JDBC驱动,完全兼容JDBC和各种ORM框架。

核心架构

图片.png

相关对比

  • Mycat:中间层方案,在应用程序和MySQL之间搭建一层Proxy
  • Sharding-JDBC:轻量级JDBC框架,基于jdbc层面操作。

溯源项目优化

优化方案

针对溯源项目我们进行了如下优化:

垂直分表

我们将原有的标签表垂直分表为标签表和标签附属表。

垂直分库

将原来的溯源的单体数据库垂直分为标签库、商品库、订单库。

水平分库分表

我们按照业务每年2000万的增长速度,对标签表化分为20个库,每个库20个表,每张表500万数据进行了划分。这样水平分库分表后我们能支撑20亿的标签数据量.

技术选型

通过相关对比和研究,溯源项目最终的技术选型为Sharding-jdbc,之所以选择Sharding-jbdc存在如下优点

  • 直接封装底层JDBC API,为增强版的JDBC驱动,旧代码迁移成本几乎为零.
  • 轻量Java框架,使用客户端直连数据库,以jar包形式提供服务,无proxy代理层,无需额外部署。
  • 分片策略灵活,可支持等号、between、in等多维度分片,也可支持多分片键
  • SQL解析功能完善,支持聚合、分组、排序、limit、or等查询。

数据归档

我们将N年之前的数据迁移定期迁移到ElasticSearch中,从而保证Mysql中的数据在一个可以接受的范围。

其他问题

分库分表虽然能解决项目中的问题,但是也带来了其他的问题。

数据迁移

针对历史数据如何按照新的分库分表的切分规进行迁移,我们采用的是canal进行mysql的数据迁移,关于数据迁移这块,后续进行讲解。

报表问题

原先的报表查询只需要通过相关的SQl语句进行统计即可,但是分库分表后我们无法,只能将数据通过大数据的平台来进行相关的报表处理。

总结

本文通过优化项目介绍了分库分表的规则和实现,需要注意:架构是演变而来而不是设计而来,项目初期我们是无需设计分库分表,切莫进行过度设计,关于分库分表如有疑问,可以随时反馈,大家共同学习,共同进步。

我正在参与掘金技术社区创作者签约计划招募活动,点击链接报名投稿