前言
我们最近将会话管理从 MongoDB 迁移到了 Redis。迁移本身是由我们使用 MongoDB 的经验推动的,它不能特别好地处理高频率更新和更频繁的读取。另一方面,Redis 被称为经过验证的存储,可以准确处理该用例。
数据库迁移并不总是那么容易,因为我们需要学习其他服务的新模式、最佳实践和怪癖。我们的目标是让我们的 Java 服务层尽可能简单,使其稳定且面向未来:会话管理当然是具有相当稳定功能集的服务之一,并且不会经常触及其代码。因此,对于几年后窥探它的任何人来说,保持它的简单易懂是一个重要方面。
我们面临两个问题:
Spring Data 实现二级索引的概念以及失效问题,这些导致Redis内存使用量不断增长。
Redis 的原子性范围和 Spring Data 的更新机制
本文总结了我们在使用 Spring Data 作为持久层的瘦 Java 服务中采用 Redis 的经验。
带有二级索引和 EXPIRE/TTL 的 Spring Data Redis
在 Redis 中采用 Spring Data可直接开始:您需要的只是 Gradle 或 Maven 构建的依赖项以及@EnableRedisRepositoriesSpring Boot 应用程序中的注释。Spring Boot 的大多数默认设置都是有意义的,并且可以让您非常顺利地运行 Redis 实例。
但是会遭遇:Redis内存使用量不断增长的问题,下面看看这个认识过程:
不需要通用存储库的实际实现,因为 Spring Data 允许您interface在运行时声明一个简单的通向通用实例。我们的存储库是这样开始的:
<span style="color:#333333"><span style="background-color:#f5f5f5"><strong>import</strong> org.springframework.data.repository.CrudRepository;
<strong>import</strong> org.springframework.stereotype.Repository;
@Repository
<strong>public</strong> <strong>interface</strong> SessionDataCrudRepository <strong>extends</strong> CrudRepository<SessionData, String> {
}
</span></span>
我们由该存储库管理的实体也开始变得尽可能简单:
<span style="color:#333333"><span style="background-color:#f5f5f5"><strong>import</strong> org.springframework.data.annotation.Id;
<strong>import</strong> org.springframework.data.redis.core.RedisHash;
<strong>import</strong> org.springframework.data.redis.core.TimeToLive;
<strong>import</strong> java.util.concurrent.TimeUnit;
@RedisHash(<span style="color:#00bb00">"SessionData"</span><span style="color:black">)
<strong>public</strong> <strong>class</strong> SessionData {
@Id
<strong>private</strong> String sessionId;
@TimeToLive(unit = TimeUnit.MINUTES)
<strong>private</strong> Long ttl;
...
}
</span&