【Java超高频面试题&深入探讨数据库优化-多机优化】数据库优化相关超详细解说

简介:

本期文章将深入探讨数据库优化,给学习数据库优化的兄弟姐妹们一起进步,给最近需要找工作的朋友们总结一波,帮助大家全面掌握数据库优化的核心知识点,提升竞争力,吊打面试官!

⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐


一.CAP&Base理论⭐

1.集群和分布式

1.1.什么是分布式系统

简单理解分布式就是一个计算机软件系统有多个子系统组成,每个子系统承担着部分职责,分别部署在不同的服务器上,子系统之间通过网络进行交互,共同完成完整的工作,缺一不可。 - 组合

分布式系统通常用于提高系统的可扩展性容错性性能

优点
  1. 解决高并发
  2. 解决代码臃肿
  3. 可以局部扩展集群
1.2.什么是集群

简单理解集群就是把一个计算机软件系统,部署成多份(复制)来提供工作能力,多个软件系统分别部署在不同的服务器上,每个服务器我们称之为节点,服务器之间无需通信,每个软件系统(节点)都是完整的功能。- 复制

用多个tomcat部署项目

  1. 解决单机故障和高并发
负载均衡

当我们的应用做了集群,那么就会存在多个应用节点,多个应用将会暴露多个访问地址(ip:port),那客户端是不知道该访问哪个应用节点的,这个时候我们就需要有一个请求分发的功能的组件(负载均衡器)将客户端的请求相对平均的分发多个应用节点上,这就是负载均衡

负载均衡: nginx的负载均衡器,它可以按照某种算法(轮询,ip_hash等等)将请求路由到不同的后端服务器上。

负载均衡算法如:轮询,随机,权重,ip_hash,url_hash。

2.CAP理论

2.1.什么是CAP
  • 一致性(Consistency)

    可以理解为分布式中存在多个数据副本,当其中某个数据副本发生数据更新需要实时同步到其他节点上。多个节点数据总是保持一致。例如:同一个数据同时存在于A服务器和B服务器,那么当A服务器的数据发生改变,B服务器的数据始终保持同步。

  • 可用性(Availability)

    客户端在任何时候访问集群,请求都可以正常返回结果,可以允许有一定的延迟。

  • 分区容错性(Partition tolerance)

    能够容忍当服务之间通信发生故障,整个集群别分割为多个无法相互通信的分区的情况。即当集群因为网络故障被划分为多个分区,集群仍然可用。

        CAP 理论为分布式系统的设计提供了一个重要的思考框架,它提醒我们在设计分布式系统时,必须在一致性、可用性和分区容错性之间做出权衡和选择。了解这些权衡并结合实际业务需求做出合适的设计决策,是构建高效、可靠分布式系统的基础。

2.2.常见CAP组合

定理:任何分布式系统只可同时满足二点,没法三者兼顾。

忠告:架构师不要将精力浪费在如何设计能满足三者的完美分布式系统,而是应该进行取舍。

 

1、满足CA舍弃P,也就是满足一致性和可用性,舍弃容错性。但是这也就意味着你的系统不是分布式的了,因为涉及分布式的想法就是把功能分开,部署到不同的机器上。

2、满足CP舍弃A,也就是满足一致性和容错性,舍弃可用性。如果你的系统允许有段时间的访问失效等问题,这个是可以满足的。就好比多个人并发买票,后台网络出现故障,你买的时候系统就崩溃了。 redis.set(key,value) 当我在进行操作的时候其他的要进行等待或者超时异常:如 Redis zk consol nacas

3、满足AP舍弃C,也就是满足可用性和容错性,舍弃一致性。这也就是意味着你的系统在并发访问的时候可能会出现数据不一致的情况。

3.Base理论

3.1.强一致性和最终一致性

   CAP理论告诉我们一个分布式系统最多只能同时满足一致性( Consistency)、可用性( Availability )和分区容忍性( Partition tolerance )这三项中的两项,

   其中AP在实际应用中较多, AP即舍弃一致性,保证可用性和分区容忍性,但是在实际生产中很多场景都要实现最终一致性,比如前边我们举的例子主节点向从节点同步数据,即使不要一致性,

   但是最终也要将数据同步成功来保证数据一致,这种一致性和CAP中的一致性不同, CAP中的一致性要求在任何时间查询每个结点数据都必须一致,它强调的是强一致性,但是最终一致性是允许可以在一段时间内每个结点的数据不一致,但是经过一段时间每个结点的数据必须一致,它强调的是最终一致性。

