forked from cloudwego/kitex
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
14 changed files
with
387 additions
and
23 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
# Connection Pool | ||
|
||
Kitex provides short connection pool and long connection pool for different business scenarios. | ||
|
||
## Short Connection Pool | ||
|
||
Without any settings, Kitex choose using short connection pool. | ||
|
||
## Long Connection Pool | ||
|
||
Initializing the client with an Option: | ||
|
||
```go | ||
client.WithLongConnection(connpool.IdleConfig{ | ||
MaxIdlePerAddress: 10, | ||
MaxIdleGlobal: 1000, | ||
MaxIdleTimeout: 60 * time.Second, | ||
}) | ||
``` | ||
|
||
- `MaxIdlePerAddress`: the maximum number of idle connections per downstream instance | ||
- `MaxIdleGlobal`: the global maximum number of idle connections | ||
- `MaxIdleTimeout`: the idle duration of the connection, connection that exceed this duration would be closed (minimum value is 3s, default value is 30s) | ||
|
||
## Internal Implementation | ||
|
||
Each downstream address corresponds to a connection pool, the connection pool is a ring composed of connections, and the size of the ring is `MaxIdlePerAddress`. | ||
|
||
When getting a connection of downstream address, proceed as follows: | ||
1. Try to fetch a connection from the ring, if fetching failed (no idle connections remained), then try to establish a new connection. In other words, the number of connections may exceed `MaxIdlePerAddress` | ||
2. If fetching succeed, then checking whether the idle time of the connection (since the last time it was placed in the connection pool) has exceeded `MaxIdleTimeout`, if yes, would close this connection and create a new connection | ||
|
||
When the connection is ready to be returned after used, proceed as follows: | ||
|
||
1. Check whether the connection is normal, if not, close it directly | ||
2. Check whether the idle connection number exceeds `MaxIdleGlobal`, and if yes, close it directly | ||
3. Check whether free space remained in the ring of the target connection pool, if yes, put it into the pool, otherwise close it directly | ||
|
||
## Parameter Setting | ||
|
||
The setting of parameters is suggested as follows: | ||
- `MaxIdlePerAddress`: the minimum value is 1, otherwise long connections would degenerate to short connections | ||
- What value should be set should be determined according to the throughput of downstream address. The approximate estimation formula is: `MaxIdlePerAddress = qps_per_dest_host*avg_response_time_sec` | ||
- For example, the cost of each request is 100ms, and the request spread to each downstream address is 100QPS, the value is suggested to set to 10, because each connection handles 10 requests per second, 100QPS requires 10 connections to handled | ||
- In the actual scenario, the fluctuation of traffic is also necessary to be considered. Pay attention, the connection within MaxIdleTimeout will be recycled if it is not used | ||
- Summary: this value be set too large or too small would lead to degenerating to short connection | ||
- `MaxIdleGlobal`: should be larger than the total number of `downstream targets number * MaxIdlePerAddress` | ||
- Notice: this value is not very valuable, it is suggested to set it to a super large value. In subsequent versions, considers discarding this parameter and providing a new interface | ||
- `MaxIdleTimeout`: since the server will clean up inactive connections within 10min, the client also needs to clean up long-idle connections in time to avoid using invalid connections. This value cannot exceed 10min when the downstream is also a Kitex service | ||
|
||
## Status Monitoring | ||
|
||
Connection pooling defines the `Reporter` interface for connection pool status monitoring, such as the reuse rate of long connections. | ||
Users should implement the interface themselves and inject it by `SetReporter`. | ||
|
||
```go | ||
// Reporter report status of connection pool. | ||
type Reporter interface { | ||
ConnSucceed(poolType ConnectionPoolType, serviceName string, addr net.Addr) | ||
ConnFailed(poolType ConnectionPoolType, serviceName string, addr net.Addr) | ||
ReuseSucceed(poolType ConnectionPoolType, serviceName string, addr net.Addr) | ||
} | ||
|
||
// SetReporter set the common reporter of connection pool, that can only be set once. | ||
func SetReporter(r Reporter) | ||
``` | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
# Serialization Protocol | ||
|
||
Kitex support had support two serialization protocol: Thrift and Protobuf. | ||
|
||
## Thrift | ||
|
||
Kitex only support Thrift [Binary](https://github.com/apache/thrift/blob/master/doc/specs/thrift-binary-protocol.md) protocol codec, [Compact](https://github.com/apache/thrift/blob/master/doc/specs/thrift-compact-protocol.md) currently is not supported. | ||
|
||
If you want using thrift protocol encoding, should generate codes by kitex cmd: | ||
|
||
Client side: | ||
|
||
``` | ||
kitex -type thrift ${service_name} ${idl_name}.thrift | ||
``` | ||
|
||
Server side: | ||
|
||
``` | ||
kitex -type thrift -service ${service_name} ${idl_name}.thrift | ||
``` | ||
|
||
We have optimized Thrift's Binary protocol codec. For details of the optimization, please refer to the "Reference - High Performance Thrift Codec" chapter. If you want to close these optimizations, you can add the `-no-fast-api` argument when generating code. | ||
|
||
## Protobuf | ||
|
||
### Protocol Type | ||
|
||
There are two types suporting of protobuf: | ||
|
||
1. **Custom message protocol**: it's been considered as kitex protobuf, the way of generated code is consistent with Thrift. | ||
2. **gRPC protocol**: it can communication with grpc directly, and support streaming. | ||
|
||
If the streaming method is defined in the IDL, the serialization protocol would adopt gRPC protocol, otherwise Kitex protobuf would be adopted. If you want using gRPC protocol, but without stream definition in your proto file, you need specify the transport protocol when initializing client (No changes need to be made on the server because protocol detection is supported): | ||
|
||
```go | ||
// Using WithTransportProtocol specify the transport protocol | ||
cli, err := service.NewClient(destService, client.WithTransportProtocol(transport.GRPC)) | ||
``` | ||
|
||
### Generated Code | ||
|
||
Only support proto3, the grammar reference: https://developers.google.com/protocol-buffers/docs/gotutorial. | ||
|
||
Notice: | ||
|
||
1. What is different from other languages, generating go codes must define `go_package` in the proto file | ||
2. Instead of the full path, just using `go_package` specify the package name, such as: go_package = "pbdemo" | ||
3. Download the `protoc` binary and put it in the $PATH directory | ||
|
||
Client side: | ||
|
||
``` | ||
kitex -type protobuf -I idl/ idl/${proto_name}.proto | ||
``` | ||
|
||
Server side: | ||
|
||
``` | ||
kitex -type protobuf -service ${service_name} -I idl/ idl/${proto_name}.proto | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
# Visit Directly | ||
|
||
If you want to send the requet to downstream that address determined, you can choose visiting directly without service discovery. | ||
|
||
Client can specify downstream addresse in two forms: | ||
|
||
- Using `WithHostPort` Option, supports two parameters: | ||
- Normal IP address, in the form of `host:port`, support `IPv6` | ||
- Sock file address, communicating with UDS (Unix Domain Socket) | ||
- Using `WithURL` Option, the parameter must be valid HTTP URL address |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,6 @@ | ||
# 直连访问 | ||
|
||
在明确下游地址时,可以选择直连访问的方式,不需要经过服务发现。 | ||
在明确要访问某个下游地址时,可以选择直连访问的方式,不需要经过服务发现。 | ||
|
||
client 可以有两种形式指定下游地址: | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
# Monitoring Extension | ||
|
||
[kitex-contrib](https://github.com/kitex-contrib/monitor-prometheus) has provided the prometheus monitoring extensions. | ||
|
||
If you want to get the more detailed monitoring, such as message packet size, or want to adopt other data source, such as InfluxDB, you can implement the `Trace` interface according to your requirements and inject by `WithTracer` Option. | ||
|
||
```go | ||
// Tracer is executed at the start and finish of an RPC. | ||
type Tracer interface { | ||
Start(ctx context.Context) context.Context | ||
Finish(ctx context.Context) | ||
} | ||
``` | ||
|
||
RPCInfo can be obtained from ctx, and further request time cost, package size, and error information returned by the request can be obtained from RPCInfo, for example: | ||
|
||
```go | ||
type clientTracer struct { | ||
// contain entities which recording metric | ||
} | ||
|
||
// Start record the beginning of an RPC invocation. | ||
func (c *clientTracer) Start(ctx context.Context) context.Context { | ||
// do nothing | ||
return ctx | ||
} | ||
|
||
// Finish record after receiving the response of server. | ||
func (c *clientTracer) Finish(ctx context.Context) { | ||
ri := rpcinfo.GetRPCInfo(ctx) | ||
rpcStart := ri.Stats().GetEvent(stats.RPCStart) | ||
rpcFinish := ri.Stats().GetEvent(stats.RPCFinish) | ||
cost := rpcFinish.Time().Sub(rpcStart.Time()) | ||
// TODO: record the cost of request | ||
} | ||
``` | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
# Service Discovery Extension | ||
|
||
[kitex-contrib](https://github.com/kitex-contrib/resolver-dns) has provided the DNS service discovery extensions. | ||
|
||
If you want to adopt other service discovery protocol, such as ETCD, you can implement the `Resolver` interface, and clients can inject it by `WithResolver` Option. | ||
|
||
## Interface Definition | ||
|
||
The interface is defined in `pkg/discovery/discovery.go` and is defined as follows: | ||
|
||
```go | ||
type Resolver interface { | ||
Target(ctx context.Context, target rpcinfo.EndpointInfo) string | ||
Resolve(ctx context.Context, key string) (Result, error) | ||
Diff(key string, prev, next Result) (Change, bool) | ||
Name() string | ||
} | ||
|
||
type Result struct { | ||
Cacheable bool // if can be cached | ||
CacheKey string // the unique key of cached result | ||
Instances []Instance // the result of service discovery | ||
} | ||
|
||
// the diff result | ||
type Change struct { | ||
Result Result | ||
Added []Instance | ||
Updated []Instance | ||
Removed []Instance | ||
} | ||
``` | ||
|
||
`Resolver` interface detail: | ||
|
||
- `Resolve`: as the core method of `Resolver`, it obtains the service discovery result from target key | ||
- `Target`: it resolves the unique target endpoint that from the downstream endpoints provided by `Resolve`, and the result will be used as the unique key of the cache | ||
- `Diff`: it is used to compare the discovery results with the last time. The differences in results are used to notify other components, such as [loadbalancer](https://github.com/cloudwego/kitex/blob/develop/docs/guide/extension/loadbalance.md) and circuitbreaker, etc | ||
- `Name`: it is used to specify a unique name for `Resolver`, and will use it to cache and reuse `Resolver` | ||
|
||
## Usage Example | ||
|
||
You need to implement the the `Resolver` interface, and using it by Option: | ||
|
||
```go | ||
import ( | ||
"xx/kitex/client" | ||
) | ||
|
||
func main() { | ||
opt := client.WithResolver(YOUR_RESOLVER) | ||
|
||
// new client | ||
xxx.NewClient("p.s.m", opt) | ||
} | ||
``` | ||
|
||
## Attention | ||
|
||
To improve performance, Kitex reusing `Resolver`, so the `Resolver` method implementation must be concurrent security. | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.