|
|
分库 | 分库:当一个库中的表过多(单机容量不够),访问量太大(单个实例无法支持)时候,可以分库 水平分库:一般是在垂直拆分后进行;将存储的同张表的数据划分到不同的库中(压力分摊到不同的库,如:订单、用户);问题:数据路由 垂直分库:将系统中不存关联关系或不同业务的数据放在不同库中;一定程度能突破IO、连接数及单机硬件资源的瓶颈;问题:跨数据库的事务,join查询等问题 分库后的问题:分布式事务、跨库join、排序|分页|分组 |
分表 | 分表:把一张表按一定的规则分解成N个具有独立存储空间的实体表。分为水平分表和垂直分表。 |
分区 | 分区:将表的数据均衡分摊到不同的硬盘,系统或是不同服务器存储介质中。(重点突破硬盘瓶颈) 垂直分区: ????? 分表 & 分区: 区别:(分区提高读写,分表提高并发)分区重点是如何突破磁盘的读写能力,分表重点是存取数据时如何提高mysql并发。 当访问量大,且表数据比较大时,两种方式可以互相配合使用。 |
分片 | 数据分片: (1)确定数据在多台存储设备上分布的技术:数据分布均匀,访问负载均衡,扩缩容数据迁移少。 (2)将数据集划分成相互独立、正交的数据子集,然后将数据子集分布到不同的节点上。 分片方式: (1)使用Key或Key的哈希值来计算Key的分布 (2)划分号段:缺点是数据可能分布不均匀、数据热度不同导致各个设备的负载不均衡,扩容也不够灵活,只能成倍地增加设备 (3)取模:Hash(Key)%N就可以确定数据所在的设备编号。缺点:扩容的时候,会产生大量的数据迁移 (4)检索表:在检索表中存储Key和设备的映射关系。缺点:需要存储检索表的空间可能比较大 (5)一致性哈希的算法: 简单而巧妙,很容易做到数据均分布,其单调性也保证了扩缩容的数据迁移是比较少的。 |
目录
5.1.1、端上除了partition key只有一个非partition key作为条件查询
5.1.2、端上除了partition key不止一个非partition key作为条件查询
5.1.3、后台除了partition key还有各种非partition key组合条件查询
5.2、非partition key跨库跨表分页查询问题---ES
一、数据库瓶颈
1、IO瓶颈---分库和垂直分表
第一种:磁盘读IO瓶颈,热点数据太多,数据库缓存放不下,每次查询时会产生大量的IO,降低查询速度 -> **分库和垂直分表**。
第二种:网络IO瓶颈,请求的数据太多,网络带宽不够 -> **分库**。
2、CPU瓶颈---SQL优化和水平分表
第一种:SQL问题,如SQL中包含join,group by,order by,非索引字段条件查询等,增加CPU运算的操作 -> **SQL优化**,建立合适的索引,在业务Service层进行业务计算。
第二种:单表数据量太大,查询时扫描的行太多,SQL效率低,CPU率先出现瓶颈 -> **水平分表**。
二、什么时候分库分表?
经测试在单表1000万条记录一下,写入读取性能是比较好的。再留点buffer,那么单表全是数据字型的保持在800万条记录以下, 有字符型的单表保持在500万以下。如果按100库100表来规划,如用户业务:500万 x 100 x 100 = 5000000万 = 500亿记录。
三、分库分表
1、水平分库和水平分表
(1)划分:以字段为依据,按照一定策略(hash、range等),将一个库/表中的数据拆分到多个库/表中。
(2)使用场景:库多了,io和cpu的压力自然可以成倍缓解;单表数据量少了,单次SQL执行效率高,减轻了CPU的负担。
2、垂直分库和垂直分表
(1)垂直分库
划分:以表为依据,按照业务归属不同,将不同的表拆分到不同的库中。
使用场景:公用的配置表、字典表等越来越多,这时可以将这些表拆到单独的库中,甚至可以服务化。
(2)垂直分表
划分:以字段为依据,按照字段的活跃性,将表中字段拆到不同的表(主表和扩展表)中。
使用场景:将热点数据(可能会冗余经常一起查询的数据)放在一起作为主表,非热点数据放在一起作为扩展表。减少了随机读IO;注意分表后,要想获得全部数据就需要关联两个表来取数据,记住千万别用join,因为join不仅会增加CPU负担并且会讲两个表耦合在一起(必须在一个数据库实例上)。关联数据,应该在业务Service层做文章,分别获取主表和扩展表数据然后用关联字段关联得到全部数据。
四、分库分表的工具和步骤
1、分库分表的工具---mycat
sharding-sphere:jar,前身是sharding-jdbc;
TDDL:jar,Taobao Distribute Data Layer;
Mycat:中间件。
2、分库分表步骤
根据容量(当前容量和增长量)评估分库或分表个数 -> 选key(均匀)-> 分表规则(hash或range等)-> 执行(一般双写)-> 扩容问题(尽量减少数据的移动)。
五、分库分表问题
5.1、非partition key的查询问题
基于**水平分库分表**,拆分策略为常用的**hash法**。
5.1.1、端上除了partition key只有一个非partition key作为条件查询
(1)映射法
(2)基因法
注:写入时,基因法生成user_id,如图。关于xbit基因,例如要分8张表,23=8,故x取3,即3bit基因。根据user_id查询时可直接取模路由到对应的分库或分表。根据user_name查询时,先通过user_name_code生成函数生成user_name_code再对其取模路由到对应的分库或分表。id生成常用snowflake算法。
5.1.2、端上除了partition key不止一个非partition key作为条件查询
映射法
冗余法
注:按照order_id或buyer_id查询时路由到db_o_buyer库中,按照seller_id查询时路由到db_o_seller库中。
5.1.3、后台除了partition key还有各种非partition key组合条件查询
NoSQL法
冗余法
5.2、非partition key跨库跨表分页查询问题---ES
基于水平分库分表,拆分策略为常用的hash法。解决方法是用NoSQL法解决(ES等)。
5.3、扩容问题
基于水平分库分表,拆分策略为常用的hash法。
水平扩容库(升级从库法),注:扩容是成倍的。
水平扩容表(双写迁移法)
第一步:(同步双写)修改应用配置和代码,加上双写,部署;第二步:(同步双写)将老库中的老数据复制到新库中;第三步:(同步双写)以老库为准校对新库中的老数据;第四步:(同步双写)修改应用配置和代码,去掉双写,部署;注:双写是通用方案。
六、分库分表总结
分库分表,首先得知道瓶颈在哪里,然后才能合理地拆分(分库还是分表?水平还是垂直?分几个?)。且不可为了分库分表而拆分。
选key很重要,既要考虑到拆分均匀,也要考虑到非partition key的查询。
只要能满足需求,拆分规则越简单越好。
七、分库分表示例
[分库分表的git示例](https://link.zhihu.com/?target=https://github.com/littlecharacter4s/study-sharding)
[1]: https://zhuanlan.zhihu.com/p/137368446
转自:[分库分表方案](https://zhuanlan.zhihu.com/p/137368446)