1、强一致性

对于关系型数据库,要求更新过的数据能被后续的访问都能看到,这是强一致性。比如小明更新V0到V1,那么小华读取的时候也应该是V1。

2、弱一致性

如果能容忍后续的部分或者全部访问不到,则是弱一致性。比如小明更新VO到V1,可以容忍那么小华读取的时候是V0。

3、最终一致性

如果经过一段时间后要求能访问到更新后的数据,则是最终一致性。比如小明更新VO到V1,可以使得小华在一段时间之后读取的时候是V1。

分布式系统通常为了保证系统的可用性,牺牲强一致性,采用最终一致性。

3.2.Base理论

BASE理论是针对CAP理论的一个补充概念,它提供了一种在分布式系统中处理数据一致性问题的不同方法。BASE理论的全称是 Basically Available, Soft state, Eventual consistency,即基本可用、软状态、最终一致性。它与CAP理论中的AP系统(可用性+分区容错性)相对应,是对CAP理论中一致性(C)和可用性(A)权衡的进一步解释和应用。

1. 基本可用(Basically Available)

  • 定义:系统在出现不可预见的故障时,仍然能够保证基本的可用性,而不是完全不可用。

  • 说明:基本可用意味着即使在某些情况下系统无法完全正常工作,它依然可以提供部分服务或降低性能的服务。例如,在高峰期,系统可能会延迟响应时间或者部分功能被降级,但整体系统仍然可用。

2. 软状态(Soft State)

  • 定义:系统中的状态可以在不接收输入的情况下改变,允许存在中间状态,且系统的状态不必是强一致的。

  • 说明:在BASE模型中,系统的状态并不是永久固定的,而是可能处于一种未完全一致的中间状态。这种软状态允许系统数据在不同节点之间存在暂时的不一致性,随着时间的推移,通过数据同步和协调机制,逐步达到最终一致性。

3. 最终一致性(Eventual Consistency)

  • 定义:系统确保所有节点的数据在经过一段时间后会达到一致状态,即最终一致。

  • 说明:最终一致性是指系统不要求数据在任何时间点上都保持一致,而是允许在一定的时间窗口内存在不一致性,系统会通过异步复制和数据同步机制,最终使所有节点的数据达到一致。这种一致性保证了系统在一定的延迟后,数据仍然能够达到一致的状态,而不会永远处于不一致状态。

二.Mysql主从复制⭐

1.Mysql集群概述

1.1.为什么要做Mysql集群

1、提高并发能力

2、提高可用性,防止单点故障

3、防止数据丢失

1.2.集群方案

集群:多个服务器一起对外提供一个服务。是一种特殊分布式。

Mysql集群有N种方式,我们这里选择主从模式,因为根据2/8原则,数据库的性能瓶颈往往都在80%的读操作上,我们需要减轻读的压力

1.3.什么是Mysql主从?

一个主(Master)多从(Slave),主负责写操作,从负责读操作,从库的数据从主库同步复制,这样的集群模式就主从同步 。主从复制MySql自己就能完成,我们需要做一些配置即可。

主从同步的有点是减轻读的压力,如果主库的写并发比较高或者为了解决主库单点故障,可用做成多个主库,多个主库相互复制,这样即提高了主库写的并发能力,也解决了单节点故障问题。

做了主从同步,我们的应用就需要做读写分离,写请求访问主库,读请求访问主/从库,可以借助一些框架来实现读写分离,如:msyqlproxy , mycat ,ShardingJdbc ,如下图:

2.Mysql主从

2.1.Mysql主从复制原理

主从复制是通过重放binlog实现主库数据的异步复制。即当主库执行了一条sql命令,那么在从库同样的执行一遍,从而达到主从复制的效果

主从复制步骤:

  1. 将Master的binary-log日志文件打开,mysql会把所有的DDL,DML,TCL写入BinaryLog日志文件中

  2. Master会生成一个 log dump 线程,用来给从库的 i/o线程传binlog

  3. 从库的i/o线程去请求主库的binlog,并将得到的binlog日志写到中继日志(relaylog)中

  4. 从库的sql线程,会读取relaylog文件中的日志,并解析成具体操作,通过主从的操作一致,而达到最终数据一致

2.2.准备环境

