欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

适用于高并发的本地缓存方案

程序员文章站 2022-03-04 15:00:42
...

使用本地缓存需要注意两个问题:

1 内存管理,及时解除无用对象的引用。防止大量无用对象进入old区,引发full gc。

2 数据同步,如果应用是一个集群,需要保持各台机器的数据一致性。

 

问题1的解决可以采用LRU算法,预先定好缓存大小。达到最大值后,清除最近最少使用的对象。

问题2比较复杂,需要有一个集中的地方控制缓存一致,比如可以采用消息中间件,写时进行异步复制。这种方式成本较大。

 

其实对于业务系统,用户通过浏览器访问的数据,不需要很强的一致性。只要在3秒内,各台机器能够保持最终一致,用户是感觉不大不同机器数据的不同步。

因此通过控制缓存时间为3秒或其它很短的时间,就可以保证一定程度的数据一致,避免数据同步的开销和复杂度。

缓存时间短又会引发另外一个问题,就是缓存的命中率。在高并发访问下,缓存时间短可能会导致,大量的访问刚好都没有命中,缓存穿透给系统带来瞬间的高峰压力。

 

综合考虑以上几个矛盾点,可以对缓存数据进行封装,使用有效失效次数的缓存对象,保证在高并发情况下,大量的访问都能命中缓存,同时又能保证缓存及时失效和更新。代码如下

 

首先是LRUHashMap。需要注意的是LRUHashMap不是线程安全的,非线程安全访问是否会带来问题,取决于业务场景,对共享变量进行相互覆盖的影响(参考http://www.iteye.com/topic/656670)。

 

	class LRUHashMap extends LinkedHashMap<String, Object> {
		private int MAX_ENTRIES;

		public LRUHashMap(int size) {
			MAX_ENTRIES = size;
		}

		protected boolean removeEldestEntry(Map.Entry<String, Object> eldest) {
			return size() > MAX_ENTRIES;
		}
	}

 

缓存对象

 

public class CacheObject implements Serializable {
	long createTime;
	long lifeTime;
	Object value;
	AtomicInteger invalidTimes;

	public CacheObject(long lifeTime, Object value) {
		this.lifeTime = lifeTime;
		this.value = value;
		invalidTimes = new AtomicInteger(0);
		this.createTime = System.currentTimeMillis();
	}

	public long getCreateTime() {
		return createTime;
	}

	public void setCreateTime(long createTime) {
		this.createTime = createTime;
	}

	public long getLifeTime() {
		return lifeTime;
	}

	public void setLifeTime(long lifeTime) {
		this.lifeTime = lifeTime;
	}

	public Object getValue() {
		// 如果已经失效很久,说明很久没有被访问,那么直接返回null,不对失效次数进行判断。
		if ((System.currentTimeMillis() - createTime) > 10 * lifeTime) {
			return null;
		}
		// 保证在高并发下,缓存失效也可以保证较高的命中率
		if (System.currentTimeMillis() - createTime > lifeTime) {
			if (invalidTimes.incrementAndGet() > 3) {
				return value;
			} else {
				return null;
			}
		}
		return value;
	}

	public void setValue(Object value) {
		this.value = value;
	}

	public AtomicInteger getInvalidTimes() {
		return invalidTimes;
	}

	public void setInvalidTimes(AtomicInteger invalidTimes) {
		this.invalidTimes = invalidTimes;
	}
}

 

本地缓存

 

 

public class LocalCache {
	LRUHashMap cacheArea = new LRUHashMap(20);

	public Object get(String key) {
		CacheObject cacheObject = (CacheObject) cacheArea.get(key);
		return cacheObject == null ? null : cacheObject.getValue();
	}

	public void put(String key, Object value, long lifeTime) {
		CacheObject cacheObject = new CacheObject(lifeTime, value);
		cacheArea.put(key, cacheObject);
	}
}

 

参考http://www.cnblogs.com/redcreen/archive/2011/02/15/1955248.html

 

 

 

相关标签: 缓存