Springboot整合sharding-jdbc
基本概念
Sharding-JDBC是Apache ShardingSphere生态系统中的一个核心组件,现在已经更名为ShardingSphere-JDBC。它是一个轻量级的Java框架,专门用于解决分库分表的问题。
核心作用
Sharding-JDBC本质上是一个数据库中间件,但它采用的是"客户端代理"模式,而不是传统的"服务端代理"模式。它在应用程序和数据库之间增加了一层逻辑,让应用程序感觉像是在操作一个数据库,实际上底层可能操作的是多个数据库和多张表。
这种设计的好处是对应用程序几乎透明,开发人员只需要配置好分片规则,业务代码基本不需要修改。同时因为是客户端模式,不存在单点故障问题,性能开销也相对较小。
为什么要进行分库分表
分库分表是数据库架构演进过程中的一个重要阶段,主要是为了解决单一数据库在面对大规模数据和高并发访问时遇到的瓶颈问题。
1、数据量增长带来的挑战
随着业务发展,数据量会呈指数级增长。一个电商平台的订单表,刚开始可能只有几万条记录,但经过几年发展可能达到几千万甚至上亿条记录。当单表数据量超过千万级别时,即使有索引,查询性能也会明显下降。
数据量大还会影响数据库的日常维护工作。备份恢复时间会变得很长,可能需要几个小时甚至更久。在线DDL操作(比如加索引、修改表结构)也会变得非常耗时,甚至可能影响正常业务。存储成本也会快速上升,单个数据库服务器的存储容量毕竟有限。
2、并发访问的性能瓶颈
单一数据库的并发处理能力是有上限的。MySQL的InnoDB引擎虽然支持行级锁,但在高并发场景下仍然会出现锁竞争。特别是热点数据的访问,比如热门商品的库存更新,会导致大量请求排队等待。
数据库连接数也是一个限制因素。单个MySQL实例通常只能支持几百到几千个并发连接,当应用服务器增加时,数据库连接很容易成为瓶颈。CPU和内存资源在高并发下也容易成为瓶颈,查询缓存命中率下降,磁盘IO压力增大。
3、可用性和风险控制
把所有数据放在一个数据库中存在很大的风险。如果这个数据库出现故障,整个系统就会不可用。即使有主从复制,主库故障时的切换过程也会有一定的服务中断时间。
数据安全性也是考虑因素。将数据分散到多个数据库中,可以降低单点故障造成的数据丢失风险。某个数据库出现问题时,只影响部分用户,而不是全部用户。
4、地理分布的需要
对于全国性或全球性的业务,用户分布在不同的地理位置。如果所有数据都集中在一个地方的数据库中,远程用户的访问延迟会很高。通过分库将数据分布到不同地区的数据中心,可以让用户就近访问数据,提升用户体验。
合规性要求也可能需要数据本地化。某些国家或地区的法律要求用户数据必须存储在本地,这就需要按地域进行分库。
5、业务隔离的需求
不同业务模块对数据库资源的需求可能差别很大。比如用户中心的读操作比较多,订单系统的写操作比较频繁,日志系统需要大量的存储空间。将这些业务的数据分别存储在不同的数据库中,可以针对性地进行优化。
业务隔离还有助于系统的模块化开发和维护。不同团队可以独立负责自己业务相关的数据库,减少相互影响。当某个业务需要进行大的变更时,不会影响到其他业务。
6、扩展性的考虑
单一数据库的纵向扩展(升级硬件)成本很高,而且有天花板。通过分库分表实现的横向扩展成本更低,扩展能力理论上没有上限。当业务增长时,可以通过增加更多的数据库节点来提升整体性能。
水平扩展还有助于更好地利用硬件资源。多个较小的数据库实例可以部署在不同的服务器上,充分利用每台服务器的CPU、内存、磁盘资源。
7、维护和管理的便利性
大型单一数据库的维护工作很复杂。数据备份文件很大,恢复时间长。在线维护操作风险高,可能影响整个系统。通过分库分表,可以将维护工作分散到多个较小的数据库上,降低单次维护的影响范围。
监控和诊断也更容易。可以针对不同的数据库设置不同的监控策略,更容易定位性能问题的根源。当某个数据库出现问题时,影响范围是可控的。
8、成本效益分析
虽然分库分表会增加系统的复杂性,但从长远来看通常是值得的。硬件成本可以通过使用多台中等配置的服务器替代单台高配置服务器来降低。运维成本虽然会增加,但系统的稳定性和性能提升带来的价值通常更大。
开发成本需要权衡。虽然分库分表会增加开发复杂度,但现在有很多成熟的中间件和框架可以降低开发难度。而且这种投入是一次性的,一旦架构稳定,后续的维护成本反而可能更低。
9、业务发展的必然趋势
随着互联网业务的发展,用户数量和数据量的增长是不可避免的。与其在系统出现性能问题时被动地进行架构调整,不如在业务发展的早期就考虑分库分表的架构设计。
现代的微服务架构也天然适合分库分表。每个微服务管理自己的数据,数据库的拆分可以与服务的拆分保持一致,形成更清晰的架构边界。
总结
分库分表本质上是一种用复杂性换取性能和可扩展性的技术选择。虽然会增加系统的复杂度,但对于大规模、高并发的系统来说,这种选择通常是必要的。关键是要在合适的时机做出这个决策,既不要过早优化,也不要等到系统已经无法承载时才开始改造。
分片策略设计
分库策略
通常基于业务维度来设计。最常见的是按用户ID分库,比如用户ID取模分到不同的数据库。也可以按地域分库,比如北京用户的数据存储在北京数据库,上海用户的数据存储在上海数据库。
分表策略
一般按数据量或时间维度。按数据量分表适用于数据增长相对均匀的场景,比如订单表按订单ID取模分成多张表。按时间分表适用于有明显时间特征的数据,比如日志表按月份分表,每个月一张表。
复合分片策略
同时使用多个分片键进行分库分表的策略,适用于复杂的业务场景。
代码示例
1、添加依赖
2、配置文件
3、实体类
创建User类
创建Order类
创建OrderItem类
创建Dict类
4、Mapper接口
创建UserMapper
创建OrderMapper
创建OrderItemMapper
创建DictMapper
5、Service层
创建UserService接口
创建UserServiceImpl类
创建OrderService接口
创建OrderServiceImpl类
6、Controller层
创建UserController
创建OrderController
7、创建请求对象实体类
8、创建返回结果类
9、自定义分片算法
10、启动类
11、数据库表结构
说明:在每个数据库中创建对应的分表
创建 t_order_item_1, t_order_item_2, t_order_item_3...