目录
分库分表的诞生?
分库分表的核心目的?
为什么分库?
为什么分表?
垂直拆分
水平拆分
支持分库分表的中间件?数据分片的核心基础概念
表
逻辑表
真实表
绑定表
广播表
单表
数据节点
均匀分布
自定义分布
分片
分片键
分片算法
自动化分片算法
自定义分片算法
分片策略
强制分片路由
行表达式
分布式主键
细节问题
分片键的选择:
历史数据的迁移:
查询:
在如今人人都参与互联网的年代,对于数据的存储来说,所面临的挑战也是越来越大。尤其对传统的关系型数据库比如Mysql、Oracle来说,当数据越来越多,所面临的存储容量和执行效率也越来越慢的问题也越来越需要考虑。即使加的索引非常的合理,但随着表的量级越来越大,索引的的容量也越来越大,效率始终还是下降。
为了应对这种问题,如今主流的方案有分布式数据库和分库分表两种方案存在。
分布式数据的优点是上手简单,和正常的数据库用法相同,无需考虑分库分表、分片键、分片算法的问题,但目前的分布式数据对服务器的性能要求比较高,对于预算紧张的公司来说,不太适合。另外目前来说分布式数据库的稳定性还不是如传统的Mysql、Oracle。
另一种就是常说的分库分表,其实分库分表是由分库和分表这两个独立概念组成的,只不过通常分库与分表的操作会同时进行,以至于我们习惯性的将它们合在一起叫做分库分表。
通过一定的规则,如按时间范围划分,根据hash取模、指定分片等算法,将数据量大的数据库拆分成多个单独数据库,将原本数据量大的表拆分成若干个数据表,使得单一的库、表性能达到最优的效果(响应速度快),以此提升整体数据库性能。
单表行数超 500 万行或者单表容量超过 2GB,推荐分库分表
连接数问题:虽然现在服务连接数据库都使用了数据源这种池化的缓存方案,但每个数据库的连接数始终是有上限的,当并发量突增,很快就会将数据库的连接全部用掉,其他的请求就会失败。
容量问题每台机器给数据库分配的磁盘容量是有限的,随着数据量的增加,依旧存在容量会被占满的问题。
SQL执行效率:对于表来说,最需要考虑的问题就是sql的执行效率,导致sql执行厅效率慢的原因有很多,没命中索引、like扫全表、用了函数计算等等。这些在数据量不大的时候以及用上索引问题都不是很大,但一旦表中的数据量很大的话,假如是一亿数据量,就算用上索引效率也不是很高,原因是InnoDB存储引擎,聚簇索引结构的B+树的层级变高,磁盘I/O变多,查询性能变慢。
垂直分库:在开始规模比较小的单体项目来说,所有的业务都是放在同一个数据库中,比如产品、订单、用户、支付都是在同一个库中,但随着项目越来越庞大,数据量也越来越大,就需要按照不同的业务来拆分成多个库。
垂直分表:垂直分表适用于字段非常多的表,对于很多的查询来说,其实不需要一次将所有的字段全都查询出来,这样很浪费性能,影响效率,那么就将经常查询的字段单独拆分出一个表,将另外的字段单独拆分成另一个表,拆分后的表通过某个字段关联起来,这样既可以减少表的容量大小,又可以提升查询效率。
垂直拆分其实还是根据业务进行模块拆分的,当单表的容量越来越大的时候,还是不能解决单表的读写、存储的性能瓶颈,这时候就需要水平拆分了。
水平分库:水平分库是把同一个表按一定规则拆分到不同的数据库中,每个库可以位于不同的服务器上,每个数据库的库和表结构都是相同的,只有表中的数据不同。可以实现水平扩展,有效缓解单库的性能瓶颈。
水平分表:水平分表是在同一个数据库内,对大表进行水平拆分,分割成多个表结构相同的表
在使用和完善以及热度上ShardingSphere好用。
官网:https://shardingsphere.apache.org/document/5.3.2/cn/features/sharding/concept/
表是透明化数据分片的关键概念。 Apache ShardingSphere 通过提供多样化的表类型,适配不同场景下的数据分片需求。
相同结构的水平拆分数据库(表)的逻辑名称,是 SQL 中表的逻辑标识。 例:订单数据根据主键尾数拆分为 10 张表,分别是 t_order_0
到 t_order_9
,他们的逻辑表名为 t_order
。
在水平拆分的数据库中真实存在的物理表。 即上个示例中的 t_order_0
到 t_order_9
。
指分片规则一致的一组分片表。 使用绑定表进行多表关联查询时,必须使用分片键进行关联,否则会出现笛卡尔积关联或跨库关联,从而影响查询效率。 例如:t_order
表和 t_order_item
表,均按照 order_id
分片,并且使用 order_id
进行关联,则此两张表互为绑定表关系。 绑定表之间的多表关联查询不会出现笛卡尔积关联,关联查询效率将大大提升。
指所有的分片数据源中都存在的表,表结构及其数据在每个数据库中均完全一致。 适用于数据量不大且需要与海量数据的表进行关联查询的场景,例如:字典表。
指所有的分片数据源中仅唯一存在的表。 适用于数据量不大且无需分片的表。
数据分片的最小单元,由数据源名称和真实表组成。 例:ds_0.t_order_0。 逻辑表与真实表的映射关系,可分为均匀分布和自定义分布两种形式。
指数据表在每个数据源内呈现均匀分布的态势
指数据表呈现有特定规则的分布
用于将数据库(表)水平拆分的数据库字段。 例:将订单表中的订单主键的尾数取模分片,则订单主键为分片字段。 SQL 中如果无分片字段,将执行全路由,性能较差。 除了对单分片字段的支持,Apache ShardingSphere 也支持根据多个字段进行分片。
用于将数据分片的算法,支持 =
、>=
、<=
、>
、<
、BETWEEN
和 IN
进行分片。 分片算法可由开发者自行实现,也可使用 Apache ShardingSphere 内置的分片算法语法糖,灵活度非常高。
分片算法语法糖,用于便捷的托管所有数据节点,使用者无需关注真实表的物理分布。 包括取模、哈希、范围、时间等常用分片算法的实现。
提供接口让应用开发者自行实现与业务实现紧密相关的分片算法,并允许使用者自行管理真实表的物理分布。 自定义分片算法又分为:
标准分片算法
用于处理使用单一键作为分片键的 =
、IN
、BETWEEN AND
、>
、<
、>=
、<=
进行分片的场景。
复合分片算法
用于处理使用多键作为分片键进行分片的场景,包含多个分片键的逻辑较复杂,需要应用开发者自行处理其中的复杂度。
Hint 分片算法
用于处理使用 Hint
行分片的场景。
包含分片键和分片算法,由于分片算法的独立性,将其独立抽离。 真正可用于分片操作的是分片键 + 分片算法,也就是分片策略。
对于分片字段并非由 SQL 而是其他外置条件决定的场景,可使用 SQL Hint 注入分片值。 例:按照员工登录主键分库,而数据库中并无此字段。 SQL Hint 支持通过 Java API 和 SQL 注释两种方式使用。 详情请参见强制分片路由。
行表达式是为了解决配置的简化与一体化这两个主要问题。在繁琐的数据分片规则配置中,随着数据节点的增多,大量的重复配置使得配置本身不易被维护。 通过行表达式可以有效地简化数据节点配置工作量。
对于常见的分片算法,使用 Java 代码实现并不有助于配置的统一管理。 通过行表达式书写分片算法,可以有效地将规则配置一同存放,更加易于浏览与存储。
行表达式的使用非常直观,只需要在配置中使用 ${ expression }
或 $->{ expression }
标识行表达式即可。 目前支持数据节点和分片算法这两个部分的配置。 行表达式的内容使用的是 Groovy 的语法,Groovy 能够支持的所有操作,行表达式均能够支持。 例如:
${begin..end}
表示范围区间 ${[unit1, unit2, unit_x]}
表示枚举值
行表达式中如果出现连续多个 ${ expression }
或 $->{ expression }
表达式,整个表达式最终的结果将会根据每个子表达式的结果进行笛卡尔组合。
传统数据库软件开发中,主键自动生成技术是基本需求。而各个数据库对于该需求也提供了相应的支持,比如 MySQL 的自增键,Oracle 的自增序列等。 数据分片后,不同数据节点生成全局唯一主键是非常棘手的问题。同一个逻辑表内的不同实际表之间的自增键由于无法互相感知而产生重复主键。 虽然可通过约束自增主键初始值和步长的方式避免碰撞,但需引入额外的运维规则,使解决方案缺乏完整性和可扩展性。
目前有许多第三方解决方案可以完美解决这个问题,如 UUID 等依靠特定算法自生成不重复键,或者通过引入主键生成服务等。为了方便用户使用、满足不同用户不同使用场景的需求, Apache ShardingSphere 不仅提供了内置的分布式主键生成器,例如 UUID、SNOWFLAKE,还抽离出分布式主键生成器的接口,方便用户自行实现自定义的自增主键生成器。
如何选择分片键在分库分表中非常的重要,可以说直接影响了整个分库分表的性能,如果分片键选择不当,很可能会导致 全路由 查询,也就是将分库分表的中所有的库以及所有的表都要路由一遍,这样效率是非常低下的,所以一定要慎重考虑分片键。
考虑点:
业务相关性:分片键应该与业务密切相关,能够反映出数据访问的模式。通常,选择那些经常作为查询条件的字段作为分片键,可以减少跨分片的查询,提高查询效率。
均匀分布数据:理想的分片键能够确保数据在各个分片间均匀分布,避免某些分片数据量过大而成为瓶颈。均匀的数据分布有助于负载均衡,提升整体性能。
写入性能:在考虑分片键时,应考虑到写入操作的性能。一个好的分片键可以减少写入时的热点问题,避免某个分片因为频繁的写入操作而过载。
避免频繁修改:分片键一旦选择并开始使用后,修改起来将非常困难且成本很高。因此,应选择那些不会或很少需要修改的字段作为分片键。
考虑未来的扩展性:在选择分片键时,还需要考虑到数据量增长和系统扩展的需要。分片键的选择应该能够适应数据量的增加,允许在不影响现有系统的前提下添加更多的分片。
避免业务操作跨分片:如果业务操作需要跨多个分片进行,可能会严重影响性能。因此,应尽可能选择可以将相关数据局部化的分片键,减少跨分片操作的需求。
安全和隐私考虑:在某些情况下,分片键的选择还需要考虑数据的安全和隐私要求。例如,使用敏感信息(如用户ID)作为分片键时,需要确保分片策略遵守相关的数据保护法规。
分库分表的方案确实使用后,有个一定要考虑的问题,就是如何平滑的迁移历史数据,增量数据和全量数据迁移
一般用表中的id是分片键的最佳选择,但存在一个问题,比如搜索条件的分页查询,比如说查询职员列表,可根据 职员类型、所在部门、入职时间 这些条件查询列表,这些条件没有 职员id 的分片键,就会造成全路由的问题,那么要去怎么解决呢?