您是否喜欢阅读有关如何追踪和修复各种与性能相关的问题?如果是这样,这就是我们如何通过优化 JedisPool 来解决我们面临的 Redis 性能问题的故事。我们希望这将帮助您加强您的 IT 环境。
我们的 Redis 性能问题以及寻找原因的努力
响应时间激增
Site24x7 使用 Redis 内存数据结构来减少对我们后端数据库的访问。我们开始发现我们的应用程序响应时间偶尔会出现峰值。经过调查,我们发现 Redis 缓存调用失败,并且 servlet 开始访问数据库,这导致整个应用程序响应时间出现峰值。这随机发生了几秒钟,然后应用程序恢复正常,Redis 故障为零。
Redis 大键
由于我们到 Redis 的流量几乎全天保持不变,因此我们排除了与扩展相关的问题。然后,我们开始监控 Redis 机器参数,发现每当 Redis 连接下降时,我们就会观察到 CPU 过高警报。然后,我们能够将高 CPU 使用率与 Redis 故障相关联,但高 CPU 使用率的原因仍然是个谜。
我们的怀疑指向 BigKeys 和 CPU 密集型命令,例如 SMEMBERS 密钥。Redis 命令行提供了一个选项来扫描 BigKeys (redis-cli --bigkeys) 并根据数据类型查看 BigKeys 列表。作为解决问题的下一步,我们删除了大于 1MB 的 BigKey。我们还尝试使用Redis 慢日志 列出所有可能降低系统速度的命令,但没有列出 CPU 密集型命令。
Redis连接
此时,我们有点疑惑,因为我们在慢日志中找不到任何 BigKey 或慢命令,但我们仍然观察到 CPU 峰值和连接断开。由于创建新连接是一项 I/O 密集型操作,我们开始观察新连接的模式。令我们惊讶的是,我们发现每秒创建的连接数等于执行的命令数。我们对这一发现感到惊讶,因为我们已经在使用 JedisPool(可重用 Jedis 连接的集合)来重用连接,并且没有更改我们的 JedisPool 配置。
经过进一步研究,我们了解到 JedisPool 提供了许多选项来根据应用程序的需要设置配置。但是我们使用的是默认配置。当我们有较少的应用程序服务器时,这工作得很好。随着我们扩展应用服务器,默认配置导致 JedisPool 的使用效率低下。
Jedis 是 Redis 最常用的 Java 客户端库之一,也是 Redis 官方客户端列表中推荐的客户端之一。您可以在此处下载最新版本。
由于单个 Jedis 实例不是线程安全的,因此在多线程环境中使用它们会导致各种错误或不一致。此外,为每个 Redis 查询创建新连接并不是一个理想的选择,因为这会产生 I/O 开销,从而导致性能问题。为了克服这些挑战,我们决定尝试 JedisPool,它是线程安全的 Jedis 实例的集合。
默认情况下,与 JedisPool 相关的 maxPoolSize 和 maxIdle 值都是 8。随着产品的增长,我们需要更多的连接,因此我们将 maxPoolSize 增加到 150,而 maxIdle 保持不变。因此,使用此配置,JedisPool 可以在任何给定时间创建最多 150 个连接。尽管如此,它一次只能在池中保存 8 个空闲连接,并且剩余的连接被丢弃。
绝地连接