這些天在設計SNA的架構,接觸了一些遠程緩衝、叢集、session複製等的東西,以前做企業應用的時候感覺作用不大,現在設計面對internet的系統架構時就非常有用了,而且在調試後看到壓力測試的情況還是比較爽的。
4uV^M*b.W(d0在緩衝的選擇上有過很多的思考,雖然說memcached結合java在序列化上效能不怎麼樣,不過也沒有更好的叢集環境下的緩衝解決方案了,就選擇了memcached。本來計劃等公司買的伺服器到位裝個linux再來研究memcached,但這兩天在找到了一個windows下的Memcached版本,就動手開始調整現有的架構了。
windows下的Server端很簡單,不用安裝,雙擊運行後預設服務連接埠是11211,沒有試著去更改連接埠,因為反正以後會用unix版本,到時再記錄安裝步驟。下載用戶端的javaAPI包,介面非常簡單,參考API手冊上就有現成的例子。
目標,對舊架構緩衝部分進行改造:
1、緩衝工具類
2、hibernate的provider
3、用緩衝實現session機制
今天先研究研究緩衝工具類的改造,在舊架構中部分函數用了ehcache對執行結果進行了緩衝處理,現在目標是提供一個緩衝工具類,在設定檔中配置使用哪種緩衝(memcached或ehcached),使其它程式對具體的緩衝不依賴,同時使用AOP方式來對方法執行結果進行緩衝。
首先是工具類的實現:
在Spring中配置
<!-- EhCache Manager --><br /><bean id="cacheManager"<br /> class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean"><br /> <property name="configLocation"><br /> <value>classpath:ehcache.xml</value><br /> </property><br /></bean> </p><p><bean id="localCache"<br /> class="org.springframework.cache.ehcache.EhCacheFactoryBean"><br /> <property name="cacheManager" ref="cacheManager" /><br /> <property name="cacheName"<br /> value="×××.cache.LOCAL_CACHE" /><br /></bean> </p><p><bean id="cacheService"<br /> class="×××.core.cache.CacheService" init-method="init" destroy-method="destory"><br /> <property name="cacheServerList" value="${cache.servers}"/><br /> <property name="cacheServerWeights" value="${cache.cacheServerWeights}"/><br /> <property name="cacheCluster" value="${cache.cluster}"/><br /> <property name="localCache" ref="localCache"/><br /></bean><br /><!-- EhCache Manager --><br /><bean id="cacheManager"<br />class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean"><br /><property name="configLocation"><br /><value>classpath:ehcache.xml</value><br /></property><br /></bean><br /><bean id="localCache"<br />class="org.springframework.cache.ehcache.EhCacheFactoryBean"><br /><property name="cacheManager" ref="cacheManager" /><br /><property name="cacheName"<br />value="×××.cache.LOCAL_CACHE" /><br /></bean></p><p><bean id="cacheService"<br />class="×××.core.cache.CacheService" init-method="init" destroy-method="destory"><br /><property name="cacheServerList" value="${cache.servers}"/><br /><property name="cacheServerWeights" value="${cache.cacheServerWeights}"/><br /><property name="cacheCluster" value="${cache.cluster}"/><br /><property name="localCache" ref="localCache"/><br /></bean>在properties檔案中配置${cache.servers} ${cache.cacheServerWeights} ${cache.cluster}
Java
代碼/**<br /> * @author Marc<br /> *<br /> */<br />public class CacheService {<br /> private Log logger = LogFactory.getLog(getClass()); </p><p> private Cache localCache; </p><p> String cacheServerList; </p><p> String cacheServerWeights; </p><p> boolean cacheCluster = false; </p><p> int initialConnections = 10; </p><p> int minSpareConnections = 5; </p><p> int maxSpareConnections = 50; </p><p> long maxIdleTime = 1000 * 60 * 30; // 30 minutes </p><p> long maxBusyTime = 1000 * 60 * 5; // 5 minutes </p><p> long maintThreadSleep = 1000 * 5; // 5 seconds </p><p> int socketTimeOut = 1000 * 3; // 3 seconds to block on reads </p><p> int socketConnectTO = 1000 * 3; // 3 seconds to block on initial<br /> // connections. If 0, then will use blocking<br /> // connect (default) </p><p> boolean failover = false; // turn off auto-failover in event of server<br /> // down </p><p> boolean nagleAlg = false; // turn off Nagle's algorithm on all sockets in<br /> // pool </p><p> MemCachedClient mc; </p><p> public CacheService(){<br /> mc = new MemCachedClient();<br /> mc.setCompressEnable(false);<br /> }<br /> /**<br /> * 放入<br /> *<br /> */<br /> public void put(String key, Object obj) {<br /> Assert.hasText(key);<br /> Assert.notNull(obj);<br /> Assert.notNull(localCache);<br /> if (this.cacheCluster) {<br /> mc.set(key, obj);<br /> } else {<br /> Element element = new Element(key, (Serializable) obj);<br /> localCache.put(element);<br /> }<br /> }<br /> /**<br /> * 刪除<br /> */<br /> public void remove(String key){<br /> Assert.hasText(key);<br /> Assert.notNull(localCache);<br /> if (this.cacheCluster) {<br /> mc.delete(key);<br /> }else{<br /> localCache.remove(key);<br /> }<br /> }<br /> /**<br /> * 得到<br /> */<br /> public Object get(String key) {<br /> Assert.hasText(key);<br /> Assert.notNull(localCache);<br /> Object rt = null;<br /> if (this.cacheCluster) {<br /> rt = mc.get(key);<br /> } else {<br /> Element element = null;<br /> try {<br /> element = localCache.get(key);<br /> } catch (CacheException cacheException) {<br /> throw new DataRetrievalFailureException("Cache failure: "<br /> + cacheException.getMessage());<br /> }<br /> if(element != null)<br /> rt = element.getValue();<br /> }<br /> return rt;<br /> }<br /> /**<br /> * 判斷是否存在<br /> *<br /> */<br /> public boolean exist(String key){<br /> Assert.hasText(key);<br /> Assert.notNull(localCache);<br /> if (this.cacheCluster) {<br /> return mc.keyExists(key);<br /> }else{<br /> return this.localCache.isKeyInCache(key);<br /> }<br /> }<br /> private void init() {<br /> if (this.cacheCluster) {<br /> String[] serverlist = cacheServerList.split(",");<br /> Integer[] weights = this.split(cacheServerWeights);<br /> // initialize the pool for memcache servers<br /> SockIOPool pool = SockIOPool.getInstance();<br /> pool.setServers(serverlist);<br /> pool.setWeights(weights);<br /> pool.setInitConn(initialConnections);<br /> pool.setMinConn(minSpareConnections);<br /> pool.setMaxConn(maxSpareConnections);<br /> pool.setMaxIdle(maxIdleTime);<br /> pool.setMaxBusyTime(maxBusyTime);<br /> pool.setMaintSleep(maintThreadSleep);<br /> pool.setSocketTO(socketTimeOut);<br /> pool.setSocketConnectTO(socketConnectTO);<br /> pool.setNagle(nagleAlg);<br /> pool.setHashingAlg(SockIOPool.NEW_COMPAT_HASH);<br /> pool.initialize();<br /> logger.info("初始化memcached pool!");<br /> }<br /> } </p><p> private void destory() {<br /> if (this.cacheCluster) {<br /> SockIOPool.getInstance().shutDown();<br /> }<br /> }<br />} AOP攔截類public class CachingInterceptor implements MethodInterceptor { </p><p> private CacheService cacheService;<br /> private String cacheKey; </p><p> public void setCacheKey(String cacheKey) {<br /> this.cacheKey = cacheKey;<br /> } </p><p> public void setCacheService(CacheService cacheService) {<br /> this.cacheService = cacheService;<br /> } </p><p> public Object invoke(MethodInvocation invocation) throws Throwable {<br /> Object result = cacheService.get(cacheKey);<br /> //如果函數返回結果不在Cache中,執行函數並將結果放入Cache<br /> if (result == null) {<br /> result = invocation.proceed();<br /> cacheService.put(cacheKey,result);<br /> }<br /> return result;<br /> }<br />}<br />public class CachingInterceptor implements MethodInterceptor {<br /> private CacheService cacheService;<br /> private String cacheKey;<br /> public void setCacheKey(String cacheKey) {<br /> this.cacheKey = cacheKey;<br /> }<br /> public void setCacheService(CacheService cacheService) {<br /> this.cacheService = cacheService;<br /> }<br /> public Object invoke(MethodInvocation invocation) throws Throwable {<br /> Object result = cacheService.get(cacheKey);<br /> //如果函數返回結果不在Cache中,執行函數並將結果放入Cache<br /> if (result == null) {<br /> result = invocation.proceed();<br /> cacheService.put(cacheKey,result);<br /> }<br /> return result;<br /> }<br />}Spring的AOP配置如下: <aop:config proxy-target-class="true"><br /> <aop:advisor<br /> pointcut="execution(* ×××.PoiService.getOne(..))"<br /> advice-ref="PoiServiceCachingAdvice" /><br /> </aop:config> </p><p> <bean id="BasPoiServiceCachingAdvice"<br /> class="×××.core.cache.CachingInterceptor"><br /> <property name="cacheKey" value="PoiService" /><br /> <property name="cacheService" ref="cacheService" /><br /> </bean><br />http://space.itpub.net/583467/viewspace-614201