筑巢网站建设,济南企业做网站推广网站,做一张网站图得多少钱,如何给网站设置关键词系列文章目录 文章目录系列文章目录前言一、什么是分库分表二、分库分表的原因分库分表三、如何分库分表3.1 垂直拆分1.垂直分库2、垂直分表3.2 水平拆分水平分库水平分表水平分库分表的策略hash取模算法range范围rangehash取模混合地理位置分片预定义算法四、分库分表的问题分…系列文章目录 文章目录系列文章目录前言一、什么是分库分表二、分库分表的原因分库分表三、如何分库分表3.1 垂直拆分1.垂直分库2、垂直分表3.2 水平拆分水平分库水平分表水平分库分表的策略hash取模算法range范围rangehash取模混合地理位置分片预定义算法四、分库分表的问题分页、排序、跨节点联合查询事务一致性全局唯一的主键多数据库高效治理历史数据迁移参考前言
想要开发一个基于 HashMap 核心设计原理使用哈希散列扰动函数的方式把数据散列到多个库表中的组件并验证使用。这里是分库分表的基础知识
一、什么是分库分表
分库就是一个数据库分成多个数据库部署到不同机器。
分表就是一个数据库表分成多个表。
二、分库分表的原因
分库
如果业务量剧增数据库可能会出现性能瓶颈这时候我们就需要考虑拆分数据库。从这几方面来看
磁盘存储
业务量剧增MySQL单机磁盘容量会撑爆拆成多个数据库磁盘使用率大大降低。
并发连接支撑
我们知道数据库连接是有限的。在高并发的场景下大量请求访问数据库MySQL单机是扛不住的当前非常火的微服务架构出现就是为了应对高并发。它把订单、用户、商品等不同模块拆分成多个应用并且把单个数据库也拆分成多个不同功能模块的数据库订单库、用户库、商品库以分担读写压力。
分表
数据量太大的话SQL的查询就会变慢。如果一个查询SQL没命中索引千百万数据量的表可能会拖垮这个数据库。 即使SQL命中了索引如果表的数据量超过一千万的话查询也是会明显变慢的。这是因为索引一般是B树结构数据千万级别的话B树的高度会增高查询就变慢啦。
一棵高度为2的B树能存放1170 * 1618720条这样的数据记录。同理一棵高度为3的B树能存放1170 *1170 *16 21902400大概可以存放两千万左右的记录。B树高度一般为1-3层如果B到了4层查询的时候会多查磁盘的次数SQL就会变慢。 因此单表数据量超过千万就需要考虑分表啦。 是否分库分表的关键指标是数据量
三、如何分库分表 分库分表的核心就是对数据的分片Sharding并相对均匀的路由在不同的库、表中以及分片后对数据的快速定位与检索结果的整合。 首先我们要知道为什么要用分库分表其实就是由于业务体量较大数据增长较快所以需要把用户数据拆分到不同的库表中去减轻数据库压力。
分库分表操作主要有垂直拆分和水平拆分
垂直拆分指按照业务将表进行分类分布到不同的数据库上这样也就将数据的压力分担到不同的库上面。最终一个数据库由很多表的构成每个表对应着不同的业务也就是专库专用。 水平拆分如果垂直拆分后遇到单机瓶颈可以使用水平拆分。相对于垂直拆分的区别是垂直拆分是把不同的表拆到不同的数据库中而水平拆分是把同一个表拆到不同的数据库中。如user_001、user_002
3.1 垂直拆分
1.垂直分库 但是随着业务蒸蒸日上系统功能逐渐完善。这时候可以按照系统中的不同业务进行拆分比如拆分成用户库、订单库、积分库、商品库把它们部署在不同的数据库服务器这就是垂直分库。 垂直分库把一个库的压力分摊到多个库提升了一些数据库性能但并没有解决由于单表数据量过大导致的性能问题所以就需要配合后边的分表来解决。
2、垂直分表
如果一个单表包含了几十列甚至上百列管理起来很混乱每次都select *的话还占用IO资源。这时候我们可以将一些不常用的、数据较大或者长度较长的列拆分到另外一张表。 比如一张用户表它包含user_id、user_name、mobile_no、age、email、nickname、address、user_desc如果email、address、user_desc等字段不常用我们可以把它拆分到另外一张表命名为用户详细信息表。这就是垂直分表 3.2 水平拆分
当我们的应用已经无法在细粒度的垂直切分时依旧存在单库读写、存储性能瓶颈这时就要配合水平分库、水平分表一起了。
水平分库
水平分库是指将表的数据量切分到不同的数据库服务器上每个服务器具有相同的库和表只是表中的数据集合不一样。它可以有效的缓解单机单库的性能瓶颈和压力。 例如db_orde_1、db_order_2两个数据库内有完全相同的t_order表我们在访问某一笔订单时可以通过对订单的订单编号取模的方式 订单编号 mod 2 数据库实例数 指定该订单应该在哪个数据库中操作。 这种方案往往能解决单库存储量及性能瓶颈问题但由于同一个表被分配在不同的数据库中数据的访问需要额外的路由工作因此系统的复杂度也被提升了。
水平分表
水平分表是在同一个数据库内把一张大数据量的表按一定规则切分成多个结构完全相同表而每个表只存原表的一部分数据。 例如一张t_order订单表有900万数据经过水平拆分出来三个表t_order_1、t_order_2、t_order_3每张表存有数据300万以此类推。 水平分库分表的策略
如果一个表的数据量太大可以按照某种规则如hash取模、range把数据切分到多张表去。
其实这个规则它是一种路由算法决定了一条数据具体应该存在哪个数据库的哪张表里。
常见的有 取模算法 、范围限定算法、范围取模算法 、预定义算法
hash取模算法
hash取模策略指定的路由key一般是user_id、订单id作为key对分表总数进行取模把数据分散到各个表中。
比如id1对4取模就会得到1就把它放到第1张表即t_order_0;id3对4取模就会得到3就把它放到第3张表即t_order_2;
这种方案的优点
hash取模的方式不会存在明显的热点问题。
缺点
如果一开始按照hash取模分成4个表了未来某个时候表数据量又到瓶颈了需要扩容这就比较棘手了。比如你从4张表又扩容成8张表那之前id5的数据是在5%41即第一张表现在应该放到5%85即第5张表也就是说历史数据要做迁移了。
range范围
range即范围策略划分表。比如我们可以将表的主键按照从01000万的划分为一个表10002000万划分到另外一个表。如下图 这种方案的优点
这种方案有利于扩容不需要数据迁移。假设数据量增加到5千万我们只需要水平增加一张表就好啦之前0~4000万的数据不需要迁移。
缺点
这种方案会有热点问题因为订单id是一直在增大的也就是说最近一段时间都是汇聚在一张表里面的。比如最近一个月的订单都在1000万~2000万之间平时用户一般都查最近一个月的订单比较多请求都打到order_1表啦这就导致表的数据热点问题。
rangehash取模混合
既然range存在热点数据问题hash取模扩容迁移数据比较困难我们可以综合两种方案一起嘛取之之长弃之之短。 比较简单的做法就是在拆分库的时候我们可以先用range范围方案比如订单id在04000万的区间划分为订单库1id在4000万8000万的数据划分到订单库2,将来要扩容时id在8000万~1.2亿的数据划分到订单库3。然后订单库内再用hash取模的策略把不同订单划分到不同的表。
地理位置分片
地理位置分片其实是一个更大的范围按城市或者地域划分比如华东、华北数据放在不同的分片库、表。
预定义算法
预定义算法是事先已经明确知道分库和分表的数量可以直接将某类数据路由到指定库或表中查询的时候亦是如此。
四、分库分表的问题
分页、排序、跨节点联合查询
分页、排序、联合查询这些看似普通开发中使用频率较高的操作在分库分表后却是让人非常头疼的问题。把分散在不同库中表的数据查询出来再将所有结果进行汇总合并整理后提供给用户。 比如我们要查询11、12月的订单数据如果两个月的数据是分散到了不同的数据库实例则要查询两个数据库相关的数据在对数据合并排序、分页过程繁琐复杂。
方案1在个节点查到对应结果后在代码端汇聚再分页。方案2把分页交给前端前端传来pageSize和pageNo在各个数据库节点都执行分页然后汇聚总数量前端。这样缺点就是会造成空查如果分页需要排序也不好搞。排序问题 跨节点的count,order by,group by以及聚合函数等问题可以分别在各个节点上得到结果后在应用程序端进行合并。
事务一致性
分库分表后由于表分布在不同库中不可避免会带来跨库事务问题。后续会分别以阿里的Seata和MySQL的XA协议实现分布式事务用来比较各自的优势与不足。
全局唯一的主键
分库分表后数据库表的主键ID业务意义就不大了因为无法在标识唯一一条记录例如多张表t_order_1、t_order_2的主键ID全部从1开始会重复此时我们需要主动为一条记录分配一个ID这个全局唯一的ID就叫分布式ID发放这个ID的系统通常被叫发号器。
分布式ID 数据库被切分后不能再依赖数据库自身的主键生成机制啦最简单可以考虑UUID或者使用雪花算法生成分布式ID。
多数据库高效治理
对多个数据库以及库内大量分片表的高效治理是非常有必要因为像某宝这种大厂一次大促下来订单表可能会被拆分成成千上万个t_order_n表如果没有高效的管理方案手动建表、排查问题是一件很恐怖的事。
历史数据迁移
分库分表架构落地以后首要的问题就是如何平滑的迁移历史数据增量数据和全量数据迁移 排序问题
参考
https://juejin.cn/post/7085132195190276109#heading-15 https://juejin.cn/post/7155784807702593572#heading-39