feat(triple): Implement TriClientPool and Delay triple client Method Binding
About this PR and draft status
This PR introduces TriClientPool, which is used to reuse tri.Client in the Triple scenario, reducing the overhead of client creation and initialization, and helping improve throughput in high-concurrency situations.
During the implementation of the pool, in order to better support client reuse, we made some adjustments to the timing of tri.Client usage.
Previously, tri.Client would bind methods at creation, and this binding was permanent and at the method level, making it impossible to reuse the client across different calls. Now it has been changed to bind at the service level: each client only knows which service it corresponds to, while method-related logic (such as parsing and binding) is deferred until the actual RPC call is made. In this way, tri.Client only handles connection and communication initialization at creation, and call-specific information exists only in the execution path of a single request.
This adjustment prevents the client instance from holding method state permanently, making it easier to reuse across different calls, while reducing unnecessary initialization and potential contention, thereby better supporting the pool.
Since this change was introduced during the implementation of TriClientPool and affects how tri.Client is used, the PR is marked as draft to first confirm that this adjustment aligns with expectations. Once the semantics are agreed upon, the implementation and related tests can be further completed.
This PR introduces changes to tri.Client and ClientManager, mainly focusing on:
Unified TriClientPool
- Previously,
ClientManagermaintained amap[string]*TriClientPool, one pool per method. - Now the entire
ClientManagershares a singleTriClientPool, simplifying management and reducing memory overhead. - The pool supports auto-scaling, non-blocking
Put(), safeClose(), and other enhancements.
Delayed tri.Client Method Binding
- Method binding is moved from client construction to actual RPC call time.
- Avoids unnecessary pre-binding for unused methods and improves flexibility.
- Fully compatible with the unified
TriClientPoolarchitecture.
Other Changes
- Added optional per-client transport mode (
tri.per_client_transportURL parameter) - Unit tests and performance benchmarks included to validate pool behavior and throughput
Benefits
- Pooling improves resource reuse and high-concurrency throughput
- Delayed method binding reduces overhead and increases flexibility
- Simplifies
ClientManagermaintenance and future extensibility
TriClientPool API
-
NewTriClientPool(warmUpSize int, maxSize int, factory func() *tri.Client) *TriClientPool
Create a new pool with initial warm-up size, maximum size, and a client factory function. -
Get(timeout time.Duration) (*tri.Client, error)
Retrieves a client from the pool.- Tries non-blocking receive first.
- Expands the pool if allowed.
- If timeout occurs, returns a fallback client to ensure at least one usable client.
-
Put(client *tri.Client)
Returns a client to the pool. Non-blocking; drops the client if the pool is full (part of shrinking). -
Close()
Safely closes the pool. -
MaxSize() int
Returns the maximum allowed pool size. -
Closed() bool
Returns whether the pool has been closed.
Per-Client Transport Option
Added a URL parameter: tri.per_client_transport
-
true: each client gets a dedicated transport connection
-
false (default): all clients share a common transport
Benchmark Results
run go test -bench . at protocol/triple you will see the result of benchmark like
BenchmarkThroughputComparisonDelay/delay_1ms/SingleClient-24 28291 44420 ns/op
BenchmarkThroughputComparisonDelay/delay_1ms/TriClientPool-24 80985 15073 ns/op
BenchmarkThroughputComparisonDelay/delay_100ms/SingleClient-24 547 2056883 ns/op
BenchmarkThroughputComparisonDelay/delay_100ms/TriClientPool-24 1530 699295 ns/op
Integration Tests
Integration tests have been implemented to validate the correctness and stability of TriClientPool and delayed method binding.
TriClientPool Usage
pool := triple.NewTriClientPool(2, 10, func() *triple.Client {
// Create a new tri.Client
return /* tri.Client instance */
})
defer pool.Close()
ctx := context.Background()
client, _ := pool.Get(50 * time.Millisecond)
// Use the client to make an RPC call
pool.Put(client)
issue #3087
please fix the code format
Maybe it would be better to put TriClientPool in a separate new file instead of cramming it into the existing client.go?
This PR is still in progress. I’ll update it once it's ready for review.
Fix ci error.
Codecov Report
:x: Patch coverage is 48.38710% with 96 lines in your changes missing coverage. Please review.
:white_check_mark: Project coverage is 37.12%. Comparing base (60d1c2a) to head (3e6d54a).
:warning: Report is 660 commits behind head on develop.
| Files with missing lines | Patch % | Lines |
|---|---|---|
| protocol/triple/client_pool.go | 61.22% | 46 Missing and 11 partials :warning: |
| protocol/triple/client.go | 0.00% | 39 Missing :warning: |
Additional details and impacted files
@@ Coverage Diff @@
## develop #3086 +/- ##
===========================================
- Coverage 46.76% 37.12% -9.65%
===========================================
Files 295 461 +166
Lines 17172 33143 +15971
===========================================
+ Hits 8031 12305 +4274
- Misses 8287 19603 +11316
- Partials 854 1235 +381
:umbrella: View full report in Codecov by Sentry.
:loudspeaker: Have feedback on the report? Share it here.
:rocket: New features to boost your workflow:
- :snowflake: Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
@marsevilspirit review
@marsevilspirit done
Write a performance test to demonstrate that your change can improve the throughput of triple.
Thanks for reviewing. I will fix later
protocol/triple/client_pool.goneeds sound unit tests, please write a test file for it
done @Alanxtl
Do you have test results? If so, please post them on this thread.
Enhance the PR description by detailing the implementation approach, making it easier for future reference.
Refer to this link: https://github.com/apache/dubbo-go/pull/3090#issue-3666897313
Quality Gate passed
Issues
0 New issues
0 Accepted issues
Measures
0 Security Hotspots
0.0% Coverage on New Code
0.0% Duplication on New Code