分布式专题——10.4 ShardingSphere-Proxy服务端分库分表

1 为什么要有服务端分库分表?

  • ShardingSphere-Proxy 是 ShardingSphere 提供的服务端分库分表工具,定位是“透明化的数据库代理”。

    • 它模拟 MySQL 或 PostgreSQL 的数据库服务,应用程序(Application)只需像访问单个数据库一样访问 ShardingSphere-Proxy;

    • 实际的分库分表逻辑,由 ShardingSphere-Proxy 在代理层完成,对应用程序完全透明;

      在这里插入图片描述

  • ShardingSphere-JDBC 已经能实现分库分表,为什么还需要 ShardingSphere-Proxy?

    • 对 ORM 框架更友好

      • ShardingSphere-JDBC 的问题:需要在业务代码中直接写分库分表逻辑(比如代码里写:数据该路由到哪个库/表)。如果项目用了 ORM 框架(如 MyBatis、Hibernate),这种代码侵入式的逻辑容易和 ORM 冲突;

      • ShardingSphere-Proxy 的解决:作为第三方服务端代理,分库分表逻辑在代理层(ShardingSphere-Proxy)处理,应用程序完全不用关心。应用只需按访问单库的方式写代码,无缝对接 ORM 框架;

    • 对 DBA(数据库管理员)更友好

      • ShardingSphere-JDBC 的问题:DBA 要管理分库分表后的数据库,得先了解 ShardingSphere 的专属功能和 API,学习成本高;

      • ShardingSphere-Proxy 的解决:对 DBA 完全透明。DBA 可以直接操作原始数据库(像平时管理 MySQL/PostgreSQL 一样),无需了解 ShardingSphere 的技术细节,简化了 DBA 的工作;

    • 避免业务代码侵入分库分表逻辑

      • ShardingSphere-JDBC 的问题:分库分表的规则配置(比如“按用户 ID 分库”的规则)要写在业务代码里,会让业务代码变得臃肿。如果规则变更(比如从“按用户 ID 分”改成“按订单 ID 分”),要修改大量业务代码,维护成本高;

      • ShardingSphere-Proxy 的解决:通过外部配置文件管理分库分表规则,业务代码完全不用关心这些逻辑。规则变更时,只需改配置,不影响业务代码;

    • 实现“无中心化”数据治理

      • ShardingSphere-JDBC 的局限:多数据源的治理(比如跨库监控、报警、统一管理)难以统一;

      • ShardingSphere-Proxy 的解决:多个数据源可以注册到同一个 ShardingSphere-Proxy 代理服务中。基于代理,能实现跨数据源的数据治理(比如统一监控、报警、数据管理),特别适合大规模微服务系统的运维。

2 基本使用

2.1 部署 ShardingSphere-Proxy

  • 下载并解压(注意不要有中文,此处选择的版本:Apache Archive Distribution Directory);

    在这里插入图片描述

  • ShardingSphere-Proxy 是一个典型的 Java 应用程序,解压后目录结构如下:

    在这里插入图片描述

  • 解压完成后,如果要连接 MySQL 数据库,那么需要手动将 JDBC 的驱动包mysql-connector-java-8.0.20.jar复制到 ShardingSphere-Proxy 的lib目录下(ShardingSphere-Proxy 默认只附带了 PostgreSQL 的 JDBC 驱动包,没有包含 MySQL 的 JDBC 驱动包);

  • 打开conf目录,在这个目录下就有 ShardingSphere-Proxy 的所有配置文件(不同版本的会不一样):

    在这里插入图片描述

  • 打开server.yaml,把其中的rules部分和props部分的注释取消:

    rules:# 权限控制规则配置- !AUTHORITYusers:# 定义用户权限:root用户可从任何主机(%)访问,拥有root角色;sharding用户可从任何主机访问,拥有sharding角色- root@%:root- sharding@:shardingprovider:# 权限提供者类型:ALL_PERMITTED表示允许所有操作(无权限限制)type: ALL_PERMITTED# 事务管理配置- !TRANSACTION# 默认事务类型:XA分布式事务defaultType: XA# 事务管理器提供者:Atomikos(一种XA事务管理器实现)providerType: Atomikos# SQL解析器配置- !SQL_PARSER# 启用SQL注释解析功能sqlCommentParseEnabled: truesqlStatementCache:# SQL语句缓存初始容量initialCapacity: 2000# SQL语句缓存最大容量maximumSize: 65535parseTreeCache:# 解析树缓存初始容量initialCapacity: 128# 解析树缓存最大容量maximumSize: 1024# 属性配置
    props:# 每个查询允许的最大连接数max-connections-size-per-query: 1# 内核线程池大小(默认无限制)kernel-executor-size: 16# 代理前端刷新阈值(网络数据包刷新条件)proxy-frontend-flush-threshold: 128# 是否启用Hint功能(强制路由提示)proxy-hint-enabled: false# 是否在日志中显示SQL语句sql-show: false# 是否启用表元数据一致性检查check-table-metadata-enabled: false# 代理后端查询获取大小:-1表示使用不同JDBC驱动程序的最小值proxy-backend-query-fetch-size: -1# 代理前端执行线程数:0表示由Netty自动决定proxy-frontend-executor-size: # 代理后端执行模式:OLAP(联机分析处理)或OLTP(联机事务处理)proxy-backend-executor-suitable: OLAP# 代理前端最大连接数:0或负数表示无限制proxy-frontend-max-connections: 0# SQL联邦查询类型:NONE(禁用),ORIGINAL(原始),ADVANCED(高级)sql-federation-type: NONE# 代理后端驱动类型:JDBC(标准)或ExperimentalVertx(实验性Vert.x)proxy-backend-driver-type: JDBC# 默认MySQL版本号(当缺少schema信息时使用)proxy-mysql-default-version: 8.0.20# 代理服务默认端口proxy-default-port: 3307# Netty网络连接后备队列长度proxy-netty-backlog: 1024
    
    • 注意:为了与 MySQL JDBC 的驱动包mysql-connector-java-8.0.20.jar兼容,将proxy-mysql-default-version修改为8.0.20
  • 启动:

    在这里插入图片描述

  • 然后就可以使用 MySQL 的客户端(比如 DataGrip)去连接 ShardingSphere-Proxy 了,且可以像用 MySQL 一样去使用 ShardingSphere-Proxy:

    mysql> show databases;
    +--------------------+
    | schema_name        |
    +--------------------+
    | shardingsphere     |
    | information_schema |
    | performance_schema |
    | mysql              |
    | sys                |
    +--------------------+
    5 rows in set (0.01 sec)mysql> use shardingsphere
    Database changed
    mysql> show tables;
    +---------------------------+------------+
    | Tables_in_shardingsphere  | Table_type |
    +---------------------------+------------+
    | sharding_table_statistics | BASE TABLE |
    +---------------------------+------------+
    1 row in set (0.01 sec)mysql> select * from sharding_table_statistics;
    Empty set (1.25 sec)
    
  • 不过要注意,此时 ShardingSphere-Proxy 只是一个虚拟库,所以并不能像 MySQL 一样去随意建表或修改数据,比如下面就建表失败:

    mysql> CREATE TABLE test  (id varchar(255) NOT NULL);
    Query OK, 0 rows affected (0.00 sec)mysql> select * from test;
    30000 - Unknown exception: At line 0, column 0: Object 'test' not found
    mysql> show tables;
    +---------------------------+------------+
    | Tables_in_shardingsphere  | Table_type |
    +---------------------------+------------+
    | sharding_table_statistics | BASE TABLE |
    +---------------------------+------------+
    1 row in set (0.01 sec)
    

