這次是Fotolog的經驗,傳說中比Flickr更大的網站,Fotolog在21臺服務器上部署了51個memcached實例,總計有254G緩存空間可用,緩存了多達175G的內容,這個數量比很多網站的數據庫都要大的多,原文是A Bunch of Great Strategies for Using Memcached and MySQL Better Together,我這里還是選擇性的翻譯以及按照我的理解補充,感謝Todd Hoff,總能給我們一些學習的案例,從這里也能看出國外技術的開放態度,不似我們,其實就那么點小九九還藏著掖著,好了,進入正題。
一、關于memcached
還不知道這個?那你去面試的時候要吃虧了,趕緊去官方網站看一下http://www.danga.com/memcached/,另外google一下用法,硬盤總是太慢,把數據存在內存里面吧,如果你只有一臺服務器,推薦用一下APC(Facebook在用)或者eaccelerator或者Xcache(國人開發的),這些產品單機效果更好,如果你需要分布式的緩存方案,那么用memcached吧。
二、memcached如何與mysql并肩作戰?
通過數據庫分片來解決數據庫寫擴展的問題把數據庫分片,部署到不同的服務器上,免得只有一個主服務器,寫操作成為瓶頸以及可能有的“單點故障”,一般的數據庫分片主要是按照業務來分,盡可能的拆分業務,不相干的都獨立起來做成服務也好
前端mysql和一堆memcached服務器來應付讀的問題應用程序首先從memcached中獲取數據,獲取不到再從數據庫中獲得并保存在memcached中,以前看過一篇文章說好的應用95%的數據從memcache的中獲得,3%的數據從mysql的query cache中獲得,剩下2%才去查表,對比一下你的應用,差距有多遠?
通過mysql復制(master-slave)來解決讀的問題
首先mysql數據庫通過master-slave讀寫分離,多個slave來應對應用程序讀的操作。
三、為什么不用mysql的query cache?
我們都知道mysql有個query cache,可以緩存上次查詢的結果,可實際上幫不上太多的忙,下面是mysql quety cache的不足:
只能有一個實例
意味著你能存儲內容的上限就是你服務器的可用內存,一臺服務器能有多少內存?你又能存多少呢?
只要有寫操作,mysql的query cache就失效
只要數據庫內容稍有改變,那怕改變的是其他行,mysql的query cache也會失效
mysql的query cache只能緩存數據庫數據行
意味著其他內容都不行,比如數組,比如對象,而memcached理論上可以緩存任何內容,甚至文件^_^
四、Fotolog的緩存技術
非確定性緩存你不確定你要的數據緩存中有沒有,你也不知道是不是過期了,于是你就試探性的問memcached,我要的什么什么數據你那有嗎?我可不要過期的數據啊,memcached告訴你說有并且給你,你就開心了,如果沒有呢,你就要從數據庫或者別的地方去獲取了,這是memcached典型的應用。主要應用在:1.復雜的數據需要多次讀取,你的數據庫做了分片處理,從多個數據庫中獲取數據并組合起來是一個非常大的開銷,你大可以把這些數據取出來之后存到memcached中
2.mysql query cache的一個好的替代方案,這樣數據庫其他部門改變了,只要自己沒改變就沒問題(注意數據庫更新的問題,后面會提到)
3.把關系或者列表緩存起來,比如某個欄目下的多篇文章列表
4.被多個頁面調用并且獲取起來很慢的數據,或者是更新很慢的數據,比如文章瀏覽排行榜
5.如果cache的開銷超過重新獲取的開銷,那么不要緩存它吧
6.標簽云和自動建議(類似google sugest)
例如:當一個用戶上傳一個圖片,這個用戶的好友頁面上都要列出這張圖片來,那么把它緩存起來吧。
潛在問題:
memcached消耗的主要是服務器內存,對CPU消耗很小,所以Fotolog把memcached部署在他們的應用服務器上(貌似我們也是這樣),他們遇到了CPU搞到90%的使用率(怎么會那么高?哪出問題了吧)、內存回收(這是個大問題)等等問題。
狀態緩存把應用服務的當前狀態存在memcached中主要應用在:1.“昂貴”的操作,開銷大的操作2.sessions會話,Flickr把session存在數據庫中,個人感覺還是存memcached比較“便宜”些,如果memecached服務器down掉了,那么重新登錄吧。
3.記錄用戶在線信息(我們也是這樣做的)
確定性緩存對于某些特定數據庫的全部內容,都緩存到memcached,有一個專門的應用服務來保障你要的數據都在memcached中,其他應用服務直接從memcached中獲取數據而不去取數據庫,因為數據庫已經全部保存到memcached中并保持同步。主要應用在:1.讀取伸展,所有的讀取都從memcached中獲得,數據庫沒有負載
2.”永不過期“(相對的)的數據,比如行政規劃數據,變動很小吧
3.經常調用的內容
4.用戶的認證信息
5.用戶的概要信息
6.用戶的參數設置
7.用戶當前常用的媒體文件列表,比如用戶的圖片
8.用戶登錄,不走數據庫,只走memcached(個人覺得這個不太好,登錄信息還是需要持久化的,用類似BDB這樣效果也不錯)
使用方式:
1.多個專門的緩存池而不是一個大的緩存服務器,多個緩存池保障了高可用性,一個緩存實例掛掉了走其他的緩存實例,所有的緩存實例掛掉了,走數據庫(估計數據庫抗不住^_^)
2.所有的緩存池都用程序來維護,比如數據庫有更新時,程序自動把更新后的內容同步到多個緩存實例中
3.服務器重啟之后,緩存要比網站先啟動,這就意味著當網站已經啟動了,所有的緩存都可用
4.讀取的請求可以負載均衡到多個緩存實例中去,高性能,高可靠性
潛在的問題:
1.你需要足夠多的內存來存儲那么多的數據
2.數據以行記錄數據,而memcached以對象來存儲數據,你的邏輯要把行列的數據轉換成緩存對象
3.要維護多個緩存實例非常麻煩,Fotolog用Java/Hibernate,他們自己寫了個客戶端來輪詢
4.管理多個緩存實例會增加應用程序的許多開銷,但這些開銷相對于多個緩存得到的好處來說算不了什么
主動緩存數據魔法般的出現在緩存中,當數據庫中有更新的時候,緩存立馬填充,更新的數據被調用的可能性更高(比如一篇新文章,看的的人當然多),是非確定性緩存的一種變形(原文是It’s non-deterministic caching with a twist.我覺得這樣翻譯怪怪的)。主要應用在:1.預填充緩存:讓memcached盡可能的少調用mysql如果內容不展現的話。
2.“預熱”緩存:當你需要跨數據中心復制的時候
使用步驟:s
1.解析數據庫更新的二進制日志,發現數據庫更新時對memcached也進行同樣的更新
2.執行用戶自定義函數,設置觸發器調用UDF更新,具體參考http://tangent.org/586/Memcached_Functions_for_MySQL.html
3.使用BLACKHOLE策略,傳說中Facebook也用mysql的Blackhole存儲引擎來填充緩存,寫到Blackhole的數據復制到緩存中,Facebook用這來設置數據作廢以及跨國界的復制,好處是數據庫的復制不走mysql,這就意味著沒有二進制日志以及對CPU使用不那么多(啊?難道通過memcached存儲二進制日志,然后復制到不同的數據庫?有經驗的同志在這個話題上可以補充。)
文件系統緩存把文件直接緩存在memcached中,哇,夠BT的,減輕NFS的負擔,估計只緩存那些過于熱門的圖片吧。
部分頁面內容緩存如果頁面的某些部分獲取起來非常費勁,以其緩存頁面的原始數據還不如把頁面的部分內容直接緩存起來直接調用
應用程序級別的復制通過API來更新緩存,API的執行細節如下:1.一個應用把數據寫到某個緩存實例,這個緩存實例把內容復制到其他緩存實例(memcached同步)2.自動獲得緩存池地址以及實例個數
3.同時對多個緩存實例更新
4.如果某個緩存實例down掉了,跳到下一個實例,直到更新成功
整個過程非常******以及低開銷
其他技巧1.多節點以應對”單點故障”2.使用熱備技術,當某個節點down掉了,另外一臺服務自動替換成它的IP,這樣客戶端不用更新memcached的IP地址3.memcached可以通過TCP/UDP訪問,持續連接可以減輕負載,系統設計成可同時承受1000個連接
4.不同的應用服務,不同的緩存服務器群
5.檢查一下你的數據大小是否匹配你分配的緩存,更多請參考http://download.tangent.org/talks/Memcached%20Study.pdf
6.不要考慮數據行緩存,緩存復雜的對象
7.不要在你的數據庫服務器上跑memcached,兩個都是吃內存的怪獸
8.不要被TCP延遲困擾,本地的TCP/IP對內存復制是做了優化的
9.盡可能的并行處理數據
10.并不是所有的memcached的客戶端都是一樣的,仔細研究你用的語言所對應的(好像php和memcached配合的不錯)
11.盡可能的是數據過期而不是使數據無效,memcached可以設定過期時間
12.選擇一個好的緩存標識key,比如更新的時候加上版本號
13.把版本號存儲在memcached中