memcache簡單介紹


一、概述 

1. Memcache 

Memcache(Memcached)是集羣環境下的緩存解決方案。

Memcache 是danga.com的一個項目,最早是爲 LiveJournal 服務的,目前全世界不少人使用這個緩存項目來構建自己大負載的網站,來分擔數據庫的壓力。它可以應對任意多個連接,使用非阻塞的網絡IO。它的工作機制是在內存中開闢一塊空間,然後建立一個HashTable,或者說是hash隊列,Memcached自管理這些HashTable。

Memcache官方網站:http://www.danga.com/memcached,更多詳細的信息可以來這裏瞭解。


2. 爲什麼會有Memcache和memcached兩種名稱 

其實Memcache是這個項目的名稱,而memcached是它服務器端的主程序文件名,知道我的意思了吧。一個是項目名稱,一個是主程序文件名,在網上看到了很多人不明白,於是混用了。


3. 如何在Java開發中使用Memcache 

在Java開發中使用Memcache,一般要用到以下幾個程序:


1)      Memcached 

該程序用來在Linux或Windows服務器上建立和管理緩存。

其項目網址爲:http://danga.com/memcached/


2)      Magent 

Magent是一款開源的Memcached代理服務器軟件,使用它可以搭建高可用性的集羣應用的Memcached服務,其項目網址爲:http://code.google.com/p/memagent/


3)      Memcached 

至於Memcached的客戶端程序,一般推薦用memcached client for java,爲什麼推薦用這種客戶端,後面會講到具體的原因,其項目的網址爲:http://github.com/gwhalin/Memcached-Java-Client/


4)      其它程序 

i.              Libevent 

在 Linux環境下應用Memcache時,Memcache用到了libevent這個庫,用於Socket的處理,所以還需要安裝libevent。 libevent的最新版本是libevent-1.4.13。(如果你的系統已經安裝了libevent,可以不用安裝)。

官網:http://www.monkey.org/~provos/libevent/

下載:http://www.monkey.org/~provos/libevent-1.4.13-stable.tar.gz

ii.              Windows 

Memcache也可以安裝在Windows服務器下,安裝程序:memcached-1.2.1-win32.zip

可以從這裏下載:http://jehiah.cz/projects/memcached-win32/

是什麼 客戶端程序 下的安裝程序
1. 啓動一個Memcache的服務器端 

進入到memcached的安裝目錄,如:

#cd /usr/local/memcached-1.4.5

# ./memcached -d -m 10 -u root -l 10.11.15.222 -p 12000 -c 256 -P /tmp/memcached.pid

?  -d  選項是啓動一個守護進程,

?  -m  是分配給Memcache使用的內存數量,單位是MB,我這裏是10MB,

?  -u  是運行Memcache的用戶,我這裏是root,

?  -l  是監聽的服務器IP地址,我這裏指定了服務器的IP地址10.11.15.222,

?  -p  是設置Memcache監聽的端口,我這裏設置了12000,最好是1024以上的端口,

?  -c  是最大運行的併發連接數,默認1024,這裏設置了256,按照服務器的負載量來設定,

?  -P  是設置保存Memcache的pid文件,我這裏是保存在/tmp/memcached.pid,

2. 結束一個Memcache進程 

如果要結束Memcache進程,執行:

# kill `cat /tmp/memcached.pid`

