1、概念html
Memcached是danga.com開發的一套分佈式內存對象緩存系統,用於在動態系統中減小數據庫負載,提高性能。java
2、原理mysql
Memcached有兩個核心組件組成:服務端(ms)和客戶端(mc)。首先mc拿到ms列表,並對key作hash轉化,根據hash值肯定kv對所存的ms位置。而後在一個memcached的查詢中,mc先經過計算key的hash值來肯定kv對所處在的ms位置。當ms肯定後,客戶端就會發送一個查詢請求給對應的ms,讓它來查找確切的數據。由於ms之間並無護衛備份,也就不須要互相通訊,因此效率較高。
c++
3、適用場合
1.分佈式應用。因爲memcached自己基於分佈式的系統,因此尤爲適合大型的分佈式系統。
2.數據庫前段緩存。數據庫經常是網站系統的瓶頸。數據庫的大併發量訪問,經常形成網站內存溢出。固然咱們也可使用Hibernate的緩存機制。但memcached是基於分佈式的,並可獨立於網站應用自己,因此更適合大型網站進行應用的拆分。
3.服務器間數據共享。舉例來說,咱們將網站的登陸系統、查詢系統拆分爲兩個應用,放在不一樣的服務器上,並進行集羣,那這個時候用戶登陸後,登陸信息如何從登陸系統服務器同步到查詢系統服務器呢?這時候,咱們即可以使用memcached,登陸系統將登陸信息緩存起來,查詢系統即可以得到登陸信息,就像獲取本地信息同樣。
4、客戶端版本算法
Memcached Client目前有一下四種:
Memcached Client for Java,比 SpyMemcached更穩定、更早、更普遍;
SpyMemcached,比 Memcached Client for Java更高效;
XMemcached,比 SpyMemcache併發效果更好。
alisoft-xplatform-asf-cache阿里軟件的架構師岑文初進行封裝的。裏面的註釋都是中文的,比較好
spring
5、服務器端sql
安裝數據庫
這裏介紹windows環境的安裝。
1.下載memcache的windows穩定版,解壓放某個盤下面,好比在c:\memcached
2.在cmd下輸入 'c:\memcached\memcached.exe -d install' 安裝
3.再輸入: 'c:\memcached\memcached.exe -d start' 啓動。
之後memcached將做爲windows的一個服務每次開機時自動啓動。這樣服務器端已經安裝完畢了。windows
內存分配api
默認狀況下,ms是用一個內置的叫「塊分配器」的組件來分配內存的。捨棄c++標準的malloc/free的內存分配,而採用塊分配器的主要目的 是爲了不內存碎片,不然操做系統要花費更多時間來查找這些邏輯上連續的內存塊(其實是斷開的)。用了塊分配器,ms會輪流的對內存進行大塊的分配,並 不斷重用。固然因爲塊的大小各不相同,當數據大小和塊大小不太相符的狀況下,仍是有可能致使內存的浪費。
同時,ms對key和data都有相應的限制,key的長度不能超過250字節,data也不能超過塊大小的限制 --- 1MB。
由於 mc所使用的hash算法,並不會考慮到每一個ms的內存大小。理論上mc會分配機率上等量的kv對給每一個ms,這樣若是每一個ms的內存都不太同樣,那可能 會致使內存使用率的下降。因此一種替代的解決方案是,根據每一個ms的內存大小,找出他們的最大公約數,而後在每一個ms上開n個容量=最大公約數的 instance,這樣就等於擁有了多個容量大小同樣的子ms,從而提供總體的內存使用率。
緩存策略
當ms的hash表滿了以後,新的插入數據會替代老的數據,更新的策略是LRU(最近最少使用),以及每一個kv對的有效時限。Kv對存儲有效時限是在mc端由app設置並做爲參數傳給ms的。
同時ms採用是偷懶替代法,ms不會開額外的進程來實時監測過期的kv對並刪除,而是當且僅當,新來一個插入的數據,而此時又沒有多餘的空間放了,纔會進行清除動做。
6、範例
1.加載commons-pool-1.5.6.jar、java_memcached-release_2.6.6.jar、slf4j-api-1.6.1.jar、slf4j-simple-1.6.1.jar
2.建立memcached工具類:
- public class MemcachedUtil {
-
- /**
- * memcached客戶端單例
- */
- private static MemCachedClient cachedClient = new MemCachedClient();
-
- /**
- * 初始化鏈接池
- */
- static {
- //獲取鏈接池的實例
- SockIOPool pool = SockIOPool.getInstance();
-
- //服務器列表及其權重
- String[] servers = {"127.0.0.1:11211"};
- Integer[] weights = {3};
-
- //設置服務器信息
- pool.setServers(servers);
- pool.setWeights(weights);
-
- //設置初始鏈接數、最小鏈接數、最大鏈接數、最大處理時間
- pool.setInitConn(10);
- pool.setMinConn(10);
- pool.setMaxConn(1000);
- pool.setMaxIdle(1000*60*60);
-
- //設置鏈接池守護線程的睡眠時間
- pool.setMaintSleep(60);
-
- //設置TCP參數,鏈接超時
- pool.setNagle(false);
- pool.setSocketTO(60);
- pool.setSocketConnectTO(0);
-
- //初始化並啓動鏈接池
- pool.initialize();
-
- //壓縮設置,超過指定大小的都壓縮
- // cachedClient.setCompressEnable(true);
- // cachedClient.setCompressThreshold(1024*1024);
- }
-
- private MemcachedUtil(){
- }
-
- public static boolean add(String key, Object value) {
- return cachedClient.add(key, value);
- }
-
- public static boolean add(String key, Object value, Integer expire) {
- return cachedClient.add(key, value, expire);
- }
-
- public static boolean put(String key, Object value) {
- return cachedClient.set(key, value);
- }
-
- public static boolean put(String key, Object value, Integer expire) {
- return cachedClient.set(key, value, expire);
- }
-
- public static boolean replace(String key, Object value) {
- return cachedClient.replace(key, value);
- }
-
- public static boolean replace(String key, Object value, Integer expire) {
- return cachedClient.replace(key, value, expire);
- }
-
- public static Object get(String key) {
- return cachedClient.get(key);
- }
-
- }
3. 建立須要緩存的對象:
- public class UserBean implements Serializable {
-
- private static final long serialVersionUID = 9174194101246733501L;
-
- private String username;
-
- private String password;
-
- public UserBean(String username, String password) {
- this.username = username;
- this.password = password;
- }
-
- public String getUsername() {
- return username;
- }
-
- public void setUsername(String username) {
- this.username = username;
- }
-
- public String getPassword() {
- return password;
- }
-
- public void setPassword(String password) {
- this.password = password;
- }
-
- @Override
- public int hashCode() {
- final int prime = 31;
- int result = 1;
- result = prime * result
- + ((password == null) ? 0 : password.hashCode());
- result = prime * result
- + ((username == null) ? 0 : username.hashCode());
- return result;
- }
-
- @Override
- public boolean equals(Object obj) {
- if (this == obj)
- return true;
- if (obj == null)
- return false;
- if (getClass() != obj.getClass())
- return false;
- UserBean other = (UserBean) obj;
- if (password == null) {
- if (other.password != null)
- return false;
- } else if (!password.equals(other.password))
- return false;
- if (username == null) {
- if (other.username != null)
- return false;
- } else if (!username.equals(other.username))
- return false;
- return true;
- }
-
- @Override
- public String toString() {
- return "username:" + username + ",password:" + password;
- }
- }
4.建立測試用例:
- public class MemcachedUtilTest {
-
- @Test
- public void testMemcached() {
- MemcachedUtil.put("hello", "world", 60);
- String hello = (String) MemcachedUtil.get("hello");
- Assert.assertEquals("world", hello);
-
- for(int i = 0; i < 10000000; ++i) {
- UserBean userBean = new UserBean("Jason" + i, "123456-" + i);
- MemcachedUtil.put("user" + i, userBean, 60);
- Object obj = MemcachedUtil.get("user" + i);
- Assert.assertEquals(userBean, obj);
- }
- }
- }
5.經過spring注入memcached:
- <?xml version="1.0" encoding="UTF-8"?>
- <beans xmlns="http://www.springframework.org/schema/beans"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://www.springframework.org/schema/beans
- http://www.springframework.org/schema/beans/spring-beans.xsd">
-
- <bean id="memcachedPool" class="com.danga.MemCached.SockIOPool"
- factory-method="getInstance" init-method="initialize">
- <constructor-arg>
- <value>neeaMemcachedPool</value>
- </constructor-arg>
- <property name="servers">
- <list>
- <value>127.0.0.1:11211</value>
- </list>
- </property>
- <property name="initConn">
- <value>20</value>
- </property>
- <property name="minConn">
- <value>10</value>
- </property>
- <property name="maxConn">
- <value>50</value>
- </property>
- <property name="nagle">
- <value>false</value>
- </property>
- <property name="socketTO">
- <value>3000</value>
- </property>
- </bean>
- <bean id="memcachedClient" class="com.danga.MemCached.MemCachedClient">
- <constructor-arg>
- <value>neeaMemcachedPool</value>
- </constructor-arg>
- </bean>
- </beans>
6.建立測試用例:
- public class MemcachedSpringTest {
-
- private MemCachedClient cachedClient;
-
- @Before
- public void init() {
- ApplicationContext context = new ClassPathXmlApplicationContext("com/luo/config/beans.xml");
- cachedClient = (MemCachedClient)context.getBean("memcachedClient");
- }
-
- @Test
- public void testMemcachedSpring() {
- UserBean user = new UserBean("luo", "hi");
- cachedClient.set("user", user);
- UserBean cachedBean = (UserBean)user;
- Assert.assertEquals(user, cachedBean);
- }
- }
7、注意點
第1、memcached是在服務器端的內存中緩存對象的,不是緩存或硬盤;
第2、memcached的pool能夠關聯多個server,
String[] servers = {"10.20.185.12:11001","10.20.185.25:11001"};
Integer[] weights = {3,7};
該配置表示30%的緩存在放在第一臺服務器,70%的將放在第二臺服務器,這樣即可以充分利用不一樣服務器的內存了;
第3、我最困惑的是client是如何獲得相應的pool的,後然看了點源碼才知道是這樣的。client是經過pool的name關聯到某個pool的,上面的例子中在SockIOPool pool = SockIOPool.getInstance(); 和MemCachedClient client=new MemCachedClient();雖然都沒寫poolName,但就是新建了一個」default「的pool,而後client關聯到了這個」default「的pool。固然咱們在新建這兩個對象時能夠給定具體的poolName。
下一篇:memcached真實項目中的應用http://blog.csdn.net/sup_heaven/article/details/32728477
參考文章:
http://snowolf.iteye.com/blog/1471805
http://my249645546.iteye.com/blog/1420061
http://blog.csdn.NET/loujinhe/article/details/8491673?reload
http://hzp.iteye.com/blog/1872664