【问题标题】:Spring Redis - Indexes not deleted after main entry expiresSpring Redis - 主条目过期后未删除索引
【发布时间】:2017-06-01 07:37:35
【问题描述】:

我正在使用 Spring Data Repository 保存新条目。每个条目的 TTL 为 10 秒。

当我使用索引保存条目时,这就是我在 Redis 中得到的内容

127.0.0.1:6379> keys *
1) "job:campaignId:aa"
2) "job:a6d6e491-5d75-4fd0-bd8e-71692f6d18be"
3) "job:recipient:dd"
4) "job:a6d6e491-5d75-4fd0-bd8e-71692f6d18be:phantom"
5) "job:listId:cc"
6) "job:accountId:bb"
7) "job"
8) "job:a6d6e491-5d75-4fd0-bd8e-71692f6d18be:idx"

过期后我还有数据:

127.0.0.1:6379> keys *
1) "job:campaignId:aa"
2) "job:recipient:dd"
3) "job:listId:cc"
4) "job:accountId:bb"
5) "job"
6) "job:a6d6e491-5d75-4fd0-bd8e-71692f6d18be:idx"

没有任何 TTL。

他们为什么不删除自己?我怎么能这样做?

【问题讨论】:

    标签: spring redis spring-data spring-data-redis


    【解决方案1】:

    Spring Data Redis Repositories 使用多个 Redis 功能将域对象持久保存在 Redis 中。

    域对象主要存储在散列 (job:a6d6e491-5d75-4fd0-bd8e-71692f6d18be) 中。任何过期都直接应用于哈希,因此 Redis 可以使密钥过期。 Spring Data Redis 还维护二级索引(job:campaignId:aajob:recipient:dd)以提供特定字段值的查找。集合中的单个元素不能过期。只有整个数据结构可以过期,但这不是您想要做的事情,因为所有未过期的元素都会以这种方式消失。

    因此 Spring Data Redis 将原始哈希的副本保留为幻像哈希 (job:a6d6e491-5d75-4fd0-bd8e-71692f6d18be:phantom),具有稍长的 TTL。

    Spring Data Redis 订阅键事件(设置@EnableRedisRepositories(enableKeyspaceEvents = EnableKeyspaceEvents.ON_STARTUP)来监听到期事件。一旦原始哈希过期,Spring Data Redis 就会加载幻像哈希以执行清理(从二级索引中删除引用)。

    未执行数据清理的原因可能有多种原因:

    1. 如果您运行控制台应用程序只是为了插入数据并终止,则到期会删除哈希但不会执行索引清理,因为您的应用程序不再运行。 Redis 发布的任何事件都是瞬态的,如果您的应用程序没有在监听,那么这些事件就会丢失
    2. 如果您仅使用 @EnableRedisRepositories 启用了存储库支持(未启用 keyspace-events),则 Keyspace 事件侦听器处于非活动状态,并且 Spring Data Redis 不会订阅任何到期事件。

    【讨论】:

    • 谢谢!这就是我需要的解释。我错过了文档中的某些内容吗?另一个相关问题,如何在 Spring Data 删除过期键之前获取它的值?
    • 在您的应用程序中观察RedisKeyExpiredEvent。它包含密钥(字节)和过期的域对象。有关到期的详细信息,请参阅docs.spring.io/spring-data/redis/docs/current/reference/html/…
    • 在使用@EnableRedisRepositories(enableKeyspaceEvents = EnableKeyspaceEvents.ON_STARTUP) 进行了一些测试后,我看到幻像与真正的键同时被删除,但在文档中,它说它将被删除 5分钟后。也许有一个属性或什么的?
    • 我在我的模型中将 TTL 强制为 5 秒 @TimeToLive public long getTimeToLive() { return 5; }
    • 为什么 enableKeyspaceEvents 默认不开启?我看不出谁不想要这种行为。没有它,这意味着你的 Redis 迟早会耗尽内存。
    【解决方案2】:

    如果您不设置过期时间,则不会自动删除任何键/值。

    所以要自动删除你必须设置过期时间的数据。

    redis> SET mykey "Hello"
    "OK"
    redis> EXPIRE mykey 10
    (integer) 1
    

    参考:https://redis.io/commands/expire

    下面是Spring代码sn-p向redis添加数据并设置过期时间

    @Component
    public class RedisUtil {
        @Autowired
        private RedisTemplate<String, String> template;
    
        @Resource(name = "redisTemplate")
        ValueOperations<String, String> ops;
    
        public boolean addValue(String key, String value) {
    
            if (template.hasKey(Constants.REDIS_KEY_PREFIX + key)) {
                // key is already there
                return false;
            } else {
                ops.set(Constants.REDIS_KEY_PREFIX + key, value);
                template.expireAt(Constants.REDIS_KEY_PREFIX + key, 10);
            }
            return true;
        }
    }
    

    【讨论】:

    • 好的,所以我必须手动完成?我将 Spring Data Redis 与存储库一起使用,并且当作业的主键已过期并因此被删除时,为索引创建的键/值(模型中的 @Indexed)不会被删除..
    • 是的,您必须通过代码为每个数据设置过期时间。
    • 好吧,我认为使用 spring 会更简单.. 只是做一个 repo.save(entry)
    • 查看更新后的答案,我已经添加了代码 sn-p 供您参考。
    • 谢谢,我知道如何使用 RedisTemplate。我试图使用存储库docs.spring.io/spring-data/redis/docs/current/reference/html/… 和注释索引docs.spring.io/spring-data/redis/docs/current/reference/html/…
    猜你喜欢
    • 2019-08-29
    • 1970-01-01
    • 2019-12-25
    • 2022-01-27
    • 1970-01-01
    • 2020-06-09
    • 1970-01-01
    • 2021-11-11
    • 2016-06-08
    相关资源
    最近更新 更多