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

来源:互联网 发布:wind软件使用 编辑:程序博客网 时间:2024/06/07 07:24

在高并发的场景里面经常会使用到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 checksynchronized (element) {pastTime = now - element.getLastUpdateTime();if (pastTime >= expireTime) {// expired, update entryelement.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 {@Autowiredprivate 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() {@Overridepublic 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. 使用示例

@Autowiredprivate LafiteContainer lafiteContainer;private String namespace = LafiteNameSpace.PermitCommon;@SuppressWarnings("unchecked")@Transactionalpublic List<PermitCommonDO> getPermitDOCache() {LafiteResult lafiteResult = lafiteContainer.getAll(namespace);if(lafiteResult.getDefaultModel() != null) {return (List<PermitCommonDO>) lafiteResult.getDefaultModel();}return null;}
原创粉丝点击