【异常】com.alicp.jetcache.CacheException: refresh error

简介: 【异常】com.alicp.jetcache.CacheException: refresh error

一、背景描述

技术栈:Spring Boot(2.1.5.RELEASE) + Spring Cloud
Oopenfeign(2.1.1.RELEASE) + jetCache(2.5.14) + redis(3.1.0)

由于项目使用了微服务架构,各个服务职责不同,又相互引用,所以就经常在服务A中调用服务B的接口,我们使用的是Feign客户端,即 FeignClient。通过接口调用返回的数据,在服务A中先进行了缓存(使用了JetCache),减少对服务B的频繁调用,减轻服务B的压力。

由于 jetCache 可以使用两级缓存(本地缓存 + 远程缓存),所以在代码中便开启了两级缓存,本地缓存(内存中)数量限制为50个,远程缓存(redis)不限制数量。

使用两个注解就可以实现添加缓存和刷新缓存。分别是 @Cached 添加缓存,@CacheRefresh 刷新缓存,如果开启两级缓存,那么两级缓存都会刷新,如果只有一级缓存,那么只会缓存一级缓存。

缓存时间为30分钟,每60秒对缓存进行刷新一次。于是代码如下:

package com.iot.back.message.process.rpc;
import com.alicp.jetcache.anno.CacheRefresh;
import com.alicp.jetcache.anno.CacheType;
import com.alicp.jetcache.anno.Cached;
import com.iot.basic.iotsmarthome.api.client.floor.FloorClient;
import com.iot.framework.core.response.CommResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.util.concurrent.TimeUnit;
/**
 * <p>FloorClientRpc 此类用于:调用基础家居服务楼层相关接口 </p>
 * <p>@author:hujm</p>
 * <p>@date:2022年07月20日 14:18</p>
 * <p>@remark:</p>
 */
@Slf4j
@Component
public class FloorClientRpc {
    @Resource
    FloorClient floorClient;
    @Cached(name = "back-process-service:jetCache:singleFloor:", expire = 30, timeUnit = TimeUnit.MINUTES, cacheType = CacheType.BOTH, localLimit = 50)
    @CacheRefresh(refresh = 60)
    public Boolean singleFloor(String sn) {
        CommResponse<Boolean> commResponse = floorClient.singleFloor(sn);
        if (commResponse == null || commResponse.isFail()) {
            log.error("P0|FloorClientRpc|singleFloor|调用基础家居服务时,根据【sn = {}】获取当前家庭是否为单楼层失败!", sn);
            return null;
        }
        return commResponse.getData();
    }
}

出现的现象是在本机的电脑上(Windows 10)跑代码,刷新缓存正常,也不报错。部署到服务器上(Linux )就会报刷新缓存错误的问题。

二、报错内容

[2022-11-22 16:38:59 ERROR com.alicp.jetcache.RefreshCache.run(RefreshCache.java:257) JetCacheHeavyIOExecutor5   :] refresh error: key=[Ljava.lang.Object;@1f4c18af
com.alicp.jetcache.CacheException: refresh error
  at com.alicp.jetcache.RefreshCache$RefreshTask.lambda$externalLoad$0(RefreshCache.java:207)
  at com.alicp.jetcache.Cache.tryLockAndRun(Cache.java:272)
  at com.alicp.jetcache.RefreshCache$RefreshTask.externalLoad(RefreshCache.java:212)
  at com.alicp.jetcache.RefreshCache$RefreshTask.run(RefreshCache.java:252)
  at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
  at java.util.concurrent.FutureTask.runAndReset(FutureTask.java:308)
  at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$301(ScheduledThreadPoolExecutor.java:180)
  at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:294)
  at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
  at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
  at java.lang.Thread.run(Thread.java:748)
Caused by: java.lang.NullPointerException: null
• 1
• 2
• 3
• 4
• 5
• 6
• 7
• 8
• 9
• 10
• 11
• 12
• 13
• 14

三、报错原因

根据报错内容,查看源码后得知是 key 为空,发生了空指针异常。源码如下图所示:

这一行代码唯一可能为空的就是 lockKey,只有这里可能会发生空指针

使用 jetCache 之后,就开启了两级缓存(本地缓存 + 远程缓存)即在 @Cached 注解上添加了 cacheType = CacheType.BOTH 这个属性。开启了两级缓存,那么使用 @CacheRefresh 注解,会使两级缓存都进行刷新。