至少需要两台服务器,以后肯定是独立两台电脑,当然也可以使用虚拟机. 教学的时候,可以安装多个服务(使用不同的端口)来代替服务器.

1、分别构造主、从数据库并输出日志(方便定位问题)

  • 关闭MySql服务

  • 拷贝mysql安装目录,重命名:master

  • 修改新的Mysql的my.ini配置:端口,日志目录,安装目录,数据目录

  • 拷贝数据:去老的MySql的数据目录拷贝 data\mysql 和 data\performance_schema 到新的MySql的数据目录,这个是MySql的初始化数据。在my.ini中datadir就是数据目录第位置

2、安装及启动

  • 修改master中的my.ini 路径改为master的路径

  • 执行命令安装新的Mysql的服务 ,进入bin目录,cmd执行

mysqld --install master --defaults-file="C:\Program Files (x86)\MySQL\master\my.ini"

(install/remove of the service denied 权限不足 以管理身份运行cmd.exe)

2.3.master服务器配置

1. 修改master方的my.ini,在[mysqld]下

log-bin=mysql-bin
server-id=1

innodb_flush_log_at_trx_commit=1
sync_binlog=1
binlog_ignore_db=mysql
binlog_checksum=none

2. 重启master服务,登录

3. 授权savle服务器的使用的账号及权限

Mysql> GRANT REPLICATION SLAVE ON *.* to 'slaveuser'@'172.16.6.254'identified by '123456';

参数说明:

  • lvtest:slave连接master使用的账号

  • IDENTIFIED BY 'admin' :slave连接master使用的密码

  • 192.168.77.128:slave IP

4. 查询主数据库状态

Mysql> show master status;

记录 File 和 Position的值,File对应的是binlog文件 , position指的是当前slave同步数据的最新行。在slave端会使用这两个信息。

2.4.slave配置

1、修改slave服务器的配置文件my.ini将 server-id = 1修改为 server-id = 10,并确保这个ID没有被别的MySQL服务所使用。

log-bin=mysql-bin
server-id=2

2、启动slave服务器,登录

3、在slave端,配置master链接信息 (执行语句)

Mysql>  change master to
        master_host='172.16.6.254',   #master IP
        master_user='slaveuser',          #master数据库通过GRANT授权的账号
        master_password='123456',         #master数据库通过GRANT授权的密码
        master_port=3307,              #master数据库的端口
        master_log_file='mysql-bin.000001', 
        #master数据库中通过show master status显示的File名称
        master_log_pos=269         
        #master数据库的通过show master status显示的Position的值

4、启动同步

 Mysql> start slave;

5、主从同步检查

show slave status;

其中Slave_IO_Running 与 Slave_SQL_Running 的值都必须为YES,才表明状态正常。

6、 测试

  • 在master上,建库、建表、添加数据

  • 刷新slave库,记录也存在

由此,整个MySQL主从复制的过程就完成了,接下来,我们进行MySQL读写分离的安装与配置。

三.分库分表实战⭐

1.分库分表认识

1.1.垂直分表-宽表拆分

垂直分表可以理解成按列分表,比如一个用户表中包括了 用户登录相关信息,用户基本资料,用户账户信息等等信息,这个表字段太多变得非常庞大,查询的时候必定会有性能影响。

t_user

再加上我们在查询的时候不会把用户的所有数据都要查出来,做登录时只需要登录相关字段,查询个人资料时就只需要基本信息,加载账户的时候只需要账户相关的字段,但是所有字段都在一个表浪费了查询的性能。针对于这种情况我们可以按照业务维度进行垂直分表,每个表有不同的列,如:

t_login

t_user_info

t_account

上面的分表的方式就是垂直分表 , 多个包之间外键关联,如果表关系是一对一,使用相同的ID也可以。

1.2.垂直分库-按业务分库

一个mysql服务,要安装在一台服务器上面,这台服务器资源(内存,cpu等)是有限的.当数据库的并发请求非常高。

一个mysql数据处理不了就可以考虑使用多个mysql服务来分担压力,垂直分库就是把一个数据库中的N张表,按照模块/业务 划分到多个Mysql数据库,每个数据库都有自己的服务器,进行分布式部署。

[注意]微服务架构:天然就是分库. 它要求各自服务都要有自己数据库服务器.

2.水平分库分表-海量表拆分小表

2.1.水平分表

