【问题标题】:Spring Data Redis, Expiring and Redis ClusterSpring Data Redis、Expiring 和 Redis Cluster
【发布时间】:2020-10-07 13:43:51
【问题描述】:

我有一个应用正在使用

  • Spring Boot 2.2.6.RELEASE (spring-boot-starter-data-redis)
  • 绝地武士 3.1.0.

我有一个包含 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 分钟后自行过期,但附加集 ex @987654325 @(包含所有 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;
    }
}

不幸的是,给出了相同的结果。

【问题讨论】:

    标签: java redis spring-data-redis jedis


    【解决方案1】:

    事实证明 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 提供的所有东西背道而驰。

    【讨论】:

      【解决方案2】:

      尝试使用Redisson库更多的特性和缓存管理、调度......

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

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

      【讨论】:

      • 正如你所建议的,我使用了 redisson-spring-data-22 版本 3.13.5,创建了Config,使用useClusterServers() 设置,使用addNodeAddress("redis://127.0.0.1:7000",...) 添加了节点并创建了new RedissonConnectionFactory(config) bean。然后我用它来创建RedisTemplate bean。效果是一样的 - 在哈希过期后我仍然有相同的孤立密钥。
      猜你喜欢
      • 1970-01-01
      • 2016-05-30
      • 2021-09-13
      • 1970-01-01
      • 2020-11-07
      • 2016-03-18
      • 1970-01-01
      • 2022-10-05
      • 1970-01-01
      相关资源
      最近更新 更多