2.2 常用的分库分表配置策略

  • 打开config-sharding.yaml,配置逻辑表course

    # 逻辑数据库名称(客户端连接时使用的虚拟数据库名)
    databaseName: sharding_db# 数据源配置(定义实际的后端数据库连接)
    dataSources:# 第一个数据源,命名为m0m0:# MySQL数据库连接URL,指向192.168.65.212服务器的3306端口,数据库名为shardingdb1url: jdbc:mysql://192.168.65.212:3306/shardingdb1?serverTimezone=UTC&useSSL=falseusername: rootpassword: root# 连接超时时间(毫秒)connectionTimeoutMilliseconds: 30000# 连接空闲超时时间(毫秒)idleTimeoutMilliseconds: 60000# 连接最大生命周期(毫秒)maxLifetimeMilliseconds: 1800000# 连接池最大大小maxPoolSize: 50# 连接池最小大小minPoolSize: 1# 第二个数据源,命名为m1m1:url: jdbc:mysql://192.168.65.212:3306/shardingdb2?serverTimezone=UTC&useSSL=falseusername: rootpassword: rootconnectionTimeoutMilliseconds: 30000idleTimeoutMilliseconds: 60000maxLifetimeMilliseconds: 1800000maxPoolSize: 50minPoolSize: 1# 分片规则配置
    rules:
    - !SHARDING  # 分片规则标识tables:# 配置course表的分片规则course:# 实际数据节点:分布在m0和m1数据库的course_1和course_2表中actualDataNodes: m${0..1}.course_${1..2}# 数据库分片策略databaseStrategy:standard:  # 标准分片策略shardingColumn: cid  # 分片列(根据此字段的值决定数据路由到哪个数据库)shardingAlgorithmName: course_db_alg  # 使用的分片算法名称# 表分片策略tableStrategy:standard:  # 标准分片策略shardingColumn: cid  # 分片列(根据此字段的值决定数据路由到哪个表)shardingAlgorithmName: course_tbl_alg  # 使用的分片算法名称# 主键生成策略keyGenerateStrategy:column: cid  # 需要生成主键的列名keyGeneratorName: alg_snowflake  # 使用的主键生成器名称# 分片算法定义shardingAlgorithms:# 数据库分片算法:取模算法course_db_alg:type: MOD  # 取模分片算法props:sharding-count: 2  # 分片数量(2个数据库)# 表分片算法:行表达式算法course_tbl_alg:type: INLINE  # 行表达式分片算法props:# 算法表达式:根据cid字段的值取模2再加1,得到表后缀(1或2)algorithm-expression: course_${cid%2+1}# 主键生成器定义keyGenerators:# 雪花算法生成器,用于生成分布式唯一IDalg_snowflake:type: SNOWFLAKE  # 使用雪花算法
    
  • 重新启动 ShardingSphere-Proxy 服务:

    mysql> show databases;
    +--------------------+
    | schema_name        |
    +--------------------+
    | information_schema |
    | performance_schema |
    | sys                |
    | shardingsphere     |
    | sharding_db        |
    | mysql              |
    +--------------------+
    6 rows in set (0.02 sec)mysql> use sharding_db;
    Database changed
    mysql> show tables;
    +-----------------------+------------+
    | Tables_in_sharding_db | Table_type |
    +-----------------------+------------+
    | course                | BASE TABLE |
    | user_2                | BASE TABLE |
    | user                  | BASE TABLE |
    | user_1                | BASE TABLE |
    +-----------------------+------------+
    4 rows in set (0.02 sec)mysql> select * from course;
    +---------------------+-------+---------+---------+
    | cid                 | cname | user_id | cstatus |
    +---------------------+-------+---------+---------+
    | 1017125767709982720 | java  |    1001 | 1       |
    | 1017125769383510016 | java  |    1001 | 1       |mysql> select * from course_1;
    +---------------------+-------+---------+---------+
    | cid                 | cname | user_id | cstatus |
    +---------------------+-------+---------+---------+
    | 1017125767709982720 | java  |    1001 | 1       |
    | 1017125769383510016 | java  |    1001 | 1       |
    
    • 可以看到多了一个sharding_db库。

3 ShardingSphere-Proxy 中的分布式事务机制

3.1 为什么需要分布式事务?

  • XA 事务 :: ShardingSphere;

  • 2.1 部署 ShardingSphere-Proxy中配置server.yaml时,有一个TRANSACTION配置项:

    rules:
    - !TRANSACTIONdefaultType: XAproviderType: Atomikos
    
  • 为什么 ShardingSphere-Proxy 需要分布式事务?

    • ShardingSphere(尤其是 ShardingSphere-Proxy)要操作分布式的数据库集群(多个库、多个节点)。而数据库的本地事务只能保证单个数据库内的事务安全,无法覆盖跨多个数据库的场景;

    • 因此,必须引入分布式事务管理机制,才能保证 ShardingSphere-Proxy 中 SQL 执行的原子性。开启分布式事务后,开发者不用再手动考虑跨库 SQL 的事务问题。