水平分表可以理解成按行分表,一个表中的数据量一千万行,查询注定慢,我们可以把这个表中的数据拆分成10个小表,每个表一百万行数据,每个小表拥有相同的列

水平分表会带来很多的问题?比如按什么规则来分表,场景的分表规则有:

1. 按区间范围分表

一般在有严格的自增id需求上,如按照user_id水平分表:

  • table_1 user_id从1~100w

  • table_2 user_id从101~200w

  • table_3 user_id从201~300w

实现方式有:

  • 新创建一个表,该表的自增ID作为分表的ID(性能差)

  • 使用Redis的自增incr 命令

  • 使用UUID(比较low)

2. 按时间分表

比如一个月分一个表,那么一年也就分12张表 ,这种方式适用于时效性很强的场景,比如登录日志,一般都是看最近一个月的日志,很少去看一月前的,或者一年前的。甚至更老旧的数据可以直接删掉。

3. Hash分表

通过ID或者名称通过一定的hash算法计算出数据存储表的表名然后访问相应的表,这种方法比较通用

比如:准备好100个表 : t_course_01 , t_course_02, ... ,t_course_100

然后计算:hash(商品名+id) % 100 +1 ,余数就对应表名

4. 雪花算法

nowflake,雪花算法是由Twitter开源的分布式ID生成算法,以划分命名空间的方式将 64-bit位分割 成多个部分,每个部分代表不同的含义(41位时间戳,10位机器号,12位序列号)。而 Java中64bit的整数是Long类型,所以在 Java 中 SnowFlake 算法生成的 ID 就是 long 来存储的

2.2.水平分库

即使做了水平分表,表太多也会影响数据库的效率,水平分库指定是把一个数据库中的表分到多个数据库中,数据库采用分布式部署,比如电商平台针对于商品库我们可以按照商户来分,如下:

最NB方案:垂直分库 ;水平分库 ;水平分表 ; 垂直分表 ;集群(主从同步&读写分离)

分库分表操作思路:

1 按照业务进行垂直分库 商品和店铺隔离开来 微服务架构都要这样干

2 把商品业务进行水平分库 多个商品库服务器

3 可以对水平分库后每一个数据库服务器进行集群. 多个商品库服务器群

4 进行垂直分表 把多字段表拆分少量字段表. 每一个库里面宽表进行拆分

5 进行水平分表 把海量数据表拆分为多个小表 把每一个大表进行拆分

数据库优化顺序 : 垂直分表,索引,SQL优化 ,冗余设计,缓存(热点查询),全文检索(搜索场景),主从(读压力大),垂直分库 ,水平分库,水平分表- 分布式项目可以直接考虑垂直分库

先垂直+集群+优化技术能搞定就不要水平操作,因为操作比较复杂,要一定的分库分表策略。 实在满足不了,可以是使用水平操作。

3.分库分表后问题

3.1.分布式事务-垂直分库

分库后会带来一些棘手的问题:一个操作设计到多个库的话需要有分布式事务的支持

1、单数据库实例:

2、多数据库实例:

3.2.跨库操作查询-垂直分库

一个查询的数据来源于两个库,那么需要从两个库进行查询

如果是同一个库,直接宽表查询就ok,但是不同的库,想要查询商品库里面的商品信息,通过商品信息里面的商铺id到商铺库里面查询。

3.3.跨节点操作排序分页-水平分库

一个分页查询,正好某一页的数据来源于两个库,那么需要先对两个库的数据进行合并之后,在再执行SQL进行查询操作(复制,性能不好)

3.4.主键重复

如果水平分表之后,每个表ID都是自动增长,就会出现 商品表A的ID和商品表B的ID出现重复,需要使用全局唯一ID即:分布式ID,比如使用雪花算法来实现。

3.5.公共表

如果两个库都有用到某个表,该如何处理?两个库都放这个表,使用ShardingJDBC设置公共表

一切以上的问题可以直接解决,当然也可以通过三方框架实现 sharding-jdbc

3.6.水平分库分表效率说明

一定能提高效率吗? 水平分库分表在操作之前要通过分库分表策略进行计算后再来操作。这个过程也要浪费时间。如果数据量少,没有必要水平分表分库.。1亿左右

4.分库分表&集群方案

4.1.集群-主从同步,读写分离

主从同步由mysql自己实现,但是读写分离需要三方组件支持。

