于吉吉的技術(shù)博客

          建造高性能門戶網(wǎng)

            BlogJava :: 首頁 :: 新隨筆 :: 聯(lián)系 :: 聚合  :: 管理 ::
            65 隨筆 :: 6 文章 :: 149 評論 :: 0 Trackbacks
          <2010年12月>
          2829301234
          567891011
          12131415161718
          19202122232425
          2627282930311
          2345678

          公告

          本博客的文章,未注明轉(zhuǎn)載字樣的均為原創(chuàng),本著好記性不如爛博客的精神,QQ是34174409,歡迎指教和討論

          留言簿(12)

          隨筆分類

          隨筆檔案

          文章檔案

          收藏夾

          blog

          開源社區(qū)

          活動

          積分與排名

          最新評論

          大名鼎鼎的分布式緩存系統(tǒng)memcached,在開源社區(qū)中可謂是無人不知無人不曉,memcached支持分布式的橫向擴展,但memcached的服務(wù)端卻是單實例,并無"分布式"的功能,所謂的分布式只是客戶端在存儲的主鍵做分布的存儲;還有memcached組件緩存對象,如果組件無進行序列化必定無法正確取得數(shù)據(jù);如何使用memcached的java組件來監(jiān)控memcached的運行狀態(tài);以上等等的問題是我在日常的工作中碰到并解決的,拿出來跟大家做個分享^_^



          對象的序列化
          首先memcached是獨立的服務(wù)器組件,獨立于應(yīng)用系統(tǒng),從客戶端保存和讀取對象到memcached是必須通過網(wǎng)絡(luò)傳輸,因為網(wǎng)絡(luò)傳輸都是二進制的數(shù)據(jù),所以所有的對象都必須經(jīng)過序列化,否則無法存儲到memcahced的服務(wù)器端.
          正如我們以往在集群中應(yīng)用的序列化一樣,memcached的序列化的性能也是往往讓大家頭疼,如果我們對我們的domain類進行對象的序列化,第一次序列化時間會比較長,但后續(xù)會優(yōu)化,也就是說序列化最大的消耗不是對象的序列化,而是類的序列化,如果存儲的只是一個String對象,這種情況是最理想的,省去了序列化的操作.實際上String對象本身已經(jīng)實現(xiàn)了序列化接口,無法我們再次去進行序列化操作.



          memcached的原子加法
          記錄一下上次犯得一個錯誤
          <%
          static int count = 0;
          count
          ++;
          MemCachedClient mcc 
          = new MemCachedClient();
          mcc.add(
          "test.html", count);
          %>

          這段代碼的作用是將test.html的用戶訪問次數(shù)保存到memcached中,粗劣一看好像并無錯誤,但在高并發(fā)時的出來的訪問數(shù)據(jù)一定是小于實際的訪問數(shù)量,當(dāng)然這里并不是memcached對象鎖的問題,主要還是程序中線程的同步問題,但是如果使用java的synchronized或lock那么在性能上肯定是無法忍受的,memcached客戶端組件帶有原子性的加法和減法

          <%
          MemCachedClient mcc 
          = new MemCachedClient();
          System.out.println(mcc.addOrIncr(
          "test.html",1));
          %>

          long addORIncr(String key,long inc)為計數(shù)器值增加inc,如果計數(shù)器不存在,則保存inc為計數(shù)器的值,必須注意的是服務(wù)器端不會對超過2的32次方的行為進行檢查




          分布式的mencached
          memcached雖然是屬于分布式的緩存服務(wù)器,但實際上memcached服務(wù)端之間并無分布式的功能,不會互相通信共享數(shù)據(jù),如何進行分布式,這完全是取決于客戶端的實現(xiàn)



          假設(shè)我們現(xiàn)在有三臺memcached服務(wù)器分別為node1,node2,node3,應(yīng)用程序要保存鍵名分別為"test1","test2","test3",客戶端實現(xiàn)的算法就是根據(jù)鍵名來決定保存數(shù)據(jù)的memcached服務(wù)器,我們將"test1"保存到node1,"test2"保存到node2,"test3"保存到node3,并且在讀取緩存數(shù)據(jù)也是通過一樣的算法從各臺服務(wù)器上讀取相應(yīng)的key,這樣通過一個最簡單的算法將不同的鍵保存到不同的服務(wù)器上,實現(xiàn)了memcached的分布式.
          但是這種算法很難確保每臺服務(wù)器得到較為平均的數(shù)據(jù)量,我們需要改變一下客戶端的算法,簡單來說,就是根據(jù)服務(wù)器的臺數(shù)的余數(shù)進行分散

          <%
          "
          test1".hashCode()%3
          %>

          根據(jù)key的java.lang.String.hashCode()取得散列值,再將值模服務(wù)器的臺數(shù)得到余數(shù)值,我們再根據(jù)這個余數(shù)值來判定這個key要存入哪一臺服務(wù)器,當(dāng)key的數(shù)量越來越大,對key的散列取模也會趨向平均,基本可以保證幾臺memcached服務(wù)器所存儲的緩存量趨向平均
          似乎很完美,余數(shù)計算的方法很簡單,數(shù)據(jù)的分散性也很優(yōu)秀,但也有其缺點,就是當(dāng)需要添加或移除服務(wù)器時,緩存的重組代價是相當(dāng)巨大的,添加或移除服務(wù)器時,余數(shù)就會發(fā)生變化,這樣就無法取到與原來緩存時相同的服務(wù)器.
          網(wǎng)上介紹的Consistent Hashing算法基本上可以解決這個問題,這里做個簡單的說明,首先是求出memcached服務(wù)器節(jié)點的哈希值,并將其配置到0-2的32次方的圓上,然后用同樣的方法求出存儲數(shù)據(jù)的鍵的哈希值,并映射到圓上.然后從數(shù)據(jù)映射到的位置開始順時針查找,將數(shù)據(jù)保存到找到的第一個服務(wù)器上.如果超過2的32次方仍然找不到服務(wù)器,就會保存到第一臺memcached服務(wù)器上


          從上圖的狀態(tài)中添加一臺memcached服務(wù)器。余數(shù)分布式算法由于保存鍵的服務(wù)器會發(fā)生巨大變化而影響緩存的命中率,但Consistent Hashing中,只有在continuum上增加服務(wù)器的地點逆時針方向的第一臺服務(wù)器上的鍵會受到影響



          幾種連接客戶端的對比
          目前java的memcached主要有Java-Memcached-Client,Xmemached,Spymemcached三種,這三個客戶端的性能測試可以看
          http://xmemcached.googlecode.com/svn/trunk/benchmark/benchmark.html


          請求的資源為64Bytes,在低并發(fā)Java-Memcached-Client是占有一定的優(yōu)勢,但在并發(fā)數(shù)超過100以后,Java-Memcached-Client是呈現(xiàn)直線下跌,并發(fā)數(shù)達到300已經(jīng)無法承受,Spymemcached和Xmemached表現(xiàn)相對穩(wěn)定,特別是Xmemached無論在低并發(fā)或高并發(fā)都保持優(yōu)秀的性能表現(xiàn)



          并發(fā)數(shù)固定為100時,在小文件的請求Java-Memcached-Client還是占有優(yōu)勢,當(dāng)隨著請求的size越來越大,三者趨向于同一點
          如果你對memcached訪問的負載不高,那么Java-Memcached-Client是一個不錯的選擇,如果你對memcached訪問的負載要求較高,推薦使用Xmemached,如果需要異步的批量處理,可以選擇Spymemcached,如果你什么都不知道,那么建議使用Xmemached,因為無論在何種情況,它都可以表現(xiàn)出較好的性能,雖然不是最好



          監(jiān)控memcached
          推薦使用nagios或cactis進行監(jiān)控,nagios沒有配置過,cactis是需要下載一個腳本插件
          這里推薦一個從網(wǎng)上淘來的php,只要把它放到你的機器中,當(dāng)然你的機器要支持php環(huán)境,將此php放入你的網(wǎng)頁訪問網(wǎng)絡(luò)就可以訪問
          下載
          http://www.aygfsteel.com/Files/dongbule/cacti/memcache.rar
          修改php以下幾個選項

          define('ADMIN_USERNAME','memcache');    // Admin Username
          define('ADMIN_PASSWORD','password');    // Admin Password

          $MEMCACHE_SERVERS[] = '192.168.1.100:11211'// add more as an array
          #
          $MEMCACHE_SERVERS[] = 'mymemcache-server2:11211'; // add more as an array

          監(jiān)控的平臺





          理解memcached的刪除機制
          memcached內(nèi)部不會監(jiān)視記錄是否過期,而是在get時查看記錄的時間戳,檢查記錄是否過期, 這種技術(shù)被稱為lazy(惰性)expiration.因此,memcached不會在過期監(jiān)視上耗費CPU時間
          memcached會優(yōu)先使用已超時的記錄的空間,并使用LRU算法來分配空間,因此當(dāng)memcached的內(nèi)存空間不足,就從最近違背使用的記錄中搜索,并將空間分配給新的記錄
          不過在某些情況下LRU機制會造成某些麻煩,如你并不想要淘汰已被緩存過的記錄,可以在memcached啟動時添加 -M 參數(shù)來禁止LRU,但這樣在memcached的內(nèi)存用盡時,memcached會返回錯誤,是否使用LRU,在于你的需求


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

          by 陳于喆
          QQ:34174409
          Mail: dongbule@163.com



          posted on 2010-12-08 15:00 陳于喆 閱讀(5620) 評論(4)  編輯  收藏 所屬分類: web開發(fā)緩存java

          評論

          # ugg shoes 2010-12-08 16:16 ugg shoes
          看不大懂  回復(fù)  更多評論
            

          # re: memcached一些應(yīng)用點滴 2010-12-08 17:13 寂寞程序員
          學(xué)習(xí)了  回復(fù)  更多評論
            

          # re: memcached一些應(yīng)用點滴 2010-12-11 15:37 jaedong
          很好的分享,謝謝.  回復(fù)  更多評論
            

          # re: memcached一些應(yīng)用點滴 2010-12-28 21:31 吳紅軍
          memcahced在PHP里用的特多,幾乎我每做的系統(tǒng)都有memcached支持,在php里用起來比Java里簡單的多!汗!  回復(fù)  更多評論
            

          主站蜘蛛池模板: 获嘉县| 吕梁市| 翁牛特旗| 盐津县| 当雄县| 鄂托克旗| 三原县| 无为县| 株洲县| 吐鲁番市| 宁城县| 玉林市| 马尔康县| 运城市| 昆山市| 津市市| 潍坊市| 临桂县| 正阳县| 鄱阳县| 鲁山县| 应城市| 沂水县| 新巴尔虎左旗| 康定县| 新宁县| 全南县| 西盟| 吴川市| 招远市| 习水县| 翼城县| 武胜县| 武安市| 益阳市| 乡城县| 静宁县| 滦平县| 郎溪县| 赤水市| 新丰县|