什麼是緩存
凡是位於速度相差較大的兩種硬件/軟件之間的,用於協調兩者數據傳輸速度差異的結構,均可稱之爲緩存
分類
- 操作系統磁盤緩存,減少磁盤機械操作
- 數據庫緩存,減少文件系統IO
- 應用程序緩存,減少數據庫操作
- WEB服務器緩存,減少應用服務器請求
- 客戶端瀏覽器緩存,減少網站訪問
web相關
- 數據庫緩存
- 系統配置參數緩存
- ORM提供的對象緩存、查詢緩存
- 緩存服務器 EHCache、OSCache、JBossCache
- 通用緩存 memcached、radis
- 頁面緩存(動態頁面靜態化、Servlet緩存、頁面局部緩存)
- ajax查詢結果緩存
- 瀏覽器緩存
- 代理服務器緩存
- CDN加速
適用範圍
頻繁訪問且時效性不高的數據。例如:用戶信息、菜單權限、功能權限、歷史數據查詢等
memcached緩存
Memcached 是一個高性能的分佈式內存對象緩存系統,用於動態Web應用以減輕數據庫負載。它通過在內存中緩存數據和對象來減少讀取數據庫的次數,從而提高動態、數據庫驅動網站的速度。Memcached基於一個存儲鍵/值對的hashmap。其守護進程(daemon )是用C寫的,但是客戶端可以用任何語言來編寫,並通過memcached協議與守護進程通信。[http://baike.baidu.com/view/794242.htm]
alisoft Memcached Client
儘管是“分佈式”緩存服務器,但服務器端並沒有分佈式功能。各個memcached不會互相通信以共享信息。那麼,怎樣進行分佈式呢?這完全取決於客戶端的實現。所以,alisoft Memcached Client是一個支持分佈式集羣的管理客戶端。
單客戶端配置
<?xml version="1.0" encoding="UTF-8"?>
<memcached>
<client name="mclient0" compressEnable="true" defaultEncoding="UTF-8" socketpool="pool0">
<errorHandler>com.alisoft.xplatform.asf.cache.memcached.MemcachedErrorHandler</errorHandler>
</client>
<socketpool name="pool0" failover="true" initConn="5" minConn="5" maxConn="250" maintSleep="5000" nagle="false"
socketTO="3000" aliveCheck="true">
<servers>127.0.0.1:11211,127.0.0.1:11212</servers>
<weights>3,7</weights>
</socketpool>
</memcached>
- 創建memcached的標籤
創建 client的標籤
name 屬性是程序中使用Cache的唯一標識。
socketpool 屬性將會關聯到後面的socketpool配置。
errorHandler 可選,用來處理出錯情況。注意在Tag中不要使用空格或者Tab鍵。- 創建socketpool的標籤
name 屬性和client 配置中的socketpool 屬性相關聯。
maintSleep屬性是後臺線程管理SocketIO池的檢查間隔時間,如果設置爲0,則表明不需要後臺線程維護SocketIO線程池,默認需要管理。
socketTO 屬性是Socket操作超時配置,單位ms。
aliveCheck 屬性表示在使用Socket以前是否先檢查Socket狀態。 - 創建 servers 標籤作爲socketPool的子標籤.設置memcache服務端實例地址,支持多個地址設置,例如“127.0.0.1:11211” 或 “127.0.0.1:11211, 127.0.0.1:11212”
創建 weights 標籤作爲socketPool的子標籤(可選),它表明了上面設置的服務器實例的Load權重. 例如 <weights>3,7</weights>表示30% load 在 127.0.0.1:11211, 70% load 在 127.0.0.1:11212
- 單客戶端代碼
- 創建socketpool的標籤
/**
* lincl
* 2016年7月12日 下午4:56:35
*
*/
package com.lezic.core.cache.memcached;
import java.util.Calendar;
import org.junit.AfterClass;
import org.junit.Assert;
import org.junit.BeforeClass;
import org.junit.Test;
import com.alisoft.xplatform.asf.cache.ICacheManager;
import com.alisoft.xplatform.asf.cache.IMemcachedCache;
import com.alisoft.xplatform.asf.cache.memcached.CacheUtil;
import com.alisoft.xplatform.asf.cache.memcached.MemcachedCacheManager;
/**
* 單客戶端
*
* @author lincl
*
*/
public class MemcachedClient {
static ICacheManager<IMemcachedCache> manager;
/**
* 初始化上下文,加載配置文件
*
* @throws Exception
*/
@BeforeClass
public static void setUpBeforeClass() throws Exception {
manager = CacheUtil.getCacheManager(IMemcachedCache.class, MemcachedCacheManager.class.getName());
manager.setConfigFile("memcached0.xml");
manager.setResponseStatInterval(5 * 1000);
manager.start();
}
/**
* 摧毀管理器
*
* @throws java.lang.Exception
*/
@AfterClass
public static void tearDownAfterClass() throws Exception {
manager.stop();
}
/**
* 測試獲取
*
*/
@Test
public void testGet() {
try {
IMemcachedCache cache = manager.getCache("mclient0");
cache.remove("key1");
cache.remove("key2你好");
cache.put("key1", "1");
cache.put("key2你好", "你好123");
Assert.assertEquals(cache.get("key1"), "1");
Assert.assertEquals(cache.get("key2你好"), "你好123");
} catch (Exception ex) {
ex.printStackTrace();
Assert.assertTrue(false);
}
}
/**
* 測試刪除
*/
@Test
public void testRemove() {
try {
IMemcachedCache cache = manager.getCache("mclient0");
cache.remove("key1");
cache.put("key1", "value1");
Assert.assertEquals(cache.get("key1"), "value1");
cache.remove("key1");
Assert.assertNull(cache.get("key1"));
} catch (Exception ex) {
ex.printStackTrace();
Assert.assertTrue(false);
}
}
/**
* 測試是否包含key
*/
@Test
public void testContainsKey() {
try {
IMemcachedCache cache = manager.getCache("mclient0");
cache.remove("key1");
cache.put("key1", "value1");
Assert.assertTrue(cache.containsKey("key1"));
} catch (Exception ex) {
ex.printStackTrace();
Assert.assertTrue(false);
}
}
@Test
public void testAdd() {
try {
IMemcachedCache cache = manager.getCache("mclient0");
cache.remove("key1");
Assert.assertTrue(cache.add("key1", "value1"));
Assert.assertFalse(cache.add("key1", "value1"));
Assert.assertEquals(cache.get("key1"), "value1");
cache.remove("key1");
} catch (Exception ex) {
ex.printStackTrace();
Assert.assertTrue(false);
}
}
/**
* Test method for {@link com.alisoft.xplatform.asf.cache.ICache#clear()}.
*/
@Test
public void testClear() {
try {
IMemcachedCache cache = manager.getCache("mclient0");
cache.remove("key1");
cache.put("key1", "value1");
Assert.assertEquals(cache.get("key1"), "value1");
cache.clear();
Assert.assertNull(cache.get("key1"));
Thread.sleep(2000);
} catch (Exception ex) {
ex.printStackTrace();
Assert.assertTrue(false);
}
}
/**
* 保存有有效期的數據 Test method for
* {@link com.alisoft.xplatform.asf.cache.ICache#put(java.lang.Object, java.lang.Object, java.util.Date)} .
*/
@Test
public void testPutKVDate() {
try {
IMemcachedCache cache = manager.getCache("mclient0");
Calendar calendar = Calendar.getInstance();
calendar.add(Calendar.SECOND, 5);
cache.remove("key1");
cache.put("key1", "value1", calendar.getTime());
Assert.assertEquals(cache.get("key1"), "value1");
Thread.sleep(5 * 1000 + 1000);
Assert.assertNull(cache.get("key1"));
} catch (Exception ex) {
ex.printStackTrace();
Assert.assertTrue(false);
}
}
}
9.集羣配置
<?xml version="1.0" encoding="UTF-8"?>
<memcached>
<client name="mclient" compressEnable="true" defaultEncoding="UTF-8" socketpool="pool0">
<errorHandler>com.alisoft.xplatform.asf.cache.memcached.MemcachedErrorHandler</errorHandler>
</client>
<client name="mclient1" compressEnable="true" defaultEncoding="UTF-8" socketpool="pool1">
<errorHandler>com.alisoft.xplatform.asf.cache.memcached.MemcachedErrorHandler</errorHandler>
</client>
<client name="mclient2" compressEnable="true" defaultEncoding="UTF-8" socketpool="pool2">
<errorHandler>com.alisoft.xplatform.asf.cache.memcached.MemcachedErrorHandler</errorHandler>
</client>
<client name="mclient3" compressEnable="true" defaultEncoding="UTF-8" socketpool="pool3">
<errorHandler>com.alisoft.xplatform.asf.cache.memcached.MemcachedErrorHandler</errorHandler>
</client>
<client name="mclient4" compressEnable="true" defaultEncoding="UTF-8" socketpool="pool4">
<errorHandler>com.alisoft.xplatform.asf.cache.memcached.MemcachedErrorHandler</errorHandler>
</client>
<socketpool name="pool0" failover="true" initConn="5" minConn="5" maxConn="250" maintSleep="0" nagle="false"
socketTO="3000" aliveCheck="true">
<servers>127.0.0.1:11210</servers>
</socketpool>
<socketpool name="pool1" failover="true" initConn="5" minConn="5" maxConn="250" maintSleep="0" nagle="false"
socketTO="3000" aliveCheck="true">
<servers>127.0.0.1:11211</servers>
</socketpool>
<socketpool name="pool2" failover="true" initConn="5" minConn="5" maxConn="250" maintSleep="0" nagle="false"
socketTO="3000" aliveCheck="true">
<servers>127.0.0.1:11212</servers>
</socketpool>
<socketpool name="pool3" failover="true" initConn="5" minConn="5" maxConn="250" maintSleep="0" nagle="false"
socketTO="3000" aliveCheck="true">
<servers>127.0.0.1:11213</servers>
</socketpool>
<socketpool name="pool4" failover="true" initConn="5" minConn="5" maxConn="250" maintSleep="0" nagle="false"
socketTO="3000" aliveCheck="true">
<servers>127.0.0.1:11214</servers>
</socketpool>
<cluster name="cluster1" mode="active">
//mode = active,standby
<memCachedClients>mclient1,mclient2</memCachedClients>
</cluster>
<cluster name="cluster2" mode="standby">
//mode = active,standby
<memCachedClients>mclient3,mclient4</memCachedClients>
</cluster>
</memcached>
- 創建cluster標籤
- 創建memCachedClients
標籤作爲cluster的子標籤,然後將客戶端配置到memCachedClients 標籤中
- 可以配置cluster mode(如果沒有設置mode屬性,默認採用active)
集羣當前的特性
- 集羣中多節點軟負載均衡。(當前採用簡單的Hash算法加取餘來分發數據)
- 數據在多節點上異步冗餘存儲。(防止數據丟失最基本要求)
- 節點不可用切換功能。(當根據算法分發到某一失敗節點時可以轉向到其他可用節點)
- 節點恢復可用後數據Lazy複製。(當A,B兩臺機器作爲集羣的時候,如果A出現了問題,系統會去B獲取數據,當A正常以後,如果應用在A中沒有拿到數據可以去B獲取數據,並且複製到A上,這種方式也是一種lazy的複製。)
- 集羣代碼
/**
*
*/
package com.alisoft.xplatform.asf.cache;
import org.junit.AfterClass;
import org.junit.Assert;
import org.junit.BeforeClass;
import org.junit.Ignore;
import org.junit.Test;
import com.alisoft.xplatform.asf.cache.memcached.CacheUtil;
import com.alisoft.xplatform.asf.cache.memcached.MemcachedCacheManager;
/**
* 集羣測試類
* @author wenchu.cenwc
*
*/
public class MemcachedClusterTest {
static ICacheManager<IMemcachedCache> manager;
/**
* @throws java.lang.Exception
*/
@BeforeClass
public static void setUpBeforeClass() throws Exception {
manager = CacheUtil.getCacheManager(IMemcachedCache.class, MemcachedCacheManager.class.getName());
manager.setConfigFile("memcached_cluster.xml");
manager.start();
}
/**
* @throws java.lang.Exception
*/
@AfterClass
public static void tearDownAfterClass() throws Exception {
manager.stop();
}
@Test
public void testActiveMode() {
try {
IMemcachedCache cache1 = manager.getCache("mclient1");
IMemcachedCache cache2 = manager.getCache("mclient2");
cache1.put("key1", "value1");
cache1.put("key2", "value2");
cache1.put("key3", "value3");
cache1.put("key4", "value4");
cache1.put("key5", "value5");
cache1.put("key6", "value6");
// 模擬mclient1失效(結束服務端),有出錯日誌在控制檯打印
Assert.assertEquals(cache1.get("key1"), "value1");
Assert.assertEquals(cache1.get("key2"), "value2");
Assert.assertEquals(cache1.get("key3"), "value3");
Assert.assertEquals(cache1.get("key4"), "value4");
Assert.assertEquals(cache1.get("key5"), "value5");
Assert.assertEquals(cache1.get("key6"), "value6");
Assert.assertEquals(cache2.get("key1"), "value1");
Assert.assertEquals(cache2.get("key2"), "value2");
Assert.assertEquals(cache2.get("key3"), "value3");
Assert.assertEquals(cache2.get("key4"), "value4");
Assert.assertEquals(cache2.get("key5"), "value5");
Assert.assertEquals(cache2.get("key6"), "value6");
// 恢復mclient1,無出錯日誌在控制檯打印
Assert.assertEquals(cache1.get("key1"), "value1");
Assert.assertEquals(cache1.get("key2"), "value2");
Assert.assertEquals(cache1.get("key3"), "value3");
Assert.assertEquals(cache1.get("key4"), "value4");
Assert.assertEquals(cache1.get("key5"), "value5");
Assert.assertEquals(cache1.get("key6"), "value6");
Assert.assertEquals(cache2.get("key1"), "value1");
Assert.assertEquals(cache2.get("key2"), "value2");
Assert.assertEquals(cache2.get("key3"), "value3");
Assert.assertEquals(cache2.get("key4"), "value4");
Assert.assertEquals(cache2.get("key5"), "value5");
Assert.assertEquals(cache2.get("key6"), "value6");
} catch (Exception ex) {
ex.printStackTrace();
Assert.assertTrue(false);
}
}
@Test
@Ignore
public void testStandByMode() {
IMemcachedCache cache1 = manager.getCache("mclient3");
IMemcachedCache cache2 = manager.getCache("mclient4");
cache1.put("key1", "value1");
cache1.put("key2", "value2");
cache1.put("key3", "value3");
cache1.put("key4", "value4");
cache1.put("key5", "value5");
cache1.put("key6", "value6");
// 模擬mclient1失效(結束服務端),有出錯日誌在控制檯打印
Assert.assertEquals(cache1.get("key1"), "value1");
Assert.assertEquals(cache1.get("key2"), "value2");
Assert.assertEquals(cache1.get("key3"), "value3");
Assert.assertEquals(cache1.get("key4"), "value4");
Assert.assertEquals(cache1.get("key5"), "value5");
Assert.assertEquals(cache1.get("key6"), "value6");
Assert.assertEquals(cache2.get("key1"), "value1");
Assert.assertEquals(cache2.get("key2"), "value2");
Assert.assertEquals(cache2.get("key3"), "value3");
Assert.assertEquals(cache2.get("key4"), "value4");
Assert.assertEquals(cache2.get("key5"), "value5");
Assert.assertEquals(cache2.get("key6"), "value6");
// 恢復mclient1,無出錯日誌在控制檯打印
Assert.assertNull(cache1.get("key1"));
Assert.assertEquals(cache1.get("key2"), "value2");
Assert.assertNull(cache1.get("key3"));
Assert.assertEquals(cache1.get("key4"), "value4");
Assert.assertNull(cache1.get("key5"));
Assert.assertEquals(cache1.get("key6"), "value6");
Assert.assertNull(cache2.get("key1"));
Assert.assertEquals(cache2.get("key2"), "value2");
Assert.assertNull(cache2.get("key3"));
Assert.assertEquals(cache2.get("key4"), "value4");
Assert.assertNull(cache2.get("key5"));
Assert.assertEquals(cache2.get("key6"), "value6");
}
/**
* 集羣複製
*
*/
@Test
public void testClusterCopy() {
try {
IMemcachedCache cache = manager.getCache("mclient");
IMemcachedCache cache1 = manager.getCache("mclient1");
IMemcachedCache cache2 = manager.getCache("mclient2");
cache.put("key1", "value1");
cache.put("key2", "value2");
cache.put("key3", "value3");
cache.put("key4", "value4");
cache.put("key5", "value5");
cache.put("key6", "value6");
cache1.remove("key1");
cache1.remove("key2");
cache1.remove("key3");
cache1.remove("key4");
cache1.remove("key5");
cache1.remove("key6");
cache2.remove("key1");
cache2.remove("key2");
cache2.remove("key3");
cache2.remove("key4");
cache2.remove("key5");
cache2.remove("key6");
manager.clusterCopy("mclient", "cluster1");
Assert.assertEquals(cache1.get("key1"), "value1");
Assert.assertEquals(cache1.get("key2"), "value2");
Assert.assertEquals(cache1.get("key3"), "value3");
Assert.assertEquals(cache1.get("key4"), "value4");
Assert.assertEquals(cache1.get("key5"), "value5");
Assert.assertEquals(cache1.get("key6"), "value6");
Assert.assertEquals(cache2.get("key1"), "value1");
Assert.assertEquals(cache2.get("key2"), "value2");
Assert.assertEquals(cache2.get("key3"), "value3");
Assert.assertEquals(cache2.get("key4"), "value4");
Assert.assertEquals(cache2.get("key5"), "value5");
Assert.assertEquals(cache2.get("key6"), "value6");
} catch (Exception ex) {
ex.printStackTrace();
Assert.assertTrue(false);
}
}
@Test
public void testReload() {
try {
IMemcachedCache cache = manager.getCache("mclient");
IMemcachedCache cache1 = manager.getCache("mclient1");
IMemcachedCache cache2 = manager.getCache("mclient2");
IMemcachedCache cache5 = manager.getCache("mclient5");
IMemcachedCache cache6 = manager.getCache("mclient6");
Assert.assertNull(cache5);
Assert.assertNull(cache6);
cache.clear();
Thread.sleep(1000);
cache1.clear();
Thread.sleep(1000);
cache2.clear();
Thread.sleep(1000);
cache.put("key1", "1");
cache1.put("key2", "2");
Assert.assertNull(cache.get("key2"));
Assert.assertNull(cache1.get("key1"));
Thread.sleep(2000);
// manager.reload("http://10.2.226.41/sip/memcached_cluster2.xml");
manager.reload("memcached_cluster2.xml");
Thread.sleep(2000);
cache1 = manager.getCache("mclient1");
cache2 = manager.getCache("mclient2");
cache5 = manager.getCache("mclient5");
cache6 = manager.getCache("mclient6");
Assert.assertNull(cache1);
Assert.assertNull(cache2);
Assert.assertNotNull(cache5);
Assert.assertNotNull(cache6);
cache5.clear();
Thread.sleep(1000);
cache6.clear();
Thread.sleep(3000);
manager.reload("memcached_cluster3.xml");
Thread.sleep(2000);
cache = manager.getCache("mclient");
cache1 = manager.getCache("mclient1");
cache2 = manager.getCache("mclient2");
cache5 = manager.getCache("mclient5");
cache6 = manager.getCache("mclient6");
Assert.assertEquals(cache.get("key2"), "2");
Assert.assertEquals(cache1.get("key1"), "1");
Assert.assertEquals(cache2.get("key2"), "2");
Assert.assertEquals(cache5.get("key2"), "2");
Assert.assertNull(cache2.get("key1"));
Assert.assertNull(cache5.get("key1"));
Assert.assertNull(cache6.get("key1"));
Assert.assertNull(cache6.get("key2"));
} catch (Exception ex) {
ex.printStackTrace();
Assert.assertTrue(false);
}
}
}