第一章:分库分表中间件的核心概念与Go语言优势
在现代高并发、大数据量的系统架构中,单一数据库往往难以支撑业务的快速增长,分库分表成为常见的解决方案。分库分表中间件作为实现该方案的关键组件,负责对数据库进行逻辑抽象、SQL解析、路由、合并等操作,使得上层应用可以像操作单库一样操作多个数据库实例。
分库分表中间件的核心功能包括:数据分片策略定义、SQL解析与改写、结果集归并、连接管理、事务控制等。这些功能要求中间件具备高性能、低延迟和良好的扩展性。这也是为何越来越多的架构选择使用Go语言来实现这类中间件。
Go语言凭借其原生的并发模型(goroutine)、高效的调度机制、简洁的语法以及静态编译特性,非常适合构建高性能的网络服务。其标准库中丰富的网络和数据库接口,也为实现数据库中间件提供了良好的基础。例如,通过实现一个简单的SQL路由中间层,可以拦截客户端请求并根据分片规则将查询转发到对应的数据库节点:
package main
import (
"database/sql"
"fmt"
"net"
)
func main() {
listener, _ := net.Listen("tcp", ":3307")
fmt.Println("Listening on :3307")
for {
conn, _ := listener.Accept()
go handleConnection(conn)
}
}
func handleConnection(conn net.Conn) {
// 模拟SQL解析与路由逻辑
db := getShardedDB("user_123") // 根据分片规则选择数据库
rows, _ := db.Query("SELECT * FROM users WHERE id = 123")
defer rows.Close()
// 处理结果集并返回给客户端
}
var dbMap = map[string]*sql.DB{
"user_123": connectToShard("db1.example.com"),
}
func getShardedDB(key string) *sql.DB {
return dbMap[key]
}
func connectToShard(addr string) *sql.DB {
// 实际连接数据库的逻辑
return &sql.DB{}
}
上述代码展示了Go语言如何轻松构建一个具备分片路由能力的数据库中间件骨架,为后续实现完整分库分表功能打下基础。
第二章:分库分表策略与中间件架构设计
2.1 数据分片算法与一致性哈希实现
在分布式系统中,数据分片是提升存储与查询性能的关键策略。常见的分片算法包括哈希取模与一致性哈希。一致性哈希通过减少节点变化时的数据迁移量,提升了系统的稳定性与扩展性。
一致性哈希原理
一致性哈希通过将数据与节点映射到一个虚拟的哈希环上,使得节点增减时仅影响邻近节点的数据分布。以下是基于Java的简易实现:
public class ConsistentHashing {
private final SortedMap<Integer, String> circle = new TreeMap<>();
public void addNode(String node, int virtualNodes) {
for (int i = 0; i < virtualNodes; i++) {
int hash = (node + i).hashCode();
circle.put(hash, node);
}
}
public String getNode(String key) {
int hash = key.hashCode();
// 找到大于等于 key hash 的第一个节点
Map.Entry<Integer, String> entry = circle.ceilingEntry(hash);
return entry == null ? circle.firstEntry().getValue() : entry.getValue();
}
}
逻辑分析:
addNode
方法为每个物理节点添加多个虚拟节点(virtualNodes
),以增强分布均衡性;getNode
方法查找数据应分配到的节点,使用TreeMap
的ceilingEntry
实现环状查找逻辑。
虚拟节点的作用
特性 | 描述 |
---|---|
负载均衡 | 提升数据分布均匀性 |
容错性 | 节点宕机时影响范围最小化 |
可扩展性 | 添加/删除节点对整体影响小 |
数据分布示意图
graph TD
A[Key1] --> B[NodeA]
C[Key2] --> D[NodeB]
E[Key3] --> F[NodeC]
G[Key4] --> H[NodeA]
I[Key5] --> J[NodeB]
一致性哈希结合虚拟节点技术,广泛应用于分布式缓存、数据库分片等场景,是实现高可用系统的重要基石。
2.2 分库分表规则的配置化设计
在分布式数据库架构中,分库分表是提升系统扩展性的核心手段。为了实现灵活的水平拆分策略,规则的配置化设计尤为关键。
配置化设计的核心在于将分片逻辑从代码中剥离,通过配置文件定义数据路由规则。例如,可采用 YAML 格式定义如下分片策略:
sharding_rules:
user_table:
key: user_id
algorithm: hash_mod
shard_count: 4
databases: 2
tables_per_db: 2
上述配置表示对 user_table
表按 user_id
字段使用哈希取模算法,将数据分布到 2 个数据库、每个数据库包含 2 张表的结构中。
通过引入配置中心(如 Nacos、ZooKeeper),可实现运行时动态更新分片规则,避免系统重启,从而提升系统的可维护性与灵活性。
2.3 中间件的整体架构与模块划分
一个典型的中间件系统通常采用分层架构设计,以实现高内聚、低耦合的模块组织方式。整体架构可分为核心调度层、通信协议层、业务处理层三大模块。
核心调度层
该层负责任务分发与资源协调,是中间件运行的控制中枢。其主要依赖事件驱动模型进行异步处理。
通信协议层
支持多种网络协议(如HTTP、gRPC、MQTT),屏蔽底层通信细节,为上层提供统一接口。以下是一个简化版的通信接口定义:
type Communicator interface {
Send(msg []byte) error
Receive() ([]byte, error)
}
Send
:用于发送数据包,参数为字节数组;Receive
:监听并接收数据,返回字节数组和错误信息。
业务处理层
负责具体业务逻辑的执行,通常以插件形式加载,便于扩展。模块之间通过接口解耦,提升系统灵活性。
系统模块交互流程
graph TD
A[客户端请求] --> B(通信协议层)
B --> C{核心调度层}
C --> D[业务处理层]
D --> C
C --> B
B --> A
2.4 连接池管理与SQL路由机制
在高并发数据库访问场景中,连接池管理与SQL路由是提升系统性能与资源利用率的关键环节。
连接池管理
连接池通过复用数据库连接,有效减少频繁建立和释放连接所带来的开销。一个典型的连接池配置如下:
pool:
max_connections: 100 # 最大连接数
idle_timeout: 30s # 空闲连接超时时间
max_wait: 5s # 获取连接的最大等待时间
逻辑分析:上述配置定义了连接池的容量边界与生命周期策略,避免连接泄漏和资源争用,从而提升系统稳定性。
SQL路由机制
SQL路由负责将SQL语句转发到正确的数据库实例。其流程可通过mermaid表示:
graph TD
A[接收SQL请求] --> B{判断语句类型}
B -->|读操作| C[选择从节点]
B -->|写操作| D[选择主节点]
C --> E[执行查询]
D --> F[执行写入]
该机制通过识别SQL语义,实现读写分离,进一步优化数据库集群的负载分布。
2.5 分布式事务的初步支持方案
在分布式系统中,事务的 ACID 特性面临挑战,因此初步支持方案通常基于两阶段提交(2PC)或引入事务消息机制。
事务消息机制
一种常见的初步方案是使用事务消息,如 Apache RocketMQ 提供的事务消息模型,其流程如下:
// 伪代码示例
Message msg = new Message("OrderTopic", "ORDER_001".getBytes());
SendResult sendResult = producer.sendMessageInTransaction(msg, null);
逻辑分析:
Message
构造函数指定消息主题和内容;sendMessageInTransaction
方法确保消息发送与本地事务状态同步;- 消息队列中间件负责事务状态的回查与提交/回滚。
分布式事务流程(Mermaid 图)
graph TD
A[应用发送事务消息] --> B[消息系统暂存消息]
B --> C[执行本地事务]
C -->|成功| D[提交消息]
C -->|失败| E[回滚消息]
该模型通过消息中间件的事务机制,实现跨服务的数据一致性,为后续更复杂的分布式事务方案(如 TCC、Saga)打下基础。
第三章:基于Go语言的中间件开发实战
3.1 使用Go语言构建SQL解析器
在构建数据库中间件或SQL审计系统时,SQL解析器是核心组件之一。Go语言凭借其高效的并发模型和简洁的语法,成为实现SQL解析器的理想选择。
为何选择Go语言
Go语言具备静态编译、高效并发、垃圾回收等特性,非常适合构建高性能后端服务。在SQL解析场景中,常需要处理大量并发请求,Go的goroutine机制能显著提升处理效率。
构建流程概览
使用Go构建SQL解析器通常包括以下步骤:
- 词法分析:将SQL语句拆分为有意义的token;
- 语法分析:根据语法规则构建抽象语法树(AST);
- 语义处理:对AST进行解析、修改或分析。
使用ANTLR进行解析
ANTLR(Another Tool for Language Recognition)是广泛使用的语法分析器生成器。通过定义SQL语法规则,可自动生成Go语言解析器代码。
// 示例:使用ANTLR解析SQL
parser := sql.NewSQLParser(lexer)
tree := parser.Parse()
逻辑分析:
sql.NewSQLParser
初始化SQL解析器实例;lexer
是预定义的词法分析器;Parse()
方法返回SQL语句的AST结构,便于后续处理。
解析器结构示意图
graph TD
A[原始SQL语句] --> B(词法分析)
B --> C[生成Token流]
C --> D{语法分析}
D --> E[构建AST]
E --> F[语义处理或改写]
3.2 实现高性能的连接池管理
在高并发系统中,数据库连接的频繁创建与销毁会带来显著的性能开销。为了解决这一问题,连接池技术被广泛应用。它通过复用已有的连接,减少连接建立的延迟,提高系统吞吐能力。
连接池核心参数配置
连接池的性能在很大程度上取决于配置策略,以下是一些关键参数:
参数名 | 说明 | 推荐值示例 |
---|---|---|
max_connections | 连接池最大连接数 | 100 |
idle_timeout | 空闲连接超时时间(秒) | 300 |
connection_ttl | 连接最大存活时间(秒) | 600 |
获取连接的流程图
graph TD
A[请求获取连接] --> B{连接池中有空闲连接?}
B -->|是| C[直接返回空闲连接]
B -->|否| D{当前连接数 < 最大限制?}
D -->|是| E[新建连接]
D -->|否| F[等待空闲连接释放]
E --> G[返回新连接]
F --> H[超时或抛出异常]
示例代码:连接池初始化(Python)
以下是一个使用 SQLAlchemy
和 PooledDB
初始化连接池的示例:
from sqlalchemy import create_engine
from sqlalchemy.pool import QueuePool
# 初始化连接池
engine = create_engine(
"mysql+pymysql://user:password@localhost/dbname",
poolclass=QueuePool,
pool_size=5, # 初始连接数
max_overflow=10, # 最大溢出连接数
pool_recycle=300, # 连接回收时间(秒)
pool_pre_ping=True # 启用连接前检测
)
逻辑分析:
pool_size
:设置连接池中保持的连接数量,用于快速响应请求;max_overflow
:允许的额外连接数,应对突发流量;pool_recycle
:控制连接的最大空闲时间,防止数据库断连;pool_pre_ping
:在每次获取连接前进行一次健康检查,提升稳定性。
通过合理配置连接池参数和使用连接复用机制,可以显著提升系统性能,降低数据库连接的资源消耗,是构建高并发系统不可或缺的一环。
3.3 数据库节点的动态扩容实践
在高并发场景下,数据库集群需要具备动态扩容能力,以应对数据量和访问压力的增长。扩容过程通常包括数据分片迁移、节点加入与负载均衡等关键步骤。
节点扩容流程
扩容流程可概括为以下几个阶段:
- 新节点注册:将新节点加入集群并同步元数据;
- 数据分片迁移:根据负载策略重新分布数据;
- 负载均衡校验:确认数据分布均匀并更新路由表。
使用 Mermaid 可视化流程如下:
graph TD
A[扩容触发] --> B{集群状态检查}
B --> C[新节点注册]
C --> D[分片迁移]
D --> E[路由更新]
E --> F[扩容完成]
分片迁移示例代码
以下为伪代码,用于触发分片迁移任务:
def start_shard_migration(source_node, target_node, shard_id):
# 检查源节点与目标节点状态
if not is_node_healthy(source_node) or not is_node_healthy(target_node):
raise NodeUnhealthyException("源或目标节点异常,无法迁移")
# 锁定该分片防止并发操作
acquire_shard_lock(shard_id)
# 开始迁移
data = source_node.fetch_shard_data(shard_id)
target_node.replicate_data(shard_id, data)
# 数据一致性校验
if not verify_data_consistency(source_node, target_node, shard_id):
raise DataInconsistentException("数据校验失败")
# 更新元数据
update_metadata(shard_id, target_node)
# 释放锁
release_shard_lock(shard_id)
参数说明:
source_node
:源节点对象,用于读取当前分片数据;target_node
:目标节点对象,用于接收迁移数据;shard_id
:待迁移的分片唯一标识;acquire_shard_lock
:防止并发操作,确保一致性;verify_data_consistency
:通过哈希或校验和机制验证数据完整性;update_metadata
:更新集群元数据,指向新节点;release_shard_lock
:释放锁定资源,允许后续操作。
扩容后的负载均衡策略
扩容完成后,应调整数据分布策略,确保请求均匀打到各个节点。常见策略包括:
策略类型 | 说明 |
---|---|
一致性哈希 | 减少节点变动时的重新映射范围 |
范围分片 | 按主键范围划分,适合有序数据 |
哈希取模 | 简单高效,但扩容时需重新取模 |
动态权重调度 | 根据节点性能动态分配流量 |
通过上述机制,可实现数据库集群在运行时的平滑扩容,提升系统伸缩性与稳定性。
第四章:性能优化与高并发场景调优
4.1 高并发下的连接复用与负载均衡
在高并发系统中,频繁创建和销毁连接会带来显著的性能损耗。连接池技术通过复用已建立的连接,显著降低了连接建立的开销,提升了系统吞吐能力。
连接复用的实现机制
使用连接池(如 HikariCP、Druid)可有效管理数据库连接。以下是一个基于 HikariCP 的配置示例:
HikariConfig config = new HikariConfig();
config.setJdbcUrl("jdbc:mysql://localhost:3306/mydb");
config.setUsername("root");
config.setPassword("password");
config.setMaximumPoolSize(20); // 设置最大连接数
config.setIdleTimeout(30000); // 空闲连接超时时间
config.setConnectionTestQuery("SELECT 1");
HikariDataSource dataSource = new HikariDataSource(config);
逻辑分析:
setMaximumPoolSize
控制连接池上限,防止资源耗尽;setIdleTimeout
避免连接长时间闲置导致浪费;setConnectionTestQuery
确保连接有效性,防止获取失效连接。
负载均衡策略演进
在分布式服务中,负载均衡器决定请求的转发路径。常见的策略包括:
- 轮询(Round Robin):均匀分配请求;
- 最少连接(Least Connections):优先转发至负载最低节点;
- 权重轮询(Weighted Round Robin):按节点性能分配不同权重;
- 一致性哈希(Consistent Hashing):保持请求与节点的亲和性。
服务调用链路优化
通过引入 Nginx 或 Envoy 等反向代理组件,可实现请求的高效分发。以下为 Nginx 实现轮询负载均衡的配置示例:
upstream backend {
server 10.0.0.1:8080;
server 10.0.0.2:8080;
server 10.0.0.3:8080;
}
server {
listen 80;
location / {
proxy_pass http://backend;
}
}
逻辑分析:
upstream
块定义了后端服务列表;- 默认使用轮询策略(Round Robin);
- 可通过
weight
参数指定服务器权重,实现加权调度; proxy_pass
将请求转发至负载均衡组。
架构协同优化
连接复用与负载均衡常协同工作以提升整体性能。例如,客户端使用连接池减少连接开销,服务端使用负载均衡器将请求分散至多个节点,从而实现系统的横向扩展。
下图展示了高并发场景下连接池与负载均衡的协同流程:
graph TD
A[Client] --> B[Connection Pool]
B --> C[Load Balancer]
C --> D[Server Node 1]
C --> E[Server Node 2]
C --> F[Server Node 3]
流程说明:
- 客户端通过连接池获取连接;
- 请求被发送至负载均衡器;
- 负载均衡器根据策略将请求转发至目标服务节点;
- 多节点分担压力,提升系统并发处理能力。
4.2 查询缓存机制与本地化实现
在高并发系统中,查询缓存机制是提升响应速度和降低数据库压力的重要手段。通过将热点查询结果缓存在本地内存中,可以有效减少网络往返和数据库访问次数。
缓存策略设计
常见的本地缓存策略包括:
- TTL(Time To Live):设置缓存过期时间,防止数据长期不更新
- TTI(Time To Idle):基于访问频率自动清理不活跃数据
- 最大条目限制:控制缓存总量,防止内存溢出
本地缓存实现示例
public class LocalCache {
private static final Cache<String, Object> cache = Caffeine.newBuilder()
.maximumSize(1000) // 设置最大缓存条目
.expireAfterWrite(5, TimeUnit.MINUTES) // 写入后5分钟过期
.build();
public static Object get(String key) {
return cache.getIfPresent(key);
}
public static void put(String key, Object value) {
cache.put(key, value);
}
}
上述代码使用 Caffeine 实现了一个轻量级本地缓存。通过 maximumSize
控制缓存容量,expireAfterWrite
设置写入后过期时间,避免内存无限增长和数据陈旧问题。
数据同步机制
在分布式环境下,本地缓存需配合全局缓存服务进行同步。常见方式包括:
- 主动失效通知
- 定期拉取最新版本
- 基于消息队列的异步更新
性能对比(本地缓存 vs 数据库直查)
操作类型 | 平均响应时间 | QPS(并发) | CPU 使用率 |
---|---|---|---|
数据库直查 | 120ms | 150 | 65% |
本地缓存读取 | 0.5ms | 20000 | 12% |
通过本地缓存优化,查询性能可提升两个数量级以上,显著提高系统吞吐能力。
4.3 分布式ID生成策略与优化
在分布式系统中,生成全局唯一且有序的ID是一项核心挑战。传统单点自增ID无法满足分布式环境下的并发与扩展需求,因此催生了多种分布式ID生成策略。
常见生成算法
目前主流的分布式ID生成方案包括:
- Snowflake:基于时间戳+节点ID+序列号的组合方式,生成64位ID,具备高性能与全局唯一性。
- UUID:通用唯一识别码,格式为
xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx
,虽然唯一性强,但无序且存储开销大。 - Redis 自增:借助Redis的原子操作实现分布式ID生成,适用于中小规模系统。
Snowflake 示例实现(简化版)
public class SnowflakeIdGenerator {
private final long nodeId;
private long lastTimestamp = -1L;
private long nodeBits = 10L;
private long sequenceBits = 12L;
private long maxSequence = ~(-1L << sequenceBits);
private long nodeShift = sequenceBits;
private long timestampShift = sequenceBits + nodeBits;
private long sequence = 0L;
public SnowflakeIdGenerator(long nodeId) {
this.nodeId = nodeId << sequenceBits; // 节点ID左移
}
public synchronized long nextId() {
long timestamp = System.currentTimeMillis();
if (timestamp < lastTimestamp) {
throw new RuntimeException("时钟回拨");
}
if (timestamp == lastTimestamp) {
sequence = (sequence + 1) & maxSequence;
if (sequence == 0) {
timestamp = tilNextMillis(lastTimestamp);
}
} else {
sequence = 0;
}
lastTimestamp = timestamp;
return (timestamp << timestampShift) | nodeId | sequence;
}
private long tilNextMillis(long lastTimestamp) {
long timestamp = System.currentTimeMillis();
while (timestamp <= lastTimestamp) {
timestamp = System.currentTimeMillis();
}
return timestamp;
}
}
逻辑分析与参数说明:
nodeId
:节点唯一标识,用于区分不同服务实例。sequence
:同一毫秒内的序列号,防止ID重复。timestampShift
和nodeShift
:用于位运算,确保ID各部分不重叠。maxSequence
:最大序列号值,防止溢出。nextId()
方法生成一个64位长整型ID,包含时间戳、节点ID和序列号三部分。
性能对比表
算法 | 唯一性 | 有序性 | 性能 | 存储占用 | 适用场景 |
---|---|---|---|---|---|
Snowflake | 高 | 是 | 极高 | 8字节 | 高并发写入场景 |
UUID | 极高 | 否 | 高 | 16字节 | 无需排序的唯一标识 |
Redis 自增 | 中 | 是 | 中 | 8字节 | 中小型分布式系统 |
优化方向
- 时间回拨处理:引入缓存或备用时钟源,防止系统时间回退导致ID生成失败。
- 位数调整:根据业务生命周期调整时间戳、节点ID和序列号的位数分配。
- 引入中心协调服务:如使用ZooKeeper或Etcd协调节点ID分配,提升可扩展性。
ID生成架构演进示意图
graph TD
A[单机ID] --> B[分布式ID]
B --> C[Snowflake]
B --> D[UUID]
B --> E[Redis自增]
C --> F[改进型Snowflake]
E --> G[基于Etcd的协调生成]
通过不断优化ID生成策略,可以更好地满足大规模分布式系统对性能、唯一性与扩展性的综合需求。
4.4 慢查询监控与自动路由优化
在大规模分布式系统中,数据库慢查询可能显著影响整体性能。因此,建立一套完善的慢查询监控机制成为关键。
监控策略与指标采集
系统通过采集 SQL 执行时间、扫描行数、执行计划等关键指标,结合 Prometheus + Grafana 实现可视化监控。
-- 示例:MySQL 中开启慢查询日志
SET GLOBAL slow_query_log = 1;
SET GLOBAL long_query_time = 0.5; -- 设置慢查询阈值为 0.5 秒
该配置将记录所有执行时间超过 0.5 秒的 SQL,便于后续分析和优化。
自动路由优化机制
基于历史查询性能数据,系统可动态调整 SQL 请求的路由策略,实现负载均衡与性能优化。
graph TD
A[客户端请求] --> B{查询耗时预测}
B -->|高延迟| C[路由至高性能节点]
B -->|正常| D[默认路由]
通过上述机制,系统可在运行时自动识别并缓解慢查询问题,提升整体响应效率。
第五章:未来趋势与分库分表技术演进方向
随着互联网业务规模的持续扩大,数据量呈现指数级增长,传统的单库单表架构已难以支撑高并发、低延迟的业务需求。分库分表技术作为解决数据库瓶颈的重要手段,正在不断演进,并与云原生、服务化、智能调度等新兴技术深度融合。
数据分片的自动化与智能化
过去,分库分表的策略多依赖人工设计,如按用户ID哈希、时间范围划分等。但随着业务复杂度上升,静态分片策略难以适应动态变化。未来,数据分片将趋向自动化与智能化。例如,基于机器学习模型预测数据访问热点,自动调整分片策略,实现动态再平衡。一些云数据库已经开始支持自动分片功能,如阿里云PolarDB-X、TiDB等,它们通过内部调度器实现数据的自动迁移和负载均衡。
与云原生架构的深度融合
分库分表技术正在与Kubernetes、Service Mesh等云原生技术深度融合。以Kubernetes为例,数据库实例可以像普通微服务一样被容器化部署和调度,结合Operator机制实现数据库的自动扩缩容与故障自愈。例如,某电商平台在双十一期间通过Kubernetes Operator实现数据库节点的自动扩容,将分库数量从16个动态扩展到64个,有效应对了流量洪峰。
分布式事务的进一步成熟
在分库分表环境下,跨库事务处理一直是难点。随着Seata、ShardingSphere等开源项目对分布式事务的支持不断增强,TCC、SAGA、XA等模式逐渐落地。某银行系统采用ShardingSphere内置的XA事务模式,在分库分表架构下实现了转账业务的强一致性,交易成功率提升至99.99%。
查询优化与联邦查询能力增强
未来,分库分表中间件将更注重查询优化能力,支持跨库联合查询、聚合下推、执行计划缓存等高级特性。例如,Presto和Apache Calcite等技术正在被集成到分库分表解决方案中,用于实现跨多个数据源的联邦查询。某大型电商平台通过集成Calcite优化器,将跨库查询性能提升了40%,显著降低了响应延迟。
技术方向 | 当前挑战 | 演进趋势 |
---|---|---|
分片自动化 | 热点识别与迁移成本 | 基于AI的动态分片与负载预测 |
分布式事务 | 性能损耗与一致性保障 | 高性能TCC与混合事务处理模型 |
查询优化 | 跨库查询效率与复杂度 | 联邦查询引擎与执行计划智能优化 |
云原生集成 | 运维复杂度与资源调度 | 声明式配置与弹性扩缩容自动化 |
-- 示例:跨库查询优化前的SQL
SELECT order_id, SUM(amount)
FROM orders
WHERE user_id IN (SELECT user_id FROM users WHERE region = 'east');
-- 优化后,中间件自动将子查询下推到各分片执行
SELECT /*+ SHARDING_EXECUTION */ order_id, SUM(amount)
FROM orders
WHERE user_id IN (SELECT user_id FROM users WHERE region = 'east');
mermaid流程图如下,展示了未来分库分表架构中数据调度的智能化路径:
graph LR
A[业务请求] --> B{是否跨库?}
B -- 是 --> C[查询优化器]
C --> D[生成分布式执行计划]
D --> E[并行调度到多个分片]
E --> F[结果合并与返回]
B -- 否 --> G[本地执行引擎]
G --> H[直接返回结果]