--- title: "TCP 地址重用配置" date: 2026-02-25 lastmod: 2026-02-25 description: "network.tcp.reuse_address 配置项用于控制是否启用 TCP SO_REUSEADDR 套接字选项。" tags: ["网络", "TCP", "端口重用", "Socket选项"] summary: "配置项作用 # network.tcp.reuse_address 配置项用于控制是否启用 TCP 套接字的 SO_REUSEADDR 选项。 启用后允许端口在 TIME_WAIT 状态下被重用,避免"地址已在使用"错误,便于服务器快速重启。 配置项属性 # 配置路径: network.tcp.reuse_address 数据类型: Boolean(布尔值) 默认值: 平台相关 Linux/MacOS: true Windows: false 是否可选: 是 作用域: NodeScope(节点级别) 动态更新: 否(需要重启节点生效) 配置项详解 # 工作机制 # SO_REUSEADDR 作用 未启用 (false): 端口使用: ├── 绑定端口 9300 ├── 使用后关闭 ├── 进入 TIME_WAIT (通常 60 秒) └── 在此期间无法重用 ❌ 快速重启问题: ├── 节点关闭 ├── 立即重启 ├── 端口仍在 TIME_WAIT └── 绑定失败 ❌ 启用 (true): 端口使用: ├── 绑定端口 9300 ├── 使用后关闭 ├── 进入 TIME_WAIT └── 可以立即重用 ✅ 快速重启: ├── 节点关闭 ├── 立即重启 ├── 强制重用端口 └── 绑定成功 ✅ TIME_WAIT 状态 # TCP 连接关闭流程 正常关闭: 活跃节点 被动节点 │ │ ├── FIN ─────────→ │ │←──────── ACK ──┤ │ │ │←──────── FIN ──┤ ├── ACK ─────────→ │ │ │ ↓ ↓ CLOSED CLOSED 被动端直接关闭 活跃端进入 TIME_WAIT: ├── 等待 2×MSL (通常 60 秒) ├── 确保远程收到最后的 ACK └── 防止延迟的包干扰 SO_REUSEADDR: ├── 允许在此状态下绑定 ├── 跳过 TIME_WAIT 等待 └── 立即可重用 ✅ 平台差异 # 不同平台的默认值 Linux/MacOS: 默认值: true ├── Unix 系统传统 ├── 适合服务器应用 └── 推荐启用 ✅ Windows: 默认值: false ├── Windows 系统特性 ├── 避免安全问题 └── 推荐保持默认 ⚠️ 代码实现: if (Constants." --- ## 配置项作用 `network.tcp.reuse_address` 配置项用于控制**是否启用 TCP 套接字的 SO_REUSEADDR 选项**。 启用后允许端口在 TIME_WAIT 状态下被重用,避免"地址已在使用"错误,便于服务器快速重启。 ## 配置项属性 - **配置路径**: `network.tcp.reuse_address` - **数据类型**: `Boolean`(布尔值) - **默认值**: 平台相关 - Linux/MacOS: `true` - Windows: `false` - **是否可选**: 是 - **作用域**: NodeScope(节点级别) - **动态更新**: 否(需要重启节点生效) ## 配置项详解 ## 工作机制 ``` SO_REUSEADDR 作用 未启用 (false): 端口使用: ├── 绑定端口 9300 ├── 使用后关闭 ├── 进入 TIME_WAIT (通常 60 秒) └── 在此期间无法重用 ❌ 快速重启问题: ├── 节点关闭 ├── 立即重启 ├── 端口仍在 TIME_WAIT └── 绑定失败 ❌ 启用 (true): 端口使用: ├── 绑定端口 9300 ├── 使用后关闭 ├── 进入 TIME_WAIT └── 可以立即重用 ✅ 快速重启: ├── 节点关闭 ├── 立即重启 ├── 强制重用端口 └── 绑定成功 ✅ ``` ## TIME_WAIT 状态 ``` TCP 连接关闭流程 正常关闭: 活跃节点 被动节点 │ │ ├── FIN ─────────→ │ │←──────── ACK ──┤ │ │ │←──────── FIN ──┤ ├── ACK ─────────→ │ │ │ ↓ ↓ CLOSED CLOSED 被动端直接关闭 活跃端进入 TIME_WAIT: ├── 等待 2×MSL (通常 60 秒) ├── 确保远程收到最后的 ACK └── 防止延迟的包干扰 SO_REUSEADDR: ├── 允许在此状态下绑定 ├── 跳过 TIME_WAIT 等待 └── 立即可重用 ✅ ``` ## 平台差异 ``` 不同平台的默认值 Linux/MacOS: 默认值: true ├── Unix 系统传统 ├── 适合服务器应用 └── 推荐启用 ✅ Windows: 默认值: false ├── Windows 系统特性 ├── 避免安全问题 └── 推荐保持默认 ⚠️ 代码实现: if (Constants.WINDOWS) { defaultReuseAddress = false; } else { defaultReuseAddress = true; } ``` ## 配置建议 ## Linux/MacOS 生产环境(默认) ```yaml network: tcp: reuse_address: true # 默认值 ``` **建议**: 保持默认值 `true`。适合服务器应用。 ## Windows 生产环境(默认) ```yaml network: tcp: reuse_address: false # 默认值 ``` **建议**: 保持默认值 `false`。Windows 推荐配置。 ## 跨平台统一配置 ```yaml network: tcp: reuse_address: true # 统一启用 ``` **建议**: 跨平台统一设置,便于维护。 ## 开发测试环境 ```yaml network: tcp: reuse_address: true # 便于快速重启 ``` **建议**: 设置为 `true`。便于频繁重启。 ## 代码示例 ## easysearch.yml 基础配置 ```yaml network: tcp: reuse_address: true ``` ## Linux 服务器配置 ```yaml network: tcp: reuse_address: true no_delay: true keep_alive: true ``` ## Windows 客户端配置 ```yaml network: tcp: reuse_address: false # Windows 默认 ``` ## 完整 TCP 配置 ```yaml network: tcp: reuse_address: true no_delay: true keep_alive: true keep_idle: 300 keep_interval: 300 ``` ## 相关配置 | 配置项 | 作用 | 默认值 | |--------|------|--------| | `network.tcp.reuse_address` | 地址重用 | 平台相关 | | `network.tcp.no_delay` | 禁用 Nagle | true | | `network.tcp.keep_alive` | Keepalive | true | ## 功能影响分析 | reuse_address 设置 | 优点 | 缺点 | |---------------------|------|------| | false | 安全性高,避免地址冲突 | 快速重启可能失败 | | true | 支持快速重启 | 可能地址冲突 | ## 应用场景对比 ``` 启用 reuse_address 的场景 场景 1: 快速重启 节点崩溃: ├── 进程退出 ├── 端口进入 TIME_WAIT ├── 自动重启脚本 └── 立即重启成功 ✅ 场景 2: 多实例 同一主机多实例: ├── 实例 A: 绑定 9300 ├── 实例 B: 绑定 9301 ├── 实例 A 重启 ├── 端口 9300 可用 └── 重启成功 ✅ 场景 3: 故障转移 主节点故障: ├── 主节点退出 ├── 端口 TIME_WAIT ├── 备节点接管 ├── 绑定相同端口 └── 接管成功 ✅ ``` ## 使用场景 ## 推荐启用的场景 - **服务器应用**: Linux/MacOS 上的服务器 - **频繁重启**: 需要频繁重启节点 - **自动化部署**: 自动化重启和部署 - **高可用性**: 需要快速故障恢复 ## 推荐禁用的场景 - **Windows 系统**: Windows 上保持默认 `false` - **严格端口控制**: 需要严格端口管理 - **避免地址冲突**: 防止地址冲突问题 ## 平台特定建议 ``` Linux/MacOS: reuse_address: true ✅ ├── 服务器操作系统 ├── 传统 Unix 行为 ├── 广泛使用 └── 强烈推荐 Windows: reuse_address: false ✅ ├── 客户端操作系统 ├── Windows 安全特性 ├── 默认设置 └── 推荐保持 跨平台应用: 建议显式配置: ├── 统一行为 ├── 便于维护 └── 避免平台差异 ``` ## 端口绑定顺序 ``` Socket 设置顺序很重要 正确顺序: 1. socket() 2. setReuseAddress() ← 必须在 bind 之前 3. bind() 4. listen() 或 connect() 错误顺序: 1. socket() 2. bind() 3. setReuseAddress() ← 太晚了 ❌ 4. listen() 或 connect() Easysearch 实现: 正确处理: ├── 先设置 reuse_address ├── 再绑定端口 └── 确保顺序正确 ✅ ``` ## 安全考虑 ``` 安全风险分析 风险场景: reuse_address = true │ ↓ 旧连接仍存在: ├── 原进程的数据包到达 ├── 被新进程接收 ├── 数据混乱 └── 潜在安全问题 ⚠️ 风险缓解: ├── 确保旧进程完全退出 ├── 使用进程管理工具 ├── 等待 TIME_WAIT └── 监控连接状态 最佳实践: ├── 服务器环境: 可以启用 ├── 多租户: 谨慎使用 ├── 公网: 评估风险 └── 测试充分 ``` ## 注意事项 1. **默认值**: 默认值因平台而异。 2. **需要重启**: 修改此配置需要重启节点。 3. **平台差异**: Linux 和 Windows 默认值不同。 4. **快速重启**: 启用后支持快速重启。 5. **地址冲突**: 可能导致地址冲突(很少见)。 6. **设置时机**: 必须在 bind 之前设置。 7. **应用场景**: 主要用于服务器端套接字。 8. **兼容性**: 与所有平台兼容。 9. **测试建议**: 配置变更后应测试重启流程。 10. **生产环境**: 生产环境通常推荐启用(Linux/MacOS)。 ## 绑定流程 ``` 端口绑定完整流程 1. 创建 Socket socket() │ ↓ 2. 设置 Socket 选项 setReuseAddress(true) ← 必须在 bind 前 │ ↓ 3. 绑定端口 bind(port) │ ├──── 成功 → 继续执行 ✅ │ └──── 失败 → ├──── 可重用 ──→ 重试 └──── 不可用 ──→ 放弃 4. 开始监听 listen() ``` ## 相关系统配置 ``` 相关系统配置 Linux: /proc/sys/net/ipv4/tcp_tw_reuse ├── 启用 TIME_WAIT 重用 ├── 默认: 0 (关闭) └── echo 1 > /proc/sys/net/ipv4/tcp_tw_reuse /proc/sys/net/ipv4/tcp_tw_recycle ├── 快速回收 TIME_WAIT 套接字 ├── 默认: 0 (关闭) └── echo 1 > /proc/sys/net/ipv4/tcp_tw_recycle 配合使用: reuse_address: true ├── 应用层面控制 ├── 更灵活 └── 推荐使用 ✅ ```