高并发数据缓存池(基于EHcache)

在高并发的场景里面经常会使用到localcache内容,但是一直没有一个很好的内存管理工具。在开发的时候发现了ehcache,这么一个开源的工具。唯一的缺点就是无法对于多块数据单元进行一个有效的管理,并且在数据过期的时候无法提供有效的更新机制,所以这里写了一个数据缓存池来满足这个需求。

下面是设计组织结构:

这里主要是在数据实体内部封装了数据更新器,这样在数据过期的时候可以调用更新器的方法。

1. Ehcache数据缓冲的具体代码:(主要是get方法内部进行数据更新,使用对象锁的方式来进行数据过期的并发控制,缺点是可能在非常高的并发里面会出现数据阻塞的现象,但是因为这里大部分都是内存的运算操作,所以相对来说阻塞的效果还好)

package com.tmall.lafite.core.manager.localcache;

import java.util.List;

import net.sf.ehcache.Cache;
import net.sf.ehcache.CacheManager;
import net.sf.ehcache.Element;
import net.sf.ehcache.concurrent.LockType;
import net.sf.ehcache.concurrent.ReadWriteLockSync;
import net.sf.ehcache.config.CacheConfiguration;
import net.sf.ehcache.store.MemoryStoreEvictionPolicy;

import com.tmall.lafite.core.LafiteResult;
import com.tmall.lafite.core.ResultCode;

/**
 * cache数据实体
 * @author wangxiao
 *
 */
public class LafiteCache {
	
	private CacheManager cacheManager = null;
	private Cache cacheImpl = null;
	
	ReadWriteLockSync rwLock = new ReadWriteLockSync();
	
	private int capability = 30;
	private long expireTime = 30;
	
	public static final int DEFAULT_CAPABILITY = 30;
	public static final int DEFAULT_EXPIRETIME = 30;
	
	private String cacheName = "Tair Local Cache";
	
	public LafiteCache(String id, int capability, long expireTimeMS) {
		this.cacheName = id;
		this.capability = capability;
		this.expireTime = expireTimeMS;
	}
	
	public void setExpireTime(long expireTimeMS) {
		this.expireTime = expireTimeMS;
	}
	
	public void setCapacity(int cap) {
		cacheImpl.getCacheConfiguration().setMaxEntriesLocalHeap(cap);
	}
	
	public long getExpireTime() {
		return expireTime;
	}

	@SuppressWarnings("deprecation")
	public void initialize() {
		CacheConfiguration cacheConfiguration = new CacheConfiguration();
		cacheConfiguration.setDiskPersistent(false);
		
		cacheConfiguration.name(cacheName)
						  .maxEntriesLocalHeap(capability)
				   		  .diskPersistent(false)
				   		  .memoryStoreEvictionPolicy(MemoryStoreEvictionPolicy.LRU);
				   		 // .timeToLiveSeconds(expireTime);
		//cacheConfiguration.transactionalMode("LOCAL");
		//Configuration config = new Configuration().name(cacheName).cache(cacheConfiguration);
		
		cacheManager = CacheManager.create();
		
		cacheImpl =  new Cache(cacheConfiguration);
		cacheManager.addCache(cacheImpl);
		//cache = MemoryStore.create(cacheImpl, new UnboundedPool());
		
	}
	
	public int size() {
		return (int) cacheImpl.getSize();
	}
	
	public void destroy() {
		cacheImpl.dispose();
		//cacheManager.removeCache(cacheName);
		cacheManager.shutdown();
	}
	
	public void clear() {
		rwLock.lock(LockType.WRITE);
		try {
			cacheImpl.removeAll();
		} finally {
			rwLock.unlock(LockType.WRITE);
		}
	}
	
	public void del(Object key) {
		cacheImpl.remove(key);
		return;
	}
	
	public void put(Object key, Object value) {	
		cacheImpl.put(new Element(key, value));
		return ;
	}
	
	public LafiteResult get(Object key) {
		LafiteResult lafiteResult = new LafiteResult(); 
		
		Element element = cacheImpl.get(key);
		if (element == null) {
			lafiteResult.setError(ResultCode.Error.Cache.NO_DATA);
			return lafiteResult;
		}
		long now = System.currentTimeMillis();
		
		long pastTime = now - element.getLastUpdateTime();
		if (pastTime >= expireTime) {
			// double check
			synchronized (element) {
				pastTime = now - element.getLastUpdateTime();
				if (pastTime >= expireTime) {
					// expired, update entry
					element.updateUpdateStatistics();
					lafiteResult.setError(ResultCode.Error.Cache.DATA_OVERDUE);
				}
			}
		}
		// element object value never null;
		lafiteResult.setDefaultModel(element.getObjectValue());
		return lafiteResult;
	}
	
