如何安全的更新java本地缓存
程序员文章站
2022-04-21 13:32:06
...
对于某类数据,如果读的频率远远大于写的频率,数据不会经常被修改,则最适合采用本地缓存。但使用缓存,不可避免的就需要对缓存进行更新。
最近在做一个项目的时候,发现多个老系统里采用了一种不安全的更新方案,该方案的主要思路如下:
/** 本地缓存 */ private List<InterfaceConfig> configs = null; /** 本地缓存的上次更新时间 */ private long lastUpdateTime = 0; public List<InterfaceConfig> queryInterfaceList() { long currentTime = System.currentTimeMillis(); //判断本次缓存是否过期,过期则重新调用webservice查询数据,并更新缓存 if (currentTime - lastUpdateTime > 60000) { InterfaceManageResult result = interfaceManageFacade.queryAllInterfaceList(); if (null != result && result.isSuccess()) { configs = result.getInterfaceConfigList(); } lastUpdateTime = currentTime; } if (!CollectionUtils.isEmpty(configs)) { return configs; } //本地缓存为空,则重新调用webservice查询数据,并更新缓存 InterfaceManageResult result = interfaceManageFacade.queryAllInterfaceList(); if (null == result || !result.isSuccess()) { return null; } configs = result.getInterfaceConfigList(); return configs; }
当外部请求访问缓存数据时:
- 如果缓存已经过期(当前时间-缓存的上次更新时间超过缓存的有效期),则重新调用webservice访问服务端查询数据,然后更新缓存。
- 如果缓存未过期,但缓存为空,则重新调用webservice访问服务端查询数据,然后更新缓存。
仔细分析一下,该方案存在以下几处安全隐患:
- 如果某一时刻缓存过期,此时刚好有大量的请求并发访问缓存数据,则会给服务端造成很大的压力,有多少个并发请求,就会并发向服务端发起多少次webservice请求
- 缓存第一次初始化前,如果有大量的请求并发访问缓存数据,同样会给服务端早晨很大的压力。
改进后的方案:
- 系统启动时,调用webservice访问服务端查询数据,并初始化缓存
- 采用定时任务,定时触发缓存更新。
这样就将本地缓存的更新与外部请求的访问完全隔离了,外部请求不再直接触发对服务端的webservice请求,因为缓存的更新导致的服务端的峰值消除了。
其他可以优化的点:
目前服务端查询数据时,会查询DB中的所有数据,但实际上在大多数定时任务执行中,这些数据是没有发生任何变化的,即使有变化,也可能只有1%甚至更小比例的数据发生变化,缓存不需要对没有变化的数据进行更新,因此会造成一定的时间浪费。可以在缓存更新时,记录本次更新时间,然后下次更新时,只查询DB中最近修改时间在上次更新时间之后的数据,然后只对缓存中这部分数据进行更新,这样就会大大增加每次缓存更新完成的速度,也会降低对DB的压力。 既然现在只更新本地缓存中的部分数据,就需要考虑并发读写的问题,可以采用ConcurrentHashMap或者CopyOnWriteArrayList解决
本文为原创,转载请注明出处
下一篇: 过滤器与拦截器的区别
推荐阅读
-
微信小程序如何修改本地缓存key中单个数据的详解
-
教你如何突破IE安全限制获取iframe子框架内的本地cookie(图)
-
Mac上的Java7控制面板在哪里以及如何清除Java高速缓存?
-
如何通过简单的java代码读取本地磁盘目录下的所有文件或者文件夹?
-
浅谈Java如何实现一个基于LRU时间复杂度为O(1)的缓存
-
用java开发图形界面项目,如何实现从本地选择图片文件并以二进制流的形式保存到MySQL数据库,并重新现实到面板
-
Java本地缓存工具之LoadingCache的使用详解
-
Java 并发编程(四):如何保证对象的线程安全性
-
详解如何热更新线上的Java服务器代码
-
PHP如何保证通过接口执行的循环查询+本地数据更新这个过程正确完成?