You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@dubbo.apache.org by "lizining1231 (via GitHub)" <gi...@apache.org> on 2026/08/10 20:43:41 UTC
[I] [Bug] HTTP/2+HTTP/3 Dual-Protocol Startup Failure Causes Run to Hang Forever with Memory Leak [dubbo-go]
lizining1231 opened a new issue, #3640:
URL: https://github.com/apache/dubbo-go/issues/3640
### Summary
`Server.startHttp2AndHttp3` (`protocol/triple/triple_protocol/server.go`) starts
the HTTP/2 and HTTP/3 servers in parallel with `errgroup.Group{}` but does NOT
hook into the errgroup cancellation mechanism: **as long as either port is
occupied (TCP or UDP)**, the failing side returns an error, while `eg.Wait()`
never returns because it is waiting for the other service that started
normally and is still listening, causing `Run` to hang permanently, and the
successfully-started side is not closed automatically (goroutine/port leak).
### Affected Locations
| Package | Test | Test Location | Related Source Locations |
| --------------------------------- | ---------------------------------------------------------- | -------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `protocol/triple/triple_protocol` | probe test (temporary, to be promoted to a formal regression test) | `leak_probe_test.go` (local workspace) | `startHttp2AndHttp3` <https://github.com/apache/dubbo-go/blob/master/protocol/triple/triple_protocol/server.go#L288-L308> (`eg := &errgroup.Group{}` does not wire up ctx cancellation) |
### Reproduction
Using the **occupied TCP port** as an example:
```go
// Occupy the TCP port first, then start in dual mode
tcpLn, _ := net.Listen("tcp", tcpAddr) // occupy TCP (HTTP/2 will fail to bind)
srv.Run(constant.CallHTTP2AndHTTP3, tlsConf) // hangs, no return within 3s+
```
Observed output:
```text
leak_probe_test.go:199: Run did not return within 3s: it is hung on errgroup.Wait
leak_probe_test.go:210: UDP port is occupied by HTTP/3 while Run is hung: listen udp 127.0.0.1:43633: bind: address already in use
```
Symmetrically: calling `startHttp2` alone returns the error immediately when
the TCP port is occupied, and calling `startHttp3` alone does the same when
the UDP port is occupied (`listen tcp ...: bind: address already in use`),
proving the failure really happens and is simply not propagated correctly.
<br />
| TCP | UDP | Result |
| -------- | -------- | ----------------------------------------------------- |
| free | free | runs normally |
| free | occupied | HTTP/3 fails + HTTP/2 keeps listening → **Run hangs** |
| occupied | free | HTTP/2 fails + HTTP/3 keeps listening → **Run hangs** |
| occupied | occupied | both fail immediately → `Wait` returns the error |
### Root Cause
- `errgroup.Group.Wait()` waits for **ALL** goroutines to finish before
returning the first error (golang.org/x/sync v0.21.0 errgroup.go:72-102).
- The code uses `&errgroup.Group{}` (not `WithContext`); a failure only
records `g.err` and **never notifies/cancels the other goroutine**.
- Hence after the failing side exits, the successful side is still listening →
`Wait` never returns → `Run` hangs forever; even if the return path were
fixed later, the successful side would not close itself (resource leak).
This chain is **fully symmetric** in both directions: if HTTP/3 fails,
HTTP/2 keeps listening; if HTTP/2 fails, HTTP/3 keeps listening.
### Proposed Fix
Relative to the original implementation (an errgroup launching both
`ListenAndServe*` concurrently), this change:
1. **Add a certificate readiness check**: before startup, verify that
`tlsConf` has a server certificate configured (`Certificates` non-empty, or
`GetCertificate`/`GetConfigForClient` set); return an error immediately if
not — preventing `ServeTLS` from failing synchronously inside a goroutine
and hanging again.
2. **Pre-bind the sockets**: turn the implicit bind into an explicit pre-bind —
`net.Listen("tcp", s.addr)` first, then `net.ListenUDP("udp", s.addr)`;
on either failure, return immediately and close the already-bound socket
(fail-fast, no request has been served at this point).
3. **Serve concurrently**: only after both sockets are bound successfully, run
`ServeTLS(tcpLn, "", "")` and `Serve(udpConn)` concurrently in a plain
`errgroup`, with the result propagated by `eg.Wait()`.
Benefits:
- **Zero new dependencies**: `ServeTLS(ln, "", "")` and
`http3.Server.Serve(conn)` both natively accept pre-bound sockets.
- **Symmetric coverage**: one fix covers both the TCP and UDP error paths.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: notifications-unsubscribe@dubbo.apache.org.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@dubbo.apache.org
For additional commands, e-mail: notifications-help@dubbo.apache.org
Re: [I] [Bug] HTTP/2+HTTP/3 Dual-Protocol Startup Failure Causes Run to Hang Forever with Memory Leak [dubbo-go]
Posted by "lizining1231 (via GitHub)" <gi...@apache.org>.
lizining1231 commented on issue #3640:
URL: https://github.com/apache/dubbo-go/issues/3640#issuecomment-5246136057
请问这个issue是否可被采纳?若可以我想得到分配
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: notifications-unsubscribe@dubbo.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@dubbo.apache.org
For additional commands, e-mail: notifications-help@dubbo.apache.org
Re: [I] [Bug] HTTP/2+HTTP/3 Dual-Protocol Startup Failure Causes Run to Hang Forever with Resource Leak [dubbo-go]
Posted by "Alanxtl (via GitHub)" <gi...@apache.org>.
Alanxtl commented on issue #3640:
URL: https://github.com/apache/dubbo-go/issues/3640#issuecomment-5380782689
close via #3640
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: notifications-unsubscribe@dubbo.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@dubbo.apache.org
For additional commands, e-mail: notifications-help@dubbo.apache.org
Re: [I] [Bug] HTTP/2+HTTP/3 Dual-Protocol Startup Failure Causes Run to Hang Forever with Resource Leak [dubbo-go]
Posted by "Alanxtl (via GitHub)" <gi...@apache.org>.
Alanxtl closed issue #3640: [Bug] HTTP/2+HTTP/3 Dual-Protocol Startup Failure Causes Run to Hang Forever with Resource Leak
URL: https://github.com/apache/dubbo-go/issues/3640
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: notifications-unsubscribe@dubbo.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@dubbo.apache.org
For additional commands, e-mail: notifications-help@dubbo.apache.org
Re: [I] [Bug] HTTP/2+HTTP/3 Dual-Protocol Startup Failure Causes Run to Hang Forever with Resource Leak [dubbo-go]
Posted by "Alanxtl (via GitHub)" <gi...@apache.org>.
Alanxtl closed issue #3640: [Bug] HTTP/2+HTTP/3 Dual-Protocol Startup Failure Causes Run to Hang Forever with Resource Leak
URL: https://github.com/apache/dubbo-go/issues/3640
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: notifications-unsubscribe@dubbo.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@dubbo.apache.org
For additional commands, e-mail: notifications-help@dubbo.apache.org
Re: [I] [Bug] HTTP/2+HTTP/3 Dual-Protocol Startup Failure Causes Run to Hang Forever with Resource Leak [dubbo-go]
Posted by "lizining1231 (via GitHub)" <gi...@apache.org>.
lizining1231 commented on issue #3640:
URL: https://github.com/apache/dubbo-go/issues/3640#issuecomment-5252199414
好的,谢谢!
标题我已修改为准确的措辞,接下来我会调整方案、注意4个实现细节、添加全面的测试,以高优先级处理该issue
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: notifications-unsubscribe@dubbo.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@dubbo.apache.org
For additional commands, e-mail: notifications-help@dubbo.apache.org
Re: [I] [Bug] HTTP/2+HTTP/3 Dual-Protocol Startup Failure Causes Run to Hang Forever with Memory Leak [dubbo-go]
Posted by "AlexStocks (via GitHub)" <gi...@apache.org>.
AlexStocks commented on issue #3640:
URL: https://github.com/apache/dubbo-go/issues/3640#issuecomment-5248899342
这个 Issue 可以采纳,按 P1 处理。目前已经分配给你。
我核对了当前 `main`(`48d6e696e755d46df2425bbf71c413bbd1887f3f`)的实现,并分别验证了 TCP 端口被占用和 UDP 端口被占用两种路径:失败侧会立即返回 bind error,另一侧仍继续监听,`errgroup.Wait()` 因等待全部 goroutine 退出而无法返回;调用 `Stop()` 后 `Run()` 才会结束。因此核心问题成立,是双协议启动过程中的生命周期管理和资源清理缺陷。
不过有两点需要调整:
1. 标题中的 “Memory Leak” 建议改为 “Resource Leak” 或 “Startup Hang”。现有证据能确认 listener、端口和 goroutine 被持续占用,但还不足以证明存在不可回收且持续增长的内存泄漏。上层目前是在 goroutine 中调用 `Run()`,所以生产影响也不只是调用方阻塞,还包括服务部分启动、错误未及时反馈以及资源持续占用。
2. Proposed Fix 的“预绑定 TCP/UDP socket”方向可以解决启动阶段的端口冲突,但还不能完整解决生命周期问题。两个 socket 都绑定成功以后,如果任一 `Serve` 异常退出,必须主动关闭另一侧并等待两个 goroutine 都结束;仅改成 `errgroup.WithContext` 不够,因为监听中的 `Serve` 不会仅凭 context 自动退出。
实现时还需要注意:
- 外部创建的 TCP listener 和 UDP `PacketConn` 要明确所有权,并在预绑定失败、任一 Serve 失败、`Stop` 和 `GracefulStop` 路径中保证释放;`http3.Server.Serve(conn)` 不会替调用方关闭传入的连接。
- `net.ListenUDP` 的第二个参数是 `*net.UDPAddr`,不能直接传 `s.addr` 字符串;可以使用 `net.ResolveUDPAddr` + `net.ListenUDP`,或者 `net.ListenPacket`。
- TLS readiness 检查需要同时支持 `Certificates`、`GetCertificate` 和 `GetConfigForClient`。
- 请补充以下回归测试:TCP 被占用、UDP 被占用、TLS 配置没有可用证书、绑定成功后任一 Serve 异常退出、`Stop`/`GracefulStop` 后 TCP 和 UDP 端口均可重新绑定,以及相关 race 测试。
另外,#3639 正在修改同一个 Server 的生命周期字段访问,但它只处理并发访问问题,不会修复本 Issue;实现时需要协调或 rebase,避免覆盖其中的 atomic pointer 修改。
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: notifications-unsubscribe@dubbo.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@dubbo.apache.org
For additional commands, e-mail: notifications-help@dubbo.apache.org
Re: [I] [Bug] HTTP/2+HTTP/3 Dual-Protocol Startup Failure Causes Run to Hang Forever with Resource Leak [dubbo-go]
Posted by "Alanxtl (via GitHub)" <gi...@apache.org>.
Alanxtl commented on issue #3640:
URL: https://github.com/apache/dubbo-go/issues/3640#issuecomment-5253205525
close via #3639
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: notifications-unsubscribe@dubbo.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@dubbo.apache.org
For additional commands, e-mail: notifications-help@dubbo.apache.org
Re: [I] [Bug] HTTP/2+HTTP/3 Dual-Protocol Startup Failure Causes Run to Hang Forever with Memory Leak [dubbo-go]
Posted by "lizining1231 (via GitHub)" <gi...@apache.org>.
lizining1231 commented on issue #3640:
URL: https://github.com/apache/dubbo-go/issues/3640#issuecomment-5245971865
我尝试构造了一份 最小复现测试 用于辅助该issue,它在当前场景下稳定报错
1. 测试的报错日志是:
```text
=== RUN TestRepro_RunHangsOnOccupiedTCP
repro_issue9_test.go:125: BUG REPRODUCED: Run did not return within 3s after HTTP/2 failed to start (hung on errgroup.Wait)
--- FAIL: TestRepro_RunHangsOnOccupiedTCP (3.00s)
```
2. 测试的行为是:
测试拿到空闲 TCP 端口并验证同端口 UDP 空闲,然后占住 TCP 端口,用这个地址创建开启 HTTP/3 的 Server,在 goroutine 里调用 srv.Run 并把结果发到 channel。主 goroutine 用 select 等 3 秒:收到错误就打 t.Logf 日志,超时则打 t.Errorf 的 BUG REPRODUCED 日志
3. 测试的预期是:
如果 Run 在这 3 秒内返回了,带着 HTTP/2 的 bind 错误及时返回,测试通过。反之则FAIL,bug复现
4. 测试的原文件是:
[repro_issue3640_test.txt](https://github.com/user-attachments/files/30913881/repro_issue3640_test.txt)
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: notifications-unsubscribe@dubbo.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@dubbo.apache.org
For additional commands, e-mail: notifications-help@dubbo.apache.org