=那一刻,还是输给了现实=😔

基础认识

分库分表定义:

为了解决由于数据量过大而导致的数据库性能降低的问题,将原来独立的数据库拆分成若干数据库,把原来数据量大的表拆分成若干数据表,使得单一数据库、单一数据表的数据量变得足够小,从而达到提升数据库性能的效果。

在开发过程中,对于每个维度都可以采用两种拆分思路,即垂直拆分水平拆分

垂直拆分:在电商系统中,用户在打开首页时,往往会加载一些用户性别、地理位置等基础数据。对于用户表而言,这些位于首页的基础数据访问频率显然要比用户头像等数据更高。基于这两种数据的不同访问特性,可以把用户单表进行拆分,将访问频次低的用户头像等信息单独存放在一张表中,把访问频次较高的用户信息单独放在另一张表中:

垂直分表:

image-20240925215434373

垂直分表的处理方式就是将一个表按照字段分成多张表,每个表存储其中一部分字段

垂直分库:

image-20240925215507913

水平拆分:

image-20240925215554250

  • 取模算法,取模的方式有很多,比如前面介绍的按照用户 ID 进行取模,当然也可以通过表的一列或多列字段进行 hash 求值来取模;
  • 范围限定算法,范围限定也很常见,比如可以采用按年份、按时间等策略路由到目标数据库或表;
  • 预定义算法,是指事先规划好具体库或表的数量,然后直接路由到指定库或表中。

分库分表的两种常见解决方案:客户端分片与代理服务器分片

分库分表是应对数据库性能瓶颈时常用的手段,主要通过将数据划分成多个部分(分片),分别存储在不同的数据库或数据表中,从而减少单个数据库的压力。在分库分表的实现上,主要有两种常见的解决方案:客户端分片代理服务器分片

客户端分片是指分片逻辑完全由客户端(应用层)来管理和执行。客户端负责根据分片规则决定某个 SQL 请求应该发送到哪个数据库或表中。简而言之,分片规则已经前置到客户端,分片逻辑嵌入到应用层,应用直接与多个数据库实例交互。

工作原理:

  • 分片逻辑封装在客户端:分片规则和逻辑直接在应用程序中实现,应用层根据 SQL 请求的相关信息(如主键、字段值)来决定将请求路由到哪个数据库或哪个表。
  • 透明的数据库操作:通过对 JDBC 协议的重写,客户端分片框架(如 ShardingSphere-JDBC)使得业务开发人员不用关心具体的分片逻辑。开发者依然使用标准的 JDBC 进行数据库操作,底层由中间件自动完成分片操作。

代理服务器分片是在应用层和数据库之间添加一个代理层,这个代理服务器负责管理分片逻辑和数据库连接。应用程序只需要与代理服务器通信,代理服务器根据分片规则,将 SQL 请求路由到具体的数据库实例或表中。

典型框架:

  • Cobar(阿里巴巴开源的代理分片中间件)
  • MyCat(开源的数据库分片中间件)
  • ShardingSphere-Proxy(ShardingSphere 的代理模式实现)

分库分表面试必背

面试官:关于分库分表的面试问题,你了解多少?

ShardingSphere

ShardingSphere 是 Apache 基金会旗下的一个开源分布式数据库中间件生态系统,提供了分库分表、读写分离、数据加密、分布式事务等功能。其目标是帮助企业在不改变现有数据库系统的前提下,提供轻量级、可扩展的数据库分布式管理解决方案。在大规模高并发场景下,ShardingSphere 可以有效提高数据库的读写性能和扩展性,解决数据库单点瓶颈问题。

ShardingSphere 集成了 Spring 和 Spring Boot 这两款 Spring 家族的主流开发框架。

ShardingSphere

三个核心产品:

  1. ShardingSphere-JDBC:基于 JDBC 层的轻量级分库分表方案,适用于 Java 应用程序。
  2. ShardingSphere-Proxy:数据库代理服务,提供多语言支持,适合多语言应用场景。
  3. ShardingSphere-Sidecar(规划中):面向云原生环境的数据库解决方案,提供服务网格的管理能力。

功能架构

