避免 ElastiCache Redis 上的交换

Jos*_*idt 14 swap memory-usage redis amazon-elasticache

我们的 ElastiCache Redis 实例交换一直存在问题。亚马逊似乎有一些粗略的内部监控,它会注意到交换使用高峰,并简单地重新启动 ElastiCache 实例(从而丢失我们所有的缓存项目)。这是过去 14 天我们 ElastiCache 实例上 BytesUsedForCache(蓝线)和 SwapUsage(橙线)的图表:

Redis ElastiCache BytesUsedForCache 和 Swap

您可以看到不断增长的交换使用模式似乎触发了我们的 ElastiCache 实例的重启,其中我们丢失了所有缓存项目(BytesUsedForCache 降至 0)。

我们 ElastiCache 仪表板的“缓存事件”选项卡具有相应的条目:

来源 ID | 类型 | 日期 | 事件

缓存实例 ID | 缓存集群| 2015 年 9 月 22 日星期二 07:34:47 GMT-400 | 缓存节点 0001 重新启动

缓存实例 ID | 缓存集群| 2015 年 9 月 22 日星期二 07:34:42 GMT-400 | 在节点 0001 上重新启动缓存引擎时出错

缓存实例 ID | 缓存集群| 2015 年 9 月 20 日星期日 11:13:05 GMT-400 | 缓存节点 0001 重新启动

缓存实例 ID | 缓存集群| 2015 年 9 月 17 日星期四 22:59:50 GMT-400 | 缓存节点 0001 重新启动

缓存实例 ID | 缓存集群| 2015 年 9 月 16 日星期三 10:36:52 GMT-400 | 缓存节点 0001 重新启动

缓存实例 ID | 缓存集群| 2015 年 9 月 15 日星期二 05:02:35 GMT-400 | 缓存节点 0001 重新启动

(剪掉之前的条目)

亚马逊声称

SwapUsage——在正常使用中,Memcached 和 Redis 都不应该执行交换

我们的相关(非默认)设置:

  • 实例类型: cache.r3.2xlarge
  • maxmemory-policy: allkeys-lru(我们之前一直使用默认的 volatile-lru 没有太大区别)
  • maxmemory-samples: 10
  • reserved-memory: 2500000000
  • 检查实例上的 INFO 命令,我看到mem_fragmentation_ratio在 1.00 和 1.05 之间

我们联系了 AWS 支持并没有得到太多有用的建议:他们建议将保留内存调得更高(默认值为 0,我们保留了 2.5 GB)。我们没有为这个缓存实例设置复制或快照,所以我相信不应该发生 BGSAVE 并导致额外的内存使用。

maxmemorycache.r3.2xlarge的上限是 62495129600 字节,尽管我们reserved-memory很快达到了上限(减去我们的),但主机操作系统会感到有压力在这里使用如此多的交换,而且如此之快,这对我来说似乎很奇怪,除非出于某种原因,亚马逊提高了操作系统交换设置。知道为什么我们会在 ElastiCache/Redis 上造成如此多的交换使用,或者我们可以尝试的解决方法吗?

Jos*_*idt 9

由于这里没有其他人有答案,我想我会分享唯一对我们有用的东西。首先,这些想法并没有工作:

  • 更大的缓存实例类型:在比我们现在使用的 cache.r3.2xlarge 更小的实例上有同样的问题
  • 调整maxmemory-policy: volatile-lru 和 allkeys-lru 似乎都没有任何区别
  • 颠簸 maxmemory-samples
  • 颠簸 reserved-memory
  • 强制所有客户端设置一个过期时间,一般最多 24 小时,少数少数调用者允许长达 7 天,但绝大多数调用者使用 1-6 小时的过期时间。

这是最终帮助很大的方法:每 12 小时运行一次作业,对 10,000 个块 ( ) 中的所有键运行一次扫描COUNT。这是同一个实例的 BytesUsedForCache,仍然是一个 cache.r3.2xlarge 实例,使用率比以前更高,设置与以前相同:

用于缓存的字节数

内存使用量的锯齿下降对应于 cron 作业的次数。在这两周期间,我们的交换使用量已达到约 45 MB(在重新启动之前达到约 5 GB)。ElastiCache 中的缓存事件选项卡不再报告缓存重启事件。

是的,这似乎是用户不应该自己做的麻烦事,而且 Redis 应该足够聪明,可以自己处理这种清理工作。那么为什么会这样呢?嗯,Redis 并没有做太多或任何预先清理过期键,而是依赖于在 GET 期间驱逐过期键。或者,如果 Redis 意识到内存已满,那么它将开始逐出每个新 SET 的键,但我的理论是,此时 Redis 已经被冲洗掉了。