web应用程序的缓存不足_使用缓存构建更快的Web应用程序

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

JCS概述

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

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

记忆区

内存区域是使用最近最少使用(LRU)算法的纯内存缓存区域。 当内存缓存区已满时,LRU首先删除最近最少使用的缓存数据。 该数据区域的性能很好,大多数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

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

JCS有两个依赖项: concurrentcommons-logging 。 (在JCS 1.2.7.0之前,还有两个附加的依赖项: commons-collectionscommons-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的removeclear方法来清理缓存对象。

清单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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值