Skip to content

Commit 7d9cf53

Browse files
author
𝐘𝐨𝐬𝐞𝐛𝐲𝐭𝐞
authored
Merge pull request #87 from NodePassProject/main
Load Balancing Feature and Configuration, Codebase Enhancements, Documentation Updates
2 parents 8b79809 + db108b0 commit 7d9cf53

12 files changed

Lines changed: 207 additions & 46 deletions

File tree

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,8 @@ Explore the complete documentation to learn more about NodePass:
9090
- [How It Works](/docs/en/how-it-works.md)
9191
- [Troubleshooting](/docs/en/troubleshooting.md)
9292

93+
See also [DeepWiki](https://deepwiki.com/yosebyte/nodepass) for AI-powered documentation.
94+
9395
## 🌱 Ecosystem
9496

9597
The [NodePassProject](https://github.com/NodePassProject) organization develops various frontend applications and auxiliary tools to enhance the NodePass experience:

README_zh.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,8 @@ nodepass "master://:10101/api?log=debug&tls=1"
9090
- [工作原理](/docs/zh/how-it-works.md)
9191
- [故障排除](/docs/zh/troubleshooting.md)
9292

93+
参阅 [DeepWiki](https://deepwiki.com/yosebyte/nodepass) 以获取 AI 驱动的文档。
94+
9395
## 🌱 生态系统
9496

9597
[NodePassProject](https://github.com/NodePassProject) 组织开发了各种前端应用和辅助工具来增强 NodePass 体验:

docs/en/api.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -111,14 +111,16 @@ API Key authentication is enabled by default, automatically generated and saved
111111

112112
- Server: `server://<bind_addr>:<bind_port>/<target_host>:<target_port>?<parameters>`
113113
- Client: `client://<server_host>:<server_port>/<local_host>:<local_port>?<parameters>`
114-
- Supported parameters: `log`, `tls`, `crt`, `key`, `dns`, `min`, `max`, `mode`, `type`, `dial`, `read`, `rate`, `slot`, `proxy`, `notcp`, `noudp`
114+
- Supported parameters: `log`, `tls`, `crt`, `key`, `dns`, `sni`, `lbs`, `min`, `max`, `mode`, `type`, `dial`, `read`, `rate`, `slot`, `proxy`, `notcp`, `noudp`
115115

116116
### URL Query Parameters
117117

118118
- `log`: Log level (`none`, `debug`, `info`, `warn`, `error`, `event`)
119119
- `tls`: TLS encryption mode (`0`, `1`, `2`) - Server/Master mode only
120120
- `crt`/`key`: Certificate/key file paths (when `tls=2`)
121121
- `dns`: Custom DNS servers (comma-separated IP addresses, default: `1.1.1.1,8.8.8.8`) - Server/Client mode only
122+
- `sni`: Server Name Indication, specifies hostname for TLS handshake (default: `none`) - Client dual-end handshake mode only
123+
- `lbs`: Load balancing strategy (`0`=round-robin, `1`=sticky failover, default: `0`) - Controls target address selection for multi-target configurations
122124
- `min`/`max`: Connection pool capacity (`min` set by client, `max` set by server and passed to client during handshake)
123125
- `mode`: Runtime mode control (`0`, `1`, `2`) - Controls operation behavior
124126
- For server: `0`=auto, `1`=reverse mode, `2`=forward mode
@@ -1586,6 +1588,7 @@ Examples:
15861588
| `key` | Private key path | File path | None | Server only |
15871589
| `dns` | DNS cache duration | Time duration (e.g., `5m`, `30s`, `1h`) | `5m` | Both |
15881590
| `sni` | Server Name Indication | Hostname | `none` | Client dual-end handshake mode only |
1591+
| `lbs` | Load balancing strategy | `0`(round-robin), `1`(optimal-latency), `2`(primary-backup) | `0` | Both |
15891592
| `min` | Minimum pool capacity | Integer > 0 | `64` | Client dual-end handshake mode only |
15901593
| `max` | Maximum pool capacity | Integer > 0 | `1024` | Dual-end handshake mode |
15911594
| `mode` | Runtime mode control | `0`(auto), `1`(force mode 1), `2`(force mode 2) | `0` | Both |

docs/en/configuration.md

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -692,12 +692,47 @@ nodepass "client://127.0.0.1:1080/app1.local:8080,app2.local:8080?mode=1"
692692

693693
### Rotation Strategy
694694

695-
NodePass employs a Round-Robin algorithm that combines failover and load balancing features:
695+
NodePass provides three load balancing strategies controlled by the `lbs` parameter:
696696

697+
**Strategy 0 (Round-Robin):**
697698
- **Load Balancing**: After each successful connection establishment, automatically switches to the next target address for even traffic distribution
698699
- **Failover**: When a connection to an address fails, immediately tries the next address to ensure service availability
699700
- **Automatic Recovery**: Failed addresses are retried in subsequent rotation cycles and automatically resume receiving traffic after recovery
700701

702+
**Strategy 1 (Optimal-Latency):**
703+
- **Intelligent Routing**: Periodically probes targets and automatically selects the one with the lowest latency for connections.
704+
- **Sticky Selection**: Once the optimal target is chosen, subsequent connections within the cycle preferentially use that target.
705+
- **Automatic Filtering**: Unhealthy targets are automatically excluded from routing and re-evaluated only after recovery.
706+
- **Failover**: If the optimal target fails, other targets are tried in order to ensure successful connections.
707+
708+
**Strategy 2 (Primary-Backup):**
709+
- **Priority-Based**: Always attempts to connect to the first address (primary); only uses backups when primary fails
710+
- **Failover**: On primary failure, switches to the next available backup address
711+
- **Scheduled Fallback**: Automatically attempts to return to primary address at fixed intervals
712+
- **Intelligent Degradation**: On fallback failure, automatically uses the highest available priority address
713+
714+
Example configurations:
715+
716+
```bash
717+
# Round-robin (lbs=0, cycles through targets on each connection)
718+
nodepass "server://0.0.0.0:10101/backend1:8080,backend2:8080,backend3:8080?lbs=0"
719+
720+
# Optimal-latency (lbs=1, automatically routes to fastest target)
721+
nodepass "server://0.0.0.0:10101/backend1:8080,backend2:8080,backend3:8080?lbs=1"
722+
723+
# Primary-backup (lbs=2, primary priority and scheduled fallback)
724+
nodepass "server://0.0.0.0:10101/primary:8080,backup1:8080,backup2:8080?lbs=2"
725+
726+
# Custom fallback interval of 2 minutes
727+
export NP_FALLBACK_INTERVAL=2m
728+
nodepass "server://0.0.0.0:10101/main.com:443,spare1.com:443,spare2.com:443?lbs=2"
729+
```
730+
731+
Choose the appropriate strategy based on your needs:
732+
- **Use lbs=0** for even load distribution across all backends
733+
- **Use lbs=1** for intelligent routing to the lowest latency target
734+
- **Use lbs=2** for primary-backup scenarios with automatic failback
735+
701736
### Use Cases
702737

703738
Target address groups are suitable for the following scenarios:
@@ -743,6 +778,7 @@ NodePass allows flexible configuration via URL query parameters. The following t
743778
| `key` | Custom key path | N/A | File path | O | X | O |
744779
| `dns` | DNS cache TTL | `5m` | `30s`/`5m`/`1h` etc. | O | O | X |
745780
| `sni` | Server Name Indication | `none` | Hostname | X | O | X |
781+
| `lbs` | Load balancing strategy | `0` | `0`/`1`/`2` | O | O | X |
746782
| `min` | Minimum pool capacity | `64` | Positive integer | X | O | X |
747783
| `max` | Maximum pool capacity | `1024` | Positive integer | O | X | X |
748784
| `mode` | Run mode control | `0` | `0`/`1`/`2` | O | O | X |
@@ -787,6 +823,7 @@ NodePass behavior can be fine-tuned using environment variables. Below is the co
787823
| `NP_MIN_POOL_INTERVAL` | Minimum interval between connection creations | 100ms | `export NP_MIN_POOL_INTERVAL=200ms` |
788824
| `NP_MAX_POOL_INTERVAL` | Maximum interval between connection creations | 1s | `export NP_MAX_POOL_INTERVAL=3s` |
789825
| `NP_REPORT_INTERVAL` | Interval for health check reports | 5s | `export NP_REPORT_INTERVAL=10s` |
826+
| `NP_FALLBACK_INTERVAL` | Primary-backup fallback interval | 5m | `export NP_FALLBACK_INTERVAL=2m` |
790827
| `NP_SERVICE_COOLDOWN` | Cooldown period before restart attempts | 3s | `export NP_SERVICE_COOLDOWN=5s` |
791828
| `NP_SHUTDOWN_TIMEOUT` | Timeout for graceful shutdown | 5s | `export NP_SHUTDOWN_TIMEOUT=10s` |
792829
| `NP_RELOAD_INTERVAL` | Interval for cert reload/state backup | 1h | `export NP_RELOAD_INTERVAL=30m` |

docs/zh/api.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -111,14 +111,16 @@ API Key 认证默认启用,首次启动自动生成并保存在 `nodepass.gob`
111111

112112
- 服务端:`server://<bind_addr>:<bind_port>/<target_host>:<target_port>?<参数>`
113113
- 客户端:`client://<server_host>:<server_port>/<local_host>:<local_port>?<参数>`
114-
- 支持参数:`log``tls``crt``key``dns``min``max``mode``type``dial``read``rate``slot``proxy``notcp``noudp`
114+
- 支持参数:`log``tls``crt``key``dns``sni``lbs``min``max``mode``type``dial``read``rate``slot``proxy``notcp``noudp`
115115

116116
### URL 查询参数
117117

118118
- `log`:日志级别(`none``debug``info``warn``error``event`
119119
- `tls`:TLS加密模式(`0``1``2`)- 仅服务端/主控模式
120120
- `crt`/`key`:证书/密钥文件路径(当`tls=2`时)
121121
- `dns`:自定义DNS服务器(逗号分隔的IP地址,默认:`1.1.1.1,8.8.8.8`)- 仅服务端/客户端模式
122+
- `sni`:服务器名称指示(Server Name Indication),用于TLS握手时指定主机名(默认:`none`)- 仅客户端双端握手模式
123+
- `lbs`:负载均衡策略(`0`=轮询,`1`=粘性故障转移,默认:`0`)- 控制多目标配置时的目标地址选择方式
122124
- `min`/`max`:连接池容量(`min`由客户端设置,`max`由服务端设置并在握手时传递给客户端)
123125
- `mode`:运行模式控制(`0``1``2`)- 控制操作行为
124126
- 对于服务端:`0`=自动,`1`=反向模式,`2`=正向模式
@@ -1586,6 +1588,7 @@ client://<server_host>:<server_port>/<local_host>:<local_port>?<parameters>
15861588
| `key` | 私钥路径 | 文件路径 || 仅服务端 |
15871589
| `dns` | DNS缓存时间 | 时间长度 (如 `10m`, `30s`, `1h`) | `5m` | 两者 |
15881590
| `sni` | 主机名指示 | 主机名 | `none` | 仅客户端双端握手模式 |
1591+
| `lbs` | 负载均衡策略 | `0`(轮询转移), `1`(最优延迟), `2`(主备回落) | `0` | 两者 |
15891592
| `min` | 最小连接池容量 | 整数 > 0 | `64` | 仅客户端双端握手模式 |
15901593
| `max` | 最大连接池容量 | 整数 > 0 | `1024` | 双端握手模式 |
15911594
| `mode` | 运行模式控制 | `0`(自动), `1`(强制模式1), `2`(强制模式2) | `0` | 两者 |

docs/zh/configuration.md

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -692,12 +692,47 @@ nodepass "client://127.0.0.1:1080/app1.local:8080,app2.local:8080?mode=1"
692692

693693
### 轮询策略
694694

695-
NodePass采用轮询(Round-Robin)算法,结合故障转移和负载均衡特性
695+
NodePass提供三种负载均衡策略,通过 `lbs` 参数控制
696696

697+
**策略0(轮询转移):**
697698
- **负载均衡**:每次成功建立连接后,自动切换到下一个目标地址,实现流量均匀分布
698699
- **故障转移**:当某个地址连接失败时,立即尝试下一个地址,确保服务高可用
699700
- **自动恢复**:失败的地址会在轮询周期中重新尝试,故障恢复后自动接入流量
700701

702+
**策略1(最优延迟):**
703+
- **智能路由**:周期性探测,自动选择延迟最低的目标进行连接
704+
- **粘性选择**:最优目标选择后,周期内后续连接优先使用该目标
705+
- **自动筛选**:失效目标自动排除,不参与路由,直至恢复后再评估
706+
- **故障转移**:最优目标失败时按顺序尝试其他目标,确保连接成功
707+
708+
**策略2(主备回落):**
709+
- **主备优先**:首个目标地址主用,后续目标地址备用,按顺序优先级递减
710+
- **故障转移**:主目标地址失败时按顺序尝试备用地址,成功后保持粘性
711+
- **定时回落**:每隔固定时间自动尝试回落到主用目标地址
712+
- **智能降级**:回落失败时自动选择可用的最高优先级备用目标地址
713+
714+
配置示例:
715+
716+
```bash
717+
# 轮询转移(lbs=0,每次连接切换目标)
718+
nodepass "server://0.0.0.0:10101/backend1:8080,backend2:8080,backend3:8080?lbs=0"
719+
720+
# 最优延迟(lbs=1,自动路由到最快目标)
721+
nodepass "server://0.0.0.0:10101/backend1:8080,backend2:8080,backend3:8080?lbs=1"
722+
723+
# 主备回落(lbs=2,首目标优先且定时回落)
724+
nodepass "server://0.0.0.0:10101/primary:8080,backup1:8080,backup2:8080?lbs=2"
725+
726+
# 自定义回落间隔为2分钟
727+
export NP_FALLBACK_INTERVAL=2m
728+
nodepass "server://0.0.0.0:10101/main.com:443,spare1.com:443,spare2.com:443?lbs=2"
729+
```
730+
731+
根据实际需求选择合适的策略:
732+
- **使用 lbs=0** 实现所有后端的均匀负载分布
733+
- **使用 lbs=1** 智能路由到延迟最低目标地址
734+
- **使用 lbs=2** 主备模式,故障消除自动回切
735+
701736
### 使用场景
702737

703738
目标地址组适用于以下场景:
@@ -743,6 +778,7 @@ NodePass支持通过URL查询参数进行灵活配置,不同参数在 server、c
743778
| `key` | 自定义密钥路径 | N/A | 文件路径 | O | X | O |
744779
| `dns` | DNS缓存TTL | `5m` | `30s`/`5m`/`1h`| O | O | X |
745780
| `sni` | 主机名指示 | `none` | 主机名 | X | O | X |
781+
| `lbs` | 负载均衡策略 | `0` | `0`/`1`/`2` | O | O | X |
746782
| `min` | 最小连接池容量 | `64` | 正整数 | X | O | X |
747783
| `max` | 最大连接池容量 | `1024` | 正整数 | O | X | X |
748784
| `mode` | 运行模式控制 | `0` | `0`/`1`/`2` | O | O | X |
@@ -787,6 +823,7 @@ NodePass支持通过URL查询参数进行灵活配置,不同参数在 server、c
787823
| `NP_MIN_POOL_INTERVAL` | 连接创建之间的最小间隔 | 100ms | `export NP_MIN_POOL_INTERVAL=200ms` |
788824
| `NP_MAX_POOL_INTERVAL` | 连接创建之间的最大间隔 | 1s | `export NP_MAX_POOL_INTERVAL=3s` |
789825
| `NP_REPORT_INTERVAL` | 健康检查报告间隔 | 5s | `export NP_REPORT_INTERVAL=10s` |
826+
| `NP_FALLBACK_INTERVAL` | 回落故障转移间隔 | 5m | `export NP_FALLBACK_INTERVAL=2m` |
790827
| `NP_SERVICE_COOLDOWN` | 重启尝试前的冷却期 | 3s | `export NP_SERVICE_COOLDOWN=5s` |
791828
| `NP_SHUTDOWN_TIMEOUT` | 优雅关闭超时 | 5s | `export NP_SHUTDOWN_TIMEOUT=10s` |
792829
| `NP_RELOAD_INTERVAL` | 证书重载/状态备份间隔 | 1h | `export NP_RELOAD_INTERVAL=30m` |

go.mod

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,9 @@ require (
1414

1515
require (
1616
github.com/coder/websocket v1.8.14 // indirect
17-
github.com/quic-go/quic-go v0.58.0 // indirect
18-
golang.org/x/crypto v0.46.0 // indirect
19-
golang.org/x/net v0.48.0 // indirect
20-
golang.org/x/sys v0.39.0 // indirect
21-
golang.org/x/text v0.32.0 // indirect
17+
github.com/quic-go/quic-go v0.59.0 // indirect
18+
golang.org/x/crypto v0.47.0 // indirect
19+
golang.org/x/net v0.49.0 // indirect
20+
golang.org/x/sys v0.40.0 // indirect
21+
golang.org/x/text v0.33.0 // indirect
2222
)

go.sum

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -18,19 +18,19 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c
1818
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
1919
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
2020
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
21-
github.com/quic-go/quic-go v0.58.0 h1:ggY2pvZaVdB9EyojxL1p+5mptkuHyX5MOSv4dgWF4Ug=
22-
github.com/quic-go/quic-go v0.58.0/go.mod h1:upnsH4Ju1YkqpLXC305eW3yDZ4NfnNbmQRCMWS58IKU=
21+
github.com/quic-go/quic-go v0.59.0 h1:OLJkp1Mlm/aS7dpKgTc6cnpynnD2Xg7C1pwL6vy/SAw=
22+
github.com/quic-go/quic-go v0.59.0/go.mod h1:upnsH4Ju1YkqpLXC305eW3yDZ4NfnNbmQRCMWS58IKU=
2323
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
2424
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
2525
go.uber.org/mock v0.5.2 h1:LbtPTcP8A5k9WPXj54PPPbjcI4Y6lhyOZXn+VS7wNko=
2626
go.uber.org/mock v0.5.2/go.mod h1:wLlUxC2vVTPTaE3UD51E0BGOAElKrILxhVSDYQLld5o=
27-
golang.org/x/crypto v0.46.0 h1:cKRW/pmt1pKAfetfu+RCEvjvZkA9RimPbh7bhFjGVBU=
28-
golang.org/x/crypto v0.46.0/go.mod h1:Evb/oLKmMraqjZ2iQTwDwvCtJkczlDuTmdJXoZVzqU0=
29-
golang.org/x/net v0.48.0 h1:zyQRTTrjc33Lhh0fBgT/H3oZq9WuvRR5gPC70xpDiQU=
30-
golang.org/x/net v0.48.0/go.mod h1:+ndRgGjkh8FGtu1w1FGbEC31if4VrNVMuKTgcAAnQRY=
31-
golang.org/x/sys v0.39.0 h1:CvCKL8MeisomCi6qNZ+wbb0DN9E5AATixKsvNtMoMFk=
32-
golang.org/x/sys v0.39.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
33-
golang.org/x/text v0.32.0 h1:ZD01bjUt1FQ9WJ0ClOL5vxgxOI/sVCNgX1YtKwcY0mU=
34-
golang.org/x/text v0.32.0/go.mod h1:o/rUWzghvpD5TXrTIBuJU77MTaN0ljMWE47kxGJQ7jY=
27+
golang.org/x/crypto v0.47.0 h1:V6e3FRj+n4dbpw86FJ8Fv7XVOql7TEwpHapKoMJ/GO8=
28+
golang.org/x/crypto v0.47.0/go.mod h1:ff3Y9VzzKbwSSEzWqJsJVBnWmRwRSHt/6Op5n9bQc4A=
29+
golang.org/x/net v0.49.0 h1:eeHFmOGUTtaaPSGNmjBKpbng9MulQsJURQUAfUwY++o=
30+
golang.org/x/net v0.49.0/go.mod h1:/ysNB2EvaqvesRkuLAyjI1ycPZlQHM3q01F02UY/MV8=
31+
golang.org/x/sys v0.40.0 h1:DBZZqJ2Rkml6QMQsZywtnjnnGvHza6BTfYFWY9kjEWQ=
32+
golang.org/x/sys v0.40.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
33+
golang.org/x/text v0.33.0 h1:B3njUFyqtHDUI5jMn1YIr5B0IE2U0qck04r6d4KPAxE=
34+
golang.org/x/text v0.33.0/go.mod h1:LuMebE6+rBincTi9+xWTY8TztLzKHc/9C1uBCG27+q8=
3535
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
3636
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

internal/client.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,8 +58,8 @@ func NewClient(parsedURL *url.URL, logger *logs.Logger) (*Client, error) {
5858
// Run 管理客户端生命周期
5959
func (c *Client) Run() {
6060
logInfo := func(prefix string) {
61-
c.logger.Info("%v: client://%v@%v/%v?dns=%v&sni=%v&min=%v&mode=%v&dial=%v&read=%v&rate=%v&slot=%v&proxy=%v&block=%v&notcp=%v&noudp=%v",
62-
prefix, c.tunnelKey, c.tunnelTCPAddr, c.getTargetAddrsString(), c.dnsCacheTTL, c.serverName, c.minPoolCapacity,
61+
c.logger.Info("%v: client://%v@%v/%v?dns=%v&sni=%v&lbs=%v&min=%v&mode=%v&dial=%v&read=%v&rate=%v&slot=%v&proxy=%v&block=%v&notcp=%v&noudp=%v",
62+
prefix, c.tunnelKey, c.tunnelTCPAddr, c.getTargetAddrsString(), c.dnsCacheTTL, c.serverName, c.lbStrategy, c.minPoolCapacity,
6363
c.runMode, c.dialerIP, c.readTimeout, c.rateLimit/125000, c.slotLimit,
6464
c.proxyProtocol, c.blockProtocol, c.disableTCP, c.disableUDP)
6565
}

0 commit comments

Comments
 (0)