分库分表必知

news2025/1/18 7:30:00

概述

为啥要进行分库分表?
单表数据量太大,比如超过5000w行,查询时扫描的行太多,SQL效率低,CPU出现瓶颈

数据的切分就是通过某种特定的条件,将存放在同一个数据库或同一个表的数据分散存放到多个数据库(主机)或多个表中,以达到分散单台设备负载的效果,即分库分表。

根据切分规则的类型,可以分为:

  • 垂直(纵向)切分:根据业务模块或字段来划分出不同的数据库或表。可解决跨页问题,实现应用解耦合
  • 水平(横向)切分:根据表中数据行的业务概念,将同一个表中的数据按照某种条件(一般是日期)拆分到一台或多台数据库(主机)上,可实现冷热隔离

根据涉及到库和表,又分为:

  • 分库:将一个表的数据放到多个数据库实例的多个表
  • 分表:将一个表的数据放到多个表中,多个表还在同一个数据库实例

垂直分表

比较常见,通俗说法叫做大表拆小表,拆分是基于关系型数据库中的列(字段)进行的。通常,某个表中的字段比较多,可以新建立一张扩展表,将不经常使用或长度较大的字段拆分出去放到扩展表中。

字段很多时,拆分开确实更便于开发和维护。某种意义上也能避免跨页问题(MySQL、MSSQL底层都是通过数据页来存储的,跨页可能会造成额外的性能开销)。

拆分字段的操作建议在数据库设计阶段就做好。如果是在发展过程中拆分,则需要改写以前的查询语句,会额外带来一定的成本和风险,建议谨慎。

垂直分库分表

按照业务模块来划分出不同的数据库。数据库由多个表构成,每个表对应不同的业务,垂直切分是指按照业务将表进行分类,将其分布到不同的数据库上,将数据分担到不同的库上(专库专用)。

系统层面的服务化拆分操作,能够解决业务系统层面的耦合和性能瓶颈,有利于系统的扩展维护。与服务的治理和降级机制类似,也能对不同业务类型的数据进行分级管理、维护、监控、扩展等。

数据库往往最容易成为应用系统的瓶颈,而数据库本身属于有状态的,相对于Web和应用服务器来讲,是比较难实现横向扩展的。数据库的连接资源比较宝贵且单机处理能力也有限,在高并发场景下,垂直分库一定程度上能够突破IO、连接数及单机硬件资源的瓶颈,是大型分布式系统中优化数据库架构的重要手段。

优点:

  • 拆分后业务清晰,拆分规则明确
  • 系统之间进行整合或扩展很容易
  • 按照成本、应用的等级、应用的类型等将表放到不同的机器上,便于管理
  • 便于实现动静分离、冷热分离的数据库表的设计模式
  • 数据维护简单

缺点:

  • 部分业务表无法关联(Join),只能通过接口方式解决,提高系统的复杂度
  • 受每种业务的不同限制,存在单库性能瓶颈,不易进行数据扩展和提升性能
  • 事务处理复杂

水平分表

也叫横向分表,Scale Out,将表中不同的数据行按照一定规律分布到不同的数据库表中(在同一个数据库中),降低单表数据量,优化查询性能。最常见的方式就是通过主键或时间等字段进行Hash和取模后拆分。

水平分表,能够降低单表的数据量,可缓解查询性能瓶颈。但本质上这些表还保存在同一个库中,库级别还是会有IO瓶颈及响应慢的问题。分表未分库的优势是没有分布式事务问题,也方便运维管理。

水平分库分表

拆分出来的表保存在不同的数据库中。

某种意义上来讲,有些系统中使用的冷热数据分离(将一些使用较少的历史数据迁移到其他的数据库中。而在业务功能上,通常默认只提供热点数据的查询)。在高并发和海量数据的场景下,分库分表能够有效缓解单机和单库的性能瓶颈和压力,突破IO、连接数、硬件资源的瓶颈。投入的硬件成本也会更高。同时,这也会带来一些复杂的技术问题和挑战(跨分片的复杂查询,跨分片事务等)

问题

垂直分库带来跨库JOIN问题

拆分后,数据库可能分布在不同实例和不同的主机上,JOIN将变得非常麻烦。而且基于架构规范,性能,安全性等方面考虑,一般是禁止跨库join的。

