问题描述
- Spring Boot 2.2.6.RELEASE(spring-boot-starter-data-redis)
- Jedis 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分钟后过期,但是会有额外的集合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所提供的一切相违背。