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

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

下面是设计组织结构:

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

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

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
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)

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
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来循环调用内存实体里的逻辑单元进行数据的初始化)
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
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();
         
     }
}<span></span>
4. spring初始化方式
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<!-- 权限角色缓存
  <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. 使用示例

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
@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 ;
     }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值