几种解决思路

  1. 全局表
    所谓全局表,就是有可能系统中所有模块都可能会依赖到的一些表。类似于数据字典。为了避免跨库join查询,可以将这类表在其他每个数据库中均保存一份。同时,这类数据通常也很少发生修改(甚至几乎不会),所以也不用太担心一致性问题。

  2. 字段冗余
    反范式设计,通常是为了性能来避免join查询。空间换时间。但其适用场景也比较有限,比较适合依赖字段较少的情况。数据一致性问题,可以借助数据库中的触发器或者在业务代码层面去保证。当然也需要结合实际业务场景来看一致性的要求。

  3. 数据同步
    定时A库中的tab_a表和B库中tbl_b有关联,可以定时将指定的表做同步。当然,同步本来会对数据库带来一定的影响,需要性能影响和数据时效性中取得一个平衡。这样来避免复杂的跨库查询。ETL工具。

  4. 系统层组装
    在系统层面,通过调用不同模块的组件或服务,获取到数据并进行字段拼装。实践起来不简单,尤其是数据库设计上存在问题但又无法轻易调整时。

一般用最后一种方式。通过RPC或REST方式,批量或单独请求其他多个服务的多个接口,拿到响应后组装数据。节点间的网络通讯可能会是性能瓶颈,所以需要高效的序列化协议,且调用接口时尽可能只返回需要的数据,而不是把这个表PO实体类全部字段信息返回。

分库带来分布式事务问题

不停机分库分表迁移

基于水平分库分表,拆分策略为常用的hash法。

水平扩容库(升级从库法)
在这里插入图片描述
水平扩容表(双写迁移法)
在这里插入图片描述

分片

Sharding。为了切分,可能会出现冗余字段,用作区分字段或者叫做分库的标记字段。水平切分时,涉及到查询时的路由和落数据时的分片维度

  1. 路由
    在设计表时需要确定对表按照什么样的规则进行分库分表。针对输入的请求,通过分库分表规则查找到对应的表和库的过程叫作路由。
  2. 分片维度
    对数据切片有不同的切片维度,可参考Mycat提供的切片方式,最常用的两种:

哈希切片

对数据的某个字段求哈希,再除以分片总数后取模,取模后相同的数据为一个分片。

按照哈希分片常应用于数据没有时效性的情况,比如所有数据无论是在什么时间产生的,都需要进行处理或者查询,例如支付行业的客户要求可以对至少1年以内的交易进行查询和退款,那么1年以内的所有交易数据都必须停留在交易数据库中,否则就无法查询和退款。

好处:数据切片比较均匀,对数据压力分散的效果较好;缺点是数据分散后,对于查询需求需要进行聚合处理,数据迁移麻烦。

时间切片

按照时间的范围将数据分布到不同的分片上的,如可将交易数据按照月进行切片,或按季度进行切片,由交易数据的数量级来决定按照什么样的时间周期对数据进行切片。

这种切片方式适用于有明显时间特点的数据。通过按照时间进行切片,针对不同的访问频率使用不同档次的硬件资源来节省成本。

优势:数据迁移方便;缺点:数据分布不均匀。

可结合使用这两种分片方式,如:对交易数据先按照季度进行切片,然后对于某一季度的数据按照主键哈希进行切片。

实战

步骤

根据容量(当前容量和增长量)评估分库或分表个数 -> 选key(均匀)-> 分表规则(hash或range等)-> 执行(一般双写)-> 扩容问题(尽量减少数据的移动)。

工具

针对分库分表的需求,有不少优秀的开源框架(工具)。

Sharding-sphere

Sharding-JDBC,定位为轻量级Java框架,在Java的JDBC层提供的额外服务。它使用客户端直连数据库,以jar包形式提供服务,无需额外部署和依赖,增强版的JDBC驱动,完全兼容JDBC和各种ORM框架。

<dependency>
    <groupId>io.shardingsphere</groupId>
    <artifactId>sharding-jdbc-spring-boot-starter</artifactId>
</dependency>
<dependency>
    <groupId>io.shardingsphere</groupId>
    <artifactId>sharding-jdbc-spring-namespace</artifactId>
</dependency>

配置分库分表策略application.properties

