Redis Out of Memory 异常,但仍然有足够的内存

Redis Out of Memory Exceptions, but still have plenty of memory

我在我们的 .NET Core C# 项目中使用 StackeExchange.Redis 项目与 Redis 交互。

在重负载下,我们的 Redis 连接将开始失败,并出现以下异常:

StackExchange.Redis.RedisServerException: OOM command not allowed when used memory > 'maxmemory'

问题是我们剩余的可用内存量大得离谱。我们使用的是 Elasticache,所以很容易查找:

我们也可以通过一个shell连接到Elasticache,看到有可用的内存,就可以与之交互了。

这是我用作连接信息层的代码。

    public class RedisTimeConnectionManager : IRedisConnectionManager
{
    // More info about the Lazy<> pattern 
    // Additional information about the multiplexer: https://github.com/StackExchange/StackExchange.Redis/blob/master/docs/Basics.md
    private static Lazy<ConnectionMultiplexer> RedisConnectionMultiplexer = new Lazy<ConnectionMultiplexer>(() =>
    {
        return ConnectionMultiplexer.Connect(ConnectionString);
    });

    private static string ConnectionString { get; set; }

    public RedisTimeConnectionManager(string connectionString)
    {
        ConnectionString = connectionString;
    }

    public ConnectionMultiplexer GetConnectionMultiplexer()
    {
        return RedisConnectionMultiplexer.Value;
    }

    public IDatabase GetDatabaseConnection()
    {
        return RedisConnectionMultiplexer.Value.GetDatabase();
    }
}

然后我将此连接层传递给我的 redis "time" 管理器。这是引发 OOM 错误的代码:

public class TimeRedisManager : ITimeRedisManager
{
    private IRedisConnectionManager RedisConnectionManager { get; }

    public TimeRedisManager(IRedisConnectionManager redisConnectionManager)
    {
        RedisConnectionManager = redisConnectionManager;
    }

    public async Task<RedisUserTimelineGetValueDto> GetValueAsync(string id)
    {
        string key = $"time:{id}";

        HashEntry[] entries = await RedisConnectionManager.GetDatabaseConnection().HashGetAllAsync(key);

        // Parse and return values...
    }
}

因为 Elasticache 有超过 7.5GB 的可用内存,并且因为我可以通过 shell 与其交互,我假设它要么是 StackExchange.Redis 库,要么是连接管理的问题在我的代码中。

.NET 核心 2.1 StackExchange.Redis v 2.0.513

最后一件重要的事情 - 当这个异常发生时,它会一直发生。重新启动与 Redis 交互的服务不会执行任何操作。只有重新启动 Elasticache 节点才能解决问题。

Redis 可能占用其中存储数据所需内存的 2 倍。

在此处阅读更多内容:https://redis.io/topics/admin

If you are using Redis in a very write-heavy application, while saving an RDB file on disk or rewriting the AOF log Redis may use up to 2 times the memory normally used. The additional memory used is proportional to the number of memory pages modified by writes during the saving process, so it is often proportional to the number of keys (or aggregate types items) touched during this time. Make sure to size your memory accordingly.

因此,如果存储在 Redis 中的数据占用 space 的 8 Gb,在重负载下 Redis 可能会消耗 16 Gb。如果是这种情况,您可能需要相应地调整内存。