4.2.分库分表-垂直方向-设计层面

当做一个独立的表或者库处理就ok,微服务架构中,都是进行了分库的。

4.3.分库分表-水平方向

需要计算库,和计算表,也要三方组件支持。我们只需要实现水平分表和水平分库及读写分离。

4.4.组件选择

1) sharding-sphere:jar,前身是sharding-jdbc;分库分表,读写分离,当当网开源框架,文档丰富,使用成本低。

2) TDDL:jar,Taobao Distribute Data Layer;淘宝业务框架,TDDL复杂度相对较高。当前公布的文档较少,只开源动态数据源,分表分库部分还未开源,还需要依赖diamond,不推荐使用。

3) Mycat:中间件。 使用起来比较复杂,需要安装额外的环境,不稳定,第三方应用,考虑中间件备份与集群

4) Mysql-proxy(基本淘汰):mysql-proxy是官方提供的mysql中间件产品可以实现负载平衡,读写分离,failover等,但其不支持大数据量的分库分表且性能较差。

5.Sharding-sphere简介

5.1.什么是Sharding-sphere

官网:Apache ShardingSphere

Apache ShardingSphere 是一套开源的分布式数据库中间件解决方案组成的生态圈,它由 JDBC、Proxy 和 Sidecar(规划中)这 3 款相互独立,却又能够混合部署配合使用的产品组成。 它们均提供标准化的数据分片、分布式事务和数据库治理功能,可适用于如 Java 同构、异构语言、云原生等各种多样化的应用场景。

Apache ShardingSphere 定位为关系型数据库中间件,旨在充分合理地在分布式的场景下利用关系型数据库的计算和存储能力,而并非实现一个全新的关系型数据库。 它通过关注不变,进而抓住事物本质。关系型数据库当今依然占有巨大市场,是各个公司核心业务的基石,未来也难于撼动,我们目前阶段更加关注在原有基础上的增量,而非颠覆。

Apache ShardingSphere 5.x 版本开始致力于可插拔架构,项目的功能组件能够灵活的以可插拔的方式进行扩展。 目前,数据分片、读写分离、多数据副本、数据加密、影子库压测等功能,以及 MySQL、PostgreSQL、SQLServer、Oracle 等 SQL 与协议的支持,均通过插件的方式织入项目。 开发者能够像使用积木一样定制属于自己的独特系统。Apache ShardingSphere 目前已提供数十个 SPI 作为系统的扩展点,仍在不断增加中。

ShardingSphere 已于2020年4月16日成为 Apache 软件基金会的顶级项目。

Sharding-sphere是一个关系型数据的分布式中间件。有三个部分组成,sharding-jdbc(JAVA),sharding-proxy(异构系统),Sharding-Sidecar(云原声)。

5.2.Sharding-jdbc

sharding-jdbc 是一个开源的适用于微服务的分布式数据访问基础类库(jar),它始终以云原生的基础开发套件为目标。只支持java语言

sharding-jdbc定位为轻量级java框架,使用客户端直连数据库,以jar包的形式提供服务,未使用中间层,无需额外部署,并无其他依赖,,可以理解为增强版的JDBC驱动

sharding-jdbc完整的实现了分库分表/读写分离/分布式主键功能,并实现了柔性事务.特点如下:

  • 适用于任何基于Java的ORM框架,如:JPA, Hibernate, Mybatis, Spring JDBC Template或直接使用JDBC。

  • 基于任何第三方的数据库连接池,如:DBCP, C3P0, BoneCP, Druid, HikariCP等。

  • 支持任意实现JDBC规范的数据库。目前支持MySQL,Oracle,SQLServer和PostgreSQL。

5.3.Sharding-Proxy-支持多语言

定位为透明化的数据库代理端,提供封装了数据库二进制协议的服务端版本,用于完成对异构语言的支持。 目前先提供MySQL版本,它可以使用任何兼容MySQL协议的访问客户端(如:MySQL Command Client, MySQL Workbench等)操作数据,对DBA更加友好。

5.4.Sharding-Sidecar

定位为Kubernetes(k8s)或Mesos的云原生数据库代理,以DaemonSet的形式代理所有对数据库的访问。 通过无中心、零侵入的方案提供与数据库交互的的啮合层,即Database Mesh,又可称数据网格。

6.ShardingJDBC实战

6.1.集成ShardingJDBC

配置文档:Sharding-JDBC :: ShardingSphere