ShardingSphere 提供了以下几个重要功能:

  1. 数据分片(Sharding)
    • 水平分库分表:通过分片键(如订单ID、用户ID等)将数据分片到不同的数据库实例或表中,这样可以减轻单个数据库的压力。
    • 灵活的分片策略:支持多种分片策略,如范围分片、哈希分片、自定义分片等。开发人员可以根据业务需求灵活选择不同的分片方式。
    • 复杂查询支持:支持跨分片的复杂查询,如 JOINGROUP BYORDER BY 等操作,确保分片后的数据查询功能不受影响。
  2. 读写分离
    • 在主从数据库架构下,写操作发送到主库,读操作发送到从库。这种方式可以有效提高数据库的读操作性能,减轻主库的压力。
    • 支持读负载均衡策略,例如轮询、最少连接等。
  3. 分布式事务
    • 强一致性事务(2PC):支持跨库的分布式事务,保证数据的强一致性,使用两阶段提交协议(2PC)来确保事务的正确性。
    • 柔性事务:支持 BASE 理论下的柔性事务,确保在分布式环境中追求最终一致性。
  4. 数据加密
    • 提供透明的数据加密功能,能够对敏感数据(如用户的身份信息、信用卡号等)进行加密存储和解密查询,确保数据安全性。
  5. 弹性扩展
    • 提供动态扩展能力,能够在业务增长时,通过增加数据库实例来提高系统的容量和处理能力。
    • 通过高可用架构,支持数据节点的自动扩展和缩减,保证系统的灵活性。
  6. 影子库功能
    • 支持影子库,用于模拟真实流量进行灰度测试,确保新功能在生产环境下的稳定性。
  7. 统一治理中心(Governance Center)
    • 提供对数据分片、读写分离、分布式事务、数据加密等功能的统一配置和管理。通过 Zookeeper、Nacos 等注册中心实现集群配置的动态更新和监控。

ShardingSphere-JDBC

ShardingSphere 的前身是 Sharding-JDBC,所以这是整个框架中最为成熟的组件。Sharding-JDBC 的定位是一个轻量级 Java 框架,在 JDBC 层提供了扩展性服务。我们知道 JDBC 是一种开发规范,指定了 DataSource、Connection、Statement、PreparedStatement、ResultSet 等一系列接口。而各大数据库供应商通过实现这些接口提供了自身对 JDBC 规范的支持,使得 JDBC 规范成为 Java 领域中被广泛采用的数据库访问标准。

基于这一点,Sharding-JDBC 一开始的设计就完全兼容 JDBC 规范,Sharding-JDBC 对外暴露的一套分片操作接口与 JDBC 规范中所提供的接口完全一致。开发人员只需要了解 JDBC,就可以使用 Sharding-JDBC 来实现分库分表,Sharding-JDBC 内部屏蔽了所有的分片规则和处理逻辑的复杂性。显然,这种方案天生就是一种具有高度兼容性的方案,能够为开发人员提供最简单、最直接的开发支持。关于 Sharding-JDBC 与 JDBC 规范的兼容性话题,我们将会在下一课时中详细讨论。

image-20240925220607651

在实际开发过程中,Sharding-JDBC 以 JAR 包的形式提供服务。

image-20240925220528277

Sharding-Proxy

ShardingSphere-ProxyApache ShardingSphere 提供的一个数据库代理服务,它位于应用程序和实际数据库之间,作为数据库的代理层来处理分库分表、读写分离、分布式事务等操作。

通过 ShardingSphere-Proxy,应用程序与数据库的交互可以变得更加简单。应用程序只需要像往常一样发送 SQL 请求,而代理层会根据配置好的规则,将这些请求分发到不同的数据库或数据表,并处理复杂的事务、读写分离等操作。由于 ShardingSphere-Proxy 对外提供标准的数据库协议(如 MySQL、PostgreSQL 协议),因此应用程序无需修改任何代码即可使用。

ShardingSphere-Proxy 的工作流程如下:

  1. 应用程序 向 ShardingSphere-Proxy 发送标准 SQL 请求。
  2. ShardingSphere-Proxy 接收到 SQL 后,基于配置的分片规则、读写分离策略等,对 SQL 进行解析和路由。
  3. ShardingSphere-Proxy 根据业务逻辑将 SQL 请求路由到不同的数据库或表。
  4. ShardingSphere-Proxy 收集各个数据库返回的结果,并将结果整合后再返回给应用程序。

ShardingSphere-Sidecar

ShardingSphere-Sidecar 的目标是利用云原生技术(如 Kubernetes、Istio 等)来实现数据库层面的弹性扩展、动态配置和服务治理,是为云环境下的分布式数据库管理量身定制的解决方案。

数据分片

【shardingsphere】功能介绍-数据分片

在Java服务中实现高效的数据分片与路由

【Spring】SpringBoot整合ShardingSphere并实现多线程分批插入10000条数据(进行分库分表操作)。

读写分离

读写分离,实际上就是将写操作路由到主数据库,而将读操作路由到从数据库

ShardingSphere实战(5)- 读写分离

分布式事务

在 ShardingSphere 中,除本地事务之外,还提供针对分布式事务的两种实现方案,分别是 XA 事务和柔性事务。这点可以从事务类型枚举值 TransactionType 中得到验证:

1
2
3
public enum TransactionType {
LOCAL, XA, BASE
}

XA 事务

[eXtended Architecture]

