四层转发
TCP / UDP 端口转发:端口池、L4 应用、PROXY protocol、DNS、统计与节点端口。
概念
| 术语 | 定义 |
|---|---|
| L4 应用 | 在集群每个节点的一个端口上,把 TCP 连接或 UDP 会话转发给源站。 |
| 端口池 | 集群中 L4 应用可以使用的端口区间,按协议(TCP、UDP、TCP + UDP)设置。 |
| 保留端口 | 集群 HTTP / HTTPS 监听的端口,不能进入端口池。 |
| UDP 会话 | 同一客户端地址与端口发来的数据报;空闲超时前算一个会话。 |
| PROXY protocol | 连接开头的一个头部,携带客户端的地址与端口;v1 为文本,v2 为二进制。 |
工作方式
- 在集群的「端口池」页签设置端口区间,L4 应用的端口必须落在其中。
- 保存 L4 应用时发布集群的配置版本(与网站相同,经配置金丝雀;停用与删除直接到全部节点);集群每个节点在该端口监听,按权重把连接转发给源站。
- 集群开启 DNS 调度时,每个启用的应用有 CNAME 目标
<应用 UUID>.<集群域名>,客户端经它连接到健康节点。 - 节点每分钟上报每个应用的连接数、拒绝数、并发峰值与字节数,显示在应用的「统计」页签。
节点需要能力 l4-v1,见 节点要求。
设置端口池
- 打开 集群与节点,选择集群,切换到「端口池」页签(
/clusters?tab=ports,集群有节点后显示)。 - 点击「添加端口池」,选择「协议」(TCP、UDP 或 TCP + UDP),填写「起始端口」与「结束端口」。只开放一个端口时两者相同。
- 点击「保存」。控制台提示「已保存」。
- 在节点主机的防火墙与云安全组中按协议放行这些端口,容器节点还要发布它们,见 接入节点。
卡片顶部的「保留端口」列出集群 HTTP / HTTPS 监听的端口;标题旁的「四层转发」打开该集群的 L4 应用列表。
| 项目 | 行为 |
|---|---|
| 端口 | 1024–65535;起始端口不能大于结束端口(「起始端口不能大于结束端口」) |
| 数量 | 每个集群最多 64 个端口池 |
| 重叠 | 同一协议的端口池不能重叠,TCP + UDP 与 TCP、UDP 都算重叠(「端口池重叠:…」),冲突的端口池标红 |
| 缩小 | 端口池不再包含某个应用(含停用的应用)的端口时拒绝(「端口已被占用:…」) |
| 发布 | 端口池只用于校验应用的端口:保存不发布配置版本,节点不受影响 |
| 审计 | cluster.port_pools_update,元数据为修改前后的端口池 |
新建 L4 应用
-
打开 网站,用列表上方的「网站 | 四层转发」切换到「四层转发」(
/l4),点击「新建 L4 应用」。⌘K / Ctrl+K 搜索「四层转发」同样可以打开该页。 -
填写「名称」(最多 100 字符);有多个集群时选择「集群」。
-
选择「协议」(TCP 或 UDP),填写「监听端口」;转发一段端口时再填写「结束端口」。下方提示「端口池:…」列出该协议可用的端口池;集群还没有该协议的端口池时提示「集群还没有 TCP 端口池」,「设置端口池」打开集群的「端口池」页签。
-
在「源站」中填写「源站地址」「端口」「权重」,按需打开「备用」;「添加源站」添加更多源站,见 源站与健康检查。
-
按需设置「PROXY protocol」「超时」「被动健康检查」「IP 名单」与「每节点上限」。
-
「启用」默认打开。点击「创建」,控制台提示「已创建,版本 #N」。
-
验证:列表中出现该应用,「CNAME 目标」显示
<应用 UUID>.<集群域名>;连接任一节点的该端口:nc -vz <节点 IP> 9000 # TCP:连接成功 dig @<节点 IP> -p 5353 example.com +short # UDP,以转发到 DNS 源站为例 -
应用的「统计」页签开始显示连接数(每分钟上报,约 1–2 分钟后出现)。
列表与应用页
「四层转发」列表按端口排序,列为「名称」「协议」「监听端口」「源站」「CNAME 目标」「启用」;有多个集群时可选「全部集群」或单个集群。行菜单:「编辑」「统计」「删除」。
点击名称进入应用页(/l4/<应用 ID>):「概览」页签显示状态、监听端口、集群、CNAME 目标(含每条线路的目标)、源站、PROXY protocol、超时、被动健康检查、IP 名单、每节点上限与更新时间,带「编辑」「删除」;「统计」页签见 统计。
| 操作 | 位置 | 行为 |
|---|---|---|
| 编辑 | 行菜单或应用页「编辑」,对话框「编辑 L4 应用」 | 字段与新建相同,集群不能更换;保存后提示「已保存,版本 #N」 |
| 停用 / 启用 | 列表的「启用」开关,或应用页「状态」旁的开关;需要确认,停用时提示「节点不再监听这个端口,DNS 记录随之删除」 | 停用的应用保留端口与设置,不下发到节点,没有 DNS 记录;状态不变时不发布 |
| 删除 | 行菜单或应用页「删除」,确认「删除 L4 应用 {名称}?」 | 删除应用、源站与统计 |
| 变更 | 配置版本原因 | 审计 |
|---|---|---|
| 新建 | 新建 L4 应用 {应用} | l4_app.create |
| 编辑 | 修改 L4 应用 {应用} | l4_app.update(修改的字段与前后值) |
| 停用 / 启用 | 修改 L4 应用 {应用} | l4_app.disable / l4_app.enable |
| 删除 | 删除 L4 应用 {应用} | l4_app.delete |
源站与健康检查
| 字段 | 取值 | 默认值 | 作用 |
|---|---|---|---|
| 源站地址 | 域名或 IP | — | 遵守源站地址限制:特殊用途地址只在源站地址允许清单内可用;节点解析域名时检查每个解析结果 |
| 端口 | 1–65535 | — | 源站端口,可与监听端口不同 |
| 权重 | 1–100 | 1 | 按权重随机选择 |
| 备用 | 开 / 关 | 关 | 只在全部主源站不可用时使用 |
每个应用 1–32 个源站,至少一个不是备用(「至少保留一个非备用源站」)。
| 项目 | 行为 |
|---|---|
| 选择 | 健康的主源站按权重随机;主源站全部下线时只用健康的备用源站;全部下线时按主源站在前的顺序全部尝试 |
| 重试 | 只在连接源站失败(拒绝、超时)时换下一个,每个连接最多尝试 3 个源站;连接建立后不再切换 |
| 域名源站 | 由节点与网站共用的 resolver 解析;解析失败或地址全部被拒绝计一次失败 |
被动健康检查与超时:
| 字段 | 取值 | 默认值 | 作用 |
|---|---|---|---|
| 被动健康检查 · 失败次数 | 1–100 | 3 | 连接失败(UDP 另含源站不可达,如 ICMP 端口不可达)达到该次数后摘除源站 |
| 被动健康检查 · 恢复时间(秒) | 1–3600 | 30 | 摘除时长,之后重新尝试;也是失败计数的有效期,一次成功清零 |
| 超时 · 连接(秒) | 0.1–60 | 5 | 连接源站的超时 |
| 超时 · 空闲(秒) | 1–86400 | TCP 600,UDP 30 | 两个方向都没有数据多久后结束连接或会话;对话框切换协议时改为该协议的默认值(已手动修改时保留) |
健康状态只保存在各节点本机,不上报控制台,界面不显示;在节点主机上查询当前下线的源站:
sudo curl -s --unix-socket /run/edgeweir-node/control.sock http://localhost/v1/l4响应的 down 列出 {app_id, origin_id, down_until}。
端口段与源站端口
| 字段 | 取值 | 默认值 | 作用 |
|---|---|---|---|
| 结束端口 | 空,或大于监听端口;一个应用最多 1000 个端口 | 空 | 应用监听「监听端口」到「结束端口」的每个端口;端口段整体须在该协议的端口池内(可以跨相邻的端口池),与其他应用的端口或端口段不重叠 |
| 源站端口 | 固定 / 同号 | 固定 | 固定:连接源站各自的端口;同号:源站端口等于连接到达的端口(端口段 9000-9010 的 9005 连到源站的 9005),源站的端口栏留空 |
| 项目 | 规则 |
|---|---|
| 集群上限 | 一个集群的 L4 应用合计最多监听 2048 个端口(端口段按端口数计,「集群的 L4 应用最多使用 2048 个端口」) |
| 节点资源 | TCP 端口段每个端口一个监听 socket;UDP 每个端口每个 worker 一个,见 端口与防火墙 |
| 统计与 DNS | 按应用计,与单端口相同 |
| 节点能力 | 端口段、同号源站端口与 TLS 卸载需要 l4-v2 |
TLS 卸载
TCP 应用可以选择「TLS 证书」:节点终结 TLS,以明文 TCP 连接源站。
| 字段 | 取值 | 默认值 | 作用 |
|---|---|---|---|
| TLS 证书 | 不卸载 TLS / 已签发、未过期且节点能加载的证书(列表中「不可用」的证书不能选,见 HTTPS 的故障排查) | 不卸载 TLS | 握手使用的证书 |
| 最低 TLS 版本 | TLS 1.2 / TLS 1.3 | TLS 1.2 | 低于该版本的握手被拒绝 |
| 项目 | 行为 |
|---|---|
| SNI | 必须是证书中的名称(泛域名覆盖一级),否则中止握手;不带 SNI 的握手使用该证书 |
| 密码套件 | 与网站的「现代」相同,不可修改 |
| 与 PROXY protocol | 可以同时开启:「接受 PROXY protocol」时先读 PROXY 头再握手;「发送到源站」照常发送 |
| 名单与上限 | 在握手之后判断 |
| 证书 | 被应用使用的证书不能删除(「证书仍被 L4 应用使用:…」);续期后节点使用新证书,不需要 reload |
| UDP | 不支持(「TLS 卸载只用于 TCP 应用」) |
验证:
echo NAME | openssl s_client -quiet -connect <节点 IP>:9000 -servername game.example.comPROXY protocol
只用于 TCP 应用;UDP 应用显示「UDP 不支持 PROXY protocol」。
| 字段 | 取值 | 默认值 | 作用 |
|---|---|---|---|
| 发送到源站 | 不发送 / v1 / v2 | 不发送 | 每个到源站的连接先写 PROXY protocol 头:客户端的地址与端口、节点被连接的地址与端口。v2 头不带 TLV |
| 接受 PROXY protocol | 开 / 关 | 关 | 监听要求每个连接以 PROXY protocol 头开头,v1 与 v2 自动识别;用于节点前有四层负载均衡的部署。客户端地址取头部中的地址(头部为 UNKNOWN 时为 TCP 对端),IP 名单按该地址判断 |
| 接受 | 发送到源站 | 转发方式 |
|---|---|---|
| 关 | 任意 | nginx 原生转发 |
| 开 | 不发送 | nginx 原生转发 |
| 开 | v1 / v2 | Lua 中继:写入的头部带收到的头部中的客户端地址(nginx 原生发送的头部会是负载均衡器的地址)。吞吐低于原生转发;不支持半关闭,一侧关闭即结束连接 |
开启「接受 PROXY protocol」后,不带头部的连接被关闭;能直接连接该端口的客户端可以在头部声明任意地址,因此只对负载均衡器开放该端口。两项设置与端口、协议一样是结构性设置,修改时节点 reload,见 reload 与长连接。
IP 名单与连接上限
| 字段 | 取值 | 默认值 | 作用 |
|---|---|---|---|
| IP 名单 · 放行名单 | 任意 IP 名单,最多 16 个 | 无 | 选择后只接受名单内的地址 |
| IP 名单 · 拦截名单 | 任意 IP 名单,最多 16 个 | 无 | 拒绝名单内的地址 |
| 每节点上限 · 并发连接 | 0–10000000 | 0 | 每个节点同时转发的连接(UDP 为会话)上限;0 表示不限 |
| 每节点上限 · 每秒新建连接 | 0–1000000 | 0 | 每个节点每秒接受的新连接(UDP 为新会话)上限;0 表示不限 |
「添加名单」从 IP 名单 中选择,名单的「动作」不影响这里的用法。
| 项目 | 行为 |
|---|---|
| 顺序 | 放行名单、拦截名单、每秒新建连接、并发连接,第一项不满足即拒绝 |
| 拒绝 | 不转发任何数据:TCP 关闭连接(客户端已发送而未被读取的数据使内核回 RST),UDP 丢弃数据报;计入统计「拒绝」。被拒的 UDP 客户端每个数据报各计一次 |
| 计数 | 上限按节点各自计数,集群的总容量为节点数 × 上限 |
| 名单修改 | 名单条目的修改由节点热更新;被 L4 应用引用的名单不能删除(「IP 名单正在被使用:…」,列出引用者) |
| 其他防护 | 全局「拦截」「放行」名单、网站封禁与 HTTP 层的封禁、规则、WAF、挑战与 CC 防护都不作用于 L4 应用。节点具备 kernel-ban-v1 时,全局封禁由 nftables 在内核丢包,同样作用于 L4 端口,见 内核封禁 |
DNS
L4 应用使用集群的 DNS 调度,与网站相同,见 DNS 调度与告警。
| 项目 | 行为 |
|---|---|
| 记录 | 每个启用的应用一条 <应用 UUID>.<集群域名> CNAME all.<集群域名>;打开「保留站点线路别名」时另有 <线路名称>.<应用 UUID>.<集群域名> |
| 调度 | 解析线路、备用节点组、健康摘除与智能调度规则照常作用 |
| 健康 | 按节点健康摘除(心跳、数据面、已应用当前版本、调度规则),不按单个应用的源站状态 |
| 写入 | 新建或启用后,下一次对账(每分钟)写入;手动模式列在需要手动创建的记录中 |
| 停用 | 停用的应用没有记录,下一次对账删除(停用的网站保留记录) |
| DNS 不管理 | 「CNAME 目标」显示「集群 DNS 未开启」 |
客户端用 CNAME 目标与应用的端口连接,例如在自己的域名上:
game.example.com. CNAME <应用 UUID>.<集群域名>.客户端连接 game.example.com:9000。应用页「CNAME 目标」下列出每条线路的目标,可用于只走某条线路的客户端。
统计
应用页的「统计」页签(/l4/<应用 ID>?tab=stats),范围「过去 1 小时」「过去 6 小时」「过去 24 小时」(默认)「过去 7 天」,「刷新」重新读取。
| 指标 | 含义 |
|---|---|
| 连接数 | 接受的 TCP 连接或 UDP 会话 |
| 拒绝 | 被 IP 名单或每节点上限拒绝的连接或会话 |
| 并发峰值 | 每分钟各节点峰值之和,取范围内最高的一分钟 |
| 接收 | 从客户端收到的字节 |
| 发送 | 发往客户端的字节 |
图表「连接数」(连接数与拒绝)与「流量」(接收与发送);「节点」表列出每个上报节点在该范围内的数值,连接数多的在前。
| 项目 | 行为 |
|---|---|
| 上报 | 节点按应用、按分钟上报,与网站统计同批;进行中的连接每 10 秒采样一次字节数,长连接每分钟都计入 |
| 保留 | 分钟数据保留 7 天;删除应用时一并删除 |
| 丢失 | 删除集群最后一个 L4 应用或 nginx 重启时,节点尚未上报的最近一两分钟丢失 |
| 节点指标 | 节点的活动连接数(metrics-v1)包含四层的客户端连接、上游连接与 UDP 会话,调度规则的「活动连接数」条件同样计入 |
reload 与长连接
| 变更 | 节点行为 |
|---|---|
| 端口、结束端口、协议、TLS 证书的有无、「接受 PROXY protocol」、「发送到源站」的版本;新建、删除、停用、启用 | 结构性变更:重新渲染 nginx.conf 并 reload |
| 源站、权重、备用、源站端口方式、被动健康检查、超时、IP 名单及其条目、每节点上限、所选证书与最低 TLS 版本 | 热更新,不 reload;新设置作用于之后的连接 |
| 项目 | 行为 |
|---|---|
| TCP 连接 | reload 前建立的连接留在旧 worker 继续转发,直到连接结束或空闲超时;旧 worker 在最后一个连接结束后退出 |
| UDP 会话 | 不跨 reload:之后的数据报进入新 worker 的新会话(可能选到另一个源站),旧会话在空闲超时后结束 |
| 新端口 | reload 之后、L4 应用表推送之前(毫秒级)到达的连接被关闭;节点推送完成后才报告应用成功 |
| 旧 worker | 默认一直服务到连接结束,频繁的结构性变更会留下多组旧 worker。节点参数 --stream-shutdown-timeout 让旧 worker 在设定时间后关闭仍在服务的连接,同样作用于 HTTP 长连接与 WebSocket,见 接入节点 |
UDP
| 项目 | 行为 |
|---|---|
| 会话 | 同一客户端地址与端口在空闲超时内算一个会话;源站对一个数据报的回复数量不限(DNS、QUIC、游戏协议均可) |
| 空闲超时 | 默认 30 秒。DNS 这类一问一答的协议设较短的空闲超时,否则每个客户端端口在超时前都占一个并发会话 |
| PROXY protocol | 不支持 |
| 拒绝 | 被拒的数据报逐个丢弃并计数 |
节点要求
| 项目 | 行为 |
|---|---|
| 能力 | 配置中有启用的 L4 应用时需要 l4-v1 |
| 缺少能力的节点 | 拒绝含 L4 应用的配置,继续使用 last-known-good 配置,在 集群与节点 中显示「需要升级」;没有应用当前版本,2 分钟后离开 DNS 调度。端口池页签、应用列表与对话框提示「集群 {集群} 的节点 {节点} 不支持四层转发,升级前不会应用含 L4 应用的配置」 |
| 顺序 | 先升级节点,再新建 L4 应用 |
| 端口 | 节点主机与云安全组放行端口池,容器节点发布端口池,见 接入节点 |
| 权限 | 端口不低于 1024,节点的 systemd 单元与镜像不需要额外权限 |
回滚
集群「配置版本」的 回滚 下发所选版本中的 L4 应用设置:
| 情况 | 行为 |
|---|---|
| 应用现在已停用 | 不下发 |
| 应用已删除、端口已不在端口池内,或引用的 IP 名单已删除 | 拒绝回滚(「回滚引用的资源已移除、转移或不可用」) |
| 配置金丝雀回滚到稳定版本 | 上述应用被略去,其余照常下发 |
回滚不修改应用的保存值;之后的任何变更按保存值重新发布。
限制
| 项目 | 限制 |
|---|---|
| 应用 | 每个集群最多 256 个(「每个集群最多 256 个 L4 应用」),停用的也计入 |
| 端口段 | 每个应用最多 1000 个端口;每个集群合计最多 2048 个端口 |
| TLS 卸载 | 只用于 TCP;每个应用一张证书 |
| 端口 | 1024–65535,在集群该协议的端口池内;同一集群同一协议的端口只能给一个应用(含停用的应用) |
| 端口池 | 每个集群最多 64 个 |
| 源站 | 每个应用 1–32 个,至少一个不是备用 |
| IP 名单 | 放行名单、拦截名单各最多 16 个 |
| PROXY protocol | 只用于 TCP;v2 头不带 TLV;同时接受与发送时走 Lua 中继 |
| 被动健康状态 | 只在节点本机 |
| 统计 | 按分钟,保留 7 天 |
| 防护 | 只有应用自己的 IP 名单、每节点上限与内核封禁 |
| API | 服务账号不能调用端口池与 L4 应用的过程,见 API 与端点 |
故障排查
| 现象 | 原因 | 处理 |
|---|---|---|
| 「端口 {port} 不在集群此协议的端口池内」 | 端口(或端口段中的该端口)不在该协议的端口池中 | 在集群「端口池」页签添加端口池,或换端口 |
| 「结束端口须大于监听端口,最多 1000 个端口」 | 结束端口不大于监听端口,或超过 1000 个端口 | 修改结束端口 |
| 「固定源站端口时每个源站都要填写端口」 | 源站端口为「固定」而源站没有端口 | 填写端口,或改为「同号」 |
| TLS 握手失败 | SNI 不是证书中的名称;客户端最高版本低于最低 TLS 版本 | 用证书中的名称连接;调整最低 TLS 版本 |
| 「端口已被占用:{apps}」 | 新建或修改:同一集群同一协议的端口已有应用(含停用的应用);保存端口池:池外留下了应用的端口 | 换端口,或先修改、删除列出的应用 |
| 「端口池重叠:{pools}」 | 同一协议的端口池重叠;TCP + UDP 与 TCP、UDP 都重叠 | 调整区间或协议 |
| 「每个集群最多 256 个 L4 应用」 | 达到上限 | 删除不用的应用 |
| 「PROXY protocol 只用于 TCP 应用」 | API 为 UDP 应用设置了 PROXY protocol | 去掉 PROXY protocol 设置 |
| 「集群 {集群} 的节点 {节点} 不支持四层转发…」 | 节点缺少 l4-v1 | 升级节点 |
| 新建应用后部分节点离开 DNS | 同上:这些节点没有应用当前版本 | 升级节点,或先停用应用 |
| 连接超时 | 节点防火墙或安全组未放行端口;容器节点未发布端口 | 按 端口与防火墙 放行 |
| 连接被立即关闭 | 被 IP 名单或每节点上限拒绝(「拒绝」增加);开启了「接受 PROXY protocol」而客户端没有发送头部;端口刚加入 | 检查名单与上限;只在负载均衡器之后开启「接受 PROXY protocol」 |
| 连接建立后源站立即断开或报协议错误 | 「发送到源站」开启而源站不接受 PROXY protocol,或版本不符 | 源站开启对应版本,或改为「不发送」 |
| 源站看到的客户端地址是负载均衡器 | 节点前有四层负载均衡 | 负载均衡器发送 PROXY protocol,应用开启「接受 PROXY protocol」并选择「发送到源站」的版本 |
| 全部连接失败,「拒绝」不增加 | 源站全部不可达 | 在节点上查询 GET /v1/l4 的 down,检查源站地址与源站防火墙 |
| UDP「并发峰值」偏高或达到「并发连接」上限 | 每个客户端端口在空闲超时内算一个会话 | 缩短「空闲(秒)」 |
| reload 后旧 nginx worker 长期存在 | 旧 worker 仍在服务长连接 | 正常;需要限时时设置 --stream-shutdown-timeout |
| 「CNAME 目标」显示「集群 DNS 未开启」 | 集群 DNS 模式为「不管理」 | 在集群「DNS」页签绑定集群 |
| 「IP 名单正在被使用:…」 | 删除仍被列出的应用引用的名单 | 先从应用的放行、拦截名单中移除 |