<!-- 引入shardingjdbc -->
<dependency>
    <groupId>org.apache.shardingsphere</groupId>
    <artifactId>sharding-jdbc-spring-boot-starter</artifactId>
   <!-- <version>4.0.0-RC1</version> -->
    <version>4.1.1</version>
</dependency>

<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid</artifactId>
    <version>1.2.6</version>
</dependency>

注意:要使用 druid 而不是 druid-spring-boot-starter , 如果非要使用 druid-spring-boot-starter 那就需要通过:@SpringBootApplication(exclude={DruidDataSourceAutoConfigure.class}) 把datasource的自动配置排除

6.2.读写分离

配置多数据源,把配置改成如下效果:

#主从数据库的名字
spring.shardingsphere.datasource.names=master,slave0

#主数据的链接信息
spring.shardingsphere.datasource.master.type=com.alibaba.druid.pool.DruidDataSource
#spring.shardingsphere.datasource.master.type=org.apache.commons.dbcp2.BasicDataSource
spring.shardingsphere.datasource.master.driver-class-name=com.mysql.jdbc.Driver
spring.shardingsphere.datasource.master.url=jdbc:mysql://localhost:3307/hrm-course
spring.shardingsphere.datasource.master.username=root
spring.shardingsphere.datasource.master.password=123456

#从数据库的链接 信息
spring.shardingsphere.datasource.slave0.type=com.alibaba.druid.pool.DruidDataSource
spring.shardingsphere.datasource.slave0.driver-class-name=com.mysql.jdbc.Driver
spring.shardingsphere.datasource.slave0.url=jdbc:mysql://localhost:3308/hrm-course
spring.shardingsphere.datasource.slave0.username=root
spring.shardingsphere.datasource.slave0.password=123456

#从数据库的负载均衡
spring.shardingsphere.masterslave.load-balance-algorithm-type=round_robin
#集群名字
spring.shardingsphere.masterslave.name=ms
#主数据库名字
spring.shardingsphere.masterslave.master-data-source-name=master
#多个从数据名字,逗号分隔
spring.shardingsphere.masterslave.slave-data-source-names=slave0
#是否打印sql
spring.shardingsphere.props.sql.show=true

不再以默认的方式配置DataSource,而是以spring.shardingsphere前缀配置datasource,项目依然可以使用datasource

测试 : 分别执行写操作和读操作,观察控制台日志:

强制走主库

在方法执行前设置主库查询设置 HintManager.getInstance().setMasterRouteOnly();业务方法执行后执行HintmanagerHolder.clear(),取消对主库查询的强制路由。

6.3.分库分表算法

sharding-jdbc 提供了多种分片算法:

提供了抽象分片算法类:ShardingAlgorithm,根据类型又分为:精确分片算法、区间分片算法、复合分片算法以及Hint分片算法;

  • 精确分片算法:对应PreciseShardingAlgorithm类,主要用于处理 = 和 IN的分片;

  • 区间分片算法:对应RangeShardingAlgorithm类,主要用于处理 BETWEEN AND, >, <, >=, <= 分片;

  • 复合分片算法:对应ComplexKeysShardingAlgorithm类,用于处理使用多键作为分片键进行分片的场景;

  • Hint分片算法:对应HintShardingAlgorithm类,用于处理使用 Hint 行分片的场景;

6.4.ShardingJDBC的分片策略

整个ShardingJDBC 分库分表的核心就是在于配置 分片策略+分片算法

最常用的是使用的inline分片算法,即提供一个分片键和一个分片表达式来制定分片算法。

这种方式配置简单,功能灵活,是分库分表最佳的配置方式,并且对于绝大多数的分库分片场景来说,都已经非常好用了。

但是,如果针对一些更为复杂的分片策略,例如多分片键、按范围分片等场景,inline分片算法就有点力不从心了。

