Spring数据Redis,过期和Redis群集

问题描述

我有一个使用的应用

我有一个由6个节点组成的Redis 5.0.7集群:3个主节点和3个从节点,其复制为127.0.0.1:7000-7005(仅作为示例值)。

我已经通过以下方式配置了我的应用程序:

@Configuration
@EnableRedisRepositories(basePackages = "my.package.of.dtos",enableKeyspaceEvents = RediskeyvalueAdapter.EnableKeyspaceEvents.ON_STARTUP)
public class RedisConfiguration {
    @Bean
    JedisConnectionFactory jedisConnectionFactory() {
        return new JedisConnectionFactory(
            new RedisClusterConfiguration(List.of(
                "127.0.0.1:7000","127.0.0.1:7001","127.0.0.1:7002","127.0.0.1:7003","127.0.0.1:7004","127.0.0.1:7005")));
    }

    @Bean
    public Redistemplate<String,Object> redistemplate(JedisConnectionFactory jedisConnectionFactory) {
        Redistemplate<String,Object> template = new Redistemplate<>();
        template.setConnectionFactory(jedisConnectionFactory);
        return template;
    }
}

我有一些DTO,例如:

@AllArgsConstructor
@NoArgsConstructor
@Data
@Builder
@RedisHash(value = "Foo",timetoLive = 300)
public class Foo {
    private String id;
    @Indexed
    private String fooIndexedField;
    private String fooField1;
    private String fooField2;
}

和存储库:

@Repository
public interface FooRepository extends CrudRepository<Foo,String> {
    List<Foo> findByFooIndexedField(String fooIndexedField);
}

我的用例:我有一个繁忙的处理应用程序,我将数据写入Redis,并希望通过索引字段读取实体列表。数据仅在一段时间内是相关的,因此我利用Redis的到期功能

在我注意到Redis中的数据没有按预期失效之前,一切似乎都可以正常工作。当我连接到Redis集群(使用RedisClusterConfiguration)时,一旦散列过期,与之关联的其余数据将由Spring Data Redis保留,则幻影将在其自身的5分钟后过期,但是会有额外的集合Foo(具有所有ID),Foo:testId1:idx(值Foo:fooIndexedField:testIndex1)和Foo:fooIndexedField:testIndex1(值testId1)仍然存在。

我已将redis配置交换到RedisStandaloneConfiguration(用于测试目的,是单个节点),并且散列过期时所有数据都消失了。

到目前为止,我设法在Spring文档中找到的唯一东西是:Define and pin keyspaces by using @RedisHash("{yourkeyspace}") to specific slots when you use Redis cluster.这是我无法做到的。有些散列需要散布在所有节点上,因为我无法假定它们可以放在一个节点上。

由于孤立索引,导致群集无法用尽内存的唯一原因是覆盖它们的设置maxmemory_policy:allkeys-lru。这令人不安,因为我一直在查看所有节点都在使用最大内存。

我的应用程序中是否缺少Spring Data Redis或Redis集群设置?


编辑: 使用Redisson redisson-spring-data-22版本3.13.5进行配置:

@Configuration
@EnableRedisRepositories(basePackages = "my.package.of.dtos",enableKeyspaceEvents = RediskeyvalueAdapter.EnableKeyspaceEvents.ON_STARTUP)
public class RedisConfiguration {
    @Bean
    public RedissonConnectionFactory redissonConnectionFactory() {
        Config config = new Config();
        config.useClusterServers().addNodeAddress("redis://127.0.0.1:7000","redis://127.0.0.1:7001","redis://127.0.0.1:7002","redis://127.0.0.1:7003","redis://127.0.0.1:7004","redis://127.0.0.1:7005");
        return new RedissonConnectionFactory(config);
    }


    @Bean
    public Redistemplate<String,Object> redistemplate(RedissonConnectionFactory redissonConnectionFactory) {
        Redistemplate<String,Object> template = new Redistemplate<>();
        template.setConnectionFactory(redissonConnectionFactory);
        return template;
    }
}

不幸的是,得到相同的结果。

解决方法

尝试使用 Redisson 库的更多功能以及缓存管理,调度...。

我在分布式任务事务中特别使用它。

此处是所有功能的列表:https://redisson.org/feature-comparison-redisson-vs-jedis.html

,

结果证明,Spring Data Redis不是我的理想选择。 我对Spring Data Redis的经验:

  • 使用它将从Redis到应用程序的部分数据过期过程进行授权
  • 仅当来自一个哈希的数据在同一群集节点上时有效
  • 在水平缩放应用程序时无法正常工作
  • 与实际数据大小相比,峰值内存使用量增加了一倍,因为它可以节省数据和幻像
  • 一级和二级索引可能会变得非常昂贵

在彻底阅读Redis文档之后,我解决了所有这些问题。事实证明,Redis开发人员对如何使用Redis有着非常清晰的愿景。偏离该路径会导致奇怪的问题。另一方面,坚持“正确的道路”意味着您将毫不费力地获得所有Redis的好处。

我做了什么:

  • 将Redis库更改为Jedis,并基于它实现了我自己的非常简单的客户端
  • 将保存的数据限制到最低限度
  • 所有已保存数据的手动控制的TTL
  • 使用{PART_OF_KEY}(例如,在多个键上用于exists的手动控制实体插槽,要求它们全部都在一个插槽上)

我得到的结果:

  • 将单个数据大小从〜60KB减少到〜60B,消除了所有索引编制,重复项等,这又使我暂时可以比以前多保存几个数量级的数据
  • 利用Redis优化的数据到期的优势,没有TTL不会保存任何数据,因此瞬时内存使用总是准确的
  • 由于仅在需要时才进行选择性分配,所以我仍然可以利用群集中的所有节点,但同时我也可以利用所有以性能为中心的Redis调用-我从不循环通过多个键进行redis调用因为所有这些都可以在一次调用中使用多个参数完成

免责声明:当我开始从事此工作时,我只知道有关Redis的流行语,但我没有意识到它的真正潜力,也不是开发人员设想的用法。乍一看似乎一切都与潮流相反,但是我对Redis提供的功能进行的代码调整越多,使用它的意愿就越大。我认为Spring Data Redis是快速原型制作的绝佳工具,但我觉得它类似于ORM的方法就像与Redis所提供的一切相违背。