亚马逊AWS官方博客
浅谈数据库连接池优化之 Amazon ElastiCache Redis
本文主要介绍 Amazon ElastiCache Redis 数据库连接池优化技巧,通过使用 Redisson 并依据 Amazon ElastiCache Redis 具体的高可用集群结构进行对应精细化调整,最终可以实现个位数秒级自愈的 Redis 长连接连接池。
Amazon ElastiCache Redis 集群在进行原地软件升级、安全更新、机型变配或者 Redis 集群自身遇到了极低概率的底层硬件故障时,集群中单个 Redis 节点会短暂下线。为了保证 Redis 集群的整体可用,AWS 会自动对集群中的节点进行维护,通过 endpoint 对外界暴露正常工作的 Redis 节点的 private ip 地址。对连接 Redis 集群的客户端而言,如果一个现有长连接所在的 Redis 节点出现故障,那么这个客户端应该及时释放已经失效的连接,并尽快根据 endpoint 解析出的正常 Redis 节点的 ip 来重建长连接。我们知道长连接的重建是需要时间的,如果没做好连接池的精细化设计,那么应用很会感知到明显的 Redis 抖动,甚至造成短暂的服务不可用。在以往,我们观察到这个问题在线上场景中耗时大约是 30~60 秒,个别设计不规范的情况下可能更长!为了解决上述问题,了解各种 Redis 高可用集群本身的原理,并按照其特点进行连接池设计,是实现个位数秒级连接池自愈的关键。
Amazon ElastiCache Redis 集群拓扑解读
Amazon ElastiCache Redis 有 2 种高可用集群模式,分别对应于标准 Redis 的主从结构和分片结构。具体可以自行参考 ElastiCache terminology。
本文以 Amazon ElastiCache Redis(cluster mode disabled)集群模式为例讲解,这种集群由多个 Redis 节点组成,节点间形成一写多读的关系。
根据 Finding connection endpoints in ElastiCache,它的 endpoint 有 3 类:
- primary endpoint:它永远指向 Redis 集群中的 primary 节点,这个 primary 节点作为整个 Redis 集群唯一的数据写入入口,可以同时进行读写操作。当 Redis 集群中的 primary 节点维护时,Redis 集群中现有的一个 replica 节点会被自动提升为新的 primary 节点,然后 primary endpoint 会更新 DNS,指向新的 primary 节点的 private ip。当前的 primary 在维护完成后重新加入集群并成为新的 replica 节点。
- reader endpoint:它永远指向 Redis 集群中的 replica 节点,replica 节点只能进行读操作。当集群中有多个 replica 节点时,reader endpoint 的 DNS 会大致均衡地随机解析到不同的 replica 节点 ip 上,确保每个 replica 节点能均匀地被创建只读长连接,这样可以在多个 replica 节点间分摊只读操作的压力。
- instance endpoint:指向某个具体的 Redis 节点的 private ip。一般不建议直接在代码中使用 instance endpoint。
下面是它的结构图和它的 3 种 endpoint 示意图:
当我们使用 reader endpoint 时也会发现,这个 endpoint 的 DNS 会随机地指向不同的 replica 节点,方便用户做读写分离和只读压力的均衡。下图中我们也可以看到,DNS TTL 为 5 秒,这个 DNS TTL 值一般也适用于 RDS 和 DocumentDB。
全局来看我们可知,如果发生维护时会大致会经历下面的步骤:
- AWS ElastiCahe Redis 对某个 Redis 节点进行维护,并更新 DNS 解析信息。
- 应用侧 Redis 客户端本地 DNS 失效,然后获取到最新的 DNS 解析信息。
- 应用侧 Redis 客户端根据最新的 DNS 解析信息重新建立连接。
由于本身 DNS 默认有 5S 的 TTL,加上一些操作系统或者客户端本身的 DNS TTL 会更长一些,所以传统的方式很难实现个位数秒级重连。依据 Version Management for ElastiCache,如果是被动的事后重连,一般的时间在 30~60 秒,几乎没有可能完成个位数秒级连接池自愈。
主动感知 Redis 集群拓扑关系并进行重连
Redis 集群中一般为我们预留了集群整体状况相关的命令,比如 info replication、info cluster 等。如果客户端可以直接通过上述命令主动地了解当前集群的准确信息,而不是被动地等待 AWS ElastiCache Redis 通过 DNS 解析更新的方式对外公布的最终集群信息,那么理论上连接池的自愈可以不需要等待 Redis 集群内部选举、DNS 信息延迟等全部维护流程串行完成,它可以直接主动地提前进行连接池的重连操作。上述的思路就是 Redisson 实现个位数秒级连接池自愈的核心思路。对 Redisson 而言,它对 AWS ElastiCache Redis 进行了针对性的优化,详情可以参见 Github Redisson,我们根据具体的 Redis 集群类型进行针对性的精细化调整即可。
我们继续以 Amazon ElastiCache Redis(cluster mode disabled)集群模式为例进行验证,相关的代码在 aws-managed-services-best-usage-sample,本文以 SpringBoot 项目进行演示。
首先为 Amazon ElastiCache Redis(cluster mode disabled)集群针对性地使用 Redisson 连接池配置:
然后我们填写 primary endpoint 和 reader endpoint,设置好 Redisson 主动感知 Redis 集群拓扑关系的时间间隔等高级设置。这样在 redis 集群维护期,Redisson 可以尽快地获取到 Redis 集群内部的拓扑关系变化,并作出正确的反应。
我们也可以补充下 Java 自身的 DNS TTL 设置:
在应用启动后,我们发现 Redisson 可以准确地感知的集群中各个节点的详细信息,比如哪个节点是写节点哪个是只读节点、这些节点的具体的 instance endpoint 和 IP 是多少,等等。
当我们 cli 进入 Redis 集群内部检查的时候,可以清晰地看到,Redisson 定期地进行 ping 操作检查某个节点的状态,它也会通过 info replication 不断感知 Amazon ElastiCache Redis(cluster mode disabled)集群拓扑关系。
验证 Redisson 连接池自愈
将应用在宁夏 Region 中的一台 t3a.medium EC2 上正常启动后,我们使用 jmeter 不断地请求这个应用来模拟线上业务负载,在这个过程中,应用会不断地读写 primary 节点,我们通过观察日志可以估算连接池自愈的耗时。本次测试使用的 Redis 集群版本为 Valkey 7.2.6,并使用了 3 台 cache.t3.small 节点组成一主 2 读的 Amazon ElastiCache Redis(cluster mode disabled)集群,jmeter 使用 50 线程并发无限循环模式,TPS 大约在 700 左右。
在 Redis 集群正常情况下,应用在打印 redis 读写日志,期间伴随着 redis 集群的状态感知信息,这是 reader endpint 的 DNS 解析均衡设计导致的,属于正常现象,没有副作用。
如果我们直接手动粗暴地进行 primary 节点的 failover,节点角色切换现象比较明显,需要更长完成连接池的自愈,多次测试都可以控制在 40 秒以内。
手动 failover 时具体的截图入下:
failover 错误开始产生
failover 错误结束,连接池完成自愈
通过上述的截图我们可以看到,从第一个错误产生到最后一个错误结束,大致耗时 40 秒。
如果我们通过更改集群的节点类型来模拟维护操作时,我们可以观察到期间发生的预期的维护动作。一般 Redisson 可以及时地获取 redis 集群内部的协商信息来提前进行连接池的更新,观察到的时间典型值是 1 到 3 秒左右,多次测试都可以控制在 5 秒以内。
通过上述的截图我们可以看到,从第一个错误产生到连接池自愈,大致耗时 1 秒。
总结
目前主流的 Redis 连接客户端(比如Redisson 和 lettuce)基本都具备主动感知 Redis 集群内部拓扑关系的能力,我们按照相关的文档进行精细化设置后可以最大程度地减少集群维护造成的影响。维护事件也可分为不同的类型,一般相对柔性的维护,比如更改机型和软件更新等预期事件,影响时间可以缩短到个位数秒级;如果是非柔性的集群事件,比如手动 failover 或者极小概率的底层硬件故障,影响时间可能会长一些,一般在 40S 以内,建议大家在业务低峰期进行集群维护操作。此外,本文的思路也可以用在 Valkey 集群或者开源自建的 Redis 集群上。
参考链接
- Redisson
- AWS ElastiCache Lettuce client configuration
- AWS ElastiCache Redis Engine versions and upgrading
- Spring Data Redis
- Java Networking Properties
- 条条大路通罗马 —— 使用Redisson连接Amazon ElastiCache for redis 集群
- 使用 Lettuce 和 Redisson 对 Amazon Multi-AZ ElastiCache for Redis 实现就近读取