trpc.group/trpc-go/trpc-go@v1.0.2/docs/user_guide/client/connection_mode.zh_CN.md (about) 1 [English](connection_mode.md) | 中文 2 3 # tRPC-Go 客户端连接模式 4 5 6 # 前言 7 8 目前 tRPC-Go client,也就是请求发起的一方支持多种连接模式,包括短连接,连接池以及连接多路复用。client 默认使用连接池模式,用户可以根据自己的需要选择不同的连接模式。 9 `注意:这里的连接池指的是 tRPC-Go 自己实现的 transport 里面的连接池,database 以及 http 都是使用插件模式将 transport 替换成开源库,不是使用这里的连接池。` 10 11 # 原理和实现 12 13 ### 短连接 14 15 client 每次请求都会新建一个连接,请求完成后连接会被销毁。请求量很大的情况下,服务的吞吐量会受到很大的影响,性能损耗也很大。 16 17 使用场景:一次性请求或者请求的被调服务是老服务,不支持在一个连接上接受多个请求的情况下使用。 18 19 ### 连接池 20 21 client 针对每个下游 ip 都会维护一个连接池,每次请求先从名字服务获取一个 ip,根据 ip 获取对应连接池,再从连接池中获取一个连接,请求完成后连接会被放回连接池,在请求过程中,这个连接是独占的,不可复用的。连接池内的连接按照策略进行销毁和新建。一次调用绑定一个连接,当上下游规模很大的情况下,网络中存在的连接数以 MxN 的速度扩张,带来巨大的调度压力和计算开销。 22 23 使用场景:基本所有的场景都可以使用。 24 注意:因为连接池队列的策略是先进后出,如果后端是 vip 寻址方式,有可能会导致后端不同实例连接数不均衡。此时应该尽可能基于名字服务进行寻址。 25 26 ### 连接多路复用 27 28 client 在同一个连接上同时发送多个请求,每个请求通过序列号 ID 进行区分,client 与每个下游服务的节点都会建立一个长连接,默认所有的请求都是通过这个长连接来发送给服务端,需要服务端支持连接复用模式。IO 复用能够极大的减少服务之间的连接数量,但是由于 TCP 的头部阻塞,当同一个连接上并发的请求的数量过多时,会带来一定的延时(几毫秒级别),可以通过增加连接多路复用的连接数量(IO 复用默认一个 ip 建立两个连接)来一定程度上减轻这个问题。 29 30 使用场景:对稳定性和吞吐量有极致要求的场景。需要服务端支持单连接异步并发处理,和通过序列号 ID 来区分请求的能力,对 server 能力和协议字段都有一定的要求。 31 注意: 32 33 - 因为连接多路复用对每个后端节点只会建立 1 个连接,如果后端是 vip 寻址方式(从 client 角度看只有一个实例),不可使用连接多路复用,必须使用连接池模式。 34 - 被调 server(注意不是你当前这个服务,是被你调用的服务)必须支持连接多路复用,即在一个连接上对每个请求异步处理,多发多收,否则,client 这边会出现大量超时失败。 35 36 # 示例 37 38 ### 短连接 39 40 ```go 41 opts := []client.Option{ 42 client.WithNamespace("Development"), 43 client.WithServiceName("trpc.app.server.service"), 44 // 禁用默认的连接池,则会采用短连接模式 45 client.WithDisableConnectionPool(), 46 } 47 48 clientProxy := pb.NewGreeterClientProxy(opts...) 49 req := &pb.HelloRequest{ 50 Msg: "hello", 51 } 52 53 rsp, err := clientProxy.SayHello(ctx, req) 54 if err != nil { 55 log.Error(err.Error()) 56 return 57 } 58 59 log.Info("req:%v, rsp:%v, err:%v", req, rsp, err) 60 ``` 61 62 ### 连接池 63 64 ```go 65 // 默认采用连接池模式,不需要任何配置 66 opts := []client.Option{ 67 client.WithNamespace("Development"), 68 client.WithServiceName("trpc.app.server.service"), 69 } 70 71 clientProxy := pb.NewGreeterClientProxy(opts...) 72 req := &pb.HelloRequest{ 73 Msg: "hello", 74 } 75 76 rsp, err := clientProxy.SayHello(ctx, req) 77 if err != nil { 78 log.Error(err.Error()) 79 return 80 } 81 82 log.Info("req:%v, rsp:%v, err:%v", req, rsp, err) 83 ``` 84 85 自定义连接池 86 87 ```go 88 import "trpc.group/trpc-go/trpc-go/pool/connpool" 89 90 /* 91 连接池参数 92 type Options struct { 93 MinIdle int // 最小空闲连接数量,由连接池后台周期性补充,0 代表不做补充 94 MaxIdle int // 最大空闲连接数量,0 代表不做限制,框架默认值 65535 95 MaxActive int // 用户可用连接的最大并发数,0 代表不做限制 96 Wait bool // 可用连接达到最大并发数时,是否等待,默认为 false, 不等待 97 IdleTimeout time.Duration // 空闲连接超时时间,0 代表不做限制,框架默认值 50s 98 MaxConnLifetime time.Duration // 连接的最大生命周期,0 代表不做限制 99 DialTimeout time.Duration // 建立连接超时时间,框架默认值 200ms 100 ForceClose bool // 用户使用连接后是否强制关闭,默认为 false, 放回连接池 101 PushIdleConnToTail bool // 放回连接池时的方式,默认为 false, 采用 LIFO 获取空闲连接 102 } 103 */ 104 105 // 连接池参数可以通过 option 设置,具体请查看 trpc-go 的文档,连接池需要设置成都是全局变量。 106 var pool = connpool.NewConnectionPool(connpool.WithMaxIdle(65535)) 107 // 默认采用连接池模式,不需要任何配置 108 opts := []client.Option{ 109 client.WithNamespace("Development"), 110 client.WithServiceName("trpc.app.server.service"), 111 // 设置自定义连接池 112 client.WithPool(pool), 113 } 114 115 clientProxy := pb.NewGreeterClientProxy(opts...) 116 req := &pb.HelloRequest{ 117 Msg: "hello", 118 } 119 120 rsp, err := clientProxy.SayHello(ctx, req) 121 if err != nil { 122 log.Error(err.Error()) 123 return 124 } 125 126 log.Info("req:%v, rsp:%v, err:%v", req, rsp, err) 127 ``` 128 129 ###连接多路复用 130 131 ```go 132 opts := []client.Option{ 133 client.WithNamespace("Development"), 134 client.WithServiceName("trpc.app.server.service"), 135 // 开启连接多路复用 136 client.WithMultiplexed(true), 137 } 138 139 clientProxy := pb.NewGreeterClientProxy(opts...) 140 req := &pb.HelloRequest{ 141 Msg: "hello", 142 } 143 144 rsp, err := clientProxy.SayHello(ctx, req) 145 if err != nil { 146 log.Error(err.Error()) 147 return 148 } 149 150 log.Info("req:%v, rsp:%v, err:%v", req, rsp, err) 151 ``` 152 153 设置自定义连接多路复用 154 155 ```go 156 /* 157 type PoolOptions struct { 158 connectNumber int // 设置每个地址的连接数 159 queueSize int // 设置每个连接请求队列长度 160 dropFull bool // 队列满是否丢弃 161 } 162 */ 163 // 连接多路复用参数可以通过 option 设置,具体请查看 trpc-go 的文档,需要设置成都是全局变量。 164 var m = multiplexed.New(multiplexed.WithConnectNumber(16)) 165 166 opts := []client.Option{ 167 client.WithNamespace("Development"), 168 client.WithServiceName("trpc.app.server.service"), 169 // 开启连接多路复用 170 client.WithMultiplexed(true), 171 client.WithMultiplexedPool(m), 172 } 173 174 clientProxy := pb.NewGreeterClientProxy(opts...) 175 req := &pb.HelloRequest{ 176 Msg: "hello", 177 } 178 179 rsp, err := clientProxy.SayHello(ctx, req) 180 if err != nil { 181 log.Error(err.Error()) 182 return 183 } 184 185 log.Info("req:%v, rsp:%v, err:%v", req, rsp, err) 186 ```