?  注意,上面命令中的符號是 `,不是單引號’

也可以啓動多個守護進程,不過端口不能重複。

3. 啓動Magent代理 

Magent已保存到/usr/bin目錄下,可以直接執行該命令。如:

#magent -u root -n 51200 -l 127.0.0.1 -p 12000 -s 127.0.0.1:11211 -s 127.0.0.1:11212 -b 127.0.0.1:11213

命令參數:

?  -h  this message

?  -u  uid

?  -g  gid

?  -p  port, default is 11211. (0 to disable tcp support)

?  -s  ip:port, set memcached server ip and port

?  -b  ip:port, set backup memcached server ip and port

?  -l  ip, local bind ip address, default is 0.0.0.0

?  -n  number, set max ...


四、 原理與部署 

1. magent 

magent 採用的是:Consistent Hashing原理,Consistent Hashing如下所示:首先求出memcached服務器(節點)的哈希值, 並將其配置到0~232的圓(continuum)上。 然後用同樣的方法求出存儲數據的鍵的哈希值,並映射到圓上。然後從數據映射到的位置開始順時針查找,將數據保存到找到的第一個服務器上。 如果超過232仍然找不到服務器,就會保存到第一臺memcached服務器上。

從上圖的狀態中添加一臺memcached服務器。餘數分佈式算法由於保存鍵的服務器會發生巨大變化 而影響緩存的命中率,但Consistent Hashing中,只有在continuum上增加服務器的地點逆時針方向的第一臺服務器上的鍵會受到影響。

2. 部署示意圖



3. 搭建memcache集羣服務 

利用magent實現對memecache的分佈式管理,搭建一套memcache集羣服務:

?  前端java對magent的訪問跟對memcache訪問相同,不需要做任何更改,對於插入的key,magent會把值散列到各個memcache服務上,只操作magent,不用關心後端處理;

?  項目應用:以深圳電信爲例,其商呼系統如圖部署三臺機器做爲集羣,假設IP分別是:10.11.15.31, 10.11.15.32, 10.11.15.33;

?  每個前端安裝memcached服務(大內存機器可以啓動多個服務),如端口都爲12001,每個前端都安裝magent服務,端口都爲12000,後端掛載全部機器的memcached服務,

?  啓動參數示例:magent -p 12000 -s 10.11.15.31:12001 -s 10.11.15.32:12001 -s 10.11.15.33:12001,這裏將三臺機器都配置進來,如集集羣增加了機器,只需要在啓動參數裏添加進來即可。所有前端配置都是相同的,任何一個前端只需訪問本地端口的magent,這樣的memcache集羣對應用帶來很大便利。

?  這種部署可以解決session共享的應用

項目中多處已經實際應用,magent對memcache的均衡和穩定性都非常不錯,推薦使用。

的hash算法  
、            測試Memcached 

此處以二機集羣爲例。


1. 啓動Memcached及代理 

啓動兩個memcached進程,端口分別爲11211和11212:

memcached -m 1 -u root -d -l 127.0.0.1 -p 11211

memcached -m 1 -u root -d -l 127.0.0.1 -p 11212

再啓動兩個magent進程,端口分別爲10000和11000:

magent -u root -n 51200 -l 127.0.0.1 -p 10000 -s 127.0.0.1:11211 -b 127.0.0.1:11212

magent -u root -n 51200 -l 127.0.0.1 -p 11000 -s 127.0.0.1:11212 -b 127.0.0.1:11211

-s 爲要寫入的memcached, -b 爲備份用的memcached。

說明:測試環境用magent和memached的不同端口來實現,在生產環境中可以將magent和memached作爲一組放到兩臺服務器上。也就是說通過magent能夠寫入兩個memcached。

2. 數據讀寫測試 

[root@odb ~]# telnet 127.0.0.1 10000

Trying 127.0.0.1…

Connected to localhost.localdomain (127.0.0.1).

Escape character is ‘^]’.

//設置key的值(set <key> <flags> <expiration time> <bytes>)http://blog.csdn.net/zzulp/article/details/7823511

-----------------------

key key 用於查找緩存值
flags 可以包括鍵值對的整型參數,客戶機使用它存儲關於鍵值對的額外信息
expiration time 在緩存中保存鍵值對的時間長度(以秒爲單位,0 表示永遠)
bytes 在緩存中存儲的字節

-----------------------

set key 0 0 8   <—在10000端口設置key的值

88888888

STORED

quit

Connection closed by foreign host.

 

[root@odb ~]# telnet 127.0.0.1 11211

Trying 127.0.0.1…

Connected to localhost.localdomain (127.0.0.1).

Escape character is ‘^]’.

get key                     <—在11211端口獲取key的值成功,或者用gets 可以得到更新次數

VALUE key 0 8

88888888

END

quit

Connection closed by foreign host.

 

[root@odb ~]# telnet 127.0.0.1 11212

Trying 127.0.0.1…

Connected to localhost.localdomain (127.0.0.1).

Escape character is ‘^]’.

get key                     <—在11212端口獲取key的值成功

VALUE key 0 8

88888888

END

quit

Connection closed by foreign host.

**注意附加內容(操作***):memcache的讀寫測試可以參考以下

-------------------

1.簡單讀寫:http://blog.csdn.net/zzulp/article/details/7823511
1).set key 0 0 2、get key 、get keys等
2).刪除 delete key 、flush_all 、echo "flush_all" | nc 127.0.0.1 11211等


2.獲取所有key操作

http://u.sanwen.net/subject/242334.html

http://www.cnblogs.com/sunli/archive/2008/11/01/1324153.html
1).首先列出所有keys

stats items
STAT items:7:number 3 //7爲items id,number 3爲這個節點下有多少個key
STAT items:7:age 188 //age 188 已經存在時間,單位秒
STAT items:7:evicted 0 // 被踢出的數量
END

2)全部列出該節點key
stats cachedump 7 0 //7爲items id,0爲全部列出,如果爲1,則只列出1個
ITEM Sess_sidsvpc1473t1np08qnkvhf6j2 [3 b; 1394527347 s] //b爲字節數,s爲時間
END
3)上面的stats cachedump命令列出了我的session key,接下來就用get命令查找對應的session值
get Sess_sidsvpc1473t1np08qnkvhf6j2
VALUE www

--------------------

3. 高可靠性測試 

[root@odb ~]# ps aux |grep -v grep |grep memcached

root     23455  0.0  0.0  5012 1796 ?        Ss   09:22   0:00 memcached -m 1 -u root -d -l 127.0.0.1 -p 11212

root     24950  0.0  0.0  4120 1800 ?        Ss   10:58   0:00 memcached -m 1 -u root -d -l 127.0.0.1 -p 11211

[root@odb ~]# ps aux |grep -v grep |grep ‘magent -u’

root     25919  0.0  0.0  2176  484 ?        Ss   12:00   0:00 magent -u root -n 51200 -l 127.0.0.1 -p 10000 -s 127.0.0.1:11211 -b 127.0.0.1:11212

root     25925  0.0  0.0  3004  484 ?        Ss   12:00   0:00 magent -u root -n 51200 -l 127.0.0.1 -p 11000 -s 127.0.0.1:11212 -b 127.0.0.1:11211

 

[root@odb ~]# telnet 127.0.0.1 10000

Trying 127.0.0.1…

Connected to localhost.localdomain (127.0.0.1).

Escape character is ‘^]’.

set stone 0 0 6                      <—在10000端口設置stone的值

123456

STORED

quit

Connection closed by foreign host.

 

[root@odb ~]# telnet 127.0.0.1 11000

Trying 127.0.0.1…

Connected to localhost.localdomain (127.0.0.1).

Escape character is ‘^]’.

set shidl 0 0 6                 <—在11000端口設置shidl的值

666666

STORED

get stone                     <—在11000端口獲取stone的值成功

VALUE stone 0 6

123456

END

incr stone 2                   <—在11000端口修改stone的值成功

123458

get stone

VALUE stone 0 6               <—在11000端口驗證stone的值,證明上面的修改成功

123458

END

get shidl                     <—在11000端口獲取shidl的值成功

VALUE shidl 0 6

666666

END

quit                             <—退出11000端口

Connection closed by foreign host.

 

[root@odb ~]# telnet 127.0.0.1 10000

Trying 127.0.0.1…

Connected to localhost.localdomain (127.0.0.1).

Escape character is ‘^]’.

get stone                     <—在10000端口獲取stone的值,已被修改

VALUE stone 0 6

123458

END

get shidl                      <—在10000端口獲取shidl的值成功

VALUE shidl 0 6

666666

END

delete shidl                   <—在10000端口刪除shidl

DELETED

get shidl                      <—在10000端口刪除shidl生效

END

quit

Connection closed by foreign host.

 

[root@odb ~]# telnet 127.0.0.1 11000

Trying 127.0.0.1…

Connected to localhost.localdomain (127.0.0.1).

Escape character is ‘^]’.

get shidl                      <—在11000端口驗證刪除shidl生效

END

get stone                     <—在11000端口獲取stone的值成功

VALUE stone 0 6

123458

END

quit

Connection closed by foreign host.


4. Down 

1)      Down 

[root@odb ~]# kill -9 24950

[root@odb ~]# telnet 127.0.0.1 10000

Trying 127.0.0.1…

Connected to localhost.localdomain (127.0.0.1).

Escape character is ‘^]’.

get stone                      <—在10000依然可以獲取stone的值

VALUE stone 0 6

123458

END

quit

Connection closed by foreign host.

 

[root@odb ~]# telnet 127.0.0.1 11000

Trying 127.0.0.1…

Connected to localhost.localdomain (127.0.0.1).

Escape character is ‘^]’.

get stone                      <—在11000依然可以獲取stone的值

VALUE stone 0 6

123458

END

quit

Connection closed by foreign host.

 

5. Down 

1)      Down 

[root@odb ~]# kill -9 25925

[root@odb ~]# telnet 127.0.0.1 10000

Trying 127.0.0.1…

Connected to localhost.localdomain (127.0.0.1).

Escape character is ‘^]’.

get stone                      <—在10000依然可以獲取stone的值

VALUE stone 0 6

123458

END

quit

Connection closed by foreign host.

2)      重啓 

[root@lh-web-test memcached-1.4.5]# magent -u root -n 51200 -l 127.0.0.1 -p 11000 -s 127.0.0.1:11212 -b 127.0.0.1:11211

[root@lh-web-test memcached-1.4.5]# telnet 127.0.0.1 11000

Trying 127.0.0.1...

Connected to localhost.localdomain (127.0.0.1).

Escape character is '^]'.

get stone                                         <—在11000依然可以獲取stone的值

VALUE stone 0 6

123458

END

quit

Connection closed by foreign host.

五流程 機模擬測試1 掉11211端口的memcached 機模擬測試2 掉11000端口的magent 11000端口的magent


七、            Memcached 

Memcached的java客戶端已經存在三種了:

?  官方提供的基於傳統阻塞io由Greg Whalin維護的客戶端

?  Dustin Sallings實現的基於java nio的Spymemcached

?  XMemcached

1. 三種API比較 

1)      memcached client for java 

較早推出的memcached JAVA客戶端API,應用廣泛,運行比較穩定。


2)      spymemcached 

A simple, asynchronous, single-threaded memcached client written in java. 支持異步,單線程的memcached客戶端,用到了java1.5版本的concurrent和nio,存取速度會高於前者,但是穩定性不好,測試中常報timeOut等相關異常。


3)      xmemcached 

XMemcached 同樣是基於java nio的客戶端,java nio相比於傳統阻塞io模型來說,有效率高(特別在高併發下)和資源耗費相對較少的優點。傳統阻塞IO爲了提高效率,需要創建一定數量的連接形成連接池,而nio僅需要一個連接即可(當然,nio也是可以做池化處理),相對來說減少了線程創建和切換的開銷,這一點在高併發下特別明顯。因此 XMemcached與Spymemcached在性能都非常優秀,在某些方面(存儲的數據比較小的情況下)Xmemcached比 Spymemcached的表現更爲優秀,具體可以看這個Java Memcached Clients Benchmark。


2.  建議 

由於memcached client for java發佈了新版本,性能上有所提高,並且運行穩定,所以建議使用memcached client for java。

XMemcached 也使用得比較廣泛,而且有較詳細的中文API文檔,具有如下特點:高性能、支持完整的協議、支持客戶端分佈、允許設置節點權重、動態增刪節點、支持 JMX、與Spring框架和Hibernate-memcached的集成、客戶端連接池、可擴展性好等。

下面給出這三種客戶端的示例程序。


3.  示例程序 

1)      memcached client for java 

從前面介紹的Java環境的Memcached客戶端程序項目網址裏,下載最新版的客戶端程序包:java_memcached- release_2.5.1.zip,解壓後,文件夾裏找到java_memcached-release_2.5.1.jar,這個就是客戶端的JAR 包。將此JAR包添加到項目的構建路徑裏,則項目中,就可以使用Memcached了。

示例代碼如下:

package temp;

 

import com.danga.MemCached.*;

import org.apache.log4j.*;

 

public class CacheTest {

    public static void main(String[] args) {

       /**

        * 初始化SockIOPool,管理memcached的連接池

        * */

       String[] servers = { "10.11.15.222:10000" };

       SockIOPool pool = SockIOPool.getInstance();

       pool.setServers(servers);

       pool.setFailover(true);

       pool.setInitConn(10);

       pool.setMinConn(5);

       pool.setMaxConn(250);

       pool.setMaintSleep(30);

       pool.setNagle(false);

       pool.setSocketTO(3000);

       pool.setAliveCheck(true);

       pool.initialize();

      

       /**

        * 建立MemcachedClient實例

        * */

       MemCachedClient memCachedClient = new MemCachedClient();

       for (int i = 0; i < 1000; i++) {

           /**

            * 將對象加入到memcached緩存

            * */

           boolean success = memCachedClient.set("" + i, "Hello!");

           /**

            * 從memcached緩存中按key值取對象

            * */

           String result = (String) memCachedClient.get("" + i);

           System.out.println(String.format("set( %d ): %s", i, success));

           System.out.println(String.format("get( %d ): %s", i, result));

       }

    }

}


2)      spymemcached 

spymemcached當前版本是2.5版本,官方網址是:http://code.google.com/p/spymemcached/。可以從地址:http://spymemcached.googlecode.com/files/memcached-2.5.jar下載最新版本來使用。

示例代碼如下:

package temp;

 

import java.net.InetSocketAddress;

import java.util.concurrent.Future;

 

import net.spy.memcached.MemcachedClient;

 

public class TestSpyMemcache {

    public static void main(String[] args) {

       // 保存對象

       try {

           /* 建立MemcachedClient 實例,並指定memcached服務的IP地址和端口號 */

           MemcachedClient mc = new MemcachedClient(new InetSocketAddress("10.11.15.222", 10000));

           Future<Boolean> b = null;

           /* 將key值,過期時間(秒)和要緩存的對象set到memcached中 */

           b = mc.set("neea:testDaF:ksIdno", 900, "someObject");

           if (b.get().booleanValue() == true) {

              mc.shutdown();

           }

       } catch (Exception ex) {

           ex.printStackTrace();

       }

       // 取得對象

        try {

           /* 建立MemcachedClient 實例,並指定memcached服務的IP地址和端口號 */

           MemcachedClient mc = new MemcachedClient(new InetSocketAddress("10.11.15.222", 10000));

           /* 按照key值從memcached中查找緩存,不存在則返回null */

           Object b = mc.get("neea:testDaF:ksIdno");

           System.out.println(b.toString());

           mc.shutdown();

       } catch (Exception ex) {

           ex.printStackTrace();

       }

    }

}


3)      xmemcached 

Xmemcached的官方網址是:http://code.google.com/p/xmemcached/,可以從其官網上下載最新版本的1.2.4來使用。地址是:http://xmemcached.googlecode.com/files/xmemcached-1.2.4-src.tar.gz

示例代碼如下:

package temp;

 

import java.io.IOException;

import java.util.concurrent.TimeoutException;

 

import net.rubyeye.xmemcached.utils.AddrUtil;

import net.rubyeye.xmemcached.MemcachedClient;

import net.rubyeye.xmemcached.MemcachedClientBuilder;

import net.rubyeye.xmemcached.XMemcachedClientBuilder;

import net.rubyeye.xmemcached.exception.MemcachedException;

 

public class TestXMemcache {

    public static void main(String[] args) {

       MemcachedClientBuilder builder = new XMemcachedClientBuilder(AddrUtil

              .getAddresses("10.11.15.222:10000"));

       MemcachedClient memcachedClient;

       try {

           memcachedClient = builder.build();

      

           memcachedClient.set("hello", 0, "Hello,xmemcached");

           String value = memcachedClient.get("hello");

           System.out.println("hello=" + value);

           memcachedClient.delete("hello");

           value = memcachedClient.get("hello");

           System.out.println("hello=" + value);

           // close memcached client

           memcachedClient.shutdown();

       } catch (MemcachedException e) {

           System.err.println("MemcachedClient operation fail");

           e.printStackTrace();

       } catch (TimeoutException e) {

           System.err.println("MemcachedClient operation timeout");

           e.printStackTrace();

       } catch (InterruptedException e) {

           // ignore

       }catch (IOException e) {

           System.err.println("Shutdown MemcachedClient fail");

           e.printStackTrace();

       }

    }

}

2.xMemcached遍歷所有key-value

/**
* XMemcached遍歷memcached的所有key
* @throws Exception 
*/
@Test
public void getAllKey() throws Exception{
InetAddress addr = InetAddress.getByName("10.1.1.100");
InetSocketAddress ia = new InetSocketAddress(addr, 11211);
MemcachedClient client = new XMemcachedClient(ia);
KeyIterator it = client.getKeyIterator(ia);
while(it.hasNext()) {
String key = it.next();
System.out.println("key:->"+key);
System.out.println("value:->"+client.get(key));
}

client.shutdown();
}

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