所以,我们还需要学习下ShardingSphere提供的其他几种分片策略。ShardingSphere目前提供了一共五种分片策略:

  1. inline(行表达式分片策略) - 根据单一分片键进行精确分片 ,是最常用最简单的分片策略。使用Groovy的表达式,提供对SQL语句中的=和IN的分片操作支持,只支持单分片键。对于简单的分片算法,可以通过简单的配置使用,从而避免繁琐的Java代码开发,如: user_$->{u_id % 8} 表示t_user表根据u_id模8,而分成8张表,表名称为user_0到user_7。

    • 对应InlineShardingStrategy

  2. standard(标准分片策略) - 根据单一分片键进行精确或者范围分片,对应StandardShardingStrategy,支持精确和范围分片,提供对SQL语句中的=,IN,BETWEEN AND、>、<、>=、<=的分片操作支持。

    • 精确分片算法接口: PreciseShardingAlgorithm, 必选的,用于处理=和IN的分片

    • 范围分片算法接口: RangeShardingAlgorithm,用于处理BETWEEN AND, >, <, >=, <=分片

  3. complex(复合分片策略) :对应ComplexKeysShardingAlgorithm,用于处理使用多键作为分片键进行分片的场景,包含多个分片键的逻辑较复杂,需要应用开发者自行处理其中的逻辑,需要配合ComplexShardingStrategy使用。

    • 复合分片算法接口: ComplexKeysShardingAlgorithm

  4. hint策略 - 使用与sql无关的方式进行分片,对应HintShardingStrategy。通过Hint指定分片值而非从SQL中提取分片值的方式进行分片的策略

    • hint分片算法接口: HintShardingAlgorithm

  5. Hash Sharding Strategy哈希分片策略:哈希分片策略通过哈希算法对分片键进行计算,将数据均匀分布到多个节点。

        适用场景:适用于数据分布较为均匀的场景,可以防止数据热点问题,因为哈希算法能够将数据均匀散列到各个分片中。
        实现方式:使用分片键的哈希值作为路由依据,将数据分配到不同的数据库或表。

6.5.分库分表-水平方向

数据库改造:数据库改造,按照 tenant_id 分库,按照课程的 id 水平分表,使用雪花算法 ,表结构如下

两个库一样 ,t_course_type是公共表

application.properties配置

#datasource的名字,有几个数据源就写几个名字,和url中的数据库名字保持一致
spring.shardingsphere.datasource.names=hrm-course1,hrm-course2
spring.shardingsphere.datasource.hrm-course1.type=com.alibaba.druid.pool.DruidDataSource
spring.shardingsphere.datasource.hrm-course1.driver-class-name=com.mysql.jdbc.Driver
spring.shardingsphere.datasource.hrm-course1.url=jdbc:mysql://localhost:3307/hrm-course1
spring.shardingsphere.datasource.hrm-course1.username=root
spring.shardingsphere.datasource.hrm-course1.password=123456

spring.shardingsphere.datasource.hrm-course2.type=com.alibaba.druid.pool.DruidDataSource
spring.shardingsphere.datasource.hrm-course2.driver-class-name=com.mysql.jdbc.Driver
spring.shardingsphere.datasource.hrm-course2.url=jdbc:mysql://localhost:3307/hrm-course2
spring.shardingsphere.datasource.hrm-course2.username=root
spring.shardingsphere.datasource.hrm-course2.password=123456

#分库策略================================================================================================================
# tenant_id  =  110  % 2 + 1 = 1

spring.shardingsphere.sharding.default-database-strategy.inline.sharding-column=tenant_id
spring.shardingsphere.sharding.default-database-strategy.inline.algorithm-expression=hrm-course$->{tenant_id % 2 + 1}

#分表策略================================================================================================================

hrm-course1.t_course1  ;
hrm-course1.t_course2


