GRPC连接池如何实现

55次阅读
没有评论

共计 3622 个字符,预计需要花费 10 分钟才能阅读完成。

这篇文章主要讲解了“GRPC 连接池如何实现”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着丸趣 TV 小编的思路慢慢深入,一起来研究和学习“GRPC 连接池如何实现”吧!

前言

在分布式高并发服务器中,client 到 server 以及 server 中的多个节点之间的连接往往使用连接池来管理。简单来说就是将提前创建好的连接保存在池中,当有请求到来时,直接使用连接池中的连接对 server 端访问,省去了创建连接和销毁连接的开销(TCP 建立连接时的三次握手和释放连接时的四次挥手),从而提高了性能。

a name= chapter1 /a 设计原则

连接池的扩缩容

空闲连接的超时与保活

池满的处理机制

连接池的扩缩容

通常连接池属性包含最大空闲连接数和最大活跃连接数。

最大空闲连接数:连接池一直保持的连接数,无论这些连接被使用与否都会被保持。如果客户端对连接池的使用量不大,便会造成服务端连接资源的浪费。

最大活跃连接数:连接池最多保持的连接数,如果客户端请求超过次数,便要根据池满的处理机制来处理没有得到连接的请求。

扩容:当请求到来时,如果连接池中没有空闲的连接,同时连接数也没有达到最大活跃连接数,便会按照特定的增长策略创建新的连接服务该请求,同时用完之后归还到池中,而不是关闭连接。

缩容:当连接池一段时间没有被使用,同时池中的连接数超过了最大空闲连接数,那么便会关闭一部分连接,使池中的连接数始终维持在最大空闲连接数。

空闲连接的超时与保活

超时 如果连接没有被客户端使用的话,便会成为空闲连接,在一段时间后,服务端可能会根据自己的超时策略关闭空闲连接,此时空闲连接已经失效,如果客户端再使用失效的连接,便会通信失败。为了避免这种情况发生,通常连接池中的连接设有最大空闲超时时间(最好略小于服务器的空闲连接超时时间),在从池中获取连接时,判断是否空闲超时,如果超时则关闭,没有超时则可以继续使用。

保活 如果服务器发生重启,那么连接池中的连接便会全部失效,如果此时再从池中获取连接,不论获取到哪一个,都将通信失败。因此,连接池必须考虑连接的保活问题,有两种解决方法:

1、连接池设置一个 Ping 函数,专门用来做连接的保活。在从池中获取连接的时候,Ping 一下服务器,如果得到响应,则连接依然有效,便可继续使用,如果超时无响应,则关闭该连接,生成新的连接,由于每次都要 Ping 一下,必然会增加延迟。也可以后台用一个线程或者协程定期的执行 Ping 函数,进行连接的保活,缺点是感知连接的失效会有一定的延迟,从池中仍然有可能获取到失效的连接。

2、客户端加入相应的重试机制。比如重试 3 次,前两次从池中获取连接执行,如果报的错是失效的连接等有关连接问题的错误,那么第 3 次从池中获取的时候带上参数,指定获取新建的连接,同时连接池移除前两次获取的失效的连接。

池满的处理机制

连接池不可能无限的容纳连接,当池满时,有两种处理机制:

1、池新建连接,并返回给客户端,当客户端用完时,如果池满则关闭连接,否则放入池中。

2、设置一定的超时时间来等待空闲连接。需要客户端加入重试机制,避免因超时之后获取不到空闲连接产生的错误。

a name= chapter2 /a 基本原理

服务启动时建立连接池。

初始化连接池,建立最大空闲连接数个连接。

请求到来时,从池中获取一个连接。如果没有空闲连接且连接数没有达到最大活跃连接数,则新建连接;如果达到最大活跃连接数,设置一定的超时时间,等待获取空闲连接。

获取到连接后进行通信服务。

释放连接,此时是将连接放回连接池,如果池满则关闭连接。

释放连接池,关闭所有连接。

a name= chapter3 /a GRPC 特性

关于 GRPC 的介绍,不在这里阐述,可阅读深入了解 GRPC 协议,也可自行 Google。这里主要简要说明 GRPC 的两个特性:多路复用、超时重连。

多路复用 GRPC 使用 HTTP/ 2 作为应用层的传输协议,HTTP/ 2 会复用底层的 TCP 连接。每一次 RPC 调用会产生一个新的 Stream,每个 Stream 包含多个 Frame,Frame 是 HTTP/ 2 里面最小的数据传输单位。同时每个 Stream 有唯一的 ID 标识,如果是客户端创建的则 ID 是奇数,服务端创建的 ID 则是偶数。如果一条连接上的 ID 使用完了,Client 会新建一条连接,Server 也会给 Client 发送一个 GOAWAY Frame 强制让 Client 新建一条连接。一条 GRPC 连接允许并发的发送和接收多个 Stream,而控制的参数便是 MaxConcurrentStreams,Golang 的服务端默认是 100。

