memcached緩存

  1. 什麼是緩存

    凡是位於速度相差較大的兩種硬件/軟件之間的,用於協調兩者數據傳輸速度差異的結構,均可稱之爲緩存

  2. 分類

    • 操作系統磁盤緩存,減少磁盤機械操作
    • 數據庫緩存,減少文件系統IO
    • 應用程序緩存,減少數據庫操作
    • WEB服務器緩存,減少應用服務器請求
    • 客戶端瀏覽器緩存,減少網站訪問
  3. web相關

    • 數據庫緩存
    • 系統配置參數緩存
    • ORM提供的對象緩存、查詢緩存
    • 緩存服務器 EHCache、OSCache、JBossCache
    • 通用緩存 memcached、radis
    • 頁面緩存(動態頁面靜態化、Servlet緩存、頁面局部緩存)
    • ajax查詢結果緩存
    • 瀏覽器緩存
    • 代理服務器緩存
    • CDN加速
  4. 適用範圍

    頻繁訪問且時效性不高的數據。例如:用戶信息、菜單權限、功能權限、歷史數據查詢等

  5. memcached緩存

    Memcached 是一個高性能的分佈式內存對象緩存系統,用於動態Web應用以減輕數據庫負載。它通過在內存中緩存數據和對象來減少讀取數據庫的次數,從而提高動態、數據庫驅動網站的速度。Memcached基於一個存儲鍵/值對的hashmap。其守護進程(daemon )是用C寫的,但是客戶端可以用任何語言來編寫,並通過memcached協議與守護進程通信。[http://baike.baidu.com/view/794242.htm]

  6. alisoft Memcached Client

    儘管是“分佈式”緩存服務器,但服務器端並沒有分佈式功能。各個memcached不會互相通信以共享信息。那麼,怎樣進行分佈式呢?這完全取決於客戶端的實現。所以,alisoft Memcached Client是一個支持分佈式集羣的管理客戶端。

  7. 單客戶端配置

<?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

      1. 單客戶端代碼
/**
 * 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)
  • 集羣當前的特性

    1. 集羣中多節點軟負載均衡。(當前採用簡單的Hash算法加取餘來分發數據)
    2. 數據在多節點上異步冗餘存儲。(防止數據丟失最基本要求)
    3. 節點不可用切換功能。(當根據算法分發到某一失敗節點時可以轉向到其他可用節點)
    4. 節點恢復可用後數據Lazy複製。(當A,B兩臺機器作爲集羣的時候,如果A出現了問題,系統會去B獲取數據,當A正常以後,如果應用在A中沒有拿到數據可以去B獲取數據,並且複製到A上,這種方式也是一種lazy的複製。)
    1. 集羣代碼
/**
 * 
 */
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);
        }
    }

}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章