Spring数据Redis、过期和Redis集群

Spring Data Redis, Expiring and Redis Cluster

我有一个应用使用

我有一个由 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 写入的其余数据仍然存在,幻影在 5 分钟后自行过期,但额外的集合 ex 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 version 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 有着非常清晰的认识。任何偏离该路径的行为都会导致奇怪的问题。另一方面,保持 'the right path' 意味着您将毫不费力地获得所有 Redis 优势。

我做了什么:

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

我得到的结果:

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

免责声明:当我开始从事这项工作时,我只知道有关 Redis 的流行语,我没有意识到它的真正潜力,也没有意识到它是开发人员设想的用途。起初这一切似乎都在逆潮流而动,但我越是根据 Redis 提供的功能调整我的代码,就越能感受到使用它的乐趣。我认为 Spring Data Redis 是一个非常棒的快速原型制作工具,但我觉得它的类似 ORM 的方法就像与 Redis 提供的所有东西背道而驰。