java 获取RedisOutOfMemoryException

nhaq1z21  于 2023-04-04  发布在  Java
关注(0)|答案(1)|浏览(175)

我正在使用Reddison为HashMap的键设置TTL。
这是正确的。但是当插入大量数据时,例如30分钟内插入500万,数据仍然保留在Redis中并且不会过期。在AWS ElasticCache中经过几次迭代后,数据库内存使用百分比达到100%
下面是我在sprint Boot 代码实现中使用的代码,以及获取和异常
代码:

RMapCache<String, Object> map = getConnection().getMapCache(mapName);
map.put(key, obj, 15, TimeUnit.MINUTES);

例外情况:

org.redisson.client.RedisOutOfMemoryException: command not allowed when used memory > 'maxmemory'. script: 8002ee0f772fdaac4335bffe445fb53aef8dcd57, on @user_script:1.. channel: [id: 0x17227def, L:/10.224.59.44:59436 - R:10.224.57.111/10.224.57.111:6379] data: CommandData [promise=java.util.concurrent.CompletableFuture@120fc639[Not completed, 1 dependents], command=(EVAL), params=[local insertable = false; local v = redis.call('hget', KEYS[1], ARGV[5]); if v == false then insertable = true; else local t, val = struct.unpack('dLc0', v); local expireDate = 92233720368547758; local expireDateScore = redis.call('zscore', KEYS[2], ARGV[5]); if expireDateScore ~= false then expireDate = tonumber(expireDateScore) end; if t ~= 0 then local expireIdle = redis.call('zscore', KEYS[3], ARGV[5]); if expireIdle ~= false then expireDate = math.min(expireDate, tonumber(expireIdle)) end; end; if expireDate <= tonumber(ARGV[1]) then insertable = true; end; end; if tonumber(ARGV[2]) > 0 then redis.call('zadd', KEYS[2], ARGV[2], ARGV[5]); else redis.call('zrem', KEYS[2], ARGV[5]); end; if tonumber(ARGV[3]) > 0 then redis.call('zadd', KEYS[3], ARGV[3], ARGV[5]); else redis.call('zrem', KEYS[3], ARGV[5]); end; local maxSize = tonumber(redis.call('hget', KEYS[8], 'max-size')); if maxSize ~= nil and maxSize ~= 0 then     local currentTime = tonumber(ARGV[1]);     local lastAccessTimeSe..., 8, cid-phone-qa, redisson__timeout__set:{cid-phone-qa}, redisson__idle__set:{cid-phone-qa}, redisson_map_cache_created:{cid-phone-qa}, redisson_map_cache_updated:{cid-phone-qa}, redisson__map_cache__last_access__set:{cid-phone-qa}, redisson_map_cache_removed:{cid-phone-qa}, {cid-phone-qa}:redisson_options, ...], codec=org.redisson.codec.MarshallingCodec]
    at org.redisson.client.handler.CommandDecoder.decode(CommandDecoder.java:361) ~[redisson-3.18.1.jar!/:3.18.1]
    at org.redisson.client.handler.CommandDecoder.decodeCommand(CommandDecoder.java:205) ~[redisson-3.18.1.jar!/:3.18.1]
    at org.redisson.client.handler.CommandDecoder.decode(CommandDecoder.java:144) ~[redisson-3.18.1.jar!/:3.18.1]
    at org.redisson.client.handler.CommandDecoder.decode(CommandDecoder.java:120) ~[redisson-3.18.1.jar!/:3.18.1]
    at io.netty.handler.codec.ByteToMessageDecoder.decodeRemovalReentryProtection(ByteToMessageDecoder.java:501) ~[netty-codec-4.1.52.Final.jar!/:4.1.52.Final]
    at io.netty.handler.codec.ReplayingDecoder.callDecode(ReplayingDecoder.java:366) ~[netty-codec-4.1.52.Final.jar!/:4.1.52.Final]
    at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:276) ~[netty-codec-4.1.52.Final.jar!/:4.1.52.Final]
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379) ~[netty-transport-4.1.52.Final.jar!/:4.1.52.Final]
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365) ~[netty-transport-4.1.52.Final.jar!/:4.1.52.Final]
    at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:357) ~[netty-transport-4.1.52.Final.jar!/:4.1.52.Final]
    at io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1410) ~[netty-transport-4.1.52.Final.jar!/:4.1.52.Final]
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379) ~[netty-transport-4.1.52.Final.jar!/:4.1.52.Final]
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365) ~[netty-transport-4.1.52.Final.jar!/:4.1.52.Final]
    at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:919) ~[netty-transport-4.1.52.Final.jar!/:4.1.52.Final]
    at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:166) ~[netty-transport-4.1.52.Final.jar!/:4.1.52.Final]
    at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:714) ~[netty-transport-4.1.52.Final.jar!/:4.1.52.Final]
btxsgosb

btxsgosb1#

这可能是雷迪森如何被使用的问题。
你将500万条数据存储在Redis中的一个Hash中,然后尝试根据 field 使它们过期。Redis确实支持Hash中的字段级过期。它可以使键过期,但不能使键中的元素过期,如Hash中的字段、Set中的成员或List中的项目。
Redison以某种方式提供了这个功能。我不是很熟悉它,但我知道它涉及到Lua脚本。我猜Lua脚本没有机会运行,因为Redis接收数据太快了。
然而,更重要的是,我认为在一个Hash中存储那么多数据并不是最好的解决方案,至少一般来说是这样。这是一个地方有很多数据。包含这些数据的键将存在于单个分片中,而不是分散在集群中,这将影响解决方案的水平可扩展性。
你可能会更好地将每个值存储在Redis中的一个String中,使用Redis中的一个键名mapName与你所称的key相结合。这将使用大量的key,这很好,因为它允许数据在集群中分散。而且,它将允许 Redis 来处理到期,而不是Redison。
希望这有帮助!

相关问题