当系统数据库达到一定的量级,单数据库实例已经无法支撑的时候,我们就要考虑采用分库分表的策略了.那么进行数据分库分表后会
带来哪些影响呢?
在很多中小项目中,我们往往直接使用数据库自增特性来生成主键ID,这样确实比较简单。而在分库分表的环境中,数据分布在不同的分片上,如果每个分片都采用原有的主键自增策略。不可避免的会造成主键ID重复。简单介绍下使用和了解过的几种ID生成算法。
ds0.t_user 设置主键id 自动增长 起始1 步长2 -->> 1,3,5,7,9...
ds1.t_user 设置主键id 自动增长 起始2 步长2 -->> 2,4,6,8,10...
多少个库步长就为分库的数量
缺点:
优点:
缺点:
雪花算法概述
有这么一种说法,自然界中并不存在两片完全一样的雪花的。每一片雪花都拥有自己漂亮独特的形状、独一无二。雪花算法也表示生成的ID如雪花般独一无二。
组成结构
大致由:首位无效符、时间戳差值,机器(进程)编码,序列号四部分组成,雪花算法生成的ID是纯数字且具有时间顺序的。
优点:
缺点:
雪花算法在单机系统上ID是递增的,但是在分布式系统多节点的情况下,所有节点的时钟并不能保证不完全同步,所以有可能会出现不是全局递增的情况
简单配置实现
https://blog.csdn.net/womenyiqilalala/article/details/106118983
incr可以用作计数器模式,它是原子自增操作
存储的规则
根据业务需求来决定分片键 ,在业务之初分片键确定之后一般情况不更换,如果更换,对数据迁移,数据维护 非常的麻烦
Sharding-JDBC中的分片策略有两个维度:
Sharding分片策略继承自ShardingStrategy,提供了5种分片策略。
io.shardingsphere.core.routing.strategy.ShardingStrategy
--io.shardingsphere.core.routing.strategy.standard.StandardShardingStrategy
--io.shardingsphere.core.routing.strategy.standard.ComplexShardingStrategy
--io.shardingsphere.core.routing.strategy.standard.InlineShardingStrategy
--io.shardingsphere.core.routing.strategy.standard.HintShardingStrategy
--io.shardingsphere.core.routing.strategy.standard.NoneShardingStrategy
由于分片算法和业务实现紧密相关,因此Sharding-JDBC并未提供内置分片算法,而是通过分片策略将各种场景提炼出来,提供更高层级的抽象,并提供接口让应用开发者自行实现分片算法。
简单配置实现链接:https://blog.csdn.net/womenyiqilalala/article/details/106113983
简单配置实现链接:https://blog.csdn.net/womenyiqilalala/article/details/106115560
简单配置实现链接:https://blog.csdn.net/womenyiqilalala/article/details/106115295
简单配置实现链接:https://blog.csdn.net/womenyiqilalala/article/details/106115831
在分库分区中,有些特定的SQL,Sharding-jdbc、Mycat、Vitess都不支持(可以查看相关文档各自对哪些SQL不支持),例如:insert into table1 select * from table2 where ....这种SQL 路由很麻烦,需要解析table2的路由(是在ds0 /ds1 table2_0/table_1),结果集归并,insert 语句也需要同样的路由解析。这种情况Sharding-jdbc可以使用Hint分片策略来实现各种Sharding-jdbc不支持语法的限制
不分片的策略。和直接不使用Sharding-JDBC 效果相同
Sharding提供了以下4种算法接口:
跨节点多库进行查询时,会出现limit分页、order by排序等问题
分页需要按照指定字段进行排序当排序字段就是分片字段时,通过分片规则就比较容易定位到指定的分片。
当排序字段非分片字段时,就变得比较复杂。各分片节点中的数据可能是随机的,为了排序的准确性,必须把所有分片节点的前N页数据都排序好后做合并,最后再进行整体的排序。很显然,这样的操作是比较消耗资源的,用户越往后翻页,系统性能将会越差。
例如:现有db0.t_user0 ,db1.t_user1 ,db2.t_user2 三张表
select id from t__user where id < 10 order by id limit 0,2
每张表的数据:
db0.t_user0 1,4,7
db1.t_user1 5,2,8
db2.t_user2 9,6,3
必须要对db0.t_user0 ,db1.t_user1 ,db2.t_user2 三张表进行排序,然后合并为结果 1,4,7,2,5,8,3,6,9 ,再对合并的结果排序分页
在使用Max、Min、Sum、Count之类的函数进行统计和计算的时候,需要先在每个分片数据源上执行相应的函数处理,然后再将各个结果集进行二次处理
Join是关系型数据库中最常用的特性,但是在分片集群中,join也变得非常复杂(这种场景,比上面的跨分片分页更加复杂,而且对性能的影响很大),应该采取尽量避免跨分片的join查询。在分库分表中,尽量减少跨库的join,基本上所有的组件都不提供跨库join的功能,目前没有好的办法去解决
a)全局表
全局表 (等同于维度表,例如省份表,城市表,名族表等),使用的是空间换时间的思想,每个db数据库上都存在一张相同数据的表,维护同步
b) ER表
在关系型数据库中,表之间往往存在一些关联的关系。如果我们可以先确定好关联关系,并将那些存在关联关系的表记录存放在同一个分片上,那么就能很好的避免跨分片join问题
跨分片事务也叫分布式事务,想要了解分布式事务,就需要了解“XA接口”和“两阶段提交”。值得提到的是,MySQL5.5x和5.6x中的xa支持是存在问题的,会导致主从数据不一致。直到5.7x版本中才得到修复。Java应用程序可以采用Atomikos框架来实现XA事务(J2EE中JTA)
如果t_user 表分库分表之后四张表(ds0.t_user0、ds0.t_user1、ds1.t_user0、ds1.t_user1)
在sharding-jdbc 查询时:直接select * from t_user where age =18 ,shardig-jdbc回去查询四张表中符合的数据,对于程序代码sql 中t_user 是逻辑表,并不存在,而 ds0.t_user0、ds0.t_user1、ds1.t_user0、ds1.t_user1 是存放了数据并且存在的真实表(可以参考接口和实现类,接口不能不能被实例化)
也就是上面的 2.3.3中的全局表
sharding-jdbc使用绑定表名称,Mycat使用ER表名称
例如
主表-> t_person_main(id,name,age,qq_level);
子表-> t_person_detail (id,gender,address,phone_num,e-mail,city_id);
如果主表id = 1 分表时在ds0,子表id=1 在ds1 。
Select * from t_person_main as mian left join t_person_detail as detail on mian .id = detail .id where mian .id=1;查询时就需要跨库join.
sharding-jdbc 使用绑定表解决跨库join ,判断相关联的数据插入时是否在同一个库,例如 t_person_main id=1在ds0上,那么t_person_detail id=1 就不会插入到ds1上,保障主表和子表相同数据在同一个库中。出现上面id相同不同库的情况, join时也不会去其他的库上查找数据。避免跨库join
mysql单表经验
一般MySQL单表1000W左右的数据是可以不需要考虑分表的。当然,除了考虑当前的数据量和性能情况时,我们需要提前考虑系统半年到一年左右的业务增长情况。但是要避免过度设计(考虑了很多未来几年的需求。例如一张表在未来几年内 数据预计会达到几千万(存在很多的不确定性))
根据数据量增长速度,选择实现步骤
第一步:不分库不分表
第二步:同库内的分表
第三步:分库分表
不要过度设计,一上来玩大的就进行分库分表
分库如果多个实例存在同一台服务器上,只是解决了数据库最大连接数的问题
但是 io(数据库数据是存储在硬盘上,每次获取都需要去硬盘把数据捞出来),cpu 等服务器资源瓶颈并没有解决。数据库的性能取决于服务器等性能
版权说明 : 本文为转载文章, 版权归原作者所有 版权申明
原文链接 : https://blog.csdn.net/womenyiqilalala/article/details/105683828
内容来源于网络,如有侵权,请联系作者删除!