# 数据源 db0,db1,db2
sharding.jdbc.datasource.names=db0,db1,db2
# 库1
sharding.jdbc.datasource.db0.type=com.zaxxer.hikari.HikariDataSource
sharding.jdbc.datasource.db0.driver-class-name=com.mysql.cj.jdbc.Driver
sharding.jdbc.datasource.db0.jdbc-url=jdbc:mysql://localhost:3306/db0?useUnicode=true&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=UTC
sharding.jdbc.datasource.db0.username=root
sharding.jdbc.datasource.db0.password=root
# 库2
sharding.jdbc.datasource.db1.type=com.zaxxer.hikari.HikariDataSource
sharding.jdbc.datasource.db1.driver-class-name=com.mysql.cj.jdbc.Driver
sharding.jdbc.datasource.db1.jdbc-url=jdbc:mysql://localhost:3306/db1?useUnicode=true&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=UTC
sharding.jdbc.datasource.db1.username=root
sharding.jdbc.datasource.db1.password=Aa123456

# 库3
sharding.jdbc.datasource.db2.type=com.zaxxer.hikari.HikariDataSource
sharding.jdbc.datasource.db2.driver-class-name=com.mysql.cj.jdbc.Driver
sharding.jdbc.datasource.db2.jdbc-url=jdbc:mysql://localhost:3306/db2?useUnicode=true&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=UTC
sharding.jdbc.datasource.db2.username=root
sharding.jdbc.datasource.db2.password=Aa123456

# 水平拆分的数据库(表) 配置分库 + 分表策略 行表达式分片策略
# 分库策略
sharding.jdbc.config.sharding.default-database-strategy.inline.sharding-column=id
sharding.jdbc.config.sharding.default-database-strategy.inline.algorithm-expression=db$->{id % 3}

# 分表策略 其中book为逻辑表 分表主要取决于id行
sharding.jdbc.config.sharding.tables.book.actual-data-nodes=db$->{0..2}.book_$->{0..2}
sharding.jdbc.config.sharding.tables.book.table-strategy.inline.sharding-column=count
# 分片算法表达式
sharding.jdbc.config.sharding.tables.book.table-strategy.inline.algorithm-expression=book_$->{count % 3}

# 主键 UUID 18位数 如果是分布式还要进行一个设置 防止主键重复
#sharding.jdbc.config.sharding.tables.user.key-generator-column-name=id

spring.main.allow-bean-definition-overriding=true

# 打印执行的数据库以及语句
sharding.jdbc.config.props.sql.show=true

# 读写隔离配置
# 配置默认数据源ds1 默认数据源,主要用于写
spring.shardingsphere.sharding.default-data-source-name=ds1
# 配置主从名称
spring.shardingsphere.masterslave.name=ms
# 置主库master负责写
spring.shardingsphere.masterslave.master-data-source-name=ds1
# 配置从库slave
spring.shardingsphere.masterslave.slave-data-source-names=ds2,ds3
# 配置slave节点的负载均衡均衡策略,采用轮询机制
spring.shardingsphere.masterslave.load-balance-algorithm-type=round_robin

# 整合mybatis的配置
mybatis.type-aliases-package=com.ppdai.shardingjdbc.entity

# 读写分离
sharding.jdbc.datasource.dsmaster =

建表脚本

把冷热数据分开存放,即冷热分离。冷数据查询较多,更新较少,适合用MyISAM引擎,而热数据更新比较频繁,适合使用InnoDB存储引擎,这也是垂直拆分的一种。

问题
跨库join,分布式事务

解决方案:

  1. 全局表
  2. 字段冗余,空间换时间,数据一致性问题,同步更新多表
  3. 数据同步

分片规则配置
Sharding-JDBC的分片逻辑非常灵活,支持分片策略自定义、复数分片键、多运算符分片等功能

SQL路由
SQL路由是根据分片规则配置,将SQL定位至真正的数据源。主要分为单表路由、Binding表路由和笛卡尔积路由。
单表路由最为简单,但路由结果不一定落入唯一库(表),因为支持根据between和in这样的操作符进行分片,所以最终结果仍然可能落入多个库(表)。
Binding表可理解为分库分表规则完全一致的主从表。举例说明:订单表和订单详情表都根据订单ID作为分片键,任意时刻分片逻辑均相同。这样的关联查询和单表查询难度和性能相当。
笛卡尔积查询最为复杂,因为无法根据Binding关系定位分片规则的一致性,所以非Binding表的关联查询需要拆解为笛卡尔积组合执行。查询性能较低,而且数据库连接数较高,需谨慎使用。

