Memcache入門

 1       Memcache是什麼

Memcachedanga.com的一個項目,最早是爲 LiveJournal 服務的,目前全世界不少人使用這個緩存項目來構建自己大負載的網站,來分擔數據庫的壓力。

它可以應對任意多個連接,使用非阻塞的網絡IO。由於它的工作機制是在內存中開闢一塊空間,然後建立一個HashTableMemcached自管理這些HashTable

   

爲什麼會有Memcachememcached兩種名稱?

其實Memcache是這個項目的名稱,而memcached是它服務器端的主程序文件名,

    

Memcache官方網站:http://www.danga.com/memcached

 

2       Memcache工作原理

首先 memcached 是以守護程序方式運行於一個或多個服務器中,隨時接受客戶端的連接操作,客戶端可以由各種語言編寫,目前已知的客戶端 API 包括 Perl/PHP/Python/Ruby/Java/C#/C 等等。客戶端在與 memcached 服務建立連接之後,接下來的事情就是存取對象了,每個被存取的對象都有一個唯一的標識符 key,存取操作均通過這個 key 進行,保存到 memcached 中的對象實際上是放置內存中的,並不是保存在 cache 文件中的,這也是爲什麼 memcached 能夠如此高效快速的原因。注意,這些對象並不是持久的,服務停止之後,裏邊的數據就會丟失。

 

與許多 cache 工具類似,Memcached 的原理並不複雜。它採用了C/S的模式,在 server 端啓動服務進程,在啓動時可以指定監聽的 ip,自己的端口號,所使用的內存大小等幾個關鍵參數。一旦啓動,服務就一直處於可用狀態。Memcached 的目前版本是通過C實現,採用了單進程,單線程,異步I/O,基於事件 (event_based) 的服務方式.使用 libevent 作爲事件通知實現。多個 Server 可以協同工作,但這些 Server 之間是沒有任何通訊聯繫的,每個 Server 只是對自己的數據進行管理。Client 端通過指定 Server 端的 ip 地址(通過域名應該也可以)。需要緩存的對象或數據是以 key->value 對的形式保存在Server端。key 的值通過 hash 進行轉換,根據 hash 值把 value 傳遞到對應的具體的某個 Server 上。當需要獲取對象數據時,也根據 key 進行。首先對 key 進行 hash,通過獲得的值可以確定它被保存在了哪臺 Server 上,然後再向該 Server 發出請求。Client 端只需要知道保存 hash(key) 的值在哪臺服務器上就可以了。

 

        其實說到底,memcache 的工作就是在專門的機器的內存裏維護一張巨大的 hash 表,來存儲經常被讀寫的一些數組與文件,從而極大的提高網站的運行效率。

 

 

 

今天先研究研究緩存工具類的改造,在舊框架中部分函數用了ehcache對執行結果進行了緩存處理,現在目標是提供一個緩存工具類,在配置文件中配置使用哪種緩存(memcached或ehcached),使其它程序對具體的緩存不依賴,同時使用AOP方式來對方法執行結果進行緩存。
首先是工具類的實現:
在Spring中配置

Java代碼 複製代碼
  1. <!-- EhCache Manager -->   
  2. <bean id="cacheManager"  
  3.     class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean">   
  4.     <property name="configLocation">   
  5.         <value>classpath:ehcache.xml</value>   
  6.     </property>   
  7. </bean>   
  8.   
  9. <bean id="localCache"  
  10.     class="org.springframework.cache.ehcache.EhCacheFactoryBean">   
  11.     <property name="cacheManager" ref="cacheManager" />   
  12.     <property name="cacheName"  
  13.         value="×××.cache.LOCAL_CACHE" />   
  14. </bean>   
  15.   
  16. <bean id="cacheService"  
  17.     class="×××.core.cache.CacheService" init-method="init" destroy-method="destory">   
  18.     <property name="cacheServerList" value="${cache.servers}"/>   
  19.     <property name="cacheServerWeights" value="${cache.cacheServerWeights}"/>   
  20.     <property name="cacheCluster" value="${cache.cluster}"/>   
  21.     <property name="localCache" ref="localCache"/>   
  22. </bean>  

在properties文件中配置${cache.servers} ${cache.cacheServerWeights} ${cache.cluster}
具體工具類的代碼

