问答文章1 问答文章501 问答文章1001 问答文章1501 问答文章2001 问答文章2501 问答文章3001 问答文章3501 问答文章4001 问答文章4501 问答文章5001 问答文章5501 问答文章6001 问答文章6501 问答文章7001 问答文章7501 问答文章8001 问答文章8501 问答文章9001 问答文章9501

使用Copyonwrite改造本地缓存

发布网友 发布时间:2024-09-30 18:03

我来回答

1个回答

热心网友 时间:2024-10-23 05:39

背景

周四下午正在吃的下午茶,偷闲刷了一会手机(光明正大的),突然就有客服中心的小姐姐找上门来说xxx操作又出现失败了,但是多点几次又没问题了(之前也出现过,可是代码中没有任何异常处理和日志的输出很难排查,没办法老代码,前任写的我也没办法,只能加上等复现的时候再看看),看着小姐姐焦急的表情,下午茶瞬间就不香了,找bug去!

产生原因定位

在rancher上输入账号找到对应的服务,根据关键字找到相关日志映入眼帘的是java.lang.NullPointException跟随报错的行数找到了相关代码块:

if(StringUtils.isNotEmpty(feeSetting.getFileId())){returnschoolService.deal(sysConfigService.getString("url"));}

其中报错的是

schoolService.deal(sysConfigService.getString("url"));

定位问题,应该是调用StringgetString(Stringkey);空指针导致的.

分析

相关代码:

publicStringgetString(Stringkey){if(configs==null){initConfig();}returnconfigs.get(key);}

其中initConfig()的实现:

