web应用程序的缓存不足

    技术2024-03-21  92

    许多Web应用程序正在从桌面应用程序重写。 理想情况下,它们应与台式机版本一样快且可扩展。 几乎所有的Web应用程序都可以从速度的大幅提高中受益。 缓存不经常更改的经常查看的数据是减少用户等待时间的有效方法。 使用简单的非介入式API轻松处理数据缓存的实用程序可以帮助您实现此目标。 开源JCS(Apache Jakarta项目)就是这样一种工具。 本文介绍了如何配置和使用JCS为Web应用程序缓存数据。

    JCS概述

    JCS是用Java语言编写的缓存系统,可用于创建Java桌面和Web应用程序。 它提供了方便的机制来将数据存储在缓存中,从缓存中获取数据,从缓存中删除数据等等。

    使用JCS,可以将缓存的数据存储在指定的不同数据区域中。 JCS定义了四种类型的核心区域:内存,磁盘,横向和远程。 您可以将核心区域一起使用,以在存储缓存数据的方式和位置上获得极大的灵活性。 您可以指定首先使用哪个区域以及何时故障转移到另一个区域。

    记忆区

    内存区域是使用最近最少使用(LRU)算法的纯内存缓存区域。 当内存缓存区已满时,LRU首先删除最近最少使用的缓存数据。 该数据区域的性能很好,大多数JCS用户将其指定为默认使用的默认缓存区域。

    JCS的可插拔控制器

    JCS通过其Composite Cache使使用多个区域进行缓存存储变得简单。 复合缓存提供了用于缓存区域的可插拔控制器。 复合缓存负责确定何时以及如何使用每个缓存区域的艰巨任务。 作为开发人员,您只需要担心获取和设置缓存。 JCS完成了大部分艰苦的工作。

    磁盘区域

    磁盘区域是Web服务器文件磁盘上用于缓存数据的区域。 为了提高性能,JCS将缓存的数据密钥存储在内存中,同时将实际的缓存数据存储在文件磁盘上。 在首先使用内存区域的典型JCS配置中,然后将无法保存在内存区域中的所有数据写入磁盘区域。

    横向区域

    横向缓存区域提供了一种可配置的方式,可以在多个服务器之间分配缓存的数据。 缓存的数据服务器必须打开一个端口以进行侦听,并且必须创建套接字连接。 该区域确实面临潜在的问题,因为该区域不能保证高速缓存之间的数据一致性。 但是,如果按设计使用该区域,则此问题不太可能发生。

    偏远地区

    远程区域使用远程方法调用(RMI)API提供缓存区域。 该区域使用处理缓存数据的远程服务器。 多个JCS客户端应用程序可以使用远程缓存的服务器来存储缓存的数据。 定义了侦听器以收集来自客户端和服务器的请求。 该缓存区域有助于减轻序列化和多个连接点的开销。

    JCS配置

    配置JCS就像创建和填充cache.ccf文件一样简单。 该文件定义了缓存应使用的区域以及这些区域的属性或选项。 根据应用程序的需求量身定制文件是一种快速扩展缓存的便捷方法。 为了显示主要配置点,我使以下示例尽可能简单。 您可以指定许多选项和属性,以使配置完全符合您的需求。

    清单1显示了最基本的cache.ccf文件-纯内存缓存配置:

    清单1. JCS的基本配置
    jcs.default=jcs.default.cacheattributes=org.apache.jcs.engine.CompositeCacheAttributes jcs.default.cacheattributes.MaxObjects=1000 jcs.default.cacheattributes.MemoryCacheName= org.apache.jcs.engine.memory.lru.LRUMemoryCache

    从清单1的最后一行可以看到,配置文件将内存缓存指定为LRUMemoryCache 。 您还可以看到保存在内存中的最大对象数设置为1000 。

    与清单1中的大多数应用程序相比,大多数应用程序的缓存系统配置更为全面。在清单2的配置中,我在定义自己的区域( OUR_REGION )的同时使用了一个内存区域和一个磁盘区域:

    清单2.在JCS的配置中定义的区域
    jcs.default=DISK_REGION jcs.default.cacheattributes=org.apache.jcs.engine.CompositeCacheAttributes jcs.default.cacheattributes.MaxObjects=1000 jcs.default.cacheattributes.MemoryCacheName= org.apache.jcs.engine.memory.lru.LRUMemoryCache jcs.region.OUR_REGION=DISK_REGION jcs.region.OUR_REGION.cacheattributes=org.apache.jcs.engine.CompositeCacheAttributes jcs.region.OUR_REGION.cacheattributes.MaxObjects=1000 jcs.region.OUR_REGION.cacheattributes.MemoryCacheName= org.apache.jcs.engine.memory.lru.LRUMemoryCache jcs.region.OUR_REGION.cacheattributes.UseMemoryShrinker=true jcs.region.OUR_REGION.cacheattributes.MaxMemoryIdleTimeSeconds=3600 jcs.region.OUR_REGION.cacheattributes.ShrinkerIntervalSeconds=60 jcs.region.OUR_REGION.cacheattributes.MaxSpoolPerRun=500 jcs.region.OUR_REGION.elementattributes=org.apache.jcs.engine.ElementAttributes jcs.region.OUR_REGION.elementattributes.IsEternal=false jcs.auxiliary.DISK_REGION=org.apache.jcs.auxiliary.disk.indexed.IndexedDiskCacheFactory jcs.auxiliary.DISK_REGION.attributes= org.apache.jcs.auxiliary.disk.indexed.IndexedDiskCacheAttributes jcs.auxiliary.DISK_REGION.attributes.DiskPath=c:/jcs/disk_region jcs.auxiliary.DISK_REGION.attributes.maxKeySize=100000
    JCS助剂

    除了四个核心高速缓存实现之外,JCS还提供了auxiliaries ,它们是区域可以使用的可选插件。 辅助包括索引磁盘缓存,TCP横向缓存和远程缓存服务器。 例如,磁盘缓存可让您在达到内存阈值时将项目交换到磁盘上。 这使每个区域都可以在更灵活的级别上控制其缓存,与大多数操作系统使用的虚拟内存方法大致相似。 cache.ccf配置文件使您可以根据应用程序的需求来定制每个辅助区域。

    清单2中的第一行显示该配置将默认区域设置为DISK_REGION 。 DISK_REGION的类型为IndexedDiskCacheFactory ,并且在磁盘上将文件指定为c:\ jcs \ disk_region。 清单2中的第二个配置组定义了我自己的区域,为此我添加了一些选项。 这种类型的配置(一种在指定用户定义的区域的同时使用内存区域和磁盘区域的配置)是一种常见的配置。 清单2中的第三个配置组定义了一个辅助区域 。

    JCS有两个依赖项: concurrent和commons-logging 。 (在JCS 1.2.7.0之前,还有两个附加的依赖项: commons-collections和commons-lang 。)

    JCS的基本用法

    学习JCS基础知识的一种好方法是查看API最常用的方法。 最好的起点是缓存区域本身的初始化。 初始化JCS缓存区域对象使您可以访问所需的几乎所有常用方法。 清单3初始化JCS对象并获取默认缓存区域的实例:

    清单3.检索默认的缓存区域
    // Initialize the JCS object and get an instance of the default cache region JCS cache = JCS.getInstance("default");

    检索JCS实例后,可以调用最需要的方法。 put方法将一个新对象放入缓存。 所需要的只是一个key (第一个参数)和一个value (第二个参数)。 清单4显示了一个基本示例:

    清单4.设置一个缓存的项目
    // Set up String key = "key0"; String value = "value0"; // Place a new object in the cache cache.put(key, value);

    清单4中的示例使用字符串值作为参数,但是您可以使用任何对象。

    检索缓存的对象就像使用JCS提供的get方法一样简单。 清单5显示了一个简单的示例。 同样,该示例使用字符串参数,但是您可以使用任何对象。

    清单5.检索缓存的项目
    // Retrieve a cached object String cachedData = (String)cache.get(key);

    测试缓存数据的有效性是在处理缓存系统时可能需要的另一种方法。 在JCS中,没有定义测试缓存方法来简单地测试缓存项的存在。 相反, get方法的返回值可以提供帮助。 清单6显示了一种实现此必要功能的方法:

    清单6.测试缓存项的有效性
    // Retrieve a cached object String cachedData = (String)cache.get(key); // Check if the retrieval worked if (cachedData != null) { // The cachedData is valid and can be used System.out.println("Valid cached Data: " + cachedData); }

    您可能需要的最后一个更常见的缓存实用程序是在使用完它们后清理JCS,缓存的项目和缓存区域。 JCS提供了一种clear方法,用于从与之一起调用的缓存区域中删除所有缓存的数据,以及一种用于删除特定缓存项的remove方法。 还可以使用dispose方法来处理已初始化的JCS区域。 清单7显示了如何使用这些方法:

    清单7.清理缓存区域
    // Dispose of a specific cached item cache.remove(key); // Dispose of all cache data cache.clear(); // Dispose of the cache region cache.dispose();

    JCS和Java对象

    与其他缓存系统相比,JCS的优点之一(请参阅参考资料 )是它与对象配合良好。 用Java技术创建的大多数Web应用程序都使用面向对象的方法。 例如,对象的缓存可以帮助您的应用程序更好地执行,这要比它不断从数据库中逐段检索对象的情况要好。

    围绕JCS设计一个简单的面向对象的站点的第一步是从您需要存储的对象开始。 对于此示例,我将开发一个基本的博客站点,因此将存储博客对象本身。 清单8显示了我将使用的BlogObject类:

    清单8. BlogObject类
    package com.ibm.developerWorks.objects; import java.io.Serializable; import java.util.Date; public class BlogObject implements Serializable { private static final long serialVersionUID = 6392376146163510046L; private int blogId; private String author; private Date date; private String title; private String content; public BlogObject(int blogId, String author, Date date, String title, String content) { this.blogId = blogId; this.author = author; this.date = date; this.title = title; this.content = content; } public int getBlogId() { return this.blogId; } public String getAuthor() { return this.author; } public Date getDate() { return this.date; } public String getTitle() { return this.title; } public String getContent() { return this.content; } }

    将对象表示在类中之后,接下来需要一个类来管理它。 管理器处理与博客对象相关的所有管理方面和缓存功能。 在此示例中,管理器将处理三个主要任务:

    检索博客对象 在缓存中设置博客对象 从缓存中清理博客对象

    清单9中所示的getBlog方法检索博客对象。 该方法首先尝试从缓存中获取博客对象。 如果对象不在缓存中,它将通过另一种机制获取它:

    清单9.通过博客管理器检索博客对象
    public BlogObject getBlog(int id) { BlogObject blog = null; try { blogCache = JCS.getInstance(blogCacheRegion); blog = (BlogObject)blogCache.get(id); } catch (CacheException ce) { blog = null; } if (blog == null) { blog = DatabaseManager.getBlog(id); this.setBlog( blog.getBlogId(), blog.getAuthor(), blog.getDate(), blog.getTitle(), blog.getContent() ); } return blog; }

    在清单9中,我使用数据库作为检索对象的替代机制。 从另一种机制检索对象时,应将该对象设置为高速缓存,以便下次检索时可以直接从高速缓存中获取它。

    清单10中所示的setBlog方法将博客对象放置在缓存中。 此方法很简单,因为它只是使用传入的信息创建一个新的Blog对象,然后将其放置在缓存中。

    清单10.通过博客管理器将博客对象放置在缓存中
    public boolean setBlog(int bId, String author, Date date, String title, String content) { BlogObject blog = new BlogObject(bId, author, date, title, content); try { blogCache = JCS.getInstance(blogCacheRegion); blogCache.put(bId, blog); return true; } catch (CacheException ce) { return false; } }

    清单11中所示的cleanBlog方法清除一个指定的博客或将所有博客从缓存中清除。 该方法使用JCS的remove和clear方法来清理缓存对象。

    清单11.通过博客管理器从缓存中删除博客对象
    public boolean cleanBlog(int blogId) { try { blogCache = JCS.getInstance(blogCacheRegion); blogCache.remove(blogId); } catch (CacheException ce) { return false; } return true; } public boolean cleanBlog() { try { blogCache = JCS.getInstance(blogCacheRegion); blogCache.clear(); } catch (CacheException ce) { return false; } return true; }

    前面的类演示了如何使用JCS缓存对象。 使用对象的简单表示形式和该对象的管理器,您可以使用一种功能强大而简单的方法来处理Web应用程序中的对象。

    缓存元数据

    除了到目前为止向您展示的向应用程序添加缓存的基础知识外,JCS还提供了更多功能。 例如,它提供了用于收集缓存对象和缓存区域的元数据的实用程序。 您可以轻松检索:

    缓存键名称 缓存项目的创建时间 缓存将生存的最长时间 缓存的项目过期之前需要多少时间

    清单12中的示例显示了如何检索缓存项的元数据:

    清单12.检索缓存项目的元数据
    try { JCSAdminBean admin = new JCSAdminBean(); LinkedList linkedList = admin.buildElementInfo(regionName); ListIterator iterator = linkedList.listIterator(); while (iterator.hasNext()) { CacheElementInfo info = (CacheElementInfo)iterator.next(); System.out.println("Key: " + info.getKey()); System.out.println("Creation Time: " + info.getCreateTime()); System.out.println("Maximum Life (seconds): " + info.getMaxLifeSeconds()); System.out.println("Expires in (seconds): " + info.getExpiresInSeconds()); } } catch (Exception e) { }

    缓存项目的元数据很有用,但是获取每个缓存区域的元数据也很有帮助。 此信息可以让您知道有多少缓存数据进入哪个区域,包括缓存未命中,缓存命中和缓存更新。 清单13中的示例显示了如何收集此信息:

    清单13.检索缓存区域的元数据
    try { JCSAdminBean admin = new JCSAdminBean(); LinkedList linkedList = admin.buildCacheInfo(); ListIterator iterator = linkedList.listIterator(); while (iterator.hasNext()) { CacheRegionInfo info = (CacheRegionInfo)iterator.next(); CompositeCache compCache = info.getCache(); System.out.println("Cache Name: " + compCache.getCacheName()); System.out.println("Cache Type: " + compCache.getCacheType()); System.out.println("Cache Misses (not found): " + compCache.getMissCountNotFound()); System.out.println("Cache Misses (expired): " + compCache.getMissCountExpired()); System.out.println("Cache Hits (memory): " + compCache.getHitCountRam()); System.out.println("Cache Updates: " + compCache.getUpdateCount()); } } catch (Exception e) { }

    收集缓存区域和项的元数据可帮助您分析网站中需要优化的区域和项。 元数据还可以帮助您管理对时间敏感的缓存数据。 例如,您可以使用每个缓存项目的最大寿命和到期时间来刷新需要更新数据的特定用户的缓存数据。

    结论

    对于Java开发人员而言,JCS是一个功能强大且易于使用的缓存系统。 它为桌面和Web应用程序提供数据缓存。 桌面型Web应用程序的增长要求Web应用程序的速度和敏捷性提高。 数据缓存可以帮助完成这项工作。 此概述显示了如何配置和使用JCS。 我还介绍了基本缓存方法,通用Web应用程序中使用的对象的缓存以及缓存元数据的检索所需的语法。 您现在已经掌握了JCS的初步知识,可以利用数据缓存的功能快速开始开发下一个Web站点。 您可能还需要研究其他几个提供高级功能的JCS领域,例如HTTP Servlet访问,JCS实用性,基本HTTP身份验证和其他辅助区域。


    翻译自: https://www.ibm.com/developerworks/java/library/j-jcs/index.html

    Processed: 0.009, SQL: 10