Java代碼 複製代碼
  1. /**  
  2.  * @author Marc  
  3.  *   
  4.  */  
  5. public class CacheService {   
  6.     private Log logger = LogFactory.getLog(getClass());   
  7.   
  8.     private Cache localCache;   
  9.   
  10.     String cacheServerList;   
  11.   
  12.     String cacheServerWeights;   
  13.   
  14.     boolean cacheCluster = false;   
  15.   
  16.     int initialConnections = 10;   
  17.   
  18.     int minSpareConnections = 5;   
  19.   
  20.     int maxSpareConnections = 50;   
  21.   
  22.     long maxIdleTime = 1000 * 60 * 30// 30 minutes   
  23.   
  24.     long maxBusyTime = 1000 * 60 * 5// 5 minutes   
  25.   
  26.     long maintThreadSleep = 1000 * 5// 5 seconds   
  27.   
  28.     int socketTimeOut = 1000 * 3// 3 seconds to block on reads   
  29.   
  30.     int socketConnectTO = 1000 * 3// 3 seconds to block on initial   
  31.                                     // connections. If 0, then will use blocking   
  32.                                     // connect (default)   
  33.   
  34.     boolean failover = false// turn off auto-failover in event of server   
  35.                                 // down   
  36.   
  37.     boolean nagleAlg = false// turn off Nagle's algorithm on all sockets in   
  38.                                 // pool   
  39.   
  40.     MemCachedClient mc;   
  41.   
  42.     public CacheService(){   
  43.         mc = new MemCachedClient();   
  44.         mc.setCompressEnable(false);   
  45.     }   
  46.     /**  
  47.      * 放入  
  48.      *   
  49.      */  
  50.     public void put(String key, Object obj) {   
  51.         Assert.hasText(key);   
  52.         Assert.notNull(obj);   
  53.         Assert.notNull(localCache);   
  54.         if (this.cacheCluster) {   
  55.             mc.set(key, obj);   
  56.         } else {   
  57.             Element element = new Element(key, (Serializable) obj);   
  58.             localCache.put(element);   
  59.         }   
  60.     }   
  61.     /**  
  62.      * 刪除   
  63.      */  
  64.     public void remove(String key){   
  65.         Assert.hasText(key);   
  66.         Assert.notNull(localCache);   
  67.         if (this.cacheCluster) {   
  68.             mc.delete(key);   
  69.         }else{   
  70.             localCache.remove(key);   
  71.         }   
  72.     }   
  73.     /**  
  74.      * 得到  
  75.      */  
  76.     public Object get(String key) {   
  77.         Assert.hasText(key);   
  78.         Assert.notNull(localCache);   
  79.         Object rt = null;   
  80.         if (this.cacheCluster) {   
  81.             rt = mc.get(key);   
  82.         } else {   
  83.             Element element = null;   
  84.             try {   
  85.                 element = localCache.get(key);   
  86.             } catch (CacheException cacheException) {   
  87.                 throw new DataRetrievalFailureException("Cache failure: "  
  88.                         + cacheException.getMessage());   
  89.             }   
  90.             if(element != null)   
  91.                 rt = element.getValue();   
  92.         }   
  93.         return rt;   
  94.     }   
  95.     /**  
  96.      * 判斷是否存在  
  97.      *   
  98.      */  
  99.     public boolean exist(String key){   
  100.         Assert.hasText(key);   
  101.         Assert.notNull(localCache);   
  102.         if (this.cacheCluster) {   
  103.             return mc.keyExists(key);   
  104.         }else{   
  105.             return this.localCache.isKeyInCache(key);   
  106.         }   
  107.     }   
  108.     private void init() {   
  109.         if (this.cacheCluster) {   
  110.             String[] serverlist = cacheServerList.split(",");   
  111.             Integer[] weights = this.split(cacheServerWeights);   
  112.             // initialize the pool for memcache servers   
  113.             SockIOPool pool = SockIOPool.getInstance();   
  114.             pool.setServers(serverlist);   
  115.             pool.setWeights(weights);   
  116.             pool.setInitConn(initialConnections);   
  117.             pool.setMinConn(minSpareConnections);   
  118.             pool.setMaxConn(maxSpareConnections);   
  119.             pool.setMaxIdle(maxIdleTime);   
  120.             pool.setMaxBusyTime(maxBusyTime);   
  121.             pool.setMaintSleep(maintThreadSleep);   
  122.             pool.setSocketTO(socketTimeOut);   
  123.             pool.setSocketConnectTO(socketConnectTO);   
  124.             pool.setNagle(nagleAlg);   
  125.             pool.setHashingAlg(SockIOPool.NEW_COMPAT_HASH);   
  126.             pool.initialize();   
  127.             logger.info("初始化memcached pool!");   
  128.         }   
  129.     }   
  130.   
  131.     private void destory() {   
  132.         if (this.cacheCluster) {   
  133.             SockIOPool.getInstance().shutDown();   
  134.         }   
  135.     }   
  136. }  


然後實現函數的AOP攔截類,用來在函數執行前返回緩存內容

Java代碼 複製代碼
  1. public class CachingInterceptor implements MethodInterceptor {   
  2.   
  3.     private CacheService cacheService;   
  4.     private String cacheKey;   
  5.   
  6.     public void setCacheKey(String cacheKey) {   
  7.         this.cacheKey = cacheKey;   
  8.     }   
  9.   
  10.     public void setCacheService(CacheService cacheService) {   
  11.         this.cacheService = cacheService;   
  12.     }   
  13.   
  14.     public Object invoke(MethodInvocation invocation) throws Throwable {   
  15.         Object result = cacheService.get(cacheKey);   
  16.         //如果函數返回結果不在Cache中,執行函數並將結果放入Cache   
  17.         if (result == null) {   
  18.             result = invocation.proceed();   
  19.             cacheService.put(cacheKey,result);   
  20.         }   
  21.         return result;   
  22.     }   
  23. }  

Spring的AOP配置如下:

Java代碼 複製代碼
  1. <aop:config proxy-target-class="true">   
  2.         <aop:advisor   
  3.             pointcut="execution(* ×××.PoiService.getOne(..))"  
  4.             advice-ref="PoiServiceCachingAdvice" />   
  5.     </aop:config>   
  6.   
  7.     <bean id="BasPoiServiceCachingAdvice"  
  8.         class="×××.core.cache.CachingInterceptor">   
  9.         <property name="cacheKey" value="PoiService" />   
  10.         <property name="cacheService" ref="cacheService" />   
  11.     </bean>  
發佈了30 篇原創文章 · 獲贊 0 · 訪問量 836
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章