6

go-redis 连接池配置

 1 year ago
source link: https://www.cyningsun.com/06-05-2023/go-redis-connection-pool.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

go-redis 连接池配置

连接池是各种服务绕不过去的模块,它在调用链路的上下游之间建立了一个缓冲区。客户端可以从连接池中获取连接来执行数据库操作,完成后将连接返回给连接池,而不是每次都建立新的连接。

连接池的作用显而易见:

  1. 提高性能:连接池可以减少连接的创建和销毁过程,避免了频繁地与服务端建立物理连接的开销,从而提高了客户端的性能和响应速度。
  2. 节省资源:服务端连接是一种有限的资源,每个连接都占用着内存等系统资源。连接池可以限制连接的数量,避免过多的连接导致资源的浪费,提高了系统的资源利用率。
  3. 连接的复用:连接池可以重复利用已经建立的连接,避免了频繁地创建和销毁连接的开销,提高了服务端的并发性能。

但是,连接池配置众多,根据业务特征调整好连接池并不容易。

go-redis 连接池的配置参数包括:

- DialTimeout  # Dial timeout for establishing new connections.
- ReadTimeout  # Timeout for socket reads. If reached, commands will fail with a timeout instead of blocking.
- WriteTimeout  # Timeout for socket writes. If reached, commands will fail with a timeout instead of blocking.
- PoolFIFO  # Type of connection pool. true for FIFO pool, false for LIFO pool.
- PoolSize  # Maximum number of socket connections.
- PoolTimeout  # Amount of time client waits for connection if all connections are busy before returning an error.
- MinIdleConns  # Minimum number of idle connections which is useful when establishing new connection is slow.
- MaxIdleConns  # Maximum number of idle connections.
- ConnMaxIdleTime  # ConnMaxIdleTime is the maximum amount of time a connection may be idle.
- ConnMaxLifetime  # Expired connections may be closed lazily before reuse.

误区一: DialTimeout 设置过小

DialTimeout(拨号超时)用于指定建立网络连接的超时时间。当客户端尝试连接到服务端时,如果在 DialTimeout 指定的时间内无法建立连接,连接操作将超时失败。它通常包括域名解析、建立 TCP 连接等步骤的超时时间。

DialTimeout 设置过小,可能会导致服务由于无法成功建立连接,启动失败。尤其是使用 DNS 作为服务发现以及跨 IDC 调用的场景下。

go-redis 默认是 5 s。3~5 s 是比较合适的,可以直接使用默认值。

误区二: PoolSize 设置不合理

如果连接池的大小设置过小,无法满足应用程序的并发需求,可能会导致连接不足的问题,影响应用程序的性能和响应速度。

如果连接池的大小设置过大,最大连接总数超过服务端最大连接数。在业务请求峰值时,会出现新建连接失败导致的请求失败。

那怎么评估连接池大小呢?

假如请求服务端的平均延迟是 duration ms,客户端进程的峰值 QPS 是 qps。单个连接 1 秒(1000)能否处理的请求总数是 1000 / duration;同时,预留一定的 Buffer 连接数 buffer 给请求变慢或请求量因为需求变化增加等场景。那么合适的连接池大小为:

PoolSize = qps / (1000 / duration) + buffer

误区三:ConnMaxLifetime 设置不当

如果连接生存时间设置得过短,则可能频繁地创建和销毁连接,影响性能。此问题比较容易理解。

如果连接生存时间设置得过长,可能会导致连接过期或失效。举个极端的例子,不设置连接生存时间。

考虑以下场景

场景一:
服务端新版本发布。假如该服务有两个实例 A、B。考虑发布过程,首先,A 升级重启,连接全部请求到 B。然后,B 升级重启,连接全部回到 A。因为没有设置连接生存时间,调用 A 不出现错误的前提下,连接永远不均匀。

场景二:
客户端到服务端短暂网络异常。假如该服务有两个实例 A、B,新建连接的机制是 Round Robin。考虑到 B 的网络异常,导致请求全部断开。然后客户端开始新建连接,到 B 的连接全部失败,最终连接池的中的连接全部连接到 A。因为没有设置连接生存时间,调用 A 不出现错误的前提下,连接永远不均匀。

go-redis 该设置默认关闭。为避免类似问题,连接生存时间一般建议配置为小时级,既避免频繁地创建和销毁连接,影响性能;同时也避免连接不均匀。

误区四:PoolFIFO 设置不当

在连接池中连接到服务端每个实例的连接数大致均匀的前提下。客户端从连接池获取连接发起请求,本质来说是一个负载均衡的问题。常见的负载均衡算法包括:

  • Round-Robin(FIFO)
  • Random
  • Weighted Round Robin
  • Weighted Random
  • Hashing

很显然,go-redis 默认使用的 LIFO 并不在列。

LIFO 并不适合作为负载均衡算法的选择。因为 LIFO 会优先处理最近使用过的连接,这可能会导致某些服务实例负载过重,而其他的服务实例却得不到充分的利用。这种不均衡的分配会影响系统的可用性、性能和容错能力。

因此,在使用 go-redis 时,PoolFIFO 应永远设置为 true。

附:连接池图例

连接使用:获取/释放流程图

go-redis%20%E8%BF%9E%E6%8E%A5%E7%AE%A1%E7%90%86-20230605190856.png

连接管理:连接状态机

go-redis%20%E8%BF%9E%E6%8E%A5%E7%AE%A1%E7%90%86-20230605191310.png

本文作者 : cyningsun
本文地址https://www.cyningsun.com/06-05-2023/go-redis-connection-pool.html
版权声明 :本博客所有文章除特别声明外,均采用 CC BY-NC-ND 3.0 CN 许可协议。转载请注明出处!


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK