1. 程式人生 > >Memcached學習筆記之二:入門使用

Memcached學習筆記之二:入門使用

使用

現在伺服器已經正常運行了,下面我們就來寫java的客戶端連線程式。

將java_memcached-release.zip解壓,把java_memcached-release.jar檔案複製到java專案的lib目錄下,

然後我們來編寫程式碼,比如我提供的一個應用類如下:

 

package memcached.test;

import java.util.Date;

import com.danga.MemCached.MemCachedClient;
import com.danga.MemCached.SockIOPool;

/**
 * 使用memcached的快取實用類.
 */
public class MemCached {
    // 建立全域性的唯一例項
    protected static MemCachedClient mcc = new MemCachedClient();

    protected static MemCached memCached = new MemCached();

    // 設定與快取伺服器的連線池
    static {
        // 伺服器列表和其權重
        String[] servers = { "127.0.0.1:11211" };
        Integer[] weights = { 3 };

        // 獲取socke連線池的例項物件
        // 這個類用來建立管理客戶端和伺服器通訊連線池,
        // 客戶端主要的工作(包括資料通訊、伺服器定位、hash碼生成等)都是由這個類完成的。
        SockIOPool pool = SockIOPool.getInstance();

        // 設定伺服器資訊
        pool.setServers(servers);
        
        // 設定Server權重
        pool.setWeights(weights);

        // 設定初始連線數、最小和最大連線數以及最大處理時間
        pool.setInitConn(5);
        pool.setMinConn(5);
        pool.setMaxConn(250);
        pool.setMaxIdle(1000 * 60 * 60 * 6);

        // 設定主執行緒的睡眠時間
        pool.setMaintSleep(30);

        // 設定連線心跳監測開關
        // true:每次通訊都要進行連線是否有效的監測,造成通訊次數倍增,加大網路負載,
        // 因此在對HighAvailability要求比較高的場合應該設為true
        // 預設狀態是false,建議保持預設。
        pool.setAliveCheck(false);

        // 設定連線失敗恢復開關
        // 設定為true,當宕機的伺服器啟動或中斷的網路連線後,這個socket連線還可繼續使用,否則將不再使用.
        // 預設狀態是true,建議保持預設。
        pool.setFailback(true);

        // 設定容錯開關
        // true:噹噹前socket不可用時,程式會自動查詢可用連線並返回,否則返回NULL
        // 預設狀態是true,建議保持預設。
        pool.setFailover(true);

        // 設定hash演算法
        // alg=0 使用String.hashCode()獲得hash code,該方法依賴JDK,可能和其他客戶端不相容,建議不使用
        // alg=1 使用original 相容hash演算法,相容其他客戶端
        // alg=2 使用CRC32相容hash演算法,相容其他客戶端,效能優於original演算法
        // alg=3 使用MD5 hash演算法
        // 採用前三種hash演算法的時候,查詢cache伺服器使用餘數方法。採用最後一種hash演算法查詢cache服務時使用consistent方法。
        // 預設值為0
        pool.setHashingAlg(0);

        // 設定是否使用Nagle演算法,因為我們的通訊資料量通常都比較大(相對TCP控制資料)而且要求響應及時,
        // 因此該值需要設定為false(預設是true)
        pool.setNagle(false);
        
        // 設定socket的讀取等待超時值
        pool.setSocketTO(3000);
        
        // 設定socket的連線等待超時值
        pool.setSocketConnectTO(0);

        // 初始化連線池
        pool.initialize();

        // 壓縮設定,超過指定大小(單位為K)的資料都會被壓縮
        // mcc.setCompressEnable(true);    //UnsupportedOperation
        // mcc.setCompressThreshold(64 * 1024);
    }

    private MemCached() {

    }

    /**
     * 獲取唯一例項.
     * singleton
     * @return
     */
    public static MemCached getInstance() {
        return memCached;
    }

    /**
     * 新增一個指定的鍵值對到快取中.
     * 
     * @param key
     * @param value
     * @return
     */
    public boolean add(String key, Object value) {
        return mcc.add(key, value);
    }

    /**
     * 新增一個指定的鍵值對到快取中.
     * 
     * @param key
     * @param value
     * @param expiry 多久之後過期
     * @return
     */
    public boolean add(String key, Object value, Date expiry) {
        return mcc.add(key, value, expiry);
    }
    
    
    public boolean set(String key, Object value) {
        return mcc.set(key, value);
    }

    public boolean set(String key, Object value, Date expiry) {
        return mcc.set(key, value, expiry);
    }

    public boolean replace(String key, Object value) {
        return mcc.replace(key, value);
    }

