数据切分根据其切分类型,可以分为两种方式:垂直(纵向)切分和水平(横向)切分
一:垂直(纵向)切分【基于表或字段划分,表结构不同】
1:垂直分库
根据业务的耦合度和数据的访问量等,进行数据的分离,存储在不同的数据库,比如按照按业务分类进行独立划分:会员服务(用户库),商品服务(商品库),订单服务(订单库),支付服务(账务库),营销服务(营销库)
2:垂直分表
垂直分表是基于数据库中的"列"进行,某个表字段较多,可以新建一张扩展表,比如订单表,基本信息在主表,商品信息单独存在订单商品明细表
垂直切分的优点:
1:解决业务系统层面的耦合,业务清晰
2:便于对不同的数据进行分级管理、维护、监控、扩展
3:高并发场景下,垂直切分一定程度的提升IO、数据库连接数、单机硬件资源的瓶颈
缺点:
1:部分表无法join,只能通过接口聚合方式解决,提升了开发的复杂度
2:分布式事务处理复杂
3:依然存在单表数据量过大的问题(需要水平切分)
二:水平(横向)切分【基于数据划分,表结构相同,数据不同】
当一个应用难以再细粒度的垂直切分,或切分后数据量行数巨大,存在单库读写、存储性能瓶颈,这时候就需要进行水平切分了
水平切分分为库内分表和分库分表(一个表的数据划分到不同的数据库,两个数据库的表结构一样),根据一定的规则,将同一个表按不同的条件分散到多个数据库或者多个表中。
库内分表:只解决了单一表数据量过大的问题,但没有将表分布到不同机器的库上,对于减轻数据库压力作用不是很大,但是单表查询会增加速度
库内分表案例:比如账务支付单表量比较大,且此表的查询操作比较频繁,就可以建一个历史表,超过当前时间一个月的数据,都保存至历史表(访问不频繁),以此减少支付单表的数据量,减轻支付单表的操作压力
水平切分的优点:
1:不存在单库数据量过大、高并发的性能瓶颈,提升系统稳定性和负载能力
2:应用端改造较小,不需要拆分业务模块
缺点:
1:跨分片的事务一致性难以保证
2:跨库的join关联查询性能较差
3:数据多次扩展难度和维护量极大
水平切分常用方法:1:根据数值范围(比如id:0-100000,100001-20000进行表存储)
2:根据数值取模:比如分了20个表,根据id%20取余选择数据库进行存储
分布式事务常用的解决方案:基于可靠消息(MQ)的解决方案、两阶段事务提交、柔性事务
三:常见问题:
1:全局主键避免重复问题
MySQL数据库里面字段有一个自增的属性,Oracle订单表也有 Sequence 序列。如果是一个数据库,那么可以保证 ID 是不重复的,但是水平分表以后,每个表都按照自己的规律自增,肯定会出现 ID 重复的问题,因此需要单独设计全局主键,以避免跨库主键重复问题。有一些常见的主键生成策略:
1、UUID
2、基于数据库自增单独维护一张 ID表
3、号段模式
4、Redis 缓存
5、雪花算法(Snowflake)
6、百度uid-generator
7、美团Leaf
8、滴滴Tinyid
2:多数据源和读写数据源的解决方案
常用的中间件:ShardingJdbc和Mycat
ShardingJdbc和MyCat的区别以及优缺点
相同点:
主流程都是SQL解析->SQL路由->SQL改写->SQL执行->结果归并
SQL 路由:实际查询中,数据不只保存在一台mysql服务器上,解析原生的sql确定使用哪些数据库,哪些数据表:目前支持分片路由和广播路由
SQL执行:通过多线程执行器异步执行SQL
结果归并:将多个执行结果集归并以便于通过统一的JDBC接口输出。结果归并包括流式归并、内存归并和使用装饰者模式的追加归并这几种方式。
区别:
架构设计不同,MyCat是基于Proxy,类似nginx,复写了MySql协议,将MycatServer伪装成一个Mysql数据库。优点是保证数据库的安全性,归并数据结果完全解耦,缺点是效率偏低。
Sharding-jdbc是基于jdbc的扩展,是以jar包的形式提供轻量级服务的。优点是效率较高,缺点是归并数据结果没有实现解耦,存在代码入侵性。还容易内存溢出,所以要做分页处理。
2.1 Sharding-jdbc 分片策略
sharding-jdbc 对于分片策略有2种维度
1:数据源分片策略(DatabaseSharingStrategy):数据被分配的目标数据源
2:表分片策略(TableShardingStrategy):数据被分配的目标表
两种分片策略API完全相同,但是表分片策略是依赖于数据源分片策略的(即:先分库然后才有分表)
1:StandardShardingStrategy
标准分片策略。提供对SQL语句中的=,IN和BETWEEN AND 的分片操作支持。
StandardShardingStrategy只支持单分片键,提供PreciseShardingAlgorithm(精准分片)和RangeShardingAlgorithm(范围分片)两个分片算法
PreciseShardingAlgorithm是必选的,用于处理=和IN的分片
RangeShardingAlgorithm是可选的,用于处理BETWEEN AND分片,如果不配置RangeShardingAlgorithm,SQL中的BETWEEN AND 将按照全库理由处理。
ComplexShardingStrategy
复合分片策略。提供对SQL语句中的=,IN,和BETWEEN AND的分片操作支持。
ComplexShardingStrategy支持多分片键,由于多分片键之间的关系复杂,因此Sharding-JDBC并未做过多的封装,而是直接将分片键值组合以及分片操作符交于算法接口,完全由应用开发者实现,提供最大的灵活度
InlineShardingStrategy
Inline表达式分片策略。使用Groovy的Inline表达式,提供对SQL语句中的=和IN的分片操作支持。
InlineShardingStrategy只支持单分片键,对于简单的分片算法,可以通过简单的配置使用,从而避免繁琐的JAVA代码开发。如:tuser${user_id%8}表示t_user表按照user_id按8取模分成8个表,表名称为t_user_0到t_user_7.
HintShardingStrategy
强制路由策略:
通过Hint而非SQL解析的方式分片的策略。对于分片字段非SQL决定,而由其他外置条件决定的场景,可使用sql hint灵活的注入分片字段
Hint分片策略是绕过SQL解析的,所以对于比较复杂的需要分片的查询,采用Hint分片策略性能可能会更好
在读写分离数据库中,Hint可以通过HintManager.setMasterRouteOnly()方法,强制读主库(主从复制存在一定延时,但在某些特定的业务场景中,可能更需要保证数据的实时性)
NoneShardingStrategy
不分片的策略
自定义分片算法
Sharding 提供了4种算法接口:
PreciseShardingAlgrorithm
RangeShardingAlgorithm
HintShardingAlgorithm
CompleKeysShardingAlgorithm