我有一个应用程序使用
spring boot 2.2.6.版本(spring boot starter data redis)
绝地武士3.1.0。
我有一个redis5.0.7集群,包含6个节点: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的expire特性。
在我注意到redis中的数据并没有像预期的那样过期之前,一切似乎都在工作。当我连接到redis群集时(使用 RedisClusterConfiguration
),一旦散列过期,与之相关的、由spring数据redis写入的其余数据将保留,幻象将在5分钟后自行过期,但额外的集合 Foo
(使用所有ID), Foo:testId1:idx
(价值 Foo:fooIndexedField:testIndex1
)以及 Foo:fooIndexedField:testIndex1
(1)仍然存在。
我把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 cluster设置中,有什么我遗漏的吗?
编辑:使用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;
}
}
不幸的是,他们给出了同样的结果。
2条答案
按热度按时间jgzswidk1#
尝试使用redisson库的更多功能和缓存管理,调度。。。。
我特别在分布式任务事务中使用它。
以下是所有功能的列表:https://redisson.org/feature-comparison-redisson-vs-jedis.html
tktrz96b2#
原来SpringDataRedis不是我要走的路。我使用spring data redis的经验:
将部分数据过期进程从redis委托给使用它的应用程序
仅当来自一个哈希的数据位于同一群集节点上时才有效
当应用程序水平缩放时,它不能正常工作
峰值内存使用量是实际数据大小的两倍,这是因为它节省了数据和内存
一级和二级索引可能会变得非常昂贵
在彻底阅读redis文档之后,我解决了所有这些问题。事实证明,redis开发人员对如何使用redis有着非常清晰的认识。任何偏离这条道路的行为都会导致奇怪的问题。另一方面,保持“正确的道路”意味着您将不费吹灰之力就获得所有redis的好处。
我所做的:
把redis库改成了jedis,实现了我自己的simle客户端
将保存的数据限制到最低限度
所有保存数据的手动控制ttl
使用手动控制实体开槽
{PART_OF_KEY}
(例如exists
在多个键上,要求所有键都在一个插槽上)我得到的结果是:
将单个数据大小从~60kb减少到~60b,消除了所有索引、重复项等,从而使我可以瞬间比以前多保存几个数量级的数据
利用redis优化的数据过期功能,没有ttl就不会保存任何数据,因此瞬时内存使用总是准确的
由于只有在需要时才进行选择性的时隙划分,我仍然可以利用集群中的所有节点,但同时我可以利用所有以性能为中心的redis调用-我从不在多个键上循环redis调用,因为所有这些调用都可以在具有多个参数的单个调用中完成
免责声明:当我开始研究这个时,我只知道redis的流行语,我没有意识到它的真正潜力,也没有意识到它的开发人员所设想的用途。一开始这一切似乎都是逆势而行,但我越是根据redis提供的特性调整代码,就越能感觉到对它的重新编写。我认为springdataredis是一个非常适合快速原型制作的工具,但我觉得它类似orm的方法与redis提供的任何东西都是背道而驰的。