如何安全的更新java本地缓存

对于某类数据,如果读的频率远远大于写的频率,数据不会经常被修改,则最适合采用本地缓存。但使用缓存,不可避免的就需要对缓存进行更新。

最近在做一个项目的时候,发现多个老系统里采用了一种不安全的更新方案,该方案的主要思路如下:

/** 本地缓存  */
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;
    }

  当外部请求访问缓存数据时:

  1. 如果缓存已经过期(当前时间-缓存的上次更新时间超过缓存的有效期),则重新调用webservice访问服务端查询数据,然后更新缓存。
  2. 如果缓存未过期,但缓存为空,则重新调用webservice访问服务端查询数据,然后更新缓存。

仔细分析一下,该方案存在以下几处安全隐患:

  1. 如果某一时刻缓存过期,此时刚好有大量的请求并发访问缓存数据,则会给服务端造成很大的压力,有多少个并发请求,就会并发向服务端发起多少次webservice请求
  2. 缓存第一次初始化前,如果有大量的请求并发访问缓存数据,同样会给服务端早晨很大的压力。
       即在某些时间点,会给服务端带来峰值抖动,其实,造成该隐患的根本原因在于:缓存的更新时机是由外部请求直接触发的。因此,消除该隐患就应该从这个点入手,改变缓存更新的触发点,消除服务端的峰值。        改进后的方案:
  1. 系统启动时,调用webservice访问服务端查询数据,并初始化缓存
  2. 采用定时任务,定时触发缓存更新。

       这样就将本地缓存的更新与外部请求的访问完全隔离了,外部请求不再直接触发对服务端的webservice请求,因为缓存的更新导致的服务端的峰值消除了。

 

       其他可以优化的点:

       目前服务端查询数据时,会查询DB中的所有数据,但实际上在大多数定时任务执行中,这些数据是没有发生任何变化的,即使有变化,也可能只有1%甚至更小比例的数据发生变化,缓存不需要对没有变化的数据进行更新,因此会造成一定的时间浪费。可以在缓存更新时,记录本次更新时间,然后下次更新时,只查询DB中最近修改时间在上次更新时间之后的数据,然后只对缓存中这部分数据进行更新,这样就会大大增加每次缓存更新完成的速度,也会降低对DB的压力。 既然现在只更新本地缓存中的部分数据,就需要考虑并发读写的问题,可以采用ConcurrentHashMap或者CopyOnWriteArrayList解决

 

本文为原创,转载请注明出处

猜你喜欢

转载自xw-z1985.iteye.com/blog/1853109
今日推荐