第一章:Go语言架构演进与全景认知
Go语言自2009年开源以来,其架构设计始终围绕“简洁、高效、可靠”三大核心原则持续演进。早期版本聚焦于并发模型(goroutine + channel)与快速编译的静态二进制构建能力;Go 1.5 实现了编译器从 C 自举到 Go 自举的关键跃迁,大幅统一运行时行为;Go 1.18 引入泛型,补全了类型抽象能力,使标准库与生态组件在保持零依赖的同时支持更严谨的接口契约;而 Go 1.21 起正式启用 io 和 slices 等现代化工具包,并强化内存模型语义一致性,标志着语言进入成熟稳定期。
Go 的运行时(runtime)并非黑盒,而是深度参与调度、垃圾回收与内存管理的轻量级系统层。其 M-P-G 模型(Machine-Processor-Goroutine)将操作系统线程(M)、逻辑处理器(P)与协程(G)解耦,实现数百万 goroutine 的低开销调度。可通过以下命令观察当前程序的调度统计:
# 编译并运行时启用调度器追踪(需 Go 1.20+)
go run -gcflags="-m" main.go 2>&1 | grep -i "sched"
# 或运行时打印 GC 和 Goroutine 统计
GODEBUG=schedtrace=1000 ./your-binary
该调试输出每秒刷新一次,显示 P 数量、可运行 G 队列长度、GC 周期等关键指标,是理解实际并发负载的直接依据。
Go 的工具链与语言特性高度协同,形成独特的一体化开发体验:
| 组件 | 特性说明 |
|---|---|
go build |
默认静态链接,生成无外部依赖的单文件二进制 |
go mod |
基于语义化版本的最小版本选择(MVS)算法 |
go vet |
静态分析捕获常见错误(如 mutex 拷贝、printf 参数不匹配) |
pprof |
内置性能剖析支持(CPU / heap / goroutine block profiles) |
这种“语言即平台”的设计理念,使得 Go 在云原生基础设施(如 Kubernetes、Docker)、高并发微服务及 CLI 工具领域展现出极强的工程穿透力——它不追求语法奇巧,而以可预测的性能、确定性的部署和清晰的抽象边界,构建起现代分布式系统的底层信任基石。
第二章:单体服务架构范式
2.1 单体架构的模块化分层设计(理论)与 Go 标准库依赖管理实践
单体应用并非“一锅炖”,而是通过清晰的分层契约实现内聚:handlers → services → repositories → models。Go 的标准库 go.mod 天然支持语义化版本约束与最小版本选择(MVS),避免隐式依赖漂移。
分层接口定义示例
// internal/service/user_service.go
type UserService interface {
CreateUser(ctx context.Context, u *model.User) error
}
该接口解耦业务逻辑与传输层,context.Context 显式传递取消信号与超时控制,*model.User 强制值对象封装,杜绝跨层数据污染。
依赖管理关键策略
- 使用
go mod tidy自动修剪未引用依赖 - 禁止
replace指向本地路径(破坏可重现构建) - 第三方库仅在
internal/外层pkg/中封装适配器
| 层级 | 典型依赖 | 是否允许 stdlib |
|---|---|---|
| handlers | net/http, chi | ✅ |
| services | time, errors | ✅ |
| repositories | database/sql | ✅ |
graph TD
A[main.go] --> B[handlers]
B --> C[services]
C --> D[repositories]
D --> E[models]
E --> F[stdlib: encoding/json]
2.2 面向接口编程与依赖注入(理论)与 wire/dig 框架实战落地
面向接口编程解耦组件职责,依赖注入(DI)则将对象创建与使用分离。Go 无原生 DI 支持,需借助工具实现编译期或运行时装配。
核心对比:wire vs dig
| 特性 | wire | dig |
|---|---|---|
| 注入时机 | 编译期生成代码 | 运行时反射解析 |
| 类型安全 | ✅ 完全静态检查 | ⚠️ 运行时 panic 风险 |
| 启动性能 | 零反射开销 | 初始化略慢 |
// wire.go:声明依赖图
func InitializeApp() (*App, error) {
wire.Build(
newDB,
newCache,
newUserService,
newApp,
)
return nil, nil
}
wire.Build声明构造函数链;newUserService依赖*DB和*Cache,wire 自动生成组合逻辑,避免手动 new 与传递。
graph TD
A[App] --> B[UserService]
B --> C[DB]
B --> D[Cache]
C --> E[PostgreSQL Driver]
D --> F[Redis Client]
依赖树由接口抽象,如 type DB interface { Query(...),便于单元测试替换 mock 实现。
2.3 并发模型驱动的服务编排(理论)与 goroutine+channel 构建高吞吐请求流
传统串行请求处理在微服务场景下易成瓶颈。并发模型驱动的编排将控制流解耦为可调度、可组合的轻量单元——goroutine 是其执行载体,channel 是其通信契约。
goroutine 启动模式对比
| 模式 | 启动开销 | 适用场景 | 生命周期管理 |
|---|---|---|---|
go f() |
极低(~2KB栈) | 短时异步任务 | 手动/隐式结束 |
go func() { defer wg.Done(); f() }() |
中等 | 需同步等待的批处理 | 依赖 WaitGroup |
请求流管道化示例
func requestPipeline(reqs <-chan *Request, resps chan<- *Response) {
// 阶段1:解析(并发)
parsed := make(chan *ParsedReq, 100)
for i := 0; i < 4; i++ {
go func() {
for req := range reqs {
parsed <- parse(req) // 非阻塞写入带缓冲channel
}
}()
}
// 阶段2:校验与转发(扇出)
for p := range parsed {
go func(pr *ParsedReq) {
if valid(pr) {
resps <- handle(pr) // 结果统一归集
}
}(p)
}
}
逻辑分析:
reqs输入通道被 4 个 goroutine 并发消费,实现 I/O 解耦;parsed缓冲通道避免生产者阻塞;闭包捕获p避免循环变量覆盖;resps作为汇聚点支持下游弹性伸缩。
数据同步机制
使用 sync.Pool 复用 Request/Response 对象,降低 GC 压力。
2.4 错误处理与可观测性嵌入(理论)与 zap+prometheus+opentelemetry 集成方案
可观测性不是日志、指标、追踪的简单叠加,而是错误上下文在运行时的自动关联与语义增强。
三位一体协同机制
- Zap:结构化、低开销日志,携带
trace_id和error_kind字段; - Prometheus:暴露
http_request_duration_seconds_bucket等 SLO 关键指标; - OpenTelemetry SDK:统一采集日志/指标/迹,并导出至后端(如 OTLP Collector)。
日志与追踪自动绑定示例
// 初始化带 trace 注入的 zap logger
logger := zap.New(zapcore.NewCore(
zapcore.NewJSONEncoder(zap.NewProductionEncoderConfig()),
os.Stdout, zapcore.InfoLevel,
)).With(zap.String("service", "api-gateway"))
// 在 HTTP 中间件中注入 trace context
ctx, span := tracer.Start(r.Context(), "http_handler")
defer span.End()
logger.With(zap.String("trace_id", trace.SpanContextFromContext(ctx).TraceID().String())).Info("request processed")
此代码确保每条日志携带当前 trace ID,使 Prometheus 告警触发时可直接下钻到对应 span 与完整日志流。
组件职责对比表
| 组件 | 核心职责 | 输出格式 | 嵌入方式 |
|---|---|---|---|
| Zap | 结构化错误上下文捕获 | JSON with error, stacktrace, trace_id |
logger.With(...) 显式注入 |
| Prometheus | 服务健康度量化 | Metrics exposition (text/plain) | promhttp.Handler() + 自定义 collector |
| OpenTelemetry | 信号标准化与路由 | OTLP/gRPC or HTTP/protobuf | sdktrace.TracerProvider + sdklog.LoggerProvider |
graph TD
A[HTTP Request] --> B[OTel Middleware]
B --> C[Zap Logger with ctx]
B --> D[Prometheus Counter]
B --> E[OTel Span]
C & D & E --> F[OTLP Exporter]
F --> G[Collector → Jaeger/Loki/Prometheus]
2.5 单体服务的可维护性边界识别(理论)与 go list+graphviz 架构健康度分析
单体服务的可维护性并非由代码行数决定,而取决于包间依赖密度与跨域调用深度。当 go list -f '{{.ImportPath}} -> {{join .Imports "\n"}}' ./... 输出呈现强连通子图或环状引用时,即触及可维护性边界。
依赖图谱生成流程
# 递归提取所有包导入关系(DOT格式)
go list -f '{{.ImportPath}} {{range .Imports}}{{.}} {{end}}' ./... | \
awk '{for(i=2;i<=NF;i++) print $1 " -> " $i}' | \
sed 's/\.//g' | \
sort -u > deps.dot
该命令提取每个包的直接依赖,-f 模板中 {{.ImportPath}} 为当前包路径,{{.Imports}} 是其全部依赖列表;awk 展开为有向边,sed 清理路径分隔符以适配 Graphviz。
健康度评估维度
| 指标 | 健康阈值 | 风险表现 |
|---|---|---|
| 平均入度(In-Degree) | 过度中心化 | |
| 强连通分量数量 | = 1 | 存在循环依赖 |
| 最长依赖链长度 | ≤ 4 | 调用栈过深 |
graph TD
A[main] --> B[service/user]
B --> C[domain/user]
C --> D[infrastructure/db]
D --> E[domain/user] %% 循环依赖!触发告警
第三章:微服务架构范式
3.1 微服务拆分原则与领域驱动设计(理论)与 Go 中 bounded context 的包组织实践
微服务拆分应以业务能力和限界上下文(Bounded Context)为根本依据,而非技术便利性。DDD 强调:同一上下文内术语含义统一,跨上下文需明确防腐层(ACL)。
Go 中的包即天然的 bounded context 边界:
// shop/ —— 订单上下文
package shop
type Order struct {
ID string `json:"id"`
Items []Item `json:"items"` // 内部值对象,不暴露领域逻辑细节
Status Status `json:"status"` // 枚举类型封装业务状态约束
}
该结构强制封装:Items 是内部切片,Status 是带校验方法的自定义类型,防止外部误赋非法值。包名 shop 直接映射领域语义,避免 models/ 或 dto/ 等泛化命名。
| 上下文边界 | Go 包路径 | 职责聚焦 |
|---|---|---|
shop/ |
github.com/org/shop |
订单创建、履约状态流转 |
payment/ |
github.com/org/payment |
支付网关适配、对账一致性 |
graph TD
A[用户下单] --> B[shop.OrderService.Create]
B --> C[shop.ValidateInventory]
C --> D[payment.ChargeRequest]
D --> E[ACL: payment.Adapter]
3.2 服务间通信模式选型(理论)与 gRPC/HTTP/Message Broker 在 Go 中的基准对比与封装
服务间通信需权衡延迟、一致性、可维护性与网络韧性。同步调用适合强依赖场景,异步解耦则提升系统弹性。
常见模式特性对比
| 模式 | 延迟 | 语义保证 | Go 生态成熟度 | 典型适用场景 |
|---|---|---|---|---|
| HTTP/1.1 (REST) | 中高 | 请求-响应 | ⭐⭐⭐⭐⭐ | 外部 API、跨语言调试 |
| gRPC (HTTP/2) | 低 | 请求-响应/流 | ⭐⭐⭐⭐ | 内部高频微服务调用 |
| Message Broker | 高 | 最终一致性 | ⭐⭐⭐ | 事件驱动、数据最终同步 |
gRPC 封装示例(Go)
// grpc_client.go:带拦截器与超时控制的泛化客户端
func NewGRPCClient(addr string) *grpc.ClientConn {
conn, _ := grpc.Dial(
addr,
grpc.WithTransportCredentials(insecure.NewCredentials()),
grpc.WithBlock(),
grpc.WithTimeout(5*time.Second), // 连接建立超时
grpc.WithUnaryInterceptor(grpc_retry.UnaryClientInterceptor()), // 自动重试
)
return conn
}
该封装统一注入超时、重试与日志拦截逻辑,避免各服务重复实现;WithTimeout 仅作用于连接阶段,实际 RPC 调用需在 context.WithTimeout 中单独设置。
数据同步机制
graph TD A[Producer Service] –>|Publish Event| B[RabbitMQ/Kafka] B –> C{Consumer Group} C –> D[Service A: Update Cache] C –> E[Service B: Audit Log] C –> F[Service C: Search Index]
3.3 分布式事务与最终一致性保障(理论)与 Saga 模式在 Go 服务链路中的状态机实现
Saga 是一种面向长事务的补偿型分布式事务模型,将全局事务拆解为一系列本地事务(T₁, T₂, …, Tₙ),每个事务对应一个可逆的补偿操作(C₁, C₂, …, Cₙ)。
核心状态流转
type SagaState int
const (
Pending SagaState = iota // 初始待执行
Executing
Compensating
Completed
Failed
)
// 状态迁移需满足幂等性与原子性约束
该枚举定义了 Saga 执行生命周期的五种关键状态。Pending 表示事务尚未触发;Executing 表示当前步骤正提交本地事务;Compensating 表示因上游失败而回滚;Completed 和 Failed 为终态,不可再迁入。
补偿策略对比
| 策略 | 触发时机 | 幂等保障方式 | 适用场景 |
|---|---|---|---|
| Chained | 同步串行调用 | 请求 ID + DB 记录 | 低延迟、强顺序链路 |
| Event-driven | 异步事件驱动 | 消息去重 + 版本号 | 高吞吐、松耦合系统 |
执行流程(Mermaid)
graph TD
A[Start] --> B[Execute T1]
B --> C{Success?}
C -->|Yes| D[Execute T2]
C -->|No| E[Compensate C1]
D --> F{Success?}
F -->|Yes| G[Complete]
F -->|No| H[Compensate C2 → C1]
第四章:云原生与弹性架构范式
4.1 容器化服务生命周期管理(理论)与 Go 程序的 init/health/readiness 探针深度定制
容器编排系统依赖三类探针协同感知服务状态:liveness(存活)、readiness(就绪)、startup(启动)。Go 程序需暴露标准化 HTTP 端点并支持可编程逻辑判断。
自定义健康检查端点
func healthHandler(w http.ResponseWriter, r *http.Request) {
// 检查数据库连接、缓存连通性、关键 goroutine 状态
if !dbPing() || !redisPing() {
http.Error(w, "dependency failed", http.StatusServiceUnavailable)
return
}
w.WriteHeader(http.StatusOK)
w.Write([]byte("ok"))
}
该 handler 响应 200 OK 表示服务健康;非 200(如 503)将触发 liveness 重启。http.StatusServiceUnavailable 显式传达依赖异常,避免误判。
探针行为对比表
| 探针类型 | 触发时机 | 失败后果 | 典型超时 |
|---|---|---|---|
| startup | 容器启动后首次 | 不重试,直接 kill | 30s |
| readiness | 启动后持续轮询 | 从 Service Endpoint 移除 | 10s |
| liveness | 就绪后周期执行 | 重启容器 | 10s |
生命周期协同流程
graph TD
A[Pod 创建] --> B[执行 startupProbe]
B -->|Success| C[启用 readinessProbe]
C -->|200| D[加入 Service Endpoints]
C -->|5xx| E[暂不接入流量]
D --> F[周期执行 livenessProbe]
F -->|Failure| G[重启容器]
4.2 Serverless 函数即服务(理论)与 AWS Lambda/GCP Cloud Functions 的 Go 运行时优化实践
Serverless FaaS 的核心在于按需执行、免运维扩缩容,而 Go 因其静态编译、低内存开销与快速冷启动特性,成为 FaaS 场景的理想语言。
冷启动优化关键路径
- 预分配 Goroutine 池(避免 runtime.newm 频繁系统调用)
- 禁用 GC 调度器抢占(
GODEBUG=schedtrace=1000辅助诊断) - 使用
upx --ultra-brute压缩二进制(Lambda 层大小敏感)
Go 构建参数对照表
| 参数 | AWS Lambda 推荐值 | GCP Cloud Functions | 说明 |
|---|---|---|---|
-ldflags |
-s -w -buildmode=exe |
-s -w |
剥离符号与调试信息 |
GOOS |
linux |
linux |
必须匹配运行时 OS |
CGO_ENABLED |
|
|
禁用 CGO 避免动态链接依赖 |
func init() {
// 预热 HTTP 客户端连接池,复用底层 TCP 连接
http.DefaultClient = &http.Client{
Transport: &http.Transport{
MaxIdleConns: 100,
MaxIdleConnsPerHost: 100,
IdleConnTimeout: 30 * time.Second,
},
}
}
此 init() 在函数实例初始化阶段执行,避免每次调用重建 Transport;MaxIdleConnsPerHost 设为 100 可显著降低 GCP 函数在高并发下 DNS 解析与 TLS 握手开销。
graph TD A[Go 源码] –> B[CGO_ENABLED=0 go build] B –> C[UPX 压缩] C –> D[Lambda Layer / CF Source Upload] D –> E[Runtime 首次加载 .text 段] E –> F[init() 执行连接池预热] F –> G[Handler 调用复用连接]
4.3 服务网格透明化治理(理论)与 Go 应用与 Istio Sidecar 协同的指标埋点与熔断策略
服务网格的“透明化治理”并非消除应用感知,而是将可观测性与弹性控制下沉至基础设施层,由 Sidecar 统一拦截、度量、决策——应用仅需暴露标准 HTTP/gRPC 接口,无需嵌入 SDK。
指标埋点:零侵入采集路径
Istio 默认通过 Envoy 的 stats filter 自动采集 request_total、request_duration_milliseconds 等指标,Go 应用无需修改代码,但可通过 OpenTelemetry SDK 补充业务维度:
// 在 HTTP handler 中注入 trace context(非强制,增强链路语义)
func orderHandler(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
span := trace.SpanFromContext(ctx)
span.SetAttributes(attribute.String("order.status", "created")) // 业务标签
}
此代码不改变流量路径,仅扩展 Prometheus 标签维度;
attribute.String生成的 label 将与 Istio 的destination_service等原生标签自动关联,支撑多维下钻分析。
熔断协同机制
Envoy 基于上游集群配置执行连接/请求级熔断,Go 应用通过返回标准 HTTP 状态码(如 503 Service Unavailable)触发 Istio 的 outlier_detection:
| 参数 | 默认值 | 作用 |
|---|---|---|
consecutive_5xx |
5 | 连续5次5xx触发驱逐 |
interval |
10s | 检测窗口 |
base_ejection_time |
30s | 驱逐时长 |
graph TD
A[Go App] -->|HTTP Request| B[Envoy Sidecar]
B --> C{Upstream Cluster}
C -->|Success| D[Return 200]
C -->|Failure| E[Increment 5xx counter]
E --> F{≥5 in 10s?}
F -->|Yes| G[Eject instance]
F -->|No| C
熔断决策完全由 Sidecar 实时计算,Go 应用仅需保障接口契约一致性。
4.4 无状态化与配置中心集成(理论)与 viper+consul/etcd 动态配置热加载实战
无状态化是云原生应用的核心设计原则,将配置从代码中剥离并交由外部配置中心统一管理,可实现环境隔离、灰度发布与运行时动态调整。
配置生命周期演进
- 静态配置(
config.yaml硬编码)→ - 外部化配置(
viper.SetConfigFile())→ - 动态监听(
viper.WatchRemoteConfig()+ Consul KV 或 etcd watch)
viper 与 Consul 集成示例
viper.AddRemoteProvider("consul", "127.0.0.1:8500", "myapp/config")
viper.SetConfigType("yaml")
_ = viper.ReadRemoteConfig()
viper.WatchRemoteConfigOnChannel() // 启动监听协程
AddRemoteProvider注册 Consul 地址与路径前缀;WatchRemoteConfigOnChannel持续轮询/v1/kv/myapp/config?recurse,变更时触发viper.OnConfigChange回调,自动重载结构体绑定。
主流配置中心对比
| 特性 | Consul | etcd |
|---|---|---|
| 一致性协议 | Raft | Raft |
| 健康检查 | 内置服务发现 | 需额外集成 |
| Watch 机制 | 长轮询(阻塞查询) | gRPC stream |
graph TD
A[应用启动] --> B[viper 初始化]
B --> C[连接 Consul/etcd]
C --> D[拉取全量配置]
D --> E[启动 Watch 协程]
E --> F{配置变更?}
F -->|是| G[触发 OnConfigChange]
F -->|否| E
G --> H[自动重绑定 struct]
第五章:架构演进路径与Gopher决策心智模型
从单体到服务网格的渐进式切分实践
某金融风控中台在2021年启动架构重构,初始为Go编写的单体服务(约12万行代码),承载用户鉴权、规则引擎、实时评分三大核心能力。团队未采用“大爆炸式”拆分,而是以业务语义边界为切分依据:首先将规则引擎剥离为独立gRPC服务(rule-engine.v1),保留HTTP入口兼容性;6个月后,将评分计算模块下沉为无状态Worker池,通过RabbitMQ解耦;最终在2023年Q2完成服务网格化——所有服务注入Envoy Sidecar,通过Istio VirtualService实现灰度路由。关键指标显示:故障平均恢复时间(MTTR)从47分钟降至8.3分钟,新规则上线周期从3天压缩至45分钟。
决策树驱动的技术选型框架
Gopher在面临技术栈抉择时,常依赖隐性经验。我们提炼出可落地的四维评估矩阵:
| 维度 | 权重 | Go生态适配示例 | 验证方式 |
|---|---|---|---|
| 可观测性深度 | 30% | Prometheus原生metric暴露支持 | go tool pprof -http压测验证 |
| 运维收敛性 | 25% | Docker镜像体积(alpine vs ubuntu) | docker image ls -s对比 |
| 协程友好度 | 25% | Redis客户端是否支持context.Context |
并发goroutine泄漏检测 |
| 生态成熟度 | 20% | GitHub Stars年增长率 >15% | gh api search-repositories脚本扫描 |
该矩阵已在3个团队落地,使Kafka客户端选型从sarama切换至franz-go的决策周期缩短至2人日。
线上流量染色验证机制
在电商大促前的链路压测中,团队构建了基于HTTP Header的轻量级染色体系:所有测试请求携带X-Trace-Mode: shadow,各服务通过中间件自动识别并路由至影子数据库(MySQL主从延迟监控告警阈值设为200ms)。关键代码片段如下:
func TraceMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if r.Header.Get("X-Trace-Mode") == "shadow" {
ctx := context.WithValue(r.Context(), "dbKey", "shadow")
r = r.WithContext(ctx)
}
next.ServeHTTP(w, r)
})
}
混沌工程常态化节奏
将Chaos Mesh注入CI/CD流水线:每日凌晨2点自动触发Pod Kill实验(持续90秒),若P95延迟突增>300ms或错误率超0.5%,则阻断次日发布。2023年共捕获3类隐蔽缺陷:etcd连接池未设置MaxIdleConnsPerHost导致DNS解析雪崩、gRPC Keepalive参数缺失引发长连接泄漏、Prometheus exporter goroutine堆积未清理。
技术债量化看板
建立Go模块技术债仪表盘,自动扫描go.mod中存在CVE漏洞的依赖(使用Trivy CLI集成)、未升级的次要版本(如github.com/gorilla/mux v1.8.0 → v1.9.0)、以及// TODO: refactor注释密度(每千行>5处标红)。某支付网关模块据此识别出golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9存在SHA-1哈希碰撞风险,两周内完成升级。
架构决策日志规范
强制要求每次重大架构变更提交ARCHITECTURE.md文件,包含:决策背景(附线上监控截图URL)、替代方案对比表格、回滚步骤(含SQL回滚脚本)、责任人签名。2022年Q4的gRPC Gateway替换方案文档中,明确记录了OpenAPI v3 schema生成器选择grpc-gateway/v2而非bufbuild/protoc-gen-validate的原因——前者对oneof字段的JSON序列化兼容性更优。
工程效能反模式清单
团队沉淀出12类高频反模式,例如:
- 在
init()函数中执行HTTP调用(违反初始化原则) - 使用
time.Now().Unix()代替time.Now().UTC().UnixMilli()(跨时区精度丢失) sync.Pool对象未重置内部字段(导致goroutine间状态污染)http.Client复用但未设置Timeout(连接耗尽)
每季度通过go vet -vettool=revive插件自动扫描,2023年拦截此类问题273次。
跨团队架构对齐会议机制
每月第三周周四14:00举行“Go架构圆桌”,强制要求各业务线技术负责人携带三份材料参会:当前服务拓扑图(Mermaid生成)、最近一次全链路压测报告(含pprof火焰图URL)、下季度技术债偿还计划(精确到PR编号)。以下为典型拓扑简化表示:
graph LR
A[API Gateway] --> B[Auth Service]
A --> C[Order Service]
B --> D[(Redis Cluster)]
C --> E[(MySQL Shard 0)]
C --> F[(MySQL Shard 1)]
E --> G[Binlog Sync Worker]
F --> G 