XA 事务提供基于两阶段提交协议的实现机制。所谓两阶段提交,顾名思义分成两个阶段,一个是准备阶段,一个是执行阶段。在准备阶段中,协调者发起一个提议,分别询问各参与者是否接受。在执行阶段,协调者根据参与者的反馈,提交或终止事务。如果参与者全部同意则提交,只要有一个参与者不同意就终止。

image-20240925221836310

XA 事务是典型的强一致性事务

BASE事务

BASE是与ACID(原子性、一致性、隔离性、持久性)相对的另一种事务处理理念。BASE是指基本可用(Basically Available)、软状态(Soft State)、最终一致性(Eventually Consistent)。相比于ACID,BASE更侧重于分布式系统的设计和实现。

举例说明:

假设有一个社交网络系统,用户可以发布动态并进行评论,系统需要保证用户发布的动态和评论在整个系统中是一致的,即保证最终一致性。

  • 当用户发布一条动态时,系统会首先将动态数据写入主数据库,并将动态数据复制到多个副本数据库中。
  • 同时,评论数据也会被写入主数据库和多个副本数据库。
  • 在用户发布动态后,在短时间内,不同用户在不同的副本数据库上查看该动态及评论可能会出现数据不一致的情况(软状态)。
  • 系统会异步地将数据进行同步,保证最终所有的副本数据库中的数据是一致的(最终一致性)。

数据脱敏

数据脱敏,是指对某些敏感信息通过脱敏规则进行数据转换,从而实现敏感隐私数据的可靠保护。

实现方式

  1. 配置规则:首先,需要在ShardingSphere的配置文件中定义数据脱敏规则,包括需要脱敏的字段、脱敏的方式(如替换、加密等)以及脱敏的规则。
  2. 数据处理:当数据库查询返回结果时,ShardingSphere会根据配置的规则对敏感数据进行脱敏处理,然后再将结果返回给用户。
  3. 保留原始数据:通常情况下,脱敏操作是在返回结果时进行的,原始数据仍然保存在数据库中,只有在返回给用户时才进行脱敏处理。

举例

假设有一个用户表(user)包含用户的姓名(name)、手机号(phone)、邮箱(email)等敏感信息,我们要对手机号和邮箱进行脱敏处理:

  • 配置规则:在ShardingSphere的配置文件中定义数据脱敏规则,指定对手机号和邮箱字段进行脱敏,可以选择使用星号遮蔽部分信息或者进行加密处理。
1
2
3
4
5
6
7
8
9
10
dataMasking:
rules:
- name: MaskPhone
columns:
- user.phone
encryptor: aes
- name: MaskEmail
columns:
- user.email
strategy: PARTIAL(2,'****',2)
  • 数据处理:当执行查询操作时,ShardingSphere会根据配置的规则对查询结果中的手机号和邮箱进行脱敏处理,然后返回给用户。

例如,原始数据:

1
2
3
| name   | phone         | email               |
|--------|---------------|---------------------|
| Alice | 12345678901 | alice@example.com |

经过ShardingSphere的数据脱敏处理后,返回给用户的结果可能是:

1
2
3
| name   | phone         | email               |
|--------|---------------|---------------------|
| Alice | 123****8901 | a****@example.com |

通过ShardingSphere的数据脱敏功能,可以有效保护用户的隐私数据,确保敏感信息在展示时不会泄露。

总结:常见的脱敏法

  1. 部分隐藏:部分隐藏是对敏感数据的部分内容进行遮蔽,常见的方式包括:
    • 部分脱敏:例如对手机号码只显示部分数字,如将中间几位数字用星号代替。
    • 部分替换:例如对邮件地址只显示部分字符,如用星号代替一部分字符。
    • 部分加密:对敏感数据进行部分加密,展示给用户时进行解密。
  2. 完全隐藏:完全隐藏是对整个敏感数据进行隐藏,不显示原始数据,常见的方式包括:
    • 完全脱敏:直接将敏感数据完全删除或替换为固定的值(如NULL)。
    • 完全加密:对整个敏感数据进行加密,展示给用户时进行解密。
  3. 数据扰动:数据扰动是对敏感数据进行混淆处理,以使原始数据难以被还原,常见的方式包括:
    • 数据乱序:对数据进行随机排序,打乱原始数据的顺序。
    • 数据混淆:对数据进行随机替换或加入噪音数据,使数据失去原始的含义。
  4. 数据掩码:数据掩码是对敏感数据进行掩盖处理,以保护数据的隐私,常见的方式包括:
    • 数据掩码:使用特定的掩码字符(如星号)来代替敏感数据,以隐藏真实数据。
    • 数据加密:对敏感数据进行加密处理,只有具有解密权限的用户才能查看原始数据。
  5. 数据一致性保护:在进行数据脱敏时,需要确保脱敏后的数据仍然保持一定的数据一致性,以避免数据泄漏。