# NGINX Zone Sync 模块详解
本文档详细介绍 NGINX Zone Sync 模块(集群区域同步)的配置与使用方法,包括工作原理、指令语法、配置示例和最佳实践。
---
## 1. Zone Sync 模块概述
### 什么是 Zone Sync 模块
Zone Sync 模块(`ngx_stream_zone_sync_module`)是 NGINX Plus 提供的**集群状态同步机制**,用于在多个 NGINX 节点之间同步共享内存区域的内容。
### 核心功能
| 功能 | 说明 |
|------|------|
| **多节点共享内存同步** | 在集群节点间自动同步 keyval、sticky sessions、limit_req 等共享内存数据 |
| **集群状态共享** | 实现分布式 NGINX 实例的状态一致性 |
| **动态节点发现** | 支持 DNS 动态发现或静态配置节点 |
| **SSL 加密传输** | 支持节点间通信加密 |
| **高性能** | 基于 TCP 流的高效同步协议 |
### 模块信息
| 属性 | 说明 |
|------|------|
| **模块名称** | `ngx_stream_zone_sync_module` |
| **首次版本** | 1.13.8 |
| **可用性** | NGINX Plus 商业订阅 |
| **上下文** | `stream`, `server` |
### 支持的同步内容
Zone Sync 模块可以同步以下类型的共享内存区域:
1. **HTTP Sticky Sessions**:`sticky learn` 创建的会话粘性数据
2. **HTTP Limit Request**:`limit_req` 的超额请求计数
3. **Keyval 键值对**:HTTP 和 Stream 的 `keyval_zone` 数据
---
## 2. Zone Sync 工作原理
### 2.1 同步架构
```
┌─────────────────┐ ┌─────────────────┐
│ NGINX Node A │◄───────►│ NGINX Node B │
│ 192.168.1.10 │ TCP │ 192.168.1.11 │
│ :12345 │ Sync │ :12345 │
└─────────────────┘ └─────────────────┘
▲ ▲
│ │
└───────────┬───────────────┘
│
▼
┌─────────────────┐
│ NGINX Node C │
│ 192.168.1.12 │
│ :12345 │
└─────────────────┘
```
### 2.2 同步协议机制
| 机制 | 说明 |
|------|------|
| **传输层** | 基于 TCP 流连接,在 `stream` 块中配置 |
| **轮询机制** | 按 `zone_sync_interval` 间隔轮询共享内存区域更新 |
| **推送机制** | 使用缓冲区推送区域内容到对等节点 |
| **双向同步** | 节点间建立双向连接,互相发送和接收更新 |
### 2.3 节点发现方式
#### 静态配置发现
```nginx
stream {
server {
zone_sync;
listen 127.0.0.1:12345;
# 静态指定集群节点
zone_sync_server 192.168.1.10:12345;
zone_sync_server 192.168.1.11:12345;
zone_sync_server 192.168.1.12:12345;
}
}
```
- 需要手动维护节点列表
- 添加/删除节点需要重新加载配置
#### 动态 DNS 发现
```nginx
stream {
resolver 192.168.1.1 valid=10s;
server {
zone_sync;
listen 127.0.0.1:12345;
# 通过 DNS 动态解析节点
zone_sync_server cluster.example.com:12345 resolve;
}
}
```
- 使用 `resolve` 参数启用 DNS 监控
- 自动检测 DNS 记录变化
- 无需重新加载配置即可扩缩容
### 2.4 状态传递流程
1. **变更检测**:每个节点按 `zone_sync_interval` 轮询本地共享内存
2. **变更缓冲**:将检测到的变更写入同步缓冲区(`zone_sync_buffers`)
3. **网络传输**:通过 TCP 连接将变更发送给其他节点
4. **接收解析**:接收节点解析同步消息并更新本地共享内存
5. **一致性保证**:所有节点最终达到状态一致
### 2.5 节点生命周期管理
| 操作 | 步骤 |
|------|------|
| **添加节点** | 1. 更新 DNS(动态)或配置(静态)
2. 启动新 NGINX 实例
3. 自动发现并开始同步 |
| **移除节点** | 1. 更新 DNS 或配置
2. 发送 `QUIT` 信号优雅关闭
3. 其他节点检测到连接关闭 |
| **更换节点 IP** | 1. 更新 DNS 记录
2. 其他节点自动检测到变化
3. 重新建立连接 |
---
## 3. 指令详解
### 3.1 zone_sync
**启用共享内存区域同步**。
| 属性 | 说明 |
|------|------|
| **语法** | `zone_sync;` |
| **默认值** | — |
| **上下文** | `server` |
| **版本** | 1.13.8+ |
**配置示例**:
```nginx
stream {
server {
# 启用 zone 同步
zone_sync;
listen 127.0.0.1:12345;
zone_sync_server 192.168.1.10:12345;
zone_sync_server 192.168.1.11:12345;
}
}
```
**注意事项**:
- 必须在 `stream` 块的 `server` 上下文中使用
- 需要配合 `zone_sync_server` 指定集群节点
- 每个节点必须有唯一的监听地址
---
### 3.2 zone_sync_server
**定义集群节点地址**。
| 属性 | 说明 |
|------|------|
| **语法** | `zone_sync_server address [resolve];` |
| **默认值** | — |
| **上下文** | `server` |
| **版本** | 1.13.8+ |
**参数说明**:
| 参数 | 说明 |
|------|------|
| `address` | 节点地址,支持以下格式:
- `IP:port`(如 `192.168.1.10:12345`)
- `域名:port`(如 `nginx-node1.example.com:12345`)
- `unix:/path/to/socket`(Unix 域套接字) |
| `resolve` | 启用 DNS 监控,域名解析变化时自动更新(需要 `resolver` 指令) |
**配置示例**:
```nginx
stream {
# 静态配置
server {
zone_sync;
listen 127.0.0.1:12345;
zone_sync_server 192.168.1.10:12345;
zone_sync_server 192.168.1.11:12345;
}
}
```
```nginx
stream {
resolver 192.168.1.1 valid=30s;
# 动态 DNS 发现
server {
zone_sync;
listen 127.0.0.1:12345;
# 解析到多个 A 记录
zone_sync_server cluster.example.com:12345 resolve;
}
}
```
**注意事项**:
- 每个节点在配置中只能出现一次
- 集群中所有节点应该使用相同的配置
- 使用 `resolve` 时必须配置 `resolver`
---
### 3.3 zone_sync_connect_timeout
**设置与集群节点建立连接的超时时间**。
| 属性 | 说明 |
|------|------|
| **语法** | `zone_sync_connect_timeout time;` |
| **默认值** | `5s` |
| **上下文** | `stream`, `server` |
| **版本** | 1.13.8+ |
**参数说明**:
| 参数 | 说明 |
|------|------|
| `time` | 超时时间,支持单位:`ms`, `s`, `m`, `h` |
**配置示例**:
```nginx
stream {
server {
zone_sync;
listen 127.0.0.1:12345;
# 连接超时设置为 10 秒
zone_sync_connect_timeout 10s;
zone_sync_server 192.168.1.10:12345;
}
}
```
**适用场景**:
- 网络延迟较高时需要增加超时
- 快速失败场景可减少超时
---
### 3.4 zone_sync_timeout
**设置连续读写操作之间的超时时间**。
| 属性 | 说明 |
|------|------|
| **语法** | `zone_sync_timeout time;` |
| **默认值** | `5s` |
| **上下文** | `stream`, `server` |
| **版本** | 1.13.8+ |
**说明**:
该指令替代了早期版本中可能的 `zone_sync_recv_timeout` 和 `zone_sync_send_timeout`,统一控制读写超时。
| 参数 | 说明 |
|------|------|
| `time` | 超时时间,两次连续读取或写入之间的最大间隔 |
**配置示例**:
```nginx
stream {
server {
zone_sync;
listen 127.0.0.1:12345;
# 读写超时设置为 30 秒
zone_sync_timeout 30s;
zone_sync_server 192.168.1.10:12345;
}
}
```
---
### 3.5 zone_sync_buffers
**设置用于推送区域内容的缓冲区数量和大小**。
| 属性 | 说明 |
|------|------|
| **语法** | `zone_sync_buffers number size;` |
| **默认值** | `8 4k` 或 `8 8k`(取决于平台内存页大小) |
| **上下文** | `stream`, `server` |
| **版本** | 1.13.8+ |
**参数说明**:
| 参数 | 说明 |
|------|------|
| `number` | 缓冲区数量 |
| `size` | 每个缓冲区大小 |
**重要限制**:
- 单个缓冲区必须足够大以容纳任何共享内存区域中的**单个条目**
- 如果条目超过缓冲区大小,同步将失败
**配置示例**:
```nginx
stream {
server {
zone_sync;
listen 127.0.0.1:12345;
# 16 个 8k 缓冲区
zone_sync_buffers 16 8k;
zone_sync_server 192.168.1.10:12345;
}
}
```
**调优建议**:
- 如果 keyval 条目较大(如 JSON 配置),增加 `size`
- 如果同步频繁,增加 `number`
---
### 3.6 zone_sync_interval
**设置轮询共享内存区域更新的间隔时间**。
| 属性 | 说明 |
|------|------|
| **语法** | `zone_sync_interval time;` |
| **默认值** | `1s` |
| **上下文** | `stream`, `server` |
| **版本** | 1.13.8+ |
**参数说明**:
| 参数 | 说明 |
|------|------|
| `time` | 轮询间隔,较短间隔意味着更快的同步但更高的 CPU 使用 |
**配置示例**:
```nginx
stream {
server {
zone_sync;
listen 127.0.0.1:12345;
# 每 500ms 轮询一次更新
zone_sync_interval 500ms;
zone_sync_server 192.168.1.10:12345;
}
}
```
**调优建议**:
- 默认 `1s` 适用于大多数场景
- 对实时性要求高的场景可减少到 `100-500ms`
- 资源受限场景可增加到 `2-5s`
---
### 3.7 zone_sync_recv_buffer_size
**设置每个连接的接收缓冲区大小,用于解析同步消息**。
| 属性 | 说明 |
|------|------|
| **语法** | `zone_sync_recv_buffer_size size;` |
| **默认值** | `4k` 或 `8k`(与 `zone_sync_buffers` 的 `size × number` 相同) |
| **上下文** | `stream`, `server` |
| **版本** | 1.13.8+ |
**参数说明**:
| 参数 | 说明 |
|------|------|
| `size` | 接收缓冲区大小,必须大于或等于 `zone_sync_buffers` 的单个缓冲区大小 |
**配置示例**:
```nginx
stream {
server {
zone_sync;
listen 127.0.0.1:12345;
zone_sync_buffers 16 8k;
# 接收缓冲区至少 8k
zone_sync_recv_buffer_size 16k;
zone_sync_server 192.168.1.10:12345;
}
}
```
---
### 3.8 zone_sync_connect_retry_interval
**设置连接失败后重试的间隔时间**。
| 属性 | 说明 |
|------|------|
| **语法** | `zone_sync_connect_retry_interval time;` |
| **默认值** | `1s` |
| **上下文** | `stream`, `server` |
| **版本** | 1.13.8+ |
**参数说明**:
| 参数 | 说明 |
|------|------|
| `time` | 重试间隔,较短间隔可以更快恢复但可能增加网络负担 |
**配置示例**:
```nginx
stream {
server {
zone_sync;
listen 127.0.0.1:12345;
# 连接失败后每 5 秒重试一次
zone_sync_connect_retry_interval 5s;
zone_sync_server 192.168.1.10:12345;
}
}
```
---
### 3.9 SSL 相关指令
Zone Sync 支持节点间 SSL 加密传输。
| 指令 | 说明 |
|------|------|
| `zone_sync_ssl on\|off` | 启用 SSL(默认 `off`) |
| `zone_sync_ssl_certificate file` | SSL 证书文件 |
| `zone_sync_ssl_certificate_key file` | SSL 密钥文件 |
| `zone_sync_ssl_protocols protocols` | SSL 协议版本(如 `TLSv1.2 TLSv1.3`) |
| `zone_sync_ssl_ciphers ciphers` | SSL 加密套件 |
| `zone_sync_ssl_server_name on\|off` | 启用 SNI(默认 `off`) |
| `zone_sync_ssl_name name` | 覆盖 SSL 验证的服务器名称 |
| `zone_sync_ssl_verify on\|off` | 启用证书验证(默认 `off`) |
| `zone_sync_ssl_verify_depth number` | 验证深度(默认 `1`) |
| `zone_sync_ssl_trusted_certificate file` | 受信任的 CA 证书 |
| `zone_sync_ssl_crl file` | 证书吊销列表 |
**SSL 配置示例**:
```nginx
stream {
resolver 192.168.1.1 valid=30s;
server {
zone_sync;
listen 127.0.0.1:12345;
zone_sync_server cluster.example.com:12345 resolve;
# 启用 SSL
zone_sync_ssl on;
zone_sync_ssl_certificate /etc/nginx/certs/cluster.crt;
zone_sync_ssl_certificate_key /etc/nginx/certs/cluster.key;
zone_sync_ssl_protocols TLSv1.2 TLSv1.3;
zone_sync_ssl_ciphers HIGH:!aNULL:!MD5;
}
}
```
---
## 4. 集群配置示例
### 4.1 最小化配置
```nginx
# nginx.conf
worker_processes auto;
events {
worker_connections 1024;
}
http {
# 定义需要同步的 zone
upstream backend {
server backend1.example.com:8080;
sticky learn
create=$upstream_cookie_session
lookup=$cookie_session
zone=session_store:1m sync;
}
server {
listen 80;
location / {
proxy_pass http://backend;
}
}
}
stream {
server {
# 启用 zone 同步
zone_sync;
listen 127.0.0.1:12345;
# 集群节点配置
zone_sync_server node1.example.com:12345;
zone_sync_server node2.example.com:12345;
}
}
```
---
### 4.2 三节点集群配置
#### 节点 1(192.168.1.10)
```nginx
# /etc/nginx/nginx.conf (Node 1)
events {
worker_connections 4096;
}
stream {
server {
zone_sync;
listen 192.168.1.10:12345;
zone_sync_server 192.168.1.10:12345;
zone_sync_server 192.168.1.11:12345;
zone_sync_server 192.168.1.12:12345;
zone_sync_connect_timeout 10s;
zone_sync_timeout 30s;
zone_sync_interval 500ms;
}
}
```
#### 节点 2(192.168.1.11)
```nginx
# /etc/nginx/nginx.conf (Node 2)
events {
worker_connections 4096;
}
stream {
server {
zone_sync;
listen 192.168.1.11:12345;
zone_sync_server 192.168.1.10:12345;
zone_sync_server 192.168.1.11:12345;
zone_sync_server 192.168.1.12:12345;
zone_sync_connect_timeout 10s;
zone_sync_timeout 30s;
zone_sync_interval 500ms;
}
}
```
#### 节点 3(192.168.1.12)
```nginx
# /etc/nginx/nginx.conf (Node 3)
events {
worker_connections 4096;
}
stream {
server {
zone_sync;
listen 192.168.1.12:12345;
zone_sync_server 192.168.1.10:12345;
zone_sync_server 192.168.1.11:12345;
zone_sync_server 192.168.1.12:12345;
zone_sync_connect_timeout 10s;
zone_sync_timeout 30s;
zone_sync_interval 500ms;
}
}
```
---
### 4.3 动态 DNS 发现配置
```nginx
# 所有节点使用相同配置
events {
worker_connections 4096;
}
stream {
# 配置 DNS 解析器
resolver 192.168.1.1 valid=10s;
server {
zone_sync;
listen 0.0.0.0:12345;
# 通过 SRV 或 A 记录动态发现节点
zone_sync_server nginx-cluster.internal:12345 resolve;
zone_sync_connect_timeout 5s;
zone_sync_connect_retry_interval 2s;
}
}
```
**DNS 记录配置示例**:
```
# DNS A 记录
nginx-cluster.internal. IN A 192.168.1.10
nginx-cluster.internal. IN A 192.168.1.11
nginx-cluster.internal. IN A 192.168.1.12
```
---
### 4.4 同步 keyval 状态
```nginx
events {
worker_connections 4096;
}
http {
# 需要同步的 keyval zone(带 timeout 和 sync 参数)
keyval_zone zone=user_sessions:64k state=/var/lib/nginx/state/sessions.keyval timeout=1h sync;
keyval_zone zone=api_keys:32k state=/var/lib/nginx/state/api_keys.keyval sync;
keyval $cookie_session $session_data zone=user_sessions;
keyval $arg_api_key $api_info zone=api_keys;
# API 管理接口
server {
listen 127.0.0.1:8080;
location /api {
api write=on;
allow 127.0.0.1;
deny all;
}
}
server {
listen 80;
location / {
if ($api_info = "") {
return 403 "API key required";
}
proxy_pass http://backend;
}
}
}
stream {
server {
zone_sync;
listen 0.0.0.0:12345;
zone_sync_server node1.example.com:12345;
zone_sync_server node2.example.com:12345;
zone_sync_buffers 16 8k;
zone_sync_interval 500ms;
}
}
```
---
### 4.5 同步 limit_conn 状态
```nginx
events {
worker_connections 4096;
}
http {
# 限制连接数 zone(需要同步)
limit_conn_zone $binary_remote_addr zone=addr_limit:10m;
# 注意:limit_conn_zone 不直接支持 sync 参数
# 需要通过 keyval 间接实现分布式限流
server {
listen 80;
location /downloads {
limit_conn addr_limit 10;
proxy_pass http://backend;
}
}
}
stream {
server {
zone_sync;
listen 0.0.0.0:12345;
zone_sync_server node1.example.com:12345;
zone_sync_server node2.example.com:12345;
}
}
```
**注意**:`limit_conn_zone` 和 `limit_req_zone` 的同步需要 NGINX Plus 特定版本支持。
---
### 4.6 同步 sticky sessions
```nginx
events {
worker_connections 4096;
}
http {
upstream api_backend {
server 192.168.1.10:8080;
server 192.168.1.11:8080;
# sticky learn 会话粘性,带 sync 参数
sticky learn
create=$upstream_cookie_route
lookup=$cookie_route
zone=sticky_sessions:2m sync;
}
server {
listen 80;
location /api {
proxy_pass http://api_backend;
}
}
}
stream {
server {
zone_sync;
listen 0.0.0.0:12345;
zone_sync_server node1.example.com:12345;
zone_sync_server node2.example.com:12345;
zone_sync_interval 200ms; # 更快的会话同步
}
}
```
---
## 5. 与 Keyval 模块配合使用
### 5.1 Keyval Zone 同步配置
```nginx
events {
worker_connections 4096;
}
http {
# ========== 需要同步的 keyval zones ==========
# 用户会话(带过期时间)
keyval_zone zone=sessions:2m state=/var/lib/nginx/state/sessions.keyval timeout=30m sync;
keyval $cookie_session $session_info zone=sessions;
# 动态路由配置
keyval_zone zone=routes:512k state=/var/lib/nginx/state/routes.keyval sync;
keyval $uri $backend_pool zone=routes;
# API 限流黑白名单
keyval_zone zone=rate_whitelist:1m type=ip sync;
keyval $remote_addr $rate_exempt zone=rate_whitelist;
# ========== 后端定义 ==========
upstream backend_pool_a {
server 192.168.1.10:8080;
server 192.168.1.11:8080;
}
upstream backend_pool_b {
server 192.168.1.20:8080;
server 192.168.1.21:8080;
}
# ========== API 管理服务器 ==========
server {
listen 127.0.0.1:8080;
location /api {
api write=on;
allow 127.0.0.1;
deny all;
}
}
# ========== 主业务服务器 ==========
server {
listen 80;
server_name app.example.com;
location / {
# 白名单跳过限流
if ($rate_exempt = "exempt") {
proxy_pass http://backend_pool_a;
break;
}
# 动态路由
if ($backend_pool = "") {
set $backend_pool "backend_pool_a";
}
proxy_pass http://$backend_pool;
}
}
}
stream {
# Zone Sync 配置
server {
zone_sync;
listen 0.0.0.0:12345;
# 集群节点
zone_sync_server 192.168.1.10:12345;
zone_sync_server 192.168.1.11:12345;
# 同步参数调优
zone_sync_buffers 32 16k;
zone_sync_interval 500ms;
zone_sync_timeout 30s;
}
}
```
---
### 5.2 通过 API 管理同步数据
```bash
#!/bin/bash
# API 端点
API_BASE="http://127.0.0.1:8080/api/9"
# 添加会话
curl -X POST "${API_BASE}/http/keyvals/sessions" \
-H "Content-Type: application/json" \
-d '{
"user123": {
"value": "{\"user_id\": 123, \"role\": \"admin\"}",
"expire": 1800000
}
}'
# 添加路由规则
curl -X POST "${API_BASE}/http/keyvals/routes" \
-H "Content-Type: application/json" \
-d '{
"/api/v1": "backend_pool_a",
"/api/v2": "backend_pool_b",
"/admin": "backend_pool_a"
}'
# 查询会话数据
curl "${API_BASE}/http/keyvals/sessions?key=user123"
# 查询所有路由
curl "${API_BASE}/http/keyvals/routes"
# 删除键
curl -X PATCH "${API_BASE}/http/keyvals/sessions" \
-H "Content-Type: application/json" \
-d '{"user123": null}'
# 清空 zone
curl -X DELETE "${API_BASE}/http/keyvals/routes"
```
---
### 5.3 集群状态监控
```bash
# 查询 Zone Sync 状态
curl http://127.0.0.1:8080/api/9/stream/zone_sync/
# 示例响应
{
"connections": {
"active": 2,
"idle": 0,
"closed": 5
},
"messages": {
"sent": 12345,
"received": 12300
},
"bytes": {
"sent": 1048576,
"received": 1024000
},
"zones": {
"sessions": {
"entries": 150,
"size": 32768
},
"routes": {
"entries": 25,
"size": 8192
}
}
}
```
---
## 6. 性能调优与最佳实践
### 6.1 缓冲区大小调优
```nginx
stream {
server {
zone_sync;
listen 0.0.0.0:12345;
# 场景 1:小型键值对(<1KB)
zone_sync_buffers 8 4k;
# 场景 2:中型配置(1-4KB)
zone_sync_buffers 16 8k;
# 场景 3:大型 JSON 配置(>4KB)
zone_sync_buffers 32 16k;
zone_sync_server node1.example.com:12345;
}
}
```
---
### 6.2 同步间隔调优
```nginx
# 高实时性场景(会话同步)
zone_sync_interval 100ms;
# 一般场景(路由配置)
zone_sync_interval 500ms;
# 低频率场景(配置同步)
zone_sync_interval 2s;
```
---
### 6.3 网络调优
```nginx
stream {
server {
zone_sync;
listen 0.0.0.0:12345;
# 高延迟网络(跨数据中心)
zone_sync_connect_timeout 15s;
zone_sync_timeout 60s;
zone_sync_connect_retry_interval 5s;
# 低延迟网络(同数据中心)
zone_sync_connect_timeout 3s;
zone_sync_timeout 10s;
zone_sync_connect_retry_interval 1s;
zone_sync_server node1.example.com:12345;
}
}
```
---
### 6.4 内存规划
```nginx
http {
# 估算内存需求
# 每个键值对:key(50B) + value(100B) + overhead(50B) ≈ 200B
# 10,000 键值对 ≈ 2MB
keyval_zone zone=large_db:4m sync;
# 建议预留 50% 余量
keyval_zone zone=with_margin:6m sync;
}
```
---
### 6.5 安全建议
```nginx
stream {
server {
zone_sync;
# 只监听内网地址
listen 192.168.1.10:12345;
# 启用 SSL 加密
zone_sync_ssl on;
zone_sync_ssl_certificate /etc/nginx/certs/cluster.crt;
zone_sync_ssl_certificate_key /etc/nginx/certs/cluster.key;
zone_sync_ssl_protocols TLSv1.3;
zone_sync_ssl_ciphers ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384;
zone_sync_server node1.internal:12345;
}
}
```
---
## 7. 故障排查
### 7.1 常见问题
| 问题 | 可能原因 | 解决方案 |
|------|----------|----------|
| 连接失败 | 防火墙/网络不通 | 检查端口连通性,确认防火墙规则 |
| 同步延迟 | 缓冲区不足 | 增加 `zone_sync_buffers` 大小 |
| 节点无法发现 | DNS 解析问题 | 检查 `resolver` 配置,验证 DNS 记录 |
| 数据不一致 | 网络分区 | 检查网络连接,增加超时时间 |
| 内存增长 | 无过期时间 | 配置 `timeout` 参数 |
---
### 7.2 调试命令
```bash
# 测试配置
nginx -t
# 重载配置
nginx -s reload
# 检查进程状态
ps aux | grep nginx
# 查看网络连接
netstat -tlnp | grep nginx
ss -tlnp | grep nginx
# 监控日志
tail -f /var/log/nginx/error.log
# 查看 Zone Sync API 状态
curl http://localhost:8080/api/9/stream/zone_sync/
```
---
## 8. 与 Lolly 项目的关系和建议
### 8.1 项目对比
[Lolly](https://github.com/xfy/lolly) 是一个使用 Go 语言编写的高性能 HTTP 服务器与反向代理。与 NGINX Zone Sync 相比:
| 特性 | NGINX Zone Sync | Lolly |
|------|-----------------|-------|
| **集群同步** | 内置支持,商业功能 | 需自行实现 |
| **状态存储** | 共享内存 | 内存/外部存储 |
| **节点发现** | 静态/DNS | 需自行实现 |
| **传输协议** | TCP(专有协议) | 可自定义 |
| **许可证** | 商业订阅 | 开源免费 |
---
### 8.2 Go 实现分布式状态同步建议
#### 方案 1:基于 Gossip 协议
```go
// internal/cluster/gossip.go
package cluster
import (
"sync"
"time"
"github.com/hashicorp/memberlist"
)
type StateSync struct {
list *memberlist.Memberlist
store sync.Map
config *Config
}
type Config struct {
NodeName string
BindAddr string
BindPort int
JoinNodes []string
SyncInterval time.Duration
}
func NewStateSync(cfg *Config) (*StateSync, error) {
s := &StateSync{config: cfg}
mlConfig := memberlist.DefaultLANConfig()
mlConfig.Name = cfg.NodeName
mlConfig.BindAddr = cfg.BindAddr
mlConfig.BindPort = cfg.BindPort
mlConfig.Delegate = s
list, err := memberlist.Create(mlConfig)
if err != nil {
return nil, err
}
s.list = list
if len(cfg.JoinNodes) > 0 {
_, err = list.Join(cfg.JoinNodes)
if err != nil {
return nil, err
}
}
return s, nil
}
// 实现 memberlist.Delegate 接口
func (s *StateSync) NodeMeta(limit int) []byte {
return []byte{}
}
func (s *StateSync) NotifyMsg(buf []byte) {
// 处理接收到的同步消息
}
func (s *StateSync) GetBroadcasts(overhead, limit int) [][]byte {
// 返回待广播的变更
return nil
}
func (s *StateSync) LocalState(join bool) []byte {
// 返回本地状态
return nil
}
func (s *StateSync) MergeRemoteState(buf []byte, join bool) {
// 合并远程状态
}
// 状态操作接口
func (s *StateSync) Set(key, value string) error {
s.store.Store(key, value)
return s.broadcastUpdate(key, value)
}
func (s *StateSync) Get(key string) (string, bool) {
val, ok := s.store.Load(key)
if !ok {
return "", false
}
return val.(string), true
}
func (s *StateSync) Delete(key string) error {
s.store.Delete(key)
return s.broadcastDelete(key)
}
```
---
#### 方案 2:基于 Redis Pub/Sub
```go
// internal/cluster/redis_sync.go
package cluster
import (
"context"
"encoding/json"
"time"
"github.com/redis/go-redis/v9"
)
type RedisSync struct {
client *redis.Client
channel string
nodeID string
store sync.Map
}
type SyncMessage struct {
Type string `json:"type"` // "set", "delete", "full"
Key string `json:"key,omitempty"`
Value interface{} `json:"value,omitempty"`
NodeID string `json:"node_id"`
Timestamp int64 `json:"timestamp"`
}
func NewRedisSync(addr, channel, nodeID string) (*RedisSync, error) {
client := redis.NewClient(&redis.Options{
Addr: addr,
})
s := &RedisSync{
client: client,
channel: channel,
nodeID: nodeID,
}
// 启动订阅协程
go s.subscribe(context.Background())
return s, nil
}
func (s *RedisSync) subscribe(ctx context.Context) {
pubsub := s.client.Subscribe(ctx, s.channel)
defer pubsub.Close()
ch := pubsub.Channel()
for msg := range ch {
if err := s.handleMessage(msg.Payload); err != nil {
// 处理错误
}
}
}
func (s *RedisSync) handleMessage(payload string) error {
var msg SyncMessage
if err := json.Unmarshal([]byte(payload), &msg); err != nil {
return err
}
// 忽略自己发送的消息
if msg.NodeID == s.nodeID {
return nil
}
switch msg.Type {
case "set":
s.store.Store(msg.Key, msg.Value)
case "delete":
s.store.Delete(msg.Key)
}
return nil
}
func (s *RedisSync) Set(ctx context.Context, key string, value interface{}) error {
msg := SyncMessage{
Type: "set",
Key: key,
Value: value,
NodeID: s.nodeID,
Timestamp: time.Now().UnixNano(),
}
data, _ := json.Marshal(msg)
s.store.Store(key, value)
return s.client.Publish(ctx, s.channel, data).Err()
}
func (s *RedisSync) Delete(ctx context.Context, key string) error {
msg := SyncMessage{
Type: "delete",
Key: key,
NodeID: s.nodeID,
Timestamp: time.Now().UnixNano(),
}
data, _ := json.Marshal(msg)
s.store.Delete(key)
return s.client.Publish(ctx, s.channel, data).Err()
}
```
---
#### 方案 3:基于 etcd 的强一致性同步
```go
// internal/cluster/etcd_sync.go
package cluster
import (
"context"
"time"
clientv3 "go.etcd.io/etcd/client/v3"
)
type EtcdSync struct {
client *clientv3.Client
prefix string
nodeID string
ctx context.Context
}
func NewEtcdSync(endpoints []string, prefix, nodeID string) (*EtcdSync, error) {
client, err := clientv3.New(clientv3.Config{
Endpoints: endpoints,
DialTimeout: 5 * time.Second,
})
if err != nil {
return nil, err
}
return &EtcdSync{
client: client,
prefix: prefix,
nodeID: nodeID,
ctx: context.Background(),
}, nil
}
func (s *EtcdSync) Set(key string, value string, ttl time.Duration) error {
ctx, cancel := context.WithTimeout(s.ctx, 5*time.Second)
defer cancel()
if ttl > 0 {
lease, err := s.client.Grant(ctx, int64(ttl.Seconds()))
if err != nil {
return err
}
_, err = s.client.Put(ctx, s.prefix+key, value,
clientv3.WithLease(lease.ID))
return err
}
_, err := s.client.Put(ctx, s.prefix+key, value)
return err
}
func (s *EtcdSync) Get(key string) (string, error) {
ctx, cancel := context.WithTimeout(s.ctx, 5*time.Second)
defer cancel()
resp, err := s.client.Get(ctx, s.prefix+key)
if err != nil {
return "", err
}
if len(resp.Kvs) == 0 {
return "", nil
}
return string(resp.Kvs[0].Value), nil
}
func (s *EtcdSync) Watch(ctx context.Context, key string) <-chan string {
ch := make(chan string)
go func() {
defer close(ch)
rch := s.client.Watch(ctx, s.prefix+key)
for wresp := range rch {
for _, ev := range wresp.Events {
ch <- string(ev.Kv.Value)
}
}
}()
return ch
}
```
---
### 8.3 Lolly 实现建议
参考 NGINX Zone Sync 模块,建议 Lolly 可以考虑以下实现:
1. **模块化设计**
- 抽象 `StateSync` 接口
- 支持多种后端(内存、Redis、etcd、Gossip)
- 插件式注册
2. **配置示例**
```yaml
# config.yaml
cluster:
enabled: true
node_id: "node-1"
bind_addr: "0.0.0.0"
bind_port: 9000
join_nodes:
- "192.168.1.10:9000"
- "192.168.1.11:9000"
sync_interval: 500ms
backend: "gossip" # 或 "redis", "etcd"
# Redis 后端配置
redis:
addr: "localhost:6379"
channel: "lolly:sync"
# etcd 后端配置
etcd:
endpoints:
- "localhost:2379"
prefix: "/lolly/state/"
```
3. **API 设计**
```go
// 定义同步状态接口
type StateSync interface {
Set(key string, value interface{}, ttl time.Duration) error
Get(key string) (interface{}, bool)
Delete(key string) error
Watch(key string) <-chan StateChange
Close() error
}
// 状态变更事件
type StateChange struct {
Key string
Value interface{}
Deleted bool
Timestamp time.Time
}
```
4. **与 NGINX Plus API 兼容**
```go
// 提供与 NGINX Plus 兼容的 REST API
// POST /api/lolly/keyvals/{zone}
// GET /api/lolly/keyvals/{zone}
// PATCH /api/lolly/keyvals/{zone}
// DELETE /api/lolly/keyvals/{zone}
```
---
## 9. 参考链接
- [NGINX Zone Sync 模块官方文档](https://nginx.org/en/docs/stream/ngx_stream_zone_sync_module.html)
- [NGINX Keyval 模块官方文档](https://nginx.org/en/docs/stream/ngx_stream_keyval_module.html)
- [NGINX Plus API 文档](https://nginx.org/en/docs/http/ngx_http_api_module.html)
- [Lolly 项目 GitHub](https://github.com/xfy/lolly)
- [memberlist (HashiCorp)](https://github.com/hashicorp/memberlist)
- [etcd 官方文档](https://etcd.io/docs/)