参考链接:
https://blog.csdn.net/wuzhiwei549/article/details/106005320
https://blog.csdn.net/weixin_44062339/article/details/100491744
分库分表
在学习分库分表的解决方案之前,我们不妨先问问自己:
- 分库分表是什么?
- 我们为什么要分库分表,选择分库分表是要解决什么问题?
- 分库分表应该适用在什么场景下?
什么是分库分表
顾名思义,简单的说,分库分表就是将单一数据库中的庞大数据量分散,分散到多个数据库、数据表中。
为什么要分库分表
以关系型数据库为例,关系型数据库本身比较容易成为系统瓶颈,单机存储容量、连接数、处理能力都有限。当单表的数据量达到1000W或100G以后,由于查询纬度较多,即使添加从库、优化索引,做很多操作时也面临着性能下降严重的问题。
单机瓶颈
1. IO瓶颈
- 第一种:磁盘IO瓶颈,热点数据太多,数据库缓存不下来,每次查询产生大量IO (分库、垂直分表)
- 第二种:网络IO瓶颈,请求的数据太多,网络带宽不够 (分库)
2. CPU瓶颈
- 第一种:SQL问题,如SQL中包含join,group by,order by,非索引字段条件查询等,增加CPU运算的操作 -> SQL优化,建立合适的索引,在业务Service层进行业务计算。
- 第二种:单表数据量太大,查询时扫描行太多,SQL效率低,CPU率出现瓶颈 (水平分表)
但是,不管是IO瓶颈还是CPU瓶颈,最终都会导致数据库的活跃连接数增加,进而逼近甚至达到数据库可承载活跃连接数的阈值,在业务service来看,就是可用数据库连接减少甚至无连接可用。
打破瓶颈
随着公司业务的快速发展,数据库中数据量猛增,面临的问题首先就是访问性能降低。如何从能打破单机数据库的性能的瓶颈,于是出现了一下两种方案:
- 方案一:通过提升服务器硬件能力来提高数据处理能力,比如增加存储容量 、CPU等,这种方案成本很高,并且如果瓶颈在MySQL本身那么提高硬件也是有很的。
- 方案二:分库分表,把数据分散在不同的数据库中,使得单一数据库的数据量变小来缓解单一数据库的性能问题,从而达到提升数据库性能的目的,通过这种数据库拆分的方法来解决数据库的性能问题。
分库分表适用原则以及问题
分库分表原则
分表分库虽然能解决大表对数据库系统的压力,但它并不是万能的,也有一些不利之处,因此首要问题是,分不分库,分哪些库,什么规则分,分多少分片。
- 能不分就不分,1000万数据以内的表,不建议分片。 可以通过优化索引、读写分离等方式,更好的进行性能优化。
- 分片数量尽可能少,分片尽量均匀分布。 因为一个SQL跨分片数量越多,它的总体性能就越差。虽然要好于所有数据在一个分片的结果,只在必要的时候进行扩容,增加分片数量。
- 分片规则需要慎重选择。 分片规则的选择,需要考虑数据的增长模式,数据的访问模式,分片关联性问题,以及分片扩容问题,最近的分片策略为范围分片,枚举分片,一致性 Hash 分片,这几种分片都有利于扩容。
- 尽量不要在一个事务中的 SQL 跨越多个分片,分布式事务一直是个不好处理的问题。
- 查询条件尽量优化,尽量避免 Select * 的方式。 大量数据结果集下,会消耗大量带宽和 CPU 资源,查询尽量避免返回大量结果集,并且尽量为频繁使用的查询语句建立索引。
分库分表后,面临的问题
- 事务支持 :分库分表后,就成了分布式事务了。如果依赖数据库本身的分布式事务管理功能去执行事务,将付出高昂的性能代价; 如果由应用程序去协助控制,形成程序逻辑上的事务,又会造成编程方面的负担。
- 多库结果集合并:分库分表后,查询的结果集不一定在一个数据库中,多库查出的结果集需要进行合并,造成负担。
- 跨库join :分库分表后表之间的关联操作将受到限制,我们无法join位于不同分库的表,也无法join分表粒度不同的表, 结果原本一次查询能够完成的业务,可能需要多次查询才能完成。 粗略的解决方法: 全局表:基础数据,所有库都拷贝一份。
- 字段冗余:这样有些字段就不用join去查询了。
- 系统层组装:分别查询出所有,然后组装起来,较复杂。
分库分表的方式
在了解了上面的问题之后,我们可以继续讨论分库分表的几种方式方案了
垂直分表
垂直分表定义:将一个表按照字段分成多表,每个表存储其中一部分字段。
举例电商网站的商品列表来说,用户在浏览商品列表时,更多的关心商品的价格等热点信息,而较少在意商品的详细描述、参数等信息。而描述信息此类字段存储占用空间较大,访问单个数据IO时间较长。
由于这两种数据的特性不一样,因此,可以将访问频率低,占用空间大的商品描述等信息放入单独的一张表中,查询时通过关联关系来查询。
垂直分表所带来的提升:
- 为了避免IO争抢并减少锁表的几率,查看详情的用户与商品信息浏览互不影响
- 充分发挥热门数据的操作效率,商品信息的操作的高效率不会被商品描述的低效率所拖累。
为什么大字段IO效率低:
- 第一是由于数据量本身大,需要更长的读取时间;
- 第二是跨页,页是数据库存储单位,很多查找及定位操作都是以页为单位,单页内的数据行越多数据库整体性能越好,而大字段占用空间大,单页内存储行数少,因此IO效率较低。
- 第三,数据库以行为单位将数据加载到内存中,这样表中字段长度较短且访问频率较高,内存能加载更多的数据,命中率更高,减少了磁盘IO,从而提升了数据库性能。
一般来说,某业务实体中的各个数据项的访问频次是不一样的,部分数据项可能是占用存储空间比较大的BLOB或是TEXT。例如上例中的商品描述。所以,当表数据量很大时,可以将表按字段切开,将热门字段、冷门字段分开放置在不同库中,这些库可以放在不同的存储设备上,避免IO争抢。垂直切分带来的性能提升主要集中在热门数据的操作效率上,而且磁盘争用情况减少。
通常我们按以下原则进行垂直拆分:
- 把不常用的字段单独放在一张表
- 把text,blob等大字段拆分出来放在附表中
- 经常组合查询的列放在一张表中
垂直分库
通过垂直分表性能得到了一定程度的提升,但是还没有达到要求,并且磁盘空间也快不够了,因为数据还是始终限制在一台服务器,库内垂直分表只解决了单一表数据量过大的问题,但没有将表分布到不同的服务器上,因此每个表还是竞争同一个物理机的CPU、内存、网络IO、磁盘。
还是以电商系统为例,可以将卖家库、商品库、店铺库分散到不同的服务器上,从而减轻单机数据库压力。
垂直分库是指按照业务将表进行分类,分布到不同的数据库上面,每个库可以放在不同的服务器上,它的核心理念是专库专用。
它带来的提升是:
- 解决业务层面的耦合,业务清晰
- 能对不同业务的数据进行分级管理、维护、监控、扩展等
- 高并发场景下,垂直分库一定程度的提升IO、数据库连接数、降低单机硬件资源的瓶颈
水平分库
垂直分库通过将表按业务分类,然后分布在不同数据库,并且可以将这些数据库部署在不同服务器上,从而达到多个服务器共同分摊压力的效果,但是依然没有解决单表数据量过大的问题。
上述电商系统,暂定有8W的店铺,每个店铺有150个商品,那么商品库中数据量就会是1500W+,并且商品库的访问频繁。此时,可以尝试进行水平分库,将店铺ID为单数的和店铺ID为双数的商品信息分别放在两个库中。
也就是说,要操作某条数据,先分析这条数据所属的店铺ID。如果店铺ID为双数,将此操作映射至RRODUCT_DB1(商品库1);如果店铺ID为单数,将操作映射至RRODUCT_DB2(商品库2)。此操作要访问数据库名称的表达式为RRODUCT_DB[店铺ID%2 + 1] 。
水平分库是把同一个表的数据按一定规则拆到不同的数据库中,每个库可以放在不同的服务器上。
垂直分库是把不同表拆到不同数据库中,它是对数据行的拆分,不影响表结构
水平分库所带来的提升:
- 解决了单库大数据,高并发的性能瓶颈。
- 提高了系统的稳定性及可用性。
稳定性体现在IO冲突减少,锁定减少,可用性指某个库出问题,部分可用
当一个应用难以再细粒度的垂直切分,或切分后数据量行数巨大,存在单库读写、存储性能瓶颈,这时候就需要进行水平分库了,经过水平切分的优化,往往能解决单库存储量及性能瓶颈。但由于同一个表被分配在不同的数据库,需要额外进行数据操作的路由工作,因此大大提升了系统复杂度。
水平分表
水平分库解决了单库数据量过大的情况,那么单表数据量过大怎么办呢?
依照水平分库的思路,我们还可以对数据量过大的表进行水平分表。与水平分库的思路类似,不过这次操作的目标是表,商品信息及商品描述被分成了两套表。如果商品ID为双数,将此操作映射至商品信息1表;如果商品ID为单数,将操作映射至商品信息2表。此操作要访问表名称的表达式为商品信息[商品ID%2 + 1] 。
水平分表是在同一个数据库内,把同一个表的数据按一定规则拆到多个表中。
水平分表所带来的提升:
- 优化单一表数据量过大而产生的性能问题
- 避免IO争抢并减少锁表的几率
库内的水平分表,解决了单一表数据量过大的问题,分出来的小表中只包含一部分数据,从而使得单个表的数据量变小,提高检索性能。
ShardingSphere笔记
传送门:
https://blog.csdn.net/weixin_40955398/article/details/124119337