在Windows电脑上使用的是管理员用户,可以向本地缓存中写数据,所以在本机上运行代码不会报错,而程序部署到服务器上,由于不是超管账户所以没有向本地缓存中写入数据的权限,导致服务器上的本地缓存没有数据。而使用 refreshCache 注解之后,它是根据缓存数据中的 key 来刷新缓存的,由于服务器本地电脑并没有成功保存数据,而导致没有查到这个 key ,所以会才报 keyNPE(NullPointerException)

四、解决方案

知道了上述原因之后,对应的就会出现两种解决方案,第一种就是把本地缓存关了,只使用远程缓存;第二种就是把服务器上的写入本地缓存的权限放开。

4.1 解决方案一,使用一级缓存

@Cached 注解上修改 cacheType = CacheType.BOTHcacheType = CacheType.REMOTE,并把 localLimit 属性删除,仅使用远程缓存,不使用本地缓存,修改过后再把代码部署到服务器上之后,刷新缓存时不再报错。已经验证可以使用。

4.2 解决方案二,开启写入权限

让运维工程师把写入本地缓存的权限放开。这个由于没有验证,只是理论上可行。有条件的可以验证一下。

完结!


相关文章
|
缓存 NoSQL Java
【JetCache】JetCache的使用方法与步骤
【JetCache】JetCache的使用方法与步骤
6629 0
|
缓存 Java Spring
【异常】com.alicp.jetcache.support.CacheEncodeException: Java Encode error.
【异常】com.alicp.jetcache.support.CacheEncodeException: Java Encode error.
285 0
|
缓存 NoSQL Java
SpringBoot实用开发篇第五章(整合第三方技术,jetcache,j2cache,Task)
SpringBoot实用开发篇第五章(整合第三方技术,jetcache,j2cache,Task)
|
11月前
|
负载均衡 算法 Java
微服务面试篇
微服务面试篇
356 2
|
消息中间件 JSON Java
Spring Boot、Spring Cloud与Spring Cloud Alibaba版本对应关系
Spring Boot、Spring Cloud与Spring Cloud Alibaba版本对应关系
22769 0
|
缓存 NoSQL Java
SpringBoot的三种缓存技术(Spring Cache、Layering Cache 框架、Alibaba JetCache 框架)
Spring Cache 是 Spring 提供的简易缓存方案,支持本地与 Redis 缓存。通过添加 `spring-boot-starter-data-redis` 和 `spring-boot-starter-cache` 依赖,并使用 `@EnableCaching` 开启缓存功能。JetCache 由阿里开源,功能更丰富,支持多级缓存和异步 API,通过引入 `jetcache-starter-redis` 依赖并配置 YAML 文件启用。Layering Cache 则提供分层缓存机制,需引入 `layering-cache-starter` 依赖并使用特定注解实现缓存逻辑。
2461 1
SpringBoot的三种缓存技术(Spring Cache、Layering Cache 框架、Alibaba JetCache 框架)
|
12月前
|
Java Spring
springboot 集成 swagger 2.x 和 3.0 以及 Failed to start bean ‘documentationPluginsBootstrapper‘问题的解决
本文介绍了如何在Spring Boot项目中集成Swagger 2.x和3.0版本,并提供了解决Swagger在Spring Boot中启动失败问题“Failed to start bean ‘documentationPluginsBootstrapper’; nested exception is java.lang.NullPointerEx”的方法,包括配置yml文件和Spring Boot版本的降级。
springboot 集成 swagger 2.x 和 3.0 以及 Failed to start bean ‘documentationPluginsBootstrapper‘问题的解决
|
Java 数据库连接 测试技术
SpringBoot 3.3.2 + ShardingSphere 5.5 + Mybatis-plus:轻松搞定数据加解密,支持字段级!
【8月更文挑战第30天】在数据驱动的时代,数据的安全性显得尤为重要。特别是在涉及用户隐私或敏感信息的应用中,如何确保数据在存储和传输过程中的安全性成为了开发者必须面对的问题。今天,我们将围绕SpringBoot 3.3.2、ShardingSphere 5.5以及Mybatis-plus的组合,探讨如何轻松实现数据的字段级加解密,为数据安全保驾护航。
894 1
|
缓存 监控 NoSQL
SpringBoot配置第三方专业缓存技术jetcache方法缓存方案
SpringBoot配置第三方专业缓存技术jetcache方法缓存方案
774 1
|
存储 消息中间件 JSON
DDD基础教程:一文带你读懂DDD分层架构
DDD基础教程:一文带你读懂DDD分层架构