com.alicp.jetcache.AbstractCache: jetcache(RedisLettuceCache) GET error. key=[XXX]
- Dominant language
- Java
- Stars
- 5.6k
- Forks
- 1.1k
- PR merge metrics
- No merged PRs in 30d
Description
## 环境:
- JDK 8 U331
- Spring Boot 2.7.2
- JetCache 2.6.7
- RedisClient :Lettuce
## 问题:
首先该问题在单体应用或者一个独立服务中,没有发现。
如果是用微服务,两个服务同时使用同一个 Redis。第一个服务没有任何问题,第二个服务中,如果缓存中使用了和第一个服务相同的Key的缓存,那么就会出现这个问题。
```
com.alicp.jetcache.AbstractCache: jetcache(RedisLettuceCache) GET error. key=[XXX]
```
## 额外说明:
这个问题在 JetCache 2.6.7 版本下存在。同样的环境,清空缓存,使用 2.6.6 就没有这个问题。
## 尝试解决:
进行了代码跟踪,尝试看看能不能解决这个问题。奈何能力和精力有限,未能解决。但是通过跟踪代码发现,主要问题出现在以下代码中:
> RedisLettuceCache
```
@Override
protected CacheGetResult do_GET(K key) {
try {
byte[] newKey = buildKey(key);
RedisFuture future = stringAsyncCommands.get(newKey);
CacheGetResult result = new CacheGetResult<>(future.handle((valueBytes, ex) -> {
if (ex != null) {
JetCacheExecutor.defaultExecutor().execute(() -> logError("GET", key, ex));
return new ResultData(ex);
} else {
try {
if (valueBytes != null) {
CacheValueHolder holder = (CacheValueHolder) valueDecoder.apply(valueBytes);
if (System.currentTimeMillis() >= holder.getExpireTime()) {
return new ResultData(CacheResultCode.EXPIRED, null, null);
} else {
return new ResultData(CacheResultCode.SUCCESS, null, holder);
}
} else {
return new ResultData(CacheResultCode.NOT_EXISTS, null, null);
}
} catch (Exception exception) {
logError("GET", key, ex);
return new ResultData(ex);
}
}
}));
setTimeout(result);
return result;
} catch (Exception ex) {
logError("GET", key, ex);
return new CacheGetResult(ex);
}
}
```
问题主要出在:**valueDecoder.apply(valueBytes)**。出问题时,valueBytes是负值,代码 AbstractValueDecoder 中,无法根据这个值转换后的identityNumber,找到对应的Decoder,导致反序列化失败。
DecoderMap 中是存有 `KryoValueDecoder` 和 `SpringJavaValueDecoder` 两个反序列化器的。不知道为什么生成的identityNumber 会变,导致找不到Decoder
```
@Override
public Object apply(byte[] buffer) {
try {
if (useIdentityNumber) {
DecoderMap.registerBuildInDecoder();
int identityNumber = parseHeader(buffer);
AbstractValueDecoder decoder = DecoderMap.getDecoder(identityNumber);
Objects.requireNonNull(decoder, "no decoder for identity number:" + identityNumber);
return decoder.doApply(buffer);
} else {
return doApply(buffer);
}
} catch (Exception e) {
throw new CacheEncodeException("decode error", e);
}
}
```
Contributor guide
No contributing guide indexed for this repository
Research direction
Start with RedisLettuceCache.do_GET and follow valueDecoder.apply(valueBytes) into AbstractValueDecoder and DecoderMap. Reproduce the shared-Redis, two-service case with JetCache 2.6.7 and compare it with 2.6.6, focusing on the identity number and decoder lookup. Done means the reported GET error no longer occurs and the decoder behavior is covered by a regression test.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- java, redis, spring-boot
- Domain
- backend, databases
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 38/100