首页 > 解决方案 > 使用 task.forget() 时 Redis 内存使用量继续攀升

问题描述

我有一个 mysql 数据库,它存储了 2 年的数千个库存 OHLC 数据。数据以 pandas 数据帧的形式从 MySQL 读取,然后以大批量作业的形式提交给 celery,最终导致“使用内存>'maxmemory'时不允许使用 OOM 命令”。

我添加了以下 celery 配置选项。这些选项使我的脚本运行时间更长,但是 redis 不可避免地会达到 2gb 内存,并且 celery 会引发 OOM 错误。

result_expires = 30
ignore_result = True
worker_max_tasks_per_child = 1000

从 redis 方面,我尝试使用 allkeys-lru 和 volatile-lru 来使用 maxmemory 策略。两者似乎都没有区别。

当芹菜遇到OOM错误时,redis cli显示最大内存使用量并且没有键?

# Memory
used_memory:2144982784
used_memory_human:2.00G
used_memory_rss:1630146560
used_memory_rss_human:1.52G
used_memory_peak:2149023792
used_memory_peak_human:2.00G
used_memory_peak_perc:99.81%
used_memory_overhead:2144785284
used_memory_startup:987472
used_memory_dataset:197500
used_memory_dataset_perc:0.01%
allocator_allocated:2144944880
allocator_active:1630108672
allocator_resident:1630108672
total_system_memory:17179869184
total_system_memory_human:16.00G
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:2147483648
maxmemory_human:2.00G
maxmemory_policy:allkeys-lru
allocator_frag_ratio:0.76
allocator_frag_bytes:18446744073194715408
allocator_rss_ratio:1.00
allocator_rss_bytes:0
rss_overhead_ratio:1.00
rss_overhead_bytes:37888
mem_fragmentation_ratio:0.76
mem_fragmentation_bytes:-514798320
mem_not_counted_for_evict:0
mem_replication_backlog:0
mem_clients_slaves:0
mem_clients_normal:2143797684
mem_aof_buffer:0
mem_allocator:libc
active_defrag_running:0
lazyfree_pending_objects:0

并且有零键?

127.0.0.1:6379[1]> keys *
(empty list or set)

当我在 200*5 请求的子集中运行相同的代码(然后终止)时,一切都会成功运行。Redis 内存使用量上限约为 100mb,当 python 进程终止时,所有内存使用量都会按预期下降。这让我相信我可能会实现一个处理程序来一次执行 200*5 个请求,但是我怀疑 python 进程(我的脚本)终止实际上是在 celery/redis 中释放内存......

我想避免对它进行子集化,并一次性处理 MySQL 中的所有内容。大约 5000 个 pandas 数据帧 * 总共 5 个任务。

我不明白为什么当我在检索结果后立即忘记所有结果时,redis 中的内存使用量会继续增长?

这是我的代码中如何完成此操作的示例:

def getTaskResults(self, caller, task):
    #Wait for the results and then call back
    #Attach this Results object in the callback along with the data
    ready = False
    while not ready:
        if task.ready():
            ready = True
            data = pd.read_json(task.get())
            data.sort_values(by=['Date'], inplace=True)
            task.forget()
            return caller.resultsCB(data, self)

这可能是我对 redis 的无知,但是如果没有键,它是如何消耗所有内存的,或者我如何验证在 redis 中实际消耗的内存是什么?

由于我将每次调用 celery 的 taskID 存储在一个对象中,我已经确认在添加 task.forget 后尝试执行 task.get 会引发错误。

标签: python-3.xpandasrediscelery

解决方案


推荐阅读