背景:公司項目中使用java和memcache相結合來搭建緩存,因此要了解下緩存的基礎知識!java
什麼是Memcache?mysql
Memcache集羣環境下緩存解決方案linux
Memcache是一個高性能的分佈式的內存對象緩存系統,經過在內存裏維護一個統一的巨大的hash表,它可以用來存儲各類格式的數據,包括圖像、視頻、文件以及數據庫檢索的結果等。簡單的說就是將數據調用到內存中,而後從內存中讀取,從而大大提升讀取速度。 spring
Memcache是danga的一個項目,最先是LiveJournal 服務的,最初爲了加速 LiveJournal 訪問速度而開發的,後來被不少大型的網站採用。 sql
Memcached是以守護程序方式運行於一個或多個服務器中,隨時會接收客戶端的鏈接和操做數據庫
爲何會有Memcache和memcached兩種名稱?
其實Memcache是這個項目的名稱,而memcached是它服務器端的主程序文件名,知道個人意思了吧。一個是項目名稱,一個是主程序文件名,在網上看到了不少人不明白,因而混用了。apache
Memcached是高性能的,分佈式的內存對象緩存系統,用於在動態應用中減小數據庫負載,提高訪問速度。Memcached由Danga Interactive開發,用於提高LiveJournal.com訪問速度的。LJ每秒動態頁面訪問量幾千次,用戶700萬。Memcached將數據庫負載大幅度下降,更好的分配資源,更快速訪問。windows
Windows下的Memcache安裝api
1. 安裝緩存
在這裏簡單介紹一下Windows下的Memcache的安裝:
1. 下載memcache的windows穩定版,解壓放某個盤下面,好比在c:\memcached
2. 在終端(也即cmd命令界面)下輸入‘c:\memcached\memcached.exe -d install’安裝
3. 再輸入:‘c:\memcached\memcached.exe -d start’啓動。NOTE: 之後memcached將做爲windows的一個服務每次開機時自動啓動。這樣服務器端已經安裝完畢了。
2. memcached的基本設置
-p 監聽的端口 -l 鏈接的IP地址, 默認是本機 -d start 啓動memcached服務 -d restart 重起memcached服務 -d stop|shutdown 關閉正在運行的memcached服務 -d install 安裝memcached服務 -d uninstall 卸載memcached服務 -u 以的身份運行 (僅在以root運行的時候有效) -m 最大內存使用,單位MB。默認64MB -M 內存耗盡時返回錯誤,而不是刪除項 -c 最大同時鏈接數,默認是1024 -f 塊大小增加因子,默認是1.25 -n 最小分配空間,key+value+flags默認是48 -h 顯示幫助
3. 設置Memcache緩存大小和端口
Memcache的默認啓動時的參數可能不知足實際生產環境的須要,因而就想到直接修改windows服務的啓動參數,操做以下:
打開註冊表,找到:HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\memcached Server
其中的ImagePath項的值爲: c:\memcached\memcached.exe" -d runservice
改爲:c:\memcached\memcached.exe" -p 12345 -m 128 -d runservice
其中,-p就是端口,-m就是緩存大小,以M爲單位。
linux下的Memcache安裝
1)安裝Memcache服務端
sudo apt-get install memcached
安裝完Memcache服務端之後,咱們須要啓動該服務:
memcached -d -m 128 -p 11111 -u root
這裏須要說明一下memcached服務的啓動參數:
-p 監聽的端口
-l 鏈接的IP地址, 默認是本機 -d start 啓動memcached服務 -d restart 重起memcached服務 -d stop|shutdown 關閉正在運行的memcached服務 -d install 安裝memcached服務 -d uninstall 卸載memcached服務 -u 以的身份運行 (僅在以root運行的時候有效) -m 最大內存使用,單位MB。默認64MB -M 內存耗盡時返回錯誤,而不是刪除項 -c 最大同時鏈接數,默認是1024 -f 塊大小增加因子,默認是1.25-n 最小分配空間,key+value+flags默認是48 -h 顯示幫助
查看是否創建成功
telnet測試memcached
telnet 192.168.1.2 11211
Trying 192.168.1.2...
Connected to 192.168.1.2.
Escape character is '^]'
查看版本
version
…
對Memcached緩存服務的狀態查詢,能夠先telnet鏈接上服務:telnet 127.0.0.1 11211 ,而後使用 stats命令查看緩存服務的狀態,會返回以下的數據:
time: 1255537291 服務器當前的unix時間戳
total_items: 54 從服務器啓動之後存儲的items總數量 connection_structures: 19 服務器分配的鏈接構造數 version: 1.2.6 memcache版本 limit_maxbytes: 67108864 分配給memcache的內存大小(字節) cmd_get: 1645 get命令(獲取)總請求次數 evictions: 0 爲獲取空閒內存而刪除的items數(分配給memcache的空間用滿後需 要刪除舊的items來獲得空間分配給新的items) total_connections: 19 從服務器啓動之後曾經打開過的鏈接數 bytes: 248723 當前服務器存儲items佔用的字節數 threads: 1 當前線程數 get_misses: 82 總未命中次數 pointer_size: 32 當前操做系統的指針大小(32位系統通常是32bit) bytes_read: 490982 總讀取字節數(請求字節數) uptime: 161 服務器已經運行的秒數 curr_connections: 18 當前打開着的鏈接數 pid: 2816 memcache服務器的進程ID bytes_written: 16517259 總髮送字節數(結果字節數) get_hits: 1563 總命中次數 cmd_set: 54 set命令(保存)總請求次數 curr_items: 28 服務器當前存儲的items數量
ps:windows下一樣能夠。
Ok,安裝memcached1.4.5成功。
一些memcache相關命令能夠慢慢搜索積累。
[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 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的值成功 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:
static {
String[] serverlist = { "server1.com:port", "server2.com:port" }; SockIOPool pool = SockIOPool.getInstance(); pool.setServers(serverlist); pool.initialize(); }
建立一個client對象:
MemCachedClient mc = new MemCachedClient();
建立一個緩存:
MemCachedClient mc = new MemCachedClient();
String key = "cacheKey1"; Object value = SomeClass.getObject(); mc.set(key, value);
經過key刪除一個緩存:
MemCachedClient mc = new MemCachedClient();
String key = "cacheKey1"; mc.delete(key);
經過key獲取緩存對象:
MemCachedClient mc = new MemCachedClient();
String key = "key"; Object value = mc.get(key);
獲取多個緩存對象:
MemCachedClient mc = new MemCachedClient();
String[] keys = { "key", "key1", "key2" }; Map<Object> values = mc.getMulti(keys);
刷新所有緩存:
MemCachedClient mc = new MemCachedClient();
mc.flushAll();
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的集成、客戶端鏈接池、可擴展性好等。
下面給出這三種客戶端的示例程序。
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(); } } }