privatevoidinitConfig(){synchronized(lock){if((configs==null)||configs.isEmpty()){configs=newHashMap<String,String>();//从db中加载到configsloadSysConfig();}}}

其中configs是个成员变量

privatestaticMap<String,String>configs=null;复制代码

查了一下数据库,有对应的数据存在,不是数据的问题

getString(Stringkey)接口内部没报错,说明这个程序没报错

抓了抓头(有点意思),只有Map中没有相应的数据才有可能报空指针,查找了相关方法,找到了如下代码:

publicvoidreload(){if((configs!=null)&&!configs.isEmpty()){configs.clear();this.initConfig();}}

只有一处调用该方法

@ComponentpublicclassSysConfgMQListenerimplementsMessageListenerConcurrently{protectedfinalLoggerlog=LoggerFactory.getLogger(SysConfgMQListener.class);@AutowiredprivateISysConfigServicesysConfigService;@OverridepublicConsumeConcurrentlyStatusconsumeMessage(List<MessageExt>msgs,ConsumeConcurrentlyContextcontext){log.info("SysConfgMQListenerretrieving...");for(MessageExtmsg:msgs){log.info("messageExt,body:{}",newString(msg.getBody()));this.sysConfigService.reload();}returnConsumeConcurrentlyStatus.CONSUME_SUCCESS;}}

这是RocketMq的消费者这里调用了,而且还是广播模式,所有节点都能消费,这个Mq的生产者是在后台触发刷新时候产生的.

*只有一个

首先触发Mq的消费,导致Map刷新,重新加载调用reload()

当执行configs.clear();之后Map就是一个空对象,没有任何数据

如果这个时候是有多个线程访问getString(Stringkey)获取到的值就是null

改造

第一个想到的是用Redis来替换,但是很快就自我否定了,这个接口在没有触发刷新机制的前提下运行了几年是好好的,而且基础配置放Redis的话过期时间的设置不好判断,并且还要多个IO的传递,性能没有本地的Map好.

第二个想到的方案就是在getString(Stringkey)方法中加锁,这只能当做下下策

正在一筹莫展的时候,突然灵光一闪,这不是跟注册中心很像吗?各个客户端去拉取数据,而nacos为了高性能就是用了Copyonwrite的思想来实现的,越想越行,干!

代码改造如下:

publicvoidreload(){if((configs!=null)&&!configs.isEmpty()){//先清除再加载会出现,在两个操作之间请求的接口获取都为空//configs.clear();//this.initConfig();this.reloadForConfigs();}}

其中this.reloadForConfigs();

privatevoidreloadForConfigs(){Map<String,String>newConfigs=newHashMap<>();try{List<Config>datas=configDao.listConfigs();if(datas!=null){for(Configcf:datas){newConfigs.put(cf.getKey(),cf.getValue());}}}catch(Exceptione){LogUtil.exception(log,e);}if(CollectionUtil.isNotEmpty(newConfigs)){//替换旧的this.configs=newConfigs;}}

这改造完上线之后,跟踪了一段时间日志中也没发现空指针(小姐姐也不来找我了-_-,不开森),有那么一点点的成就感.

总结

开发的时候要考虑多线程和并发场景

遇到问题别慌,认真分析

好的方案不是一蹴而就的

多读好的代码如框架源码,不断的积累,现在用不上,某一时刻就用上了

作者:董懂
使用Copyonwrite改造本地缓存

代码改造如下:publicvoidreload(){if((configs!=null)&amp;&amp;!configs.isEmpty()){//先清除再加载会出现,在两个操作之间请求的接口获取都为空//configs.clear();//this.initConfig();this.reloadForConfigs();}}其中this.reloadForConfigs();privatevoidreloadForConfigs(){Map&lt;String,String&gt;newConfigs=...

Redis持久化—AOF/RDB详述(看完大厂offer到手)

出于效率考虑,Linux操作系统中使用COW(CopyOnWrite)写时复制机制,fork子进程一般情况下与父进程共同使用一段物理内存,只有在进程空间中的内存发生修改时,内存空间才会复制一份出来。 在Redis中,RDB持久化就是充分的利用了这项技术,Redis在持久化时调用glibc函数fork一个子进程,全权负责持久化工作,这样父进程仍然能继续...

Nacos 1.4.1源码解析之服务注册--AP

nacos server端的API服务主要由com.alibaba.nacos.naming.controllers.InstanceController入口控制。它采用缓存结构,第一层为namespace,第二层为group分组。在service中,clusterMap按照集群分组,集群内才是实例列表。在添加、修改实例或基于集群纬度修改实例时,使用copyOnWrite方式替换。流程图展示基本操作流程。

面试说两天给结果给我,那都没有机会为什么不说今天给结果给我?_百度知 ...

另一种方案就是在往主库写数据的时候,可以直接往内存缓存中写一份,设置一个较短的过期时间,后面可以直接从缓存中读到数据。我说完之后,面试官也没给出评价,就这么过去了。 此外,还问到一些基础性的问题,比较印象深刻的是:在加锁的时候,用什么锁对象是内存占用最小的,我说是 Object 对象,面试官说不对,我一...

为什么Redis要关闭THP?

通过启用 HugePages使用大页面,可以用一个页表条目代表一个大页面,而不是使用许多条目代表较小的页面,从而可以管理更多内存,减少操作系统对页面状态的维护并提高 TLB 缓存命中率。注意,Hugepagesize的大小默认为2M,这个也是可以调整的。区间范围为2MB to 256MB。标准大页管理是预分配的方式,而透明大...

学习JAVA都要掌握哪些东西

Hibernate基本开发流程; ORM简介; 模拟SQL语句的自动生成; hibernate的检索; 性能优化 一级缓存 二级缓存 查询缓存 事务与并发 悲观锁、乐观锁 3.6、Spring4.x 简单工厂模式 ;抽象工厂; 工厂方法模式; Spring3简介; Spring的基本开发流程; IOC、DI; Bean的配置; SSH框架的整合;Spring的注解开发; ...

使用Copyonwrite改造本地缓存

代码改造如下:publicvoidreload(){if((configs!=null)&amp;&amp;!configs.isEmpty()){//先清除再加载会出现,在两个操作之间请求的接口获取都为空//configs.clear();//this.initConfig();this.reloadForConfigs();}}其中this.reloadForConfigs();privatevoidreloadForConfigs(){Map&lt;String,String&gt;newConfigs=...

缓存的视频怎么保存到本地 uc缓存视频怎么存本地 使用 Ajax 缓存 如何把缓存视频转为本地视频 手机缓存变成本地视频 腾讯视频缓存变成本地 uc缓存视频转到本地 缓存怎么用 缓存有啥用
声明声明:本网页内容为用户发布,旨在传播知识,不代表本网认同其观点,若有侵权等问题请及时与本网联系,我们将在第一时间删除处理。E-MAIL:11247931@qq.com
领组词有哪些词语有 推荐点自己个人认为不错的 简洁点的手机铃声 还有短信音 重点是... 我这个配置能带动GTX760吗 请问我的电脑配置 是配GTX660还是GTX760 电源室安钛克 VP450P_百 ... 请问我这样的配置能带起GTX760不 我现在电脑想加显卡,目前看中GTX760,我这样的配置能配这显卡吗? 以下配置能上GTX760显卡吗 为什么四氧化三铁标不出化合价 ...下铅丹(用X表示)与硝酸能发生反应:X+4HNO3═PbO2+2 四氧化三铁(Fe 3 O 4 )中铁元素的化合价有+2和+3价,其化学式可改写为F... CopyOnWriteArrayList使用及原理介绍 好久没见到蓝天白云了文言文怎么说 本人每次用定型喷雾都会每个地方喷上两三次,然后快干了再喷一圈是不是... 天秤座很容易被有什么的人吸引? 天秤座的体质会吸引什么样的人? 晚上睡觉多梦是什么原因,应该怎样避免多呢_百度拇指医生 软件设计师考试考点突破程序设计实战练习一本通图书信息 股票分红当天买入有分红吗? 股票现金分红当天买入有分红吗? 为什么我的QQ密码经常修改但还是会别人在其他方登陆 马赛克是什么意思主持人杨澜个人资料简介马赛克是什么意思 存钱最重要!个人理财的9个小窍门 请问谁知道QQ密码一直被盗是怎么回事, 什么方式存钱才安全 语文版七年级上册第二课《我的第一次文学尝试》中 希金斯为什么“背着... 还那么爱你歌曲歌词 都说常吃枸杞好 枸杞对人都有什么好处 华为nova5如何取消健康使用时间限制 成人自考本科要满足什么条件才能报名? 塑料新的杯子怎么清除味道 塑料新的杯子清除味道的方法 手机QQ跟朋友聊天的时候 对方一发来一句话就有声音 这是怎么回事 而且... 脑白质稀疏怎么办 我在QQ上聊天的时候为什么消息来的时候没有声音 小心我真实你是什么梗 脑白质稀疏应该怎么补脑,饮食方面 66岁父亲,轻度脑白质稀疏,请问治疗和护理方法 中药芡实主治功能是什么? 深圳如何查询水电 设四阶方阵A的秩R(A)=3,则其伴随矩阵A*的秩为_. ...回事?我体检左眼5.0,右眼4.9,最后结果视力正常但屈光不正,我马上铁... 我眼睛视力右5.0左4.9这正常吗? 微信朋友圈之前屏蔽了一个重要的人,但是现在想让他看我发的朋友圈,前提... ...我左眼视力4.9,右眼5.0。是不是正常啊。我电脑玩的多。是不是和电... 小学生疫情最新有创意的宣传标语及口号 发朋友圈有些朋友不让看,现在让看了,怎么把他们一个人的分组删除,他们... 暖通设计费用多少一平方 建筑设计费中,建筑专业,结构,水电的设计费是按照多少钱一平方计算... ...相互学习。相互支持,共同进步玩的开心。我该怎么回答他呢?_百度知 ... 渣男和花心男有什么区别呢? 佳能打印机打出来的照片发蓝,怎么回事?