如何停止 redis 内存使用量随着连接数的增加而增加
How can I stop redis memory usage increasing with connection count
我们通过 AWS 上的 elasticache 运行 redis,当 运行 大量刚刚读取的 lambda 函数时,我们看到内存使用量激增。这是 redis-cli --stat
的一些示例输出
------- data ------ --------------------- load -------------------- - child -
keys mem clients blocked requests connections
1002 28.11M 15 0 2751795 (+11) 53877
1002 28.07M 15 0 2751797 (+2) 53877
1002 28.07M 15 0 2751799 (+2) 53877
1002 28.11M 15 0 2751803 (+4) 53877
1002 28.07M 15 0 2751806 (+3) 53877
1001 28.11M 15 0 2751808 (+2) 53877
1007 28.08M 15 0 2751837 (+29) 53877
1007 28.08M 15 0 2751839 (+2) 53877
1005 28.10M 16 0 2751841 (+2) 53878
1007 171.68M 94 0 2752012 (+171) 53957
1006 545.93M 316 0 2752683 (+671) 54179
1006 1.07G 483 0 2753508 (+825) 54346
1006 1.54G 677 0 2754251 (+743) 54540
1006 1.98G 882 0 2755024 (+773) 54745
1006 2.35G 1010 0 2755776 (+752) 54873
1005 2.78G 1014 0 2756548 (+772) 54877
1005 2.80G 1014 0 2756649 (+101) 54877
1004 2.79G 1014 0 2756652 (+3) 54877
1008 2.79G 1014 0 2756682 (+30) 54877
1007 2.79G 1014 0 2756685 (+3) 54877
如您所见,键的数量几乎是恒定的,但随着客户端数量的增加,内存使用量上升至 2.8GB。这种内存模式是预期的吗?如果是,除了增加进程可用的 RAM 量之外,还有其他缓解它的方法吗?
lambda 客户端是使用 lettuce 5.2.1.RELEASE 和 spring-data-redis 2.2.1.RELEASE
在 Java 中编写的
除非在spring-data-redis中有一些额外的redis交互否则客户端代码基本如下
public <T> T get(final String label, final RedisTemplate<String, ?> redisTemplate) {
final BoundHashOperations<String, String, T> cache = redisTemplate.boundHashOps(REDIS_KEY);
return cache.get(label);
}
没有RedisTemplate#keys
in my codebase, the only interaction with redis is via RedisTemplate#boundHashOps
的用法
这是尖峰前后 redis-cli info memory
的输出:
之前
# Memory
used_memory:31558400
used_memory_human:30.10M
used_memory_rss:50384896
used_memory_rss_human:48.05M
used_memory_peak:6498905008
used_memory_peak_human:6.05G
used_memory_peak_perc:0.49%
used_memory_overhead:4593040
used_memory_startup:4203584
used_memory_dataset:26965360
used_memory_dataset_perc:98.58%
allocator_allocated:32930040
allocator_active:34332672
allocator_resident:50593792
used_memory_lua:37888
used_memory_lua_human:37.00K
used_memory_scripts:0
used_memory_scripts_human:0B
number_of_cached_scripts:0
maxmemory:5140907060
maxmemory_human:4.79G
maxmemory_policy:volatile-lru
allocator_frag_ratio:1.04
allocator_frag_bytes:1402632
allocator_rss_ratio:1.47
allocator_rss_bytes:16261120
rss_overhead_ratio:1.00
rss_overhead_bytes:-208896
mem_fragmentation_ratio:1.60
mem_fragmentation_bytes:18826560
mem_not_counted_for_evict:0
mem_replication_backlog:0
mem_clients_slaves:0
mem_clients_normal:269952
mem_aof_buffer:0
mem_allocator:jemalloc-5.1.0
active_defrag_running:0
lazyfree_pending_objects:0
之后
# Memory
used_memory:4939687896
used_memory_human:4.60G
used_memory_rss:4754452480
used_memory_rss_human:4.43G
used_memory_peak:6498905008
used_memory_peak_human:6.05G
used_memory_peak_perc:76.01%
used_memory_overhead:4908463998
used_memory_startup:4203584
used_memory_dataset:31223898
used_memory_dataset_perc:0.63%
allocator_allocated:5017947040
allocator_active:5043314688
allocator_resident:5161398272
used_memory_lua:37888
used_memory_lua_human:37.00K
used_memory_scripts:0
used_memory_scripts_human:0B
number_of_cached_scripts:0
maxmemory:5140907060
maxmemory_human:4.79G
maxmemory_policy:volatile-lru
allocator_frag_ratio:1.01
allocator_frag_bytes:25367648
allocator_rss_ratio:1.02
allocator_rss_bytes:118083584
rss_overhead_ratio:0.92
rss_overhead_bytes:-406945792
mem_fragmentation_ratio:0.96
mem_fragmentation_bytes:-185235352
mem_not_counted_for_evict:0
mem_replication_backlog:0
mem_clients_slaves:0
mem_clients_normal:4904133550
mem_aof_buffer:0
mem_allocator:jemalloc-5.1.0
active_defrag_running:0
lazyfree_pending_objects:0
在与 AWS 支持人员讨论过这个问题后,内存峰值的原因是 1000 个 lambda 客户端中的每一个都用大约 5mb 的数据填充了一个读取缓冲区,因为我们存储在 redis 中的数据是大量序列化的 json 个对象。
他们的建议是:
在集群中添加2-3个副本,并使用副本节点进行读取请求。您可以使用 reader 个端点来平衡请求
或者使用参数控制客户端输出缓冲区,但请注意,如果客户端达到缓冲区限制,它们将断开连接。
- client-output-buffer-limit-normal-hard-limit >> 如果客户端的输出缓冲区达到指定的字节数,客户端将断开连接。默认值为零(无硬性限制)。默认为 0,这意味着客户端可以使用尽可能多的内存。
- client-output-buffer-limit-normal-soft-limit >> 如果客户端的输出缓冲区达到指定的字节数,则客户端将断开连接,但前提是 client-output-buffer 的这种情况持续存在-limit-normal-soft-seconds。默认为零(无软限制)。
- client-output-buffer-limit-normal-soft-seconds >> 对于 Redis publish/subscribe 客户端:如果客户端的输出缓冲区达到指定的字节数,客户端将断开连接。默认值为 0
考虑到这些限制和我们的使用配置文件,我们实际上将在这种情况下切换到使用 S3。
我们通过 AWS 上的 elasticache 运行 redis,当 运行 大量刚刚读取的 lambda 函数时,我们看到内存使用量激增。这是 redis-cli --stat
------- data ------ --------------------- load -------------------- - child -
keys mem clients blocked requests connections
1002 28.11M 15 0 2751795 (+11) 53877
1002 28.07M 15 0 2751797 (+2) 53877
1002 28.07M 15 0 2751799 (+2) 53877
1002 28.11M 15 0 2751803 (+4) 53877
1002 28.07M 15 0 2751806 (+3) 53877
1001 28.11M 15 0 2751808 (+2) 53877
1007 28.08M 15 0 2751837 (+29) 53877
1007 28.08M 15 0 2751839 (+2) 53877
1005 28.10M 16 0 2751841 (+2) 53878
1007 171.68M 94 0 2752012 (+171) 53957
1006 545.93M 316 0 2752683 (+671) 54179
1006 1.07G 483 0 2753508 (+825) 54346
1006 1.54G 677 0 2754251 (+743) 54540
1006 1.98G 882 0 2755024 (+773) 54745
1006 2.35G 1010 0 2755776 (+752) 54873
1005 2.78G 1014 0 2756548 (+772) 54877
1005 2.80G 1014 0 2756649 (+101) 54877
1004 2.79G 1014 0 2756652 (+3) 54877
1008 2.79G 1014 0 2756682 (+30) 54877
1007 2.79G 1014 0 2756685 (+3) 54877
如您所见,键的数量几乎是恒定的,但随着客户端数量的增加,内存使用量上升至 2.8GB。这种内存模式是预期的吗?如果是,除了增加进程可用的 RAM 量之外,还有其他缓解它的方法吗?
lambda 客户端是使用 lettuce 5.2.1.RELEASE 和 spring-data-redis 2.2.1.RELEASE
在 Java 中编写的除非在spring-data-redis中有一些额外的redis交互否则客户端代码基本如下
public <T> T get(final String label, final RedisTemplate<String, ?> redisTemplate) {
final BoundHashOperations<String, String, T> cache = redisTemplate.boundHashOps(REDIS_KEY);
return cache.get(label);
}
没有RedisTemplate#keys
in my codebase, the only interaction with redis is via RedisTemplate#boundHashOps
这是尖峰前后 redis-cli info memory
的输出:
之前
# Memory
used_memory:31558400
used_memory_human:30.10M
used_memory_rss:50384896
used_memory_rss_human:48.05M
used_memory_peak:6498905008
used_memory_peak_human:6.05G
used_memory_peak_perc:0.49%
used_memory_overhead:4593040
used_memory_startup:4203584
used_memory_dataset:26965360
used_memory_dataset_perc:98.58%
allocator_allocated:32930040
allocator_active:34332672
allocator_resident:50593792
used_memory_lua:37888
used_memory_lua_human:37.00K
used_memory_scripts:0
used_memory_scripts_human:0B
number_of_cached_scripts:0
maxmemory:5140907060
maxmemory_human:4.79G
maxmemory_policy:volatile-lru
allocator_frag_ratio:1.04
allocator_frag_bytes:1402632
allocator_rss_ratio:1.47
allocator_rss_bytes:16261120
rss_overhead_ratio:1.00
rss_overhead_bytes:-208896
mem_fragmentation_ratio:1.60
mem_fragmentation_bytes:18826560
mem_not_counted_for_evict:0
mem_replication_backlog:0
mem_clients_slaves:0
mem_clients_normal:269952
mem_aof_buffer:0
mem_allocator:jemalloc-5.1.0
active_defrag_running:0
lazyfree_pending_objects:0
之后
# Memory
used_memory:4939687896
used_memory_human:4.60G
used_memory_rss:4754452480
used_memory_rss_human:4.43G
used_memory_peak:6498905008
used_memory_peak_human:6.05G
used_memory_peak_perc:76.01%
used_memory_overhead:4908463998
used_memory_startup:4203584
used_memory_dataset:31223898
used_memory_dataset_perc:0.63%
allocator_allocated:5017947040
allocator_active:5043314688
allocator_resident:5161398272
used_memory_lua:37888
used_memory_lua_human:37.00K
used_memory_scripts:0
used_memory_scripts_human:0B
number_of_cached_scripts:0
maxmemory:5140907060
maxmemory_human:4.79G
maxmemory_policy:volatile-lru
allocator_frag_ratio:1.01
allocator_frag_bytes:25367648
allocator_rss_ratio:1.02
allocator_rss_bytes:118083584
rss_overhead_ratio:0.92
rss_overhead_bytes:-406945792
mem_fragmentation_ratio:0.96
mem_fragmentation_bytes:-185235352
mem_not_counted_for_evict:0
mem_replication_backlog:0
mem_clients_slaves:0
mem_clients_normal:4904133550
mem_aof_buffer:0
mem_allocator:jemalloc-5.1.0
active_defrag_running:0
lazyfree_pending_objects:0
在与 AWS 支持人员讨论过这个问题后,内存峰值的原因是 1000 个 lambda 客户端中的每一个都用大约 5mb 的数据填充了一个读取缓冲区,因为我们存储在 redis 中的数据是大量序列化的 json 个对象。
他们的建议是:
在集群中添加2-3个副本,并使用副本节点进行读取请求。您可以使用 reader 个端点来平衡请求
或者使用参数控制客户端输出缓冲区,但请注意,如果客户端达到缓冲区限制,它们将断开连接。
- client-output-buffer-limit-normal-hard-limit >> 如果客户端的输出缓冲区达到指定的字节数,客户端将断开连接。默认值为零(无硬性限制)。默认为 0,这意味着客户端可以使用尽可能多的内存。
- client-output-buffer-limit-normal-soft-limit >> 如果客户端的输出缓冲区达到指定的字节数,则客户端将断开连接,但前提是 client-output-buffer 的这种情况持续存在-limit-normal-soft-seconds。默认为零(无软限制)。
- client-output-buffer-limit-normal-soft-seconds >> 对于 Redis publish/subscribe 客户端:如果客户端的输出缓冲区达到指定的字节数,客户端将断开连接。默认值为 0
考虑到这些限制和我们的使用配置文件,我们实际上将在这种情况下切换到使用 S3。