参考

  • Sharding-Jdbc实现读写分离、分库分表
  • 常用分库分表方案汇总

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/117002.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

干货 | 数字经济创新创业——网络安全

下文整理自清华大学大数据能力提升项目能力提升模块课程“Innovation & Entrepreneurship for Digital Economy”&#xff08;数字经济创新创业课程)的精彩内容。主讲嘉宾&#xff1a;Kris Singh: CEO at SRII, Palo Alto, CaliforniaVisiting Professor of Tsinghua Unive…

在 ArcGIS 中使用函数块给字段赋随机值 (指定范围内随机编号)

在 ArcMap 或 ArcGIS Pro 中通过使用字段计算器,给字段赋随机值。 通过字段计算器内置的 VB、Python 方法可以构建函数块表达式实现各种各样的赋值操作,下面我们来看看通过使用内置的 Python 函数块来实现随机赋值。 (也可以制作成工具箱哦,更加方便) ArcMap 生成随机值…

智能开关继电器-选型篇2

继电器在智能开关中承担着开通、关断的功能&#xff0c;是开关产品最根本的一项功能。这样一个关键的器件我们将分为两个篇章进行撰写&#xff1a;选型篇1、选型篇2、评估篇。其中选型篇1简述继电器的定义、分类&#xff0c;可参考《智能开关继电器-选型篇1》。选型篇2会在基于…

【TypeScript】类型声明文件的讲解与使用

目录 简介 文件类型 类型声明文件使用 简介 我们发现今天所有的JS应用都会引入许多第三方库来完成任务需求。这些第三方库无论是否是TS编写的最终都会编译成JS代码给开发者使用。我们知道TS提供了类型才有了代码提示和类型保护机制&#xff0c;但我们引入的第三方库都会有相…

搞懂 Spark 系列之 Spark Shuffle 的前世今生

注&#xff1a;本文已首发于PowerData公众号&#xff01; 1 Spark Shuffle 是什么&#xff1f; Shuffle 中文意思是“洗牌&#xff0c;混洗”&#xff0c;而在 Hadoop 的 MapReduce 框架中&#xff0c;Shuffle 是 Map 和 Reduce 中间必不可少的连接桥梁。数据在从Map 阶段结束…

优化器核心技术—Join Reorder

Join Reorder 的简介 Join Reorder 是开务数据库 SQL 优化器中的核心优化算法&#xff0c;开务数据库优化器包括 RBO 和 CBO 两部分&#xff0c;负责计划优化&#xff0c;提升 SQL 执行性能。Join Reorder 能够保证在复杂查询执行的场景下&#xff0c;枚举合法的执行路径&…

分布式系统稳定性建设指南

来源&#xff1a; 中国信息通信研究院 系统稳定性能建设是一个系统化工程&#xff0c;需要硬件软件&#xff0c;需要从企业工程建设的全环节进行设计和实施&#xff0c;充分利用以混沌工程、全链路压测为代表的分布式稳定性保障技术&#xff0c;建设保障能力&#xff0c;改造运…

域名系统 DNS(计算机网络-应用层)

目录 互联网的域名结构 顶级域名 TLD(Top Level Domain) 域名服务器 域名系统 DNS 域名解析的过程 域名服务器的四种类型 本地域名服务器 DNS 协议 DNS缓存 DNS提供的其它服务 互联网的域名结构 域名系统 DNS (Domain Name System)&#xff0c;实现主机名&#xff08;域…

(三)HTTPTomcatServlet

一、HTTP HyperText Transfer Protocol&#xff0c;超文本传输协议&#xff0c;规定了浏览器和服务器之间数据传输的规则。 HTTP协议特点&#xff1a; &#xff08;1&#xff09;基于TCP协议&#xff1a;面向连接&#xff0c;安全 &#xff08;2&#xff09;基于请求-响应模型的…

漫画 | JavaScript杀死了编程......

上班路上&#xff0c;张大胖突然想到一个点子。晚上&#xff0c;张大胖开工&#xff0c;决定把好点子给实现了。JavaScript开发效率贼高&#xff0c;项目迅速完成。项目开源发布&#xff0c;获得了不少用户&#xff0c;收获了不少star&#xff0c;张大胖非常满意。转眼间&#…