3.2 什么是 XA 事务?

  • XA 是由 X/Open Group 组织定义的分布式事务标准,主流关系型数据库(如 MySQL、Oracle 等)都实现了 XA 协议(比如 MySQL 5.0.3+ 的 InnoDB 引擎支持 XA);

  • XA 事务的核心是两阶段提交(2PC),通过**准备(Prepare)提交(Commit)**两个阶段,保证跨多个数据库的事务一致性;

  • XA 分布式事务操作示例:

    -- 1. 开启XA事务,'test'是事务标识符(XID),将事务状态设置为ACTIVE(活跃)
    -- 事务标识符用于在分布式环境中唯一标识一个事务
    XA START 'test';-- 2. 在ACTIVE状态的XA事务中执行业务SQL语句
    -- 这些操作是事务的一部分,但尚未最终提交
    INSERT INTO dict VALUES(1, 't', 'test');-- 3. 结束XA事务,将事务状态从ACTIVE改为IDLE(空闲)
    -- 表示事务内的所有操作已完成,准备进入准备阶段
    XA END 'test';-- 4. 准备提交事务,将事务状态从IDLE改为PREPARED(已准备)
    -- 此阶段事务管理器会确保所有资源管理器都已准备好提交
    XA PREPARE 'test';-- 5. 列出所有处于PREPARED状态的XA事务
    -- 返回的信息包含:gtrid(全局事务ID)、bqual(分支限定符)、formatID(格式ID)和data(数据)
    XA RECOVER;-- 6. 提交已准备的XA事务,使所有更改永久生效
    -- 这是两阶段提交的第二阶段(提交阶段)
    XA COMMIT 'test';-- 6. 替代方案:回滚已准备的XA事务,撤销所有更改
    -- 在PREPARED状态下也可以选择回滚而不是提交
    XA ROLLBACK 'test';-- 注意:也可以使用单条命令直接提交,将预备和提交合并操作
    -- XA COMMIT 'test' ONE PHASE;
    
  • ShardingSphere 集成了多个 XA 实现框架(Atomikos、Bitronix、Narayana)。在 ShardingSphere-Proxy 中,默认只集成了 Atomikos(所以配置里 providerType: Atomikos)。