	@SuppressWarnings("unchecked")
	public List<Object> getKeys() {
		List<Object> keys = cacheImpl.getKeys();
		return keys;
	}
}

2. 数据逻辑单元定义(这里封装了数据容器单元,把原来的数据池方法传入,在数据更新的时候使用namespace来获取内存实体,进而来获取数据。)

(注:这里目前还没有想好是否把数据的初始化放在容器当中,这里暂时不放入。只是在容器里面进行初始化方法的调用,真正的数据设置方式由逻辑单元获取数据池进行自身的put)

package com.tmall.lafite.core.manager.localcache.util;

import org.springframework.beans.factory.annotation.Autowired;

import com.tmall.lafite.core.LafiteResult;
import com.tmall.lafite.core.manager.localcache.LafiteContainer;

/**
 * 缓存逻辑单元
 * @author wangxiao
 *
 */
public abstract class LogicCenter {
	@Autowired
	private LafiteContainer lafiteContainer;
	
	/**
	 * 初始化方法
	 * @return
	 */
	public abstract Object initialize();
	
	/**
	 * 回调函数
	 * @param lafiteCache
	 * @param key
	 * @return
	 */
	public abstract Object callBack(String namespace, Object key, LafiteResult lafiteResult);

	public LafiteContainer getLafiteContainer() {
		return lafiteContainer;
	}
}
3. 数据池(数据池,使用init来循环调用内存实体里的逻辑单元进行数据的初始化)
package com.tmall.lafite.core.manager.localcache;


import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.tmall.lafite.core.LafiteResult;
import com.tmall.lafite.core.ResultCode;
import com.tmall.lafite.core.manager.localcache.entity.CacheEntity;
import com.tmall.lafite.core.manager.localcache.util.LogicCenter;

/**
 * cache容器
 * @author wangxiao
 *
 */
public class LafiteContainer {
	
	protected final Logger logger = LoggerFactory.getLogger(LafiteContainer.class);

	private Map<String, CacheEntity> cacheMap = new ConcurrentHashMap<String, CacheEntity>();
	
	/**
	 * 注册缓存对象
	 * @param namespace
	 * @param key
	 * @param lafiteCache 缓存对象
	 * @param logicCenter 逻辑对象 (包含:初始化方法和callback方法)
	 * @return
	 */
//	public String register(String namespace, String key, LafiteCache lafiteCache, LogicCenter logicCenter) {
//		if(namespace != null && StringUtils.isEmpty(key) && lafiteCache != null) {
//			if(cacheMap.containsKey(namespace)) {
//				return ResultCode.Error.Cache.NAMESPACE_REPETITION;
//			}
//			
//			CacheEntity cacheEntity = new CacheEntity(lafiteCache, logicCenter);
//			try {
//				cacheEntity.initialize();
//			} catch (Exception e) {
//				logger.error("LafiteContainer.register ", e);
//			}
//			cacheMap.put(namespace, cacheEntity);
//			return null;
//		} 
//		return ResultCode.Error.Cache.COMMON_PARAM_LOST;
//	}
	
	/**
	 * 获取cache内的数据
	 * @param namespace
	 * @param key
	 * @return
	 */
	public LafiteResult get(String namespace, Object key) {
		LafiteResult lafiteResult = new LafiteResult();
		CacheEntity cacheEntity = cacheMap.get(namespace);//获取缓存实体
		if(cacheEntity == null) {
			lafiteResult.setError(ResultCode.Error.Cache.NO_CACHEENTITY);
		} else {
			LafiteCache lafiteCache = cacheEntity.getLafiteCache();
			LafiteResult result = lafiteCache.get(key);
			if(ResultCode.Error.Cache.NO_DATA.equals(result.getError()) 
					|| ResultCode.Error.Cache.DATA_OVERDUE.equals(result.getError())) {
				cacheEntity.getLogicCenter().callBack(namespace, key, result);//数据过期触发callback事件
			}
			lafiteResult = result;
		}
		
		return lafiteResult;
	}
	
