数据库
首页 > 数据库> > Redis竞争锁失败异步获取兜底优化

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