分库分表技术及技术方案
一、分库分表的必要性
分库分表技术的使用,主要是数据库产生了瓶颈,如单库的并发访问或单表的查询都超出了阈值。对系统使用造成一定的影响,不得已而产生的技术。
通过分库分表技术来解决此类问题,但正因为使用此技术,会产生ACID一系列的问题,各类中间件解决此类问题各有各的优势。
提示:如场景无必要,千万不要使用分库分表。
二、分库分表的思路
1、垂直区分
垂直分库:从业务角度,一个库分成多个库,如把订单和用户信息分成两个库来存储。这样的好处就是可以微服务了。每块的业务单独部署,互不影响,通过接口去调用。
图1单库到多库
垂直分表:把大表分成多个小表,如热点数据和非热点数据分开,提高查询速度。
2、水平区分
水平分表:同一业务如数据量大了以后,根据一定的规则分为不同的表进行存储。
图2单表到多表
水平分库:如订单分成多个库存储,分解服务器压力。
以上一般来说,垂直分库和水平分表用的会多些。
三、分库分表的原理分析
分库分表常用的方案:Hash取模方案和range范围方案;
路由算法为最主要的算法,指得是把路由的Key按照指定的算法进行存放;
1、Hash取模方案
根据取余分配到不同的表里。要根据实际情况确认模的大小。此方案由于平均分配,不存在热点问题,但数据迁移很复杂。
图3hash方案
2、Range范围方案
range根据范围进行划分,如日期,大小。此方案不存在数据迁移,但存在热点问题。
图4range方案
四、分库分表的技术选型
1、技术选型
解决方案主要分为4种:MySQL的分区技术、NoSql、NewSQL、MySQL的分库分表。
(1)mysql分区技术:把一张表存放在不同存储文件。由于无法负载,使用较少。
(2)NoSQL(如MongoDB):如是订单等比较重要数据,强关联关系,需约束一致性,不太适应。
(3)NewSql(具有NoSQL对海量数据的存储管理能力,还保持了传统数据库支持ACID和SQL等特性):如TiDB可满足需求。
(4)MySQL的分库分表:如使用mysql,此种方案为主流方式。
2、中间件
解决此类问题的中间件主要为:Proxy模式、Client模式。
(1)Proxy模式
把SQL组合、数据库路由、执行结果合并等功能全部存放在一个代理服务中,而与分库分表相关的处理逻辑全部存放在另外的服务中,这种设计模式的优点是对业务代码无侵入,业务只需要关注自身的业务逻辑即可。
图5proxy模式
(2)Client模式
把分库分表相关逻辑存放在客户端,一版客户端的应用会引用一个jar,然后再jar中处理SQL组合、数据库路由、执行结果合并等相关功能。
图6client模式
(3)中间件的比较
图7中间件
由于Client模式少了一层,运维方便,相对来说容易些。
五、分库分表的实践
根据容量(当前容量和增长量)评估分库或分表个数选key(均匀)分表规则(hash或range等)执行(一般双写)扩容问题(尽量减少数据的移动)。
在这里我们选用中间件sharejdbc。
1、引入maven依赖dependencygroupIdio。shardingspheregroupIdshardingjdbccoreartifactIdversion{latest。release。version}versiondependency
2、springboot规则配置
行表达式标识符可以使用{。。。}或{。。。},但前者与Spring本身的属性文件占位符冲突,因此在Spring环境中使用行表达式标识符建议使用{。。。}。sharding。jdbc。datasource。namesds0,ds1sharding。jdbc。datasource。ds0。typeorg。apache。commons。dbcp。BasicDataSourcesharding。jdbc。datasource。ds0。driverclassnamecom。mysql。jdbc。Driversharding。jdbc。datasource。ds0。urljdbc:mysql:localhost:3306ds0sharding。jdbc。datasource。ds0。usernamerootsharding。jdbc。datasource。ds0。passwordsharding。jdbc。datasource。ds1。typeorg。apache。commons。dbcp。BasicDataSourcesharding。jdbc。datasource。ds1。driverclassnamecom。mysql。jdbc。Driversharding。jdbc。datasource。ds1。urljdbc:mysql:localhost:3306ds1sharding。jdbc。datasource。ds1。usernamerootsharding。jdbc。datasource。ds1。passwordsharding。jdbc。config。sharding。tables。torder。actualdatanodesds{0。。1}。torder{0。。1}sharding。jdbc。config。sharding。tables。torder。tablestrategy。inline。shardingcolumnorderidsharding。jdbc。config。sharding。tables。torder。tablestrategy。inline。algorithmexpressiontorder{orderid2}sharding。jdbc。config。sharding。tables。torder。keygeneratorcolumnnameorderidsharding。jdbc。config。sharding。tables。torderitem。actualdatanodesds{0。。1}。torderitem{0。。1}sharding。jdbc。config。sharding。tables。torderitem。tablestrategy。inline。shardingcolumnorderidsharding。jdbc。config。sharding。tables。torderitem。tablestrategy。inline。algorithmexpressiontorderitem{orderid2}sharding。jdbc。config。sharding。tables。torderitem。keygeneratorcolumnnameorderitemidsharding。jdbc。config。sharding。bindingtablestorder,torderitemsharding。jdbc。config。sharding。broadcasttablestconfigsharding。jdbc。config。sharding。defaultdatabasestrategy。inline。shardingcolumnuseridsharding。jdbc。config。sharding。defaultdatabasestrategy。inline。algorithmexpressionds{userid2}
3、创建DataSource
通过ShardingDataSourceFactory工厂和规则配置对象获取ShardingDataSource,ShardingDataSource实现自JDBC的标准接口DataSource。然后即可通过DataSource选择使用原生JDBC开发,或者使用JPA,MyBatis等ORM工具。setDataSource(targetDataSources,DataSourceType。SHARDING。name(),shardingDataSource);