Memcached是一個高性能的分佈式內存對象緩存系統,用於動態Web應用以減輕數據庫負載。html
它經過在內存中緩存數據和對象來減小讀取數據庫的次數,從而提供動態、數據庫驅動網站的速度。java
Memcached基於一個存儲鍵值對的hashmap。其守護進程(daemon )是用C寫的,可是客戶端能夠用任何語言來編寫,並經過memcached協議與守護進程通訊。算法
下面來了解下Memcached怎麼用~~數據庫
到http://code.jellycan.com/memcached/windows
下載memcached的windows版緩存
再下載一個java_memcached-release.jar服務器
解壓memcached-1.2.5-win32-bin.zip,CMD進入其目錄,而後執行以下命令:網絡
c:>memcached.exe -d install c:>memcached.exe -l 127.0.0.1 -m 32 -d start
第一行是安裝memcached成爲服務,這樣才能正常運行,不然運行失敗!架構
第二行是啓動memcached的,這裏簡單的只分配32M內存了(默認64M),而後監聽本機端口和以守護進行運行。socket
執行完畢後,咱們就能夠在任務管理器中看到memcached.exe這個進程了。
若是想要在同一臺Windows機器中安裝2個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
說明:
上面的例子是對於基本數據類型,對於普通的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,註釋掉的那一行把註釋去掉就能夠了。
-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的優點,那固然是:速度快,操做簡便,易擴展
不足的話,主要有2點:
若是數據庫的訪問量比較大,就須要提早作好準備,以便應對在memcached中止時發生的負載問題。
若是能在中止memcached以前,把數據複製到其餘的server就行了。恩,這個能夠經過repcached來實現。
repcached是日本人開發的實現memcached複製功能,
它是一個單master、單slave的方案,但它的master/slave都是可讀寫的,並且能夠相互同步
若是master壞掉,slave偵測到鏈接斷了,它會自動listen而成爲master