
前言之前总在聊微服务 微服务本身也是分布式系统其实微服务的核心思想是分而治之把一个复杂的单体系统按照业务的交付分成不同的自服务以降低资深复杂度同时可以提升系统的扩展性。今天想聊一下分库分表因为对于快速增长的业务来说这个是无法回避的一环。之前我在做商城相关的SAAS系统商品池是一个存储瓶颈商品池数量会基于租户增长和运营变得指数级增长短短几个月就能涨到几千万的数据而运营半年后就可能过亿。而对于订单这种数据也会跟着业务的成长也会变得愈发巨大。存储层来说提升大数据量下的存储和查询性能就涉及到了另一个层面的问题但思想还是一样的分而治之。我们面临什么样的问题关系型数据库在大于一定数据量的情况下检索性能会急剧下降。在面对海量数据情况时所有数据都存于一张表显然会轻易超过数据库表可承受的。此外单纯的分表虽然可以解决数据量过大导致检索变慢的问题但无法解决过多并发请求访问同一个库导致数据库响应变慢的问题。所以需要分库来解决单数据库实例性能瓶颈问题。数据库架构方案在讲具体解决方案之前我们需要先了解一下数据库的三种架构涉及方案。1. Shared Everything一般指的是单个主机的环境完全透明共享的CPU/内存/硬盘并行处理能力是最差的一般不考虑大规模的并发需求架构比较简单一般的应用需求基本都能满足。2. Shared Disk各处理单元使用自己的私有CPU和Memory共享磁盘系统。典型的代表是Oracle RAC、DB2 PureScale。例如Oracle RAC他用的是共享存储做到了数据共享可通过增加节点来提高并行处理的能力扩展能力较好使用Storage Area Network (SAN)光纤通道连接到多个服务器的磁盘阵列降低网络消耗提高数据读取的效率常用于并发量较高的OLTP应用。其类似于SMP(对称多处理)模式但是当存储器接口达到饱和的时候增加节点并不能获得更高的性能同时更多的节点则增加了运维的成本。3. Shared Nothing各处理单元都有自己私有的CPU/内存/硬盘等Nothing顾名思义不存在共享资源类似于MPP(大规模并行处理)模式各处理单元之间通过协议通信并行处理和扩展能力更好。典型代表DB2 DPF、带分库分表的MySQL Cluster各节点相互独立各自处理自己的数据处理后的结果可能向上层汇总或在节点间流转。我们常说的Sharding其实就是Shared Nothing他是将某个表从物理存储上被水平分割并分配给多台服务器(或多个实例)每台服务器可以独立工作具备共同的schema例如MySQL Proxy和Google的各种架构只需增加服务器数就可以增加处理能力和容量。至于MPP指的是大规模并行分析数据库(Analytical Massively Parallel Processing (MPP) Databases)他是针对分析工作负载进行了优化的数据库一般需要聚合和处理大型数据集。MPP数据库往往是列式的因此MPP数据库通常将每一列存储为一个对象而不是将表中的每一行存储为一个对象。这种体系结构使复杂的分析查询可以更快更有效地处理。例如TeraData、GreenplumGaussDB100、TBase。基于以上的这几种架构方案我们可以给出大数据量存储的解决方案[]()以上几种解决方案各有利弊分区模式最大的问题是准share everything架构无法水平扩展cpu和内存所以基本可以排除nosql本身其实是个非常好的备选方案但是nosql包括大部分开源newsql硬件消耗非常大运维成本较高。而常用的一种方案就是基于Mysql的分库分表方案。分库分表架构方案对于分库分表首先看一下市面上有哪些产品。业界组件原厂功能特性备注DBLE爱可生开源社区专注于mysql的高可扩展性的分布式中间件基于MyCAT开发出来的增强版。Meituan Atlas美团读写分离、单库分表目前已经在原厂逐步下架。Cobar阿里B2BCobar 中间件以 Proxy 的形式位于前台应用和实际数据库之间对前台的开放的接口是 MySQL 通信协议开源版本中数据库只支持 MySQL并且不支持读写分离。MyCAT阿里是一个实现了 MySQL 协议的服务器前端用户可以把它看作是一个数据库代理用 MySQL 客户端工具和命令行访问而其后端可以用MySQL 原生协议与多个 MySQL 服务器通信MyCAT 基于阿里开源的 Cobar 产品而研发Atlas360读写分离、静态分表2015年后已经不在维护Kingshard开源项目由 Go 开发高性能 MySQL Proxy 项目在满足基本的读写分离的功能上Kingshard 的性能是直连 MySQL 性能的80%以上。TDDL阿里淘宝动态数据源、读写分离、分库分表TDDL 分为两个版本, 一个是带中间件的版本, 一个是直接Java版本Zebra美团点评实现动态数据源、读写分离、分库分表、CAT监控功能齐全且有监控接入复杂、限制多。MTDDL美团点评动态数据源、读写分离、分布式唯一主键生成器、分库分表、连接池及SQL监控Vitess谷歌、Youtube集群基于ZooKeeper管理通过RPC方式进行数据处理总体分为servercommand linegui监控 3部分Youtube 大量应用DRDS阿里DRDSDistributed Relational Database Service专注于解决单机关系型数据库扩展性问题具备轻量(无状态)、灵活、稳定、高效等特性是阿里巴巴集团自主研Sharding-proxyapache开源项目提供MySQL版本它可以使用任何兼容MySQL协议的访问客户端(如MySQL Command Client, MySQL Workbench等)操作数据对DBA更加友好。向应用程序完全透明可直接当做MySQL使用。适用于任何兼容MySQL协议的客户端。Apache项目定位为透明化的数据库代理端提供封装了数据库二进制协议的服务端版本用于完成对异构语言的支持。Sharding jdbcapache开源项目完全兼容JDBC和各种ORM框架。适用于任何基于Java的ORM框架如JPA, Hibernate, Mybatis, Spring JDBC Template或直接使用JDBC。基于任何第三方的数据库连接池如DBCP,C3P0, BoneCP, Druid, HikariCP等。支持任意实现JDBC规范的数据库。目前支持MySQLOracleSQLServer和PostgreSQLApache项目定位为轻量级Java框架在Java的JDBC层提供的额外服务。 它使用客户端直连数据库以jar包形式提供服务无需额外部署和依赖可理解为增强版的JDBC驱动对于分库分表的产品模式又分为两种中间件模式和客户端模式。1. 中间件模式其优缺点中间件模式独立进程所以可以支持异构语言对当前程序没有侵入性对业务方来说是透明的mysql服务但是缺点也非常明显硬件消耗大、运维成本高尤其是在本地化实施情况下同时因为对关系型数据库增加了代理会造成问题难调试。2. 客户端模式优缺点客户端模式的主要缺点是对代码有侵入所以基本只能支持单语言同时因为每个客户端都要对schema建立连接所以如果数据库实例不多需要对连接数仔细控制但是客户端模式的优点也非常明显首先从架构上它是去中心化的这样就避免了中间件模式的proxy故障问题同时因为没有中间层性能高、灵活可控而且因为没有proxy层不需要考虑proxy的高可用和集群运维成本也比较低。sharding-jdbc接入实战sharding-jdbc其实是这些产品中最为大家熟知的也是因为它定位为轻量级 Java 框架在 Java 的 JDBC 层提供的额外服务。 它使用客户端直连数据库以 jar 包形式提供服务无需额外部署和依赖可理解为增强版的 JDBC 驱动完全兼容 JDBC 和各种 ORM 框架。适用于任何基于 JDBC 的 ORM 框架如JPA, Hibernate, Mybatis, Spring JDBC Template 或直接使用 JDBC。而且在社区活跃度代码质量等方面也是很不错的。接下来我讲详细讲一下接入细节。1. 组件集成dependency groupIdorg.apache.shardingsphere/groupId artifactIdshardingsphere-jdbc-core-spring-boot-starter/artifactId version 5.0.0/version /dependency dependency groupIdcom.baomidou/groupId artifactIddynamic-datasource-spring-boot-starter/artifactId version3.4.0/version /dependency2. bean配置配置sharding jdbc数据源并且加入到动态数据源中用于数据源路由。[]()修改原配置中心对应服务的mysql数据源配置对不分库分表的数据源配置为动态数据源默认路由[]()3. sharing JDBC配置spring.shardingsphere.enabledtrue #shardingsphere开关 spring.shardingsphere.props.sql.showtrue spring.shardingsphere.mode.typeStandalone #在使用配置中心的情况下使用standalone模式即可memery、standalone、cluster三种模式 spring.shardingsphere.mode.repository.typeFile #standalone模式下使用File即当前配置文件 spring.shardingsphere.mode.overwritetrue # 本地配置是否覆盖配置中心配置。如果可覆盖每次启动都以本地配置为准。 spring.shardingsphere.datasource.namesds-0,ds-1 #配置数据源名字真实数据源 #配置ds-0数据源 spring.shardingsphere.datasource.ds-0.jdbc-urljdbc:mysql://**** spring.shardingsphere.datasource.ds-0.typecom.zaxxer.hikari.HikariDataSource spring.shardingsphere.datasource.ds-0.driver-class-namecom.mysql.jdbc.Driver spring.shardingsphere.datasource.ds-0.username spring.shardingsphere.datasource.ds-0.password #配置ds-1数据源 spring.shardingsphere.datasource.ds-1.jdbc-urljdbc:mysql://**** spring.shardingsphere.datasource.ds-1.typecom.zaxxer.hikari.HikariDataSource spring.shardingsphere.datasource.ds-1.driver-class-namecom.mysql.jdbc.Driver spring.shardingsphere.datasource.ds-1.username spring.shardingsphere.datasource.ds-1.password #配置模式数据库分片键和相关的表 spring.shardingsphere.rules.sharding.default-database-strategy.standard.sharding-columnuser_id spring.shardingsphere.rules.sharding.default-database-strategy.standard.sharding-algorithm-namedatabase-inline spring.shardingsphere.rules.sharding.binding-tables[0]t_order,t_order_item spring.shardingsphere.rules.sharding.broadcast-tablest_address #配置广播表即所有库中都会同步增删的表以上是一些基本配置还有一些业务场景配置大家可以参考开源社区文档: https://shardingsphere.apache.org/document/4.1.0/cn/overview/总结对于具体业务场景我们首先是基于DDD的思想划分业务单元最开始先做好垂直分库。接着是针对一些特定的业务增长量巨大的表进行水平的分库处理比如商品子域中的商品池表订单子域中的订单表等等。而在分表维度业务初期就要最好垂直分表的设计。比如商品池设计中只需要存储关系信息而商品详情的信息单独存储在一个底表之中。作者京东物流 赵勇萍来源京东云开发者社区