	/**
	 * 获取指定命名空间的全部数据
	 * 	这里采用的是逐条遍历的方式
	 * @param namespace
	 * @return
	 */
	public LafiteResult getAll(String namespace) {
		LafiteResult lafiteResult = new LafiteResult();
		List<Object> objects = new ArrayList<Object>();
		
		CacheEntity cacheEntity = cacheMap.get(namespace);
		if(cacheEntity == null) {
			lafiteResult.setError(ResultCode.Error.Cache.NO_CACHEENTITY);
		} else {
			LafiteCache lafiteCache = cacheEntity.getLafiteCache();
			List<Object> keys = lafiteCache.getKeys();
			if(keys.isEmpty()) {
				lafiteResult.setError(ResultCode.Error.Cache.NO_DATA);
			} else {
				for(Object key : keys) {
					LafiteResult lr = get(namespace, key);
					objects.add(lr.getDefaultModel());
				}
			}
		}
		lafiteResult.setDefaultModel(objects);
		return lafiteResult;
	}
	
	/**
	 * 设置数据对象内容
	 * @param namespace
	 * @param key
	 * @param value
	 * @return
	 */
	public LafiteResult put(String namespace, Object key, Object value) {
		LafiteResult lafiteResult = new LafiteResult();
		CacheEntity cacheEntity = cacheMap.get(namespace);
		if(cacheEntity == null) {
			lafiteResult.setError(ResultCode.Error.Cache.NO_CACHEENTITY);
		} else {
			LafiteCache lafiteCache = cacheEntity.getLafiteCache();
			lafiteCache.put(key, value);
		}
		return lafiteResult;
	}

	public void setCacheMap(Map<String, CacheEntity> cacheMap) {
		this.cacheMap = cacheMap;
	}

	public Map<String, CacheEntity> getCacheMap() {
		return cacheMap;
	}
	
	public void initialize() {
		
		new Thread(new Runnable() {
			@Override
			public void run() {
				for(String key : cacheMap.keySet()) {
					try {
						CacheEntity cacheEntity = cacheMap.get(key);
						if(cacheEntity != null) {
							LogicCenter logicCenter = cacheEntity.getLogicCenter();
							if(logicCenter != null) {
								logicCenter.initialize();
							}
						}
					}catch (Exception e) {
						e.printStackTrace();
					}
				}
				
			}
		}).start();
		
	}
}
4. spring初始化方式
<!-- 权限角色缓存
 <bean id="permitRoleCache" class="com.tmall.lafite.core.manager.localcache.LafiteCache" init-method="initialize">
 <constructor-arg value="_permit_role_cache_"/>
 <constructor-arg value="100"/>
 <constructor-arg value="2000"/>
 </bean>
 <bean id="permitRoleLogicCenter" class="com.tmall.lafite.core.manager.permit.cache.PermitRoleLogicCenter"/>
 <bean id="permitRoleCacheEntity" class="com.tmall.lafite.core.manager.localcache.entity.CacheEntity">
 <property name="logicCenter" ref="permitRoleLogicCenter" />
 <property name="lafiteCache" ref="permitRoleCache" />
 </bean>
 -->
  
 <!-- 缓存容器 -->
 <bean id="lafiteContainer" class="com.tmall.lafite.core.manager.localcache.LafiteContainer" init-method="initialize">
 <!-- 
 <property name="cacheMap">
    	<map>
    		<entry key="PermitCommon" value-ref="permitCommonCacheEntity" />
    		<entry key="PermitAlgorithm" value-ref="permitAlgorithmCacheEntity"/>
    		<entry key="PermitRole" value-ref="permitRoleCacheEntity"/>
    	</map>
    </property> 
    -->
 </bean>

5. 使用示例

@Autowired
	private LafiteContainer lafiteContainer;
	
	private String namespace = LafiteNameSpace.PermitCommon;

	@SuppressWarnings("unchecked")
	@Transactional
	public List<PermitCommonDO> getPermitDOCache() {
		LafiteResult lafiteResult = lafiteContainer.getAll(namespace);
		if(lafiteResult.getDefaultModel() != null) {
			return (List<PermitCommonDO>) lafiteResult.getDefaultModel();
		}
		return null;
	}

转载于:https://my.oschina.net/tmallMoney/blog/127237

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值