hrm-course2.t_course1
hrm-course2.t_course2
#按照order_id 分表
spring.shardingsphere.sharding.tables.t_course.actual-data-nodes=hrm-course$->{1..2}.t_course$->{1..2}
#对order_id进行分表
spring.shardingsphere.sharding.tables.t_course.table-strategy.inline.sharding-column=id
spring.shardingsphere.sharding.tables.t_course.table-strategy.inline.algorithm-expression=t_course$->{id % 2 + 1}
#主键生成策略,order_id使用雪花算法
spring.shardingsphere.sharding.tables.t_course.key-generator.column=id
spring.shardingsphere.sharding.tables.t_course.key-generator.type=SNOWFLAKE
#=================================================================================================================================
spring.shardingsphere.sharding.tables.t_course_detail.actual-data-nodes=hrm-course$->{1..2}.t_course_detail$->{1..2}
#对order_id进行分表
spring.shardingsphere.sharding.tables.t_course_detail.table-strategy.inline.sharding-column=id
spring.shardingsphere.sharding.tables.t_course_detail.table-strategy.inline.algorithm-expression=t_course_detail$->{id % 2 + 1}
#主键生成策略,order_id使用雪花算法
spring.shardingsphere.sharding.tables.t_course_detail.key-generator.column=id
spring.shardingsphere.sharding.tables.t_course_detail.key-generator.type=SNOWFLAKE
#=================================================================================================================================
spring.shardingsphere.sharding.tables.t_course_market.actual-data-nodes=hrm-course$->{1..2}.t_course_market$->{1..2}
#对order_id进行分表
spring.shardingsphere.sharding.tables.t_course_market.table-strategy.inline.sharding-column=id
spring.shardingsphere.sharding.tables.t_course_market.table-strategy.inline.algorithm-expression=t_course_market$->{id % 2 + 1}
#主键生成策略,order_id使用雪花算法
spring.shardingsphere.sharding.tables.t_course_market.key-generator.column=id
spring.shardingsphere.sharding.tables.t_course_market.key-generator.type=SNOWFLAKE
#=================================================================================================================================
spring.shardingsphere.sharding.tables.t_course_resource.actual-data-nodes=hrm-course$->{1..2}.t_course_resource$->{1..2}
#对order_id进行分表
spring.shardingsphere.sharding.tables.t_course_resource.table-strategy.inline.sharding-column=id
spring.shardingsphere.sharding.tables.t_course_resource.table-strategy.inline.algorithm-expression=t_course_resource$->{id % 2 + 1}
#主键生成策略,order_id使用雪花算法
spring.shardingsphere.sharding.tables.t_course_resource.key-generator.column=id
spring.shardingsphere.sharding.tables.t_course_resource.key-generator.type=SNOWFLAKE
#==================================================================================================================================
#这个是绑定的表,不加后缀
spring.shardingsphere.sharding.binding-tables=t_course,t_course_detail,t_course_market,t_course_resource
#公共的表
spring.shardingsphere.sharding.broadcast-tables=t_course_type
#是否打印sql
spring.shardingsphere.props.sql.show=true

配置分片规则ShardingRuleConfiguration,包括多种配置规则:

表规则配置、绑定表配置、广播表配置、默认数据源名称、默认数据库分片策略、默认表分片策略、默认主键生成策略、主从规则配置、加密规则配置;

  • 表规则配置 tableRuleConfigs:也就是上面配置的库分片策略和表分片策略,也是最常用的配置;

  • 绑定表配置 bindingTableGroups:指分⽚规则⼀致的主表和⼦表;绑定表之间的多表关联查询不会出现笛卡尔积关联,关联查询效率将⼤⼤提升;

  • 广播表配置 broadcastTables:所有的分⽚数据源中都存在的表,表结构和表中的数据在每个数据库中均完全⼀致。适⽤于数据量不⼤且需要与海量数据的表进⾏关联查询的场景;

  • 默认数据源名称 defaultDataSourceName:未配置分片的表将通过默认数据源定位;

  • 默认数据库分片策略 defaultDatabaseShardingStrategyConfig:表规则配置可以设置数据库分片策略,如果没有配置可以在这里面配置默认的;

  • 默认表分片策略 defaultTableShardingStrategyConfig:表规则配置可以设置表分片策略,如果没有配置可以在这里面配置默认的;

  • 默认主键生成策略 defaultKeyGeneratorConfig:表规则配置可以设置主键生成策略,如果没有配置可以在这里面配置默认的;内置UUID、SNOWFLAKE生成器;

  • 主从规则配置 masterSlaveRuleConfigs:用来实现读写分离的,可配置一个主表多个从表,读面对多个从库可以配置负载均衡策略;

  • 加密规则配置 encryptRuleConfig:提供了对某些敏感数据进行加密的功能,提供了⼀套完整、安全、透明化、低改造成本的数据加密整合解决⽅案;

6.6.注意

你可能会踩的坑

1.2个库中的表都是一样的 t_order0 , t_order1

  1. 注意表名和库名,是中划线还是下划线

  2. Insert的SQL中是不需要为分表的字段添加值的

  3. 配置文件不要写错,核对核对再核对 ,datasource的名字和数据库的名字保持一致

分库分表的列就不要自动递增了,也不要主键了


结语

🔥如果文章对你有帮助的话,欢迎💗关注、👍点赞、⭐收藏、✍️评论,支持一下小老弟,蟹蟹大咖们~ 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值