【GlobalMapper精品教程】039:GM面状数据符号化设置案例教程

GM面状数据符号化设置案例教程。 文章目录 一、使用基于分类或自定义样式的默认样式二、对所有要素使用相同样式三、基于属性/名称值应用样式四、随机指定颜色给要素一、使用基于分类或自定义样式的默认样式 该样式类似于其他GIS软件的单一样式,即为数据加载的默认样式。加载…

Stable Diffusion攻略集(Stable Diffusion官方文档、kaggle notebook、webui资源帖)

文章目录第一部分一、 Features&#xff1a;Textual Inversion&#xff08;文本反转&#xff09;1.1 Textual Inversion 简介1.1.1 摘要1.1.2 算法1.1.3 模型效果1.2 Textual Inversion of webai1.2.1 预训练embedding用于图片生成1.2.2 训练embedding1.2.3 Finding embeddings…

【Redis】知识体系结构构建以及常见考题汇总

【Redis】知识体系结构构建以及常见考题汇总1、思维导图2、Redis体系结构&#xff1a;原理、部署2.1、Redis实现原理2.1.1、Redis中数据结构2.1.2、不同对象的数据类型&#xff08;基本类型、特殊类型&#xff09;2.2、Redis部署2.2.1、基本配置&#xff08;缓存的更新、删除和…

【Linux】基础命令

目录 1.ls指令 2.pwd指令 3.cd指令 4.touch指令 5.mkdir指令 6.rmdir指令 && rm 指令 7.man指令 8.cp指令 9.mv指令 10.cat指令 11.less指令 12. head和tail 13.date指令 14.grep指令 15.bc指令 16.重要的几个热键 1.ls指令 语法&#xff1a;ls 选项 …

Taro React组件开发(2) —— RuiEditor 富文本编辑器【兼容H5和微信小程序】

1. 富文本编辑器需求分析 需要实现图片上传显示,上传使用Taro的 chooseImage 和 uploadFile,完成图片的上传!!!文字的居左、居中、居右展示,使用格式化方法 format!!!文字的加粗、倾斜、下划线,使用格式化方法 format!!!2. 富文本编辑 获取提示文本 placeholder;…

【C++】string类常用函数接口

在使用库函数中的string类时&#xff0c;需要包含头文件#include 。 1.构造函数和拷贝构造 string s1;string s2("hello world");string s3(s2);下面通过VS调试的监视窗口看一下初始化之后的内容&#xff1a; 还有一种构造函数&#xff0c;是拷贝一个字符串的一部分…

Kubernetes 1.26 新功能 Pod 调度就绪特性解析

Kubernetes 1.26 新功能 Pod 调度就绪特性解析 Kubernetes 1.26 引入了 Pod 的一个新特性&#xff1a;scheduling gates。在 Kubernetes 中&#xff0c;调度门是告诉调度程序何时准备好考虑调度 Pod 的 keys。 它解决了什么问题&#xff1f; 当一个 Pod 创建时&#xff0c;调…

从发现SQL注入到ssh连接

前言&#xff1a; 某天&#xff0c;同事扔了一个教育站点过来&#xff0c;里面的url看起来像有sql注入。正好最近手痒痒&#xff0c;就直接开始。 一、发现时间盲注和源码 后面发现他发的url是不存在SQL注入的&#xff0c;但是我在其他地方发现了SQL盲注。然后改站点本身也可…

C++/Java调用C++动态链接库————附带示例和详细讲解

文章目录0 准备1 C调用动态链接库2 Java调用C动态链接库3 运行0 准备 在CMake中&#xff0c;使用如下的方法把代码编译成动态/静态链接库&#xff1a; # 设置项目名 project(getMatInfo)# 设置c版本 set(CMAKE_CXX_STANDARD 11)# 如果不填写SHARE&#xff0c;默认为静态链接…

Spring Security开发实践

Spring Security 是 Spring 家族中用于提供认证、授权和攻击防护功能的一套安全框架。它也是 Spring 应用在安全框架方面的公认标准。 Spring Security 安全框架适合为 Spring Boot 项目提供安全保护&#xff0c;所以如果您是个 Spring Boot 项目的开发人员&#xff0c;且正在寻…