3.3 实战理解 XA 事务

  • 引入 Maven 依赖:

    <dependency><groupId>org.apache.shardingsphere</groupId><artifactId>shardingsphere-transaction-xa-core</artifactId><version>5.2.1</version><exclusions><exclusion><artifactId>transactions-jdbc</artifactId><groupId>com.atomikos</groupId></exclusion><exclusion><artifactId>transactions-jta</artifactId><groupId>com.atomikos</groupId></exclusion></exclusions>
    </dependency>
    <!-- 版本滞后了 -->
    <dependency><artifactId>transactions-jdbc</artifactId><groupId>com.atomikos</groupId><version>5.0.8</version>
    </dependency>
    <dependency><artifactId>transactions-jta</artifactId><groupId>com.atomikos</groupId><version>5.0.8</version>
    </dependency>
    <!-- 使用XA事务时,可以引入其他几种事务管理器 -->
    <!--        <dependency>-->
    <!--            <groupId>org.apache.shardingsphere</groupId>-->
    <!--            <artifactId>shardingsphere-transaction-xa-bitronix</artifactId>-->
    <!--            <version>5.2.1</version>-->
    <!--        </dependency>-->
    <!--        <dependency>-->
    <!--            <groupId>org.apache.shardingsphere</groupId>-->
    <!--            <artifactId>shardingsphere-transaction-xa-narayana</artifactId>-->
    <!--            <version>5.2.1</version>-->
    <!--        </dependency>-->
    
  • 配置事务管理器:

    @Configuration
    @EnableTransactionManagement
    public class TransactionConfiguration {@Beanpublic PlatformTransactionManager txManager(final DataSource dataSource) {return new DataSourceTransactionManager(dataSource);}
    }
    
  • 测试案例:

    public class MySQLXAConnectionTest {public static void main(String[] args) throws SQLException {// 是否打印XA相关命令,用于调试目的boolean logXaCommands = true;// ============== 初始化阶段:建立数据库连接 ==============// 获取第一个数据库连接(资源管理器RM1)Connection conn1 = DriverManager.getConnection("jdbc:mysql://localhost:3306/coursedb?serverTimezone=UTC", "root", "root");// 创建XA连接包装器,用于支持分布式事务XAConnection xaConn1 = new MysqlXAConnection((com.mysql.cj.jdbc.JdbcConnection) conn1, logXaCommands);// 获取XA资源接口,用于控制分布式事务XAResource rm1 = xaConn1.getXAResource();// 获取第二个数据库连接(资源管理器RM2)Connection conn2 = DriverManager.getConnection("jdbc:mysql://localhost:3306/coursedb2?serverTimezone=UTC", "root", "root");// 创建第二个XA连接包装器XAConnection xaConn2 = new MysqlXAConnection((com.mysql.cj.jdbc.JdbcConnection) conn2, logXaCommands);// 获取第二个XA资源接口XAResource rm2 = xaConn2.getXAResource();// 生成全局事务ID(GTrid,是全局事务标识符,在整个事务生命周期中唯一)byte[] gtrid = "g12345".getBytes();int formatId = 1; // 格式标识符,通常为1,表示标准XID格式try {// ============== 分别执行RM1和RM2上的事务分支 ====================// 为第一个资源管理器生成分支事务ID(BQual)byte[] bqual1 = "b00001".getBytes();// 创建完整的事务ID(XID),包含全局ID和分支IDXid xid1 = new MysqlXid(gtrid, bqual1, formatId);// 开始第一个分支事务,TMNOFLAGS表示新建一个事务(不是加入或恢复现有事务)rm1.start(xid1, XAResource.TMNOFLAGS);// 在第一个分支事务中执行SQL操作PreparedStatement ps1 = conn1.prepareStatement("INSERT INTO `dict` VALUES (1, 'T', '测试1');");ps1.execute();// 结束第一个分支事务,TMSUCCESS表示事务执行成功rm1.end(xid1, XAResource.TMSUCCESS);// 为第二个资源管理器生成分支事务IDbyte[] bqual2 = "b00002".getBytes();// 创建第二个事务IDXid xid2 = new MysqlXid(gtrid, bqual2, formatId);// 开始第二个分支事务rm2.start(xid2, XAResource.TMNOFLAGS);// 在第二个分支事务中执行SQL操作PreparedStatement ps2 = conn2.prepareStatement("INSERT INTO `dict` VALUES (2, 'F', '测试2');");ps2.execute();// 结束第二个分支事务rm2.end(xid2, XAResource.TMSUCCESS);// =================== 两阶段提交流程 ============================// 第一阶段:准备阶段 - 询问所有资源管理器是否准备好提交事务int rm1_prepare = rm1.prepare(xid1);int rm2_prepare = rm2.prepare(xid2);// 第二阶段:提交阶段 - 根据准备阶段的结果决定提交或回滚boolean onePhase = false; // 设置为false表示使用标准的两阶段提交// 检查所有资源管理器是否都准备成功if (rm1_prepare == XAResource.XA_OK&& rm2_prepare == XAResource.XA_OK) {// 所有分支都准备成功,提交所有事务rm1.commit(xid1, onePhase);rm2.commit(xid2, onePhase);} else {// 如果有任何一个分支准备失败,回滚所有事务rm1.rollback(xid1);rm2.rollback(xid2);}} catch (XAException e) {// 处理XA异常,打印异常信息e.printStackTrace();}}
    }
    
  • XA标准规范了事务XID的格式,它由三个部分组成:gtrid [, bqual [, formatID ]],具体含义如下:

    • gtrid(全局事务标识符)

      • global transaction identifier,是用于标识一个全局事务的唯一值 。在分布式事务场景下,多个数据库节点参与同一个事务,通过这个全局事务标识符可以将这些操作关联到一起,明确它们属于同一个事务;
      • 比如在一个涉及电商系统多个数据库(订单库、库存库、支付库)的分布式事务中,通过相同的gtrid就能确认这些数据库上的操作都属于同一次购物流程对应的事务;
    • bqual(分支限定符)

      • branch qualifier ,用来进一步限定事务分支。如果没有提供,会使用默认值即一个空字符串;
      • 例如,在一个分布式事务中有多个数据库节点,每个节点上的操作可以看作事务的一个分支,bqual 就可以用来区分和标识这些不同的分支,以便更精确地管理事务在各个节点上的执行情况;
    • formatID(格式标识符)

      • 是一个数字,用于标记gtrid和bqual值的格式,是一个正整数,最小为0,默认值是1 ;
      • 它主要用于在不同的系统或数据库之间进行交互时,明确全局事务标识符和分支限定符的格式规则,以确保各方能够正确解析和处理事务标识信息。
  • 使用XA事务时的注意事项

    • 无法自动提交:与本地事务在满足一定条件下可以自动提交不同,XA事务需要开发者显式地调用提交指令(如XA COMMIT) 。这就要求开发者在编写代码时,要准确把控事务提交的时机,避免因疏忽未提交事务而导致数据不一致等问题。例如在编写一个涉及多个数据库操作的业务逻辑时,开发者需要在所有操作都成功执行后,手动调用提交语句来完成事务,否则事务会一直处于未提交状态;

    • 效率低下:XA事务执行效率远低于本地事务,通常耗时能达到本地事务的10倍。这是因为在XA事务中,全局事务的状态都需要持久化,涉及到多个数据库节点之间的协调和通信,比如在两阶段提交过程中,准备阶段各个节点要记录事务状态等信息,提交阶段又需要进行多次确认和交互,这些额外的操作增加了系统开销,降低了事务处理的速度。这就意味着在对性能要求极高的场景中,使用XA事务可能并不合适,需要谨慎评估;

    • 故障隔离困难:在XA事务提交前如果出现故障(如某个数据库节点宕机、网络中断等),很难将问题隔离开 。由于XA事务涉及多个数据库节点的协同工作,一个节点出现故障可能会影响到整个事务的执行,而且故障排查和恢复相对复杂。例如在一个跨地域的分布式数据库系统中,如果某个地区的数据库节点在XA事务准备阶段出现故障,不仅要处理该节点自身的数据恢复问题,还要协调其他节点来处理事务状态,以保证整个系统的数据一致性。

3.4 如何在 ShardingSphere-Proxy 中使用其他事务管理器?

  • ShardingSphere-Proxy 支持多种分布式事务管理器(如 Atomikos、Narayana、Bitronix)。默认集成的是 Atomikos,若要改用其它两种事务管理器,需手动配置;

  • 具体操作(以 Narayana 为例)

    • 添加 Narayana 的依赖包:

      • 将 Narayana 事务集成的 Jar 包(如 shardingsphere-transaction-xa-narayana-5.2.1.jar),放到 ShardingSphere-Proxy 的 lib 目录下;
      • 该 Jar 包可通过 Maven 依赖下载(需要在项目的 Maven 配置中引入对应依赖,构建后获取 Jar 包);
    • server.yamlrules 部分,将事务的 providerType 配置为 Narayana。配置示例:

      rules:- !TRANSACTIONdefaultType: XAproviderType: Narayana
      
  • 注意事项:ShardingSphere 版本更新快,部分依赖可能未及时维护,存在组件版本冲突的风险。使用前需确认依赖包与 ShardingSphere-Proxy 版本的兼容性。

4 ShardingSphere-Proxy 集群化部署

4.1 ShardingSphere-Proxy 的运行模式

  • server.yaml 文件中,有一段被注释的 mode 配置。这段配置的作用是指定 ShardingSphere 的运行模式,决定 ShardingSphere 如何管理复杂的配置信息:

    #mode:
    #  type: Cluster
    #  repository:
    #    type: ZooKeeper
    #    props:
    #      namespace: governance_ds
    #      server-lists: localhost:2181
    #      retryIntervalMilliseconds: 500
    #      timeToLiveSeconds: 60
    #      maxRetries: 3
    #      operationTimeoutMilliseconds: 500
    
  • ShardingSphere 支持 Standalone(独立模式)Cluster(集群模式) 两种运行模式,核心差异如下:

    • Standalone(独立模式)

      • ShardingSphere 不需要考虑其他实例的影响,直接在内存中管理核心配置规则

      • 是 ShardingSphere 默认的运行模式,配置简单,无需依赖第三方组件。

      • 适用场景:小型项目,或对性能要求较高的场景(因为没有额外的配置同步开销)。通常配合 ShardingJDBC 使用(ShardingJDBC 是客户端分库分表,更侧重性能);

    • Cluster(集群模式)

      • ShardingSphere 不仅要管理自身配置,还要与集群中其他实例同步配置规则。因此需要引入第三方配置中心(如 Zookeeper、etcd、Nacos 等)来实现配置同步;

      • 推荐的配置中心:在分库分表场景下,配置信息变动少、访问频率低,因此基于 CP 架构的 Zookeeper 最推荐(CP 架构保证数据一致性,适合配置这类强一致需求的场景);

      • 优先级:如果应用本地和 Zookeeper 都有配置,ShardingSphere 以 Zookeeper 中的配置为准(保证集群配置统一);

      • 适用场景:大规模集群环境,需要多实例协同工作,通常配合 ShardingSphere-Proxy 使用;

  • 模式选择建议

    • Standalone:小型项目、性能敏感场景 → 配合 ShardingJDBC;

    • Cluster:大规模集群环境 → 配合 ShardingSphere-Proxy,且推荐用 Zookeeper 作为配置中心。

4.2 使用 Zookeeper 进行集群部署

  • 接下来基于 Zookeeper 部署一下 ShardingSphere-Proxy 集群;

  • 首先在本地部署一个 Zookeeper,然后将server.yaml中的mode部分解除注释:

    # ShardingSphere 运行模式配置
    mode:# 运行模式类型:Cluster 表示集群模式(支持多个Proxy实例组成集群)type: Cluster# 集群元数据存储仓库配置repository:# 仓库类型:ZooKeeper(使用ZooKeeper作为分布式协调服务)type: ZooKeeper# ZooKeeper连接配置属性props:# ZooKeeper命名空间:用于在ZooKeeper中隔离不同环境的配置namespace: governance_ds# ZooKeeper服务器地址列表:支持多个服务器地址,用逗号分隔server-lists: 192.168.65.212:2181# 重试间隔时间(毫秒):连接失败后重试的等待时间retryIntervalMilliseconds: 500# 节点存活时间(秒):在ZooKeeper中创建的临时节点的存活时间timeToLiveSeconds: 60# 最大重试次数:连接ZooKeeper失败时的最大重试次数maxRetries: 3# 操作超时时间(毫秒):ZooKeeper操作(如创建、读取节点)的超时时间operationTimeoutMilliseconds: 500
    
  • 启动 ShardingSphere-Proxy 服务,在 Zookeeper 注册中心可以看到 ShardingSphere 集群模式下的节点结构如下:

    # ShardingSphere 集群模式下的 ZooKeeper 节点结构详解# 根命名空间(用于环境隔离,避免不同环境配置相互干扰)
    namespace: governance_ds
    # 全局配置节点
    ├── rules                    # 存储全局规则配置(如分片规则、加密规则等)
    ├── props                    # 存储全局属性配置(如SQL显示开关、执行模式等)
    # 元数据管理节点
    ├── metadata                 # 元数据配置根目录
    │   ├── ${databaseName}      # 逻辑数据库名称(如:sharding_db)
    │   │   ├── schemas          # 逻辑Schema列表
    │   │   │   ├── ${schemaName} # 逻辑Schema名称
    │   │   │   │   ├── tables   # 表结构配置
    │   │   │   │   │   ├── ${tableName}  # 具体表的结构定义
    │   │   │   │   │   └── ...  # 其他表
    │   │   │   │   └── views    # 视图结构配置
    │   │   │   │       ├── ${viewName}   # 具体视图的定义
    │   │   │   │       └── ...  # 其他视图
    │   │   │   └── ...          # 其他Schema
    │   │   └── versions         # 元数据版本管理
    │   │       ├── ${versionNumber} # 具体版本号(如:v1, v2)
    │   │       │   ├── dataSources # 该版本的数据源配置
    │   │       │   └── rules       # 该版本的规则配置
    │   │       ├── active_version  # 当前激活的元数据版本号
    │   │       └── ...          # 其他版本
    # 计算节点管理(Proxy和JDBC实例管理)
    ├── nodes
    │   ├── compute_nodes        # 计算节点管理根目录
    │   │   ├── online           # 在线实例列表
    │   │   │   ├── proxy        # Proxy模式实例
    │   │   │   │   ├── UUID     # 每个Proxy实例的唯一标识(如:生成的实际UUID)
    │   │   │   │   └── ...      # 其他Proxy实例
    │   │   │   └── jdbc         # JDBC模式实例
    │   │   │       ├── UUID     # 每个JDBC实例的唯一标识
    │   │   │       └── ...      # 其他JDBC实例
    │   │   ├── status           # 实例状态信息
    │   │   │   ├── UUID         # 具体实例的状态数据
    │   │   │   └── ...          # 其他实例状态
    │   │   ├── worker_id        # 工作节点ID分配
    │   │   │   ├── UUID         # 实例分配的工作ID
    │   │   │   └── ...          # 其他实例的工作ID
    │   │   ├── process_trigger  # 进程触发管理
    │   │   │   ├── process_list_id:UUID  # 进程列表与实例的关联
    │   │   │   └── ...          # 其他进程触发信息
    │   │   └── labels           # 实例标签管理
    │   │       ├── UUID         # 具体实例的标签配置
    │   │       └── ...          # 其他实例标签
    # 存储节点管理(实际数据源管理)
    │   └── storage_nodes        # 存储节点管理根目录
    │       ├── ${databaseName.groupName.ds}  # 数据源节点命名格式:逻辑库名.组名.数据源名
    │       └── ${databaseName.groupName.ds}  # 另一个数据源节点
    
  • server.yaml中的rules部分同2.1 部署 ShardingSphere-Proxy

  • 分库分表配置同2.2 常用的分库分表配置策略

4.3 统一 JDBC 和 Proxy 配置信息

  • ShardingSphere-JDBC 也能像 ShardingSphere-Proxy 一样,通过 Zookeeper 同步配置信息,从而实现两者配置的统一管理(减少配置分散,便于集群化维护)。

4.3.1 通过注册中心同步配置

  • application.properties 中,删除之前 ShardingSphere-JDBC 相关的分库分表规则等配置,只配置Zookeeper 的连接和集群模式。示例配置:

    # 指定运行模式为“集群模式(Cluster)”
    spring.shardingsphere.mode.type=Cluster
    # 指定配置中心类型为 Zookeeper
    spring.shardingsphere.mode.repository.type=Zookeeper
    # Zookeeper 的命名空间(用于隔离不同配置,自定义即可)
    spring.shardingsphere.mode.repository.props.namespace=governance_ds
    # Zookeeper 的地址和端口
    spring.shardingsphere.mode.repository.props.server-lists=localhost:2181
    # 重试间隔(毫秒)
    spring.shardingsphere.mode.repository.props.retryIntervalMilliseconds=600
    # 存活时间(秒)
    spring.shardingsphere.mode.repository.props.timeToLiveSeconds=60
    # 最大重试次数
    spring.shardingsphere.mode.repository.props.maxRetries=3
    # 操作超时时间(毫秒)
    spring.shardingsphere.mode.repository.props.operationTimeoutMilliseconds=500
    
  • 配置完成后,可继续验证对表(如 course 表)的分库分表操作,此时 ShardingSphere-JDBC 会从 Zookeeper 中拉取配置信息来执行分库分表逻辑;

  • 注意:

    • 如果在 ShardingSphere-JDBC 中读取配置中心(Zookeeper)的配置,需要用 spring.shardingsphere.database.name 指定对应的虚拟库
    • 若不配置该参数,默认值为 logic_db
    • 这个虚拟库是 ShardingSphere 中逻辑上的数据库概念,用于统一管理分库分表后的逻辑结构。

4.3.2 使用ShardingSphere-Proxy提供的JDBC驱动读取配置文件

  • ShardingSphere 过去是通过兼容 MySQL 或 PostgreSQL 服务的方式,提供分库分表功能:

    • 应用端需要用 MySQL/PostgreSQL 的 JDBC 驱动,去访问 ShardingSphere 封装的数据源(ShardingSphereDataSource);

    • 这种方式相当于模拟成 MySQL/PostgreSQL 数据库,让应用无感知地使用分库分表能力,但依赖的是第三方数据库的 JDBC 驱动;

  • 在当前版本中,ShardingSphere 直接提供了自己的 JDBC 驱动

    • 这意味着应用可以不再依赖 MySQL/PostgreSQL 的 JDBC 驱动,直接用 ShardingSphere 专属的驱动来连接和操作数据;

    • 优势是更原生、更直接地支持 ShardingSphere 的特性(分库分表、分布式事务等),减少对第三方驱动的依赖,也能更灵活地扩展功能;

  • 比如在 ShardingSphere-JDBC 中,可在类路径(classpath)下增加 config.yaml 文件,将之前 ShardingSphere-Proxy中的关键配置整合到这个文件中。这样 ShardingSphere-JDBC 就能通过自身的 JDBC 驱动,读取 config.yaml 里的配置(分库分表规则、数据源等),实现和 ShardingSphere-Proxy 类似的分库分表逻辑:

    rules:- !AUTHORITYusers:- root@%:root- sharding@:shardingprovider:type: ALL_PERMITTED- !TRANSACTIONdefaultType: XAproviderType: Atomikos- !SQL_PARSERsqlCommentParseEnabled: truesqlStatementCache:initialCapacity: 2000maximumSize: 65535parseTreeCache:initialCapacity: 128maximumSize: 1024- !SHARDINGtables:course:actualDataNodes: m${0..1}.course_${1..2}databaseStrategy:standard:shardingColumn: cidshardingAlgorithmName: course_db_algtableStrategy:standard:shardingColumn: cidshardingAlgorithmName: course_tbl_algkeyGenerateStrategy:column: cidkeyGeneratorName: alg_snowflakeshardingAlgorithms:course_db_alg:type: MODprops:sharding-count: 2course_tbl_alg:type: INLINEprops:algorithm-expression: course_$->{cid%2+1}keyGenerators:alg_snowflake:type: SNOWFLAKEprops:max-connections-size-per-query: 1kernel-executor-size: 16proxy-frontend-flush-threshold: 128proxy-hint-enabled: falsesql-show: falsecheck-table-metadata-enabled: falseproxy-backend-query-fetch-size: -1proxy-frontend-executor-size: 0proxy-backend-executor-suitable: OLAPproxy-frontend-max-connections: 0 sql-federation-type: NONEproxy-backend-driver-type: JDBCproxy-mysql-default-version: 8.0.20proxy-default-port: 3307proxy-netty-backlog: 1024databaseName: sharding_db
    dataSources:m0:dataSourceClassName: com.zaxxer.hikari.HikariDataSourceurl: jdbc:mysql://127.0.0.1:3306/coursedb?serverTimezone=UTC&useSSL=falseusername: rootpassword: rootconnectionTimeoutMilliseconds: 30000idleTimeoutMilliseconds: 60000maxLifetimeMilliseconds: 1800000maxPoolSize: 50minPoolSize: 1m1:dataSourceClassName: com.zaxxer.hikari.HikariDataSourceurl: jdbc:mysql://127.0.0.1:3306/coursedb2?serverTimezone=UTC&useSSL=falseusername: rootpassword: rootconnectionTimeoutMilliseconds: 30000idleTimeoutMilliseconds: 60000maxLifetimeMilliseconds: 1800000maxPoolSize: 50minPoolSize: 1
    
  • 然后,可以直接用 JDBC 的方式访问带有分库分表的虚拟库:

    public class ShardingJDBCDriverTest {@Testpublic void test() throws ClassNotFoundException, SQLException {// 定义ShardingSphere JDBC驱动类全限定名// 这是ShardingSphere提供的专用JDBC驱动,用于拦截和路由SQL请求String jdbcDriver = "org.apache.shardingsphere.driver.ShardingSphereDriver";// JDBC连接URL,指定使用ShardingSphere驱动和配置文件路径// classpath:config.yaml 表示配置文件位于类路径下的config.yaml文件String jdbcUrl = "jdbc:shardingsphere:classpath:config.yaml";// 要执行的SQL查询语句// 这里查询的是逻辑数据库sharding_db中的course表// ShardingSphere会根据配置将查询路由到实际的物理表String sql = "select * from sharding_db.course";// 加载ShardingSphere JDBC驱动类// 这是使用JDBC驱动的标准方式,驱动会自动注册到DriverManagerClass.forName(jdbcDriver);// 使用try-with-resources语句确保连接正确关闭try(Connection connection = DriverManager.getConnection(jdbcUrl);) {// 创建Statement对象用于执行SQL语句Statement statement = connection.createStatement();// 执行SQL查询并返回ResultSet结果集// ShardingSphere会在此处拦截SQL,根据分片规则路由到正确的数据节点ResultSet resultSet = statement.executeQuery(sql);// 遍历结果集,处理查询结果while (resultSet.next()){// 从结果集中获取cid字段的值并输出// ShardingSphere会自动合并来自多个分片的结果System.out.println("course cid= "+resultSet.getLong("cid"));}// try-with-resources会自动关闭statement和resultSet}// try-with-resources会自动关闭connection,释放数据库连接资源}
    }
    
  • 官方的说明是 ShardingSphereDriver 读取config.yaml时, 这个config.yaml配置信息与 ShardingSphere-Proxy 中的配置文件完全是相同的,甚至可以直接将 ShardingSphere-Proxy 中的配置文件拿过来用。但是从目前版本来看,还是有不少小问题的,静待后续版本跟踪吧;

  • 到这里,对于之前讲解过的 ShardingSphere 的混合架构,有没有更新的了解?

    在这里插入图片描述

5 ShardingSphere-Proxy功能扩展

  • ShardingSphere-Proxy 支持通过 SPI(Service Provider Interface)机制 进行自定义扩展,只要将自定义的扩展功能(如自定义算法、策略等)按照 SPI 规范打成 Jar 包,放入 ShardingSphere-Proxy 的 lib 目录,就能被 ShardingSphere-Proxy 加载并使用;

  • 自定义主键生成器为例:

    • 实现 KeyGeneratorAlgorithm 接口,用于生成自定义格式的主键;
    • 生成主键时,结合当前时间戳(格式化为 yyyyMMddHHmmssSSS)和自增原子变量,保证主键的唯一性和有序性;
    public class MyKeyGeneratorAlgorithm implements KeyGeneratorAlgorithm {private AtomicLong atom = new AtomicLong(0);private Properties props;@Overridepublic Comparable<?> generateKey() {LocalDateTime ldt = LocalDateTime.now();// 格式化时间为 “年月日时分秒毫秒” 格式String timestamp = DateTimeFormatter.ofPattern("yyyyMMddHHmmssSSS").format(ldt);// 结合自增数生成主键(时间戳 + 自增数)return Long.parseLong(timestamp + atom.incrementAndGet());}@Overridepublic Properties getProps() {return this.props;}@Overridepublic String getType() {// 自定义算法的类型标识,配置时会用到return "MYKEY";}@Overridepublic void init(Properties props) {this.props = props;}
    }
    
  • 要将自定义类和对应的 SPI 文件打成 Jar 包,需在 pom.xml 中配置 maven-jar-plugin

    • 指定要打包的自定义类(com/your/package/algorithm/**)和 SPI 配置文件(META-INF/services/*),生成包含扩展功能的 Jar 包;
    <build><plugins><!-- 将 SPI 扩展功能单独打成 Jar 包 --><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-jar-plugin</artifactId><version>3.2.0</version><executions><execution><id>shardingJDBDemo</id><phase>package</phase><goals><goal>jar</goal></goals><configuration><classifier>spi-extention</classifier><includes><!-- 包含自定义算法的包路径 --><include>com/your/package/algorithm/**</include><!-- 包含 SPI 配置文件(META-INF/services/ 下的文件) --><include>META-INF/services/*</include></includes></configuration></execution></executions></plugin></plugins>
    </build>
    
  • 将打包好的 Jar 包,放入 ShardingProxy 的 lib 目录。之后在 ShardingProxy 的配置中,就可以像使用内置组件一样,引用这个自定义的主键生成算法(如配置 keyGeneratorName: MYKEY)。

6 分库分表数据迁移方案

  • 分库分表场景下,数据迁移面临两大难题:

    • 海量数据迁移难度大:旧项目无分库分表,或需调整分片规则时,数据量庞大,迁移工程浩大;

    • 业务无感知难度高:迁移过程中要保证业务正常运行,不能因迁移导致服务中断;

  • 为平衡数据迁移业务连续性(在数据转移的过程中,保证不影响业务正常进行),采用冷热数据分离迁移

    • 冷数据

      • 即历史存量数据(数据量大,无法一次性迁移);
      • 策略:通过定时任务逐步迁移,减少对业务的瞬间压力;
    • 热数据

      • 即业务实时产生的新数据;
      • 策略:保证双写(同时写入旧库和新库),确保迁移过程中数据实时同步,业务不受影响;
  • 基于 ShardingSphere 的迁移方案

    在这里插入图片描述

    • 热数据双写(ShardingJDBC 数据双写库)

      • 核心逻辑:用 ShardingSphereDataSource 替换旧的 DataSource,配置双写规则(核心业务表同时写入旧库和新库);

      • 实现方式:在 ShardingJDBC 双写库中,针对需迁移的核心表配置分片规则,通过定制分片算法实现一份数据写两份库

    • 新库分片写入(ShardingJDBC 数据写入库)

      • 核心逻辑:针对新数据库集群,配置专门的 ShardingJDBC 写入库,完整实现新的分片规则(即分库分表的最终逻辑);

      • 关联方式:将这个写入库配置到之前的双写库中,保证新数据按新规则写入新库;

    • 冷数据增量迁移(定时任务 + ShardingProxy)

      • 冷数据特点:量大、迁移慢,需分批增量迁移;

      • 实现方式:

        • ElasticJob 等定时任务框架,分批读取旧库冷数据,按新分片规则写入新库;
        • 借助 ShardingProxy 服务,简化新库的分片逻辑(定时任务只需从旧库读、往新库写,分片规则由 ShardingProxy 统一管理);
        • 规则同步:通过 ShardingSphere Governance Center(如 Zookeeper),保证 ShardingProxy 和 ShardingJDBC 写入库的分片规则一致
    • 迁移完成后切换

      • 核心逻辑:冷数据迁移完成后,删除双写库和旧库依赖,只保留 ShardingJDBC 写入库(新库的分片逻辑);

      • 业务影响:应用层只需访问一个 DataSource(底层由 ShardingSphere 切换为新库逻辑),业务代码几乎无需修改;

  • 注意:迁移过程中,需梳理业务 SQL,确保 SQL 符合 ShardingSphere(尤其是 ShardingSphere-JDBC)的支持范围,避免使用不兼容的 SQL 语法导致迁移或业务异常。

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

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

相关文章

Mysql相关的面试题1

什么是聚集索引&#xff08;聚簇索引&#xff09;&#xff1f;什么是二级索引&#xff08;非聚簇索引&#xff09;&#xff1f; 聚集索引就是叶子节点关联行数据的索引&#xff0c;二级索引就是叶子节点关联主键的索引&#xff0c;聚集索引必须有且仅有一个&#xff0c;二级索引…

电涌保护器:为现代生活筑起一道隐形防雷网

何为电涌保护器&#xff1f;电涌保护器&#xff08;Surge Protective Device&#xff0c;简称SPD&#xff09;主要用于控制信号系统&#xff0c;保护电气电子设备信号线路免受雷电电磁脉冲、感应过电压、操作过电压的影响&#xff0c;广泛应用于工控、消防、安防监控、交通、电…

【uniapp微信小程序】扫普通链接二维码打开小程序

需求&#xff1a;用户A保存自己的邀请码海报&#xff0c;用户B扫描该普通连接二维码&#xff0c;打开微信小程序&#xff0c;并且携带用户A的邀请码信息&#xff0c;用户B登录时&#xff0c;跟用户A关联&#xff0c;成为用户A的下级。 tips&#xff1a;保存海报到手机相册可以参…

LeetCode 378 - 有序矩阵中第 K 小的元素

文章目录摘要描述题解答案题解代码分析代码解析示例测试及结果输出结果时间复杂度空间复杂度总结摘要 在开发中&#xff0c;我们经常遇到需要处理大规模有序数据的场景&#xff0c;比如数据库分页、排行榜查询、或者处理排序过的矩阵。LeetCode 第 378 题“有序矩阵中第 K 小的…

【Lua】Windows 下编写 C 扩展模块:VS 编译与 Lua 调用全流程

▒ 目录 ▒&#x1f6eb; 导读需求环境1️⃣ 核心原理&#xff1a;Windows下Lua与C的交互逻辑2️⃣ Windows下编写步骤&#xff1a;以mymath模块为例2.1 步骤1&#xff1a;准备Windows开发环境方式1&#xff1a;官网下载Lua源码并编译&#xff08;可控性高&#xff09;方式2&am…

Python快速入门专业版(二十九):函数返回值:多返回值、None与函数嵌套调用

目录引一、多返回值&#xff1a;一次返回多个结果的优雅方式1. 多返回值的本质&#xff1a;隐式封装为元组示例1&#xff1a;返回多个值的函数及接收方式2. 多返回值的接收技巧技巧1&#xff1a;用下划线_忽略不需要的返回值技巧2&#xff1a;用*接收剩余值&#xff08;Python …

python使用pip安装的包与卸载

1&#xff1a;基本卸载命令 # 卸载单个包 pip uninstall package_name# 示例&#xff1a;卸载requests包 pip uninstall requests2&#xff1a;卸载多个包 # 一次性卸载多个包 pip uninstall package1 package2 package3# 示例 pip uninstall requests numpy pandas3&#xff1…

超级流水线和标量流水线的原理

一、什么是流水线&#xff1f;要理解这两个概念&#xff0c;首先要明白流水线&#xff08;Pipelining&#xff09; 的基本思想。想象一个汽车装配工厂&#xff1a;* 没有流水线&#xff1a;一个工人负责组装一整辆汽车&#xff0c;装完一辆再装下一辆。效率很低。* 有了流水线&…

【Ansible】管理复杂的Play和Playbook知识点

1.什么是主机模式&#xff1f;答&#xff1a;主机模式是Ansible中用于从Inventory中筛选目标主机的规则&#xff0c;通过灵活的模式定义可精准定位需要执行任务的主机。2.主机模式的作用答&#xff1a;筛选目标&#xff1a;从主机清单中选择一个或多个主机/组&#xff0c;作为P…

FastGPT源码解析 Agent 智能体应用创建流程和代码分析

FastGPT对话智能体创建流程和代码分析 平台作为agent平台&#xff0c;平台所有功能都是围绕Agent创建和使用为核心的。平台整合各种基础能力&#xff0c;如大模型、知识库、工作流、插件等模块&#xff0c;通过可视化&#xff0c;在界面上创建智能体&#xff0c;使用全部基础能…

缺失数据处理全指南:方法、案例与最佳实践

如何处理缺失数据&#xff1a;方法、案例与最佳实践 1. 引言 在数据分析和机器学习中&#xff0c;缺失数据是一个普遍存在的问题。如何处理缺失值&#xff0c;往往直接影响到后续分析和建模的效果。处理不当&#xff0c;不仅会浪费数据&#xff0c;还可能导致模型预测结果的不准…

为什么Cesium不使用vue或者react,而是 保留 Knockout

1. Knockout-ES5 插件的语法简化优势 自动深度监听&#xff1a;Cesium 通过集成 Knockout-ES5 插件&#xff0c;允许开发者直接使用普通变量语法&#xff08;如 viewModel.property newValue&#xff09;替代繁琐的 observable() 包装&#xff0c;无需手动声明每个可观察属性。…

Word怎么设置页码总页数不包含封面和目录页

有时候使用页码格式是[第x页/共x页]或[x/x]时会遇到word总页数和实际想要的页数不一致&#xff0c;导致显示不统一&#xff0c;这里介绍一个简单的办法&#xff0c;适用于比较简单的情况。 一、wps版本 文章分节 首先将目录页与正文页进行分节&#xff1a;在目录页后面选择插入…

突破机器人通讯架构瓶颈,CAN/FD、高速485、EtherCAT,哪种总线才是最优解?

引言&#xff1a; 从协作机械臂到人形机器人&#xff0c;一文拆解主流总线技术选型困局 在机器人技术飞速发展的今天&#xff0c;从工厂流水线上的协作机械臂到科技展会上的人形机器人&#xff0c;它们的“神经系统”——通讯总线&#xff0c;正面临着前所未有的挑战。特斯拉O…

Java核心概念详解:JVM、JRE、JDK、Java SE、Java EE (Jakarta EE)

1. Java是什么&#xff1f; Java首先是一种编程语言。它拥有特定的语法、关键字和结构&#xff0c;开发者可以用它来编写指令&#xff0c;让计算机执行任务。核心特点&#xff1a; Java最著名的特点是“一次编写&#xff0c;到处运行”&#xff08;Write Once, Run Anywhere - …

OSPF高级技术 相关知识点

1.多区域OSPFospf 设计多区域原因&#xff1a;① 每个区域的路由器只需同步自己所在区域的链路状态数据库&#xff0c;分区域设 计可以使得每个区域的链路状态数据库得以减少。以降低路由器cpu、内存 的消耗。② 避免某区域内的网络故障&#xff08;例如&#xff1a;接口频繁up…

Linux / Windows 下连续发送多帧 8 字节指令,下位机只响应第一帧,第二帧“丢失”。

串口编程易错点笔记 基于 serial::Serial&#xff08;wjwwood serial 库&#xff09; 场景&#xff1a;Linux / Windows 下连续发送多帧 8 字节指令&#xff0c;下位机只响应第一帧&#xff0c;第二帧“丢失”。1. 现象 serial::Serial ser("/dev/ttyUSB0", 115200);…

三十九、案例-配置文件-参数配置化(了解即可,现在主流使用yml配置文件)

参数配置化-问题引出参数配置化-问题解决参数配置化-代码与过程解析代码&#xff1a; AliOSSUtils&#xff08;工具类&#xff09; package com.itheima.utils;import com.aliyun.oss.OSS; import com.aliyun.oss.OSSClientBuilder; import org.springframework.beans.factory.…

Linux之virtio实现原理--pci 基础

一、概述 virtio设备可以基于不同总线来实现&#xff0c;本文介绍基于pci实现的virtio-pci设备。以virtio-blk为例&#xff0c;首先介绍PCI配置空间内容&#xff0c;virtio-pci实现的硬件基础——capability&#xff0c;最后分析PIC设备的初始化以及virtio-pci设备的初始化。 …

Claude-Flow AI协同开发:从“CTO”到“人机共生体”的AI协同开发

6.1 思维的终极融合&#xff1a;从“CTO”到“人机共生体” (Human-AI Symbiote) 在之前的章节中&#xff0c;我们逐步将您的角色从“开发者”提升为“项目经理”&#xff0c;最终定位为整个“人机混合团队的CTO”。这个模型强调的是一种 “指挥-控制” (Command-and-Control) …