`
海浪儿
  • 浏览: 274322 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论
阅读更多

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

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

/** 本地缓存  */
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解决

 

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

分享到:
评论

相关推荐

    Java本地缓存的实现代码

    Java本地缓存的实现代码是指在Java应用中,使用本地缓存来提高访问频率高、更新少的数据的读取效率。在集群环境下,分布式缓存如Redis、Memcached等都是常用的选择,但是在单机环境下,本地缓存(LocalCache)则是...

    实现 Java 本地缓存的方法解析

    实现 Java 本地缓存的方法解析 本文主要介绍了实现 Java 本地缓存的方法解析,通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值。缓存肯定是项目中必不可少的,市面上有非常多的缓存工具,...

    JAVA的缓存应用介绍

    随着应用复杂性的增加,开发者可能会转向使用专业的缓存框架,如 Ehcache、Guava Cache 或 Redis,这些框架提供更高级的功能,如缓存失效策略、线程安全、分布式缓存支持等。 内存溢出问题常常出现在堆内存或方法区...

    Java缓存技术的使用实例

    在Java中,我们通常使用两种类型的缓存:本地缓存(如Java集合框架中的HashMap)和分布式缓存(如Redis、Hazelcast或 Ehcache)。 本地缓存通常适用于小型应用或内存允许的情况,而分布式缓存在多服务器环境下更...

    Java缓存技术深入了解

    - ** caffeine**: 是一个高性能的本地缓存库,设计灵感来源于Guava Cache,但提供了更优化的性能和配置选项。 3. **缓存策略** - LRU(Least Recently Used):最近最少使用的淘汰策略,当缓存满时,删除最近最少...

    DiskLruCache磁盘缓存java源码

    《DiskLruCache:Java实现的磁盘缓存解析》 在移动开发,尤其是Android应用开发中,数据缓存是优化用户体验的关键技术之一。DiskLruCache是一款基于磁盘的缓存库,由Jake Wharton编写,用于存储关键数据到本地文件...

    java 数据缓存

    Guava Cache提供了线程安全的本地缓存实现,支持自定义加载函数、过期时间、大小限制等特性。源码中,你可以看到它使用了Striped64来实现并发控制,以及WeakReference和SoftReference来管理内存占用。Guava Cache的...

    java中的缓存.pdf

    总结起来,文档深入探讨了Java中缓存技术的多个方面,包括Hibernate框架中的缓存使用、不同缓存策略的实现、本地缓存与分布式缓存的区别和配置、以及Java缓存技术在企业应用中的实际应用。这些知识对于Java开发者来...

    java中的缓存技术

    3. Ehcache:Ehcache是另一个流行的Java缓存解决方案,它既可以作为本地缓存使用,也可以作为分布式缓存。Ehcache支持磁盘存储、缓存分区、缓存预热等功能,并且与Spring框架集成良好。 4. caffeine:Caffeine是一...

    Glide如何访问已经下载到本地的缓存文件(图片地址若过期自己选别的)

    在标题和描述中提到的问题,涉及到对Glide的缓存机制进行自定义,特别是如何通过图片URL的MD5值来查找本地缓存。 首先,Glide默认使用SHA-256作为其磁盘缓存的key生成器,这确保了每个URL对应一个唯一的缓存文件名...

    Android ASimpleCache缓存本地数据

    ASimpleCache是Google的GmsCore项目中提取出来的一个轻量级、易用的本地缓存库,适用于存储小量的数据,如JSON字符串或图片的二进制数据。本文将详细介绍ASimpleCache的工作原理、使用方法以及如何在实际项目中实现...

    Java缓存Map设置过期时间实现解析

    LoadingCache是一个线程安全的本地缓存解决方案,提供缓存回收机制,监控缓存加载/命中情况,灵活强大的功能,简单易上手的API。 4. ExpiryMap实现原理: ExpiryMap是继承至HashMap,重写了所有对外的方法,对每个...

    Java的缓存系统的设计.pdf

    3. **缓存同步**:在多线程环境下,确保缓存的更新和读取是线程安全的,可以使用synchronized关键字或java.util.concurrent包下的并发工具。 4. **缓存失效**:设定缓存项的有效期,过期后自动从缓存中移除,或者...

    java缓存技术深入剖析

    1. **本地缓存**:如Java的`WeakHashMap`、`SoftReference`等,通常用于单个JVM内部,适用于小规模的数据存储。 2. **分布式缓存**:如Hazelcast、Infinispan、Ehcache和广为人知的Apache Ignite,适用于多节点环境...

    Java LocalCache 本地缓存的实现实例

    Java LocalCache 本地缓存的实现实例主要应用于Java应用中,对于访问频率高,更新少的数据,通常的方案是将这类数据加入缓存中。相对从数据库中读取来说,读缓存效率会有很大提升。在集群环境下,常用的分布式缓存有...

    java源码:java缓存工具 SimpleCache.zip

    SimpleCache是一个简洁而实用的Java缓存工具,它可以帮助开发者快速实现本地缓存功能。这个压缩包文件“SimpleCache.zip”包含了一个名为“yishh-cache-09860a6”的源码文件,我们可以从中学习到关于Java缓存的基本...

    基于 Java 开发的在线学习平台。采用分布式系统架构和 redis 本地缓存机制.zip

    但需要注意的是,本地缓存可能导致数据一致性问题,因此需要妥善设计缓存更新策略。 5. **微服务架构**:在大型项目中,通常采用微服务架构将复杂的应用程序拆分为一组小型、独立的服务,每个服务都可以独立部署和...

    基于Java的源码-Ehcache Java 缓存框架.zip

    4. **多级缓存**:Ehcache支持多级缓存结构,即本地内存、本地磁盘和远程分布式缓存,这样可以提供不同级别的性能和容错能力。 5. **缓存预热**:系统启动时,可以通过预加载关键数据到缓存中,以减少启动时间和...

    Java实现一个简单的缓存方法

    但是,仅仅使用`ConcurrentHashMap`还不足以确保所有的缓存操作都是线程安全的,因为一些操作如检查过期、更新等可能需要额外的同步机制。这是`CacheManagerImpl`的一个基本实现: ```java public class ...

    Android-一个Android和Java的reactive缓存库

    综上所述,"Android-一个Android和Java的reactive缓存库"是一个利用反应式编程设计的高效缓存解决方案,它简化了Android和Java应用的本地缓存管理,提高了数据获取的效率和用户体验。对于需要优化网络请求和提升应用...

Global site tag (gtag.js) - Google Analytics