    public boolean replace(String key, Object value, Date expiry) {
        return mcc.replace(key, value, expiry);
    }
    
    

    /**
     * 根據指定的關鍵字獲取物件.
     * 
     * @param key
     * @return
     */
    public Object get(String key) {
        return mcc.get(key);
    }

寫個Main方法測試下:

    public static void main(String[] args) {
        MemCached cache = MemCached.getInstance();
        boolean result1 = cache.add("hello", 1234, new Date(1000 * 2));// 設定2秒後過期
        System.out.println("第一次add : " + result1);
        System.out.println("Value : " + cache.get("hello"));
        
        boolean result2 =cache.add("hello", 12345, new Date(1000 * 2));// add fail
        System.out.println("第二次add : " + result2);
        
        boolean result3 =cache.set("hello", 12345, new Date(1000 * 2));// set successes
        System.out.println("呼叫set : " + result3);
        
        System.out.println("Value : " + cache.get("hello"));

        try {
            Thread.sleep(1000 * 2);
            System.out.println("已經sleep2秒了....");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("Value : " + cache.get("hello"));
    }

執行結果如下:

第一次add : true
Value : 1234
第二次add : false
呼叫set : true
Value : 12345
已經sleep2秒了....
Value : null

說明:

  1. 第二次add失敗是因為"hello"這個key已經存在了。
  2. 呼叫set成功,是因為set的時候覆蓋了已存在的鍵值對,這正是add和set的不同之處
  3. 設定過期之間之後,cache按時自動失效

 

上面的例子是對於基本資料型別,對於普通的POJO而言,如果要進行儲存的話,那麼比如讓其實現java.io.Serializable介面。

因為memcached是一個分散式的快取伺服器,多臺伺服器間進行資料共享需要將物件序列化的,所以必須實現該介面,否則會報錯的(java.io.NotSerializableException)。

下面來試試POJO的儲存:

 

package memcached.test;
public class Person implements java.io.Serializable {
    private static final long serialVersionUID = 1L;

    private String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

Main方法如下:

    public static void main(String[] args) {
        MemCached cache = MemCached.getInstance();

        Person p1 = new Person();
        p1.setName("Jack");
        cache.add("bean", p1);
        
        Person p2 = (Person) cache.get("bean");
        System.out.println("name=" + p2.getName());//Jack
        p2.setName("Rose");
        
        // cache.replace("bean", p2);
        Person p3 = (Person) cache.get("bean");
        System.out.println("name=" + p3.getName());
    }

上面的程式碼中,我們通過p2.setName("Rose")修改了物件的名字,

最後一行列印的會是什麼呢?

name=Jack
name=Jack

Why?

這是因為我們修改的物件並不是快取中的物件,而是通過序列化過來的一個例項物件

那麼要修改怎麼辦?使用replace,註釋掉的那一行把註釋去掉就可以了。

 

二、其他

Memcached的命令引數說明

-p <num>                監聽的埠
-l <ip_addr>            連線的IP地址, 預設是本機
-d start                   啟動memcached服務
-d restart                重起memcached服務
-d stop|shutdown    關閉正在執行的memcached服務
-d install                  安裝memcached服務
-d uninstall              解除安裝memcached服務
-u <username>       以<username>的身份執行 (僅在以root執行的時候有效)
-m <num>              最大記憶體使用,單位MB。預設64MB
-M                          記憶體耗盡時返回錯誤,而不是刪除項
-c <num>                最大同時連線數,預設是1024
-f <factor>              塊大小增長因子,預設是1.25
-n <bytes>             最小分配空間,key+value+flags預設是48
-h                          顯示幫助

 Memcached也可以在控制檯中新增鍵值對,首先使用命令“telnet 127.0.0.1 11211”進入到Memcached控制檯,

然後使用set、add、replace、get、delete來操作。

 

三、Memcached的優勢和不足

說到Memcached的優勢,那當然是:速度快,操作簡便,易擴充套件

不足的話,主要有2點:

  1. 資料的臨時性(資料僅儲存在記憶體中)
  2. 只能通過指定鍵來讀取資料,不支援模糊查詢

 

四、Memcached停止時的保障措施

如果資料庫的訪問量比較大,就需要提前做好準備,以便應對在memcached停止時發生的負載問題。

如果能在停止memcached之前,把資料複製到其他的server就好了。恩,這個可以通過repcached來實現。

repcached是日本人開發的實現memcached複製功能,
它是一個單master、單slave的方案,但它的master/slave都是可讀寫的,而且可以相互同步
如果master壞掉,slave偵測到連線斷了,它會自動listen而成為master