超时重连我们在通过调用 Dial 或者 DialContext 函数创建连接时,默认只是返回 ClientConn 结构体指针,同时会启动一个 Goroutine 异步的去建立连接。如果想要等连接建立完再返回,可以指定 grpc.WithBlock()传入 Options 来实现。超时机制很简单,在调用的时候传入一个 timeout 的 context 就可以了。重连机制通过启动一个 Goroutine 异步的去建立连接实现的,可以避免服务器因为连接空闲时间过长关闭连接、服务器重启等造成的客户端连接失效问题。也就是说通过 GRPC 的重连机制可以完美的解决连接池设计原则中的空闲连接的超时与保活问题。

以 Golang 的 GRPC 客户端为例:

a name= chapter4 /a GRPC 调优

GRPC 默认的参数对于传输大数据块来说不够友好,我们需要进行特定参数的调优。

MaxSendMsgSizeGRPC 最大允许发送的字节数,默认 4MiB,如果超过了 GRPC 会报错。Client 和 Server 我们都调到 4GiB。

MaxRecvMsgSizeGRPC 最大允许接收的字节数,默认 4MiB,如果超过了 GRPC 会报错。Client 和 Server 我们都调到 4GiB。

InitialWindowSize 基于 Stream 的滑动窗口,类似于 TCP 的滑动窗口,用来做流控,默认 64KiB,吞吐量上不去,Client 和 Server 我们调到 1GiB。

InitialConnWindowSize 基于 Connection 的滑动窗口,默认 16 * 64KiB,吞吐量上不去,Client 和 Server 我们也都调到 1GiB。

KeepAliveTime 每隔 KeepAliveTime 时间,发送 PING 帧测量最小往返时间,确定空闲连接是否仍然有效,我们设置为 10S。

KeepAliveTimeout 超过 KeepAliveTimeout,关闭连接,我们设置为 3S。

PermitWithoutStream 如果为 true,当连接空闲时仍然发送 PING 帧监测,如果为 false,则不发送忽略。我们设置为 true。

a name= chapter5 /a 实现细则

代码:https://github.com/shimingyah/pool

基于 GRPC 的多路复用、超时重连特性,我们很容易实现 GRPC 连接池。

接口设计

提供简洁的 Pool 和 Conn 的接口设计。

连接复用

GRPC 是支持多路复用的,所以在设计 GRPC 池的时候和其他连接池区别之一是支持连接复用,通过 MaxConcurrentStreams 控制,默认 64。我们称单个的 GRPC 为物理连接,复用的连接为逻辑连接。池的实际有效连接逻辑连接 = 物理连接 * MaxConcurrentStreams。

扩缩容

扩容初始化池的有效连接数 (逻辑连接) 为:最大空闲连接数 * MaxConcurrentStreams,每一次请求都会对池的引用计数原子 ++,同时 hash 求取选取连接,当引用计数超过逻辑连接数时,就需要进行扩容了,如果最大空闲连接没有达到最大活跃连接数,则按照 double 的方式扩容,如果达到了最大活跃连接数,我们会根据 Reuse 参数的值来做进一步操作:如果为 true,则继续使用池中的连接,即使用的是物理连接的逻辑连接,关闭连接时,对引用计数原子 – 即可,如果为 false,则新建连接,关闭连接时还需要对连接进行真正的 Close。

缩容如果池的引用计数为 0 时,便会触发缩容操作,是连接维持到最大空闲连接数。

超时保活

基于 GRPC 的 Keepalived 特性,我们不需要自己实现保活机制,也无需关注连接池中的连接是否有效,因为就算失效,GRPC 会自动重连的,此时只不过耗时会略微增加,即认为除了服务器一直处于 down 状态等原因,连接池中的连接是始终有效的。

Tips

由于使用 hash 求余,每个 GRPC 上并发的 Stream 可能会超过 MaxConcurrentStreams。

不同场景对应的连接池配置也不一样,需要根据自己的场景压测得出连接池的最佳参数配置。

感谢各位的阅读,以上就是“GRPC 连接池如何实现”的内容了,经过本文的学习后,相信大家对 GRPC 连接池如何实现这一问题有了更深刻的体会,具体使用情况还需要大家实践验证。这里是丸趣 TV,丸趣 TV 小编将为大家推送更多相关知识点的文章,欢迎关注!

正文完
 
丸趣
版权声明:本站原创文章,由 丸趣 2023-08-16发表,共计3622字。
转载说明:除特殊说明外本站除技术相关以外文章皆由网络搜集发布,转载请注明出处。
评论(没有评论)