Redis竞争锁失败异步获取兜底优化
作者:互联网
优化前
//返回对象
Object result = null;
//分布式锁
String cacheLock = CacheUtil.genLockKey(cacheKey);
if (lock.lock(cacheLock, 5000, TimeUnit.MILLISECONDS)) {
try {
//业务方法查询逻辑
result = pjp.proceed();
if (Objects.nonNull(result)) {
rwxCache.set(cacheKey, JSON.toJSONString(result), 1, TimeUnit.HOURS);
}
} catch (Exception e) {
e.printStackTrace();
rwxCache.del(cacheKey);
} finally {
lock.unlock(cacheLock);
}
} else {
Future<String> future = taskExecutor.submit(() -> rwxCache.get(cacheKey));
try {
cache = future.get(500, TimeUnit.MILLISECONDS);
result = JSON.parseObject(cache, getReturnType(pjp));
} catch (Exception e) {
//important! 这里会有问题,一旦future超时,返回的是Object result = null;则没有信息返回,而此时是有可能有值的,应该抛出异常,而不是给一个不确定的结果
e.printStackTrace();
rwxCache.del(cacheKey);
}
}
return result;
优化后
//返回对象
Object result = null;
//防止缓存穿透
// rwxCache.set(cacheKey, CacheUtil.EMPTY, 1, TimeUnit.HOURS);
//分布式锁
String cacheLock = CacheUtil.genLockKey(cacheKey);
if (lock.lock(cacheLock, 5000, TimeUnit.MILLISECONDS)) {
LOGGER.debug("[CacheFilterAspect] cache lock get. key={}", cacheKey);
try {
//业务方法查询逻辑
result = pjp.proceed();
if (Objects.nonNull(result)) {
rwxCache.set(cacheKey, JSON.toJSONString(result), 1, TimeUnit.HOURS);
}
} catch (Exception e) {
e.printStackTrace();
rwxCache.del(cacheKey);
} finally {
lock.unlock(cacheLock);
}
} else {
LOGGER.info("[CacheFilterAspect] cache async get. key={}", cacheKey);
Future<String> future = taskExecutor.submit(() -> {
//如果分布式锁一直lock状态就进行自旋轮询,每隔Thread.sleep(10)毫秒轮询一次结果,future.get(500, TimeUnit.MILLISECONDS)除以Thread.sleep(100)就是轮询次数,超时则抛出异常
while (true) {
if (!lock.isLocked(cacheLock)) {
return rwxCache.get(cacheKey);
} else {
try {
//这里会影响tp999等SLA指标,比如时间间隔太短设置5ms,cpu空转锁没释放请求redis过于频繁造成浪费;设置时间间隔太长则tp999飙高,而且锁释放了还没发起请求,这里根据tp999情况适当设置即可
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
LOGGER.error("[CacheRemoveAspect] interval wait error.", e);
//发生异常,则抛出异常,不返回明确结果
throw e;
}
}
}
});
try {
//这里是极端情况下max的值
cache = future.get(500, TimeUnit.MILLISECONDS);
result = JSON.parseObject(cache, getReturnType(pjp));
} catch (Exception e) {
e.printStackTrace();
LOGGER.error("[CacheFilterAspect] cache async get timeout failed.");
//发生异常,则抛出异常,不返回明确结果
throw e;
}
}
return result;
标签:异步,兜底,rwxCache,get,lock,Redis,cacheKey,result,TimeUnit 来源: https://blog.csdn.net/u013161278/article/details/112195599