第一节 Memcached分布式缓存入门
關于Memcached的博文太多了,以下是個人學習的收集整理。
本節討論問題:
- 簡單介紹與應用
- 下載安裝注意事項
- 簡單測試
- Memcached分布式原理
一、介紹與應用
???? 在常規的WEB開發下,基本都會利用到緩存用以降低對數據庫的壓力,提高訪問速度。有時候緩存的數據多了,并且其它站點也想獲取這些緩存數據時就出現在了問題。通常IIS站點都是以應用程序池劃分管理,同一個池下又可劃分多個應用程序域,不管是不同的應用程序域或是不同應用程序池,其之間的緩存都是無法相互訪問的。因此很多站點就會重復建立相同的緩存,以便訪問。但是,一旦一個站點的緩存被更新了,又如何通知其它站點更新呢。我記得Discuz.net中做法,是通過監控配置文件的修改來實現的,其原理就是一個站點緩存更新了,就去修改對應的配置文件中的項。其它站點監控到配置文件被修改,就去檢查哪一項目被改了,然后重新加載緩存。是不是不太靈活?如果緩存的數據要分布到其它服務器上,以降低對同一臺服務器的壓力,如何實現呢?緩存服務器又如何實現擴展呢?這便是我們這篇Memcached引入的原因。有做即時通訊,游戲大廳的還可以采用一下shuttler.net。
關于Memcached以下為摘自博文http://www.cnblogs.com/zjneter/archive/2007/07/19/822780.html
Memcached是什么?
???? ?Memcached是由Danga Interactive開發的,高性能的,分布式的內存對象緩存系統,用于在動態應用中減少數據庫負載,提升訪問速度。
Memcached能緩存什么?
???? 通過在內存里維護一個統一的巨大的hash表,Memcached能夠用來存儲各種格式的數據,包括圖像、視頻、文件以及數據庫檢索的結果等。
Memcached快么?
???? 非常快。Memcached使用了libevent(如果可以的話,在linux下使用epoll)來均衡任何數量的打開鏈接,使用非阻塞的網絡I/O,對內部對象實現引用計數(因此,針對多樣的客戶端,對象可以處在多樣的狀態), 使用自己的頁塊分配器和哈希表, 因此虛擬內存不會產生碎片并且虛擬內存分配的時間復雜度可以保證為O(1).。
Memcached的特點?
???? Memcached的緩存是一種分布式的,可以讓不同主機上的多個用戶同時訪問, 因此解決了共享內存只能單機應用的局限,更不會出現使用數據庫做類似事情的時候,磁盤開銷和阻塞的發生。
二、下載與安裝
服務端與For .net開發下載 可以參照這篇博文http://blog.csdn.net/cnkiminzhuhu/archive/2009/10/28/4739859.aspx
客戶端的版本比較多,并且不能互用,因為采用了壓縮機制,日志等功能,所以在選擇客戶端時要注意這些。
服務端源碼? 下載
a.windows下 直接使用memcached.exe 程序就可以了,也可以將此程序安裝為windows服務。安裝為windows服務后要通過telnet命令來操作服務端
命令行輸入 'c:\memcached\memcached.exe -d install'?
命令行輸入 'c:\memcached\memcached.exe -d start'?,該命令啟動 Memcached ,默認監聽端口為 11211
b.安裝為單一服務不方便管理,這里有借助于memcacheddotnet_clientlib開發的一款服務端管理工具
服務端管理工具 下載? 解壓安裝后工具里的memcached.exe比較老,可直接用最新的替換掉
我們來看一下服務端工具安裝后文件結構
運行服務端管理工具,創建memcached服務端,以下為演示步驟
1 服務端配置
2 添加Memcached服務
3 狀態觀察
4.查看Generate配置信息,提供給客戶端配置文件使用.
借助服務端管理工具可以方便的觀察,或者你也可以采用telnet方式訪問查看了。這樣服務端工作就進行了完了,接下來就是要選擇一款合的客戶端開發了
Windows / .NET
a. .Net memcached client??? 1.1.5版本測試一下。??? https://sourceforge.net/projects/memcacheddotnet?
b. .Net 2.0 memcached client 這款應用比較廣泛,不過好長時間沒有更新了,最后一次更新是在2009.10 (網上其它鏈接提供的下載版本太老了)
??? http://www.codeplex.com/EnyimMemcached
??? Client developed in .NET 2.0 keeping performance and extensibility in mind. (Supports consistent hashing.)?
????http://www.codeplex.com/memcachedproviders?? (PDF 文檔)
?? Current Release Memcached Providers 1.2(最后一版正式版)(1.2以后到1.4.4?for win32 應該都不是正式版了)
? - Walkthoughs on how to setup and use Memcached Cache Provider and Session State Provider is added to the Memcached Providers 1.2
?? 按照上面的意思Session State Provider is added 會話狀態保存的功能已經有了? 經過下載解壓后確認是有了這個功能,從1.2版本以后增加了SQL 腳本,即將Session保存到數據庫中了-_-|||。很多人擔心的Session問題終于有著落了。
c. BeIT Memcached Client (optimized C# 2.0)?? 這款最后一次更新時間是2010.8.4
??? http://code.google.com/p/beitmemcached?
d. jehiah
??? http://jehiah.cz/projects/memcached-win32?
經過一番比較,我還是比較看中a,b,c三款,分別下載下來測試一下吧。(鑒于服務端管理工具匹配還是推薦enyim比較好)
三、簡單測試
1.memcacheddonet client測試 1.1.5版本 源碼有SRC包
View Code public class MemcachedBench{
/// <summary>
/// Arguments:
/// arg[0] = the number of runs to do
/// arg[1] = the run at which to start benchmarking
/// </summary>
/// <param name="args"></param>
[STAThread]
public static void Main(String[] args)
{
int runs = 100;
int start = 200;
if(args.Length > 1)
{
runs = int.Parse(args[0]);
start = int.Parse(args[1]);
}
//設置服務器列表
string[] serverlist = { "172.16.76.98:11211", "172.16.0.21:11211", "172.16.125.76:11211", "172.16.125.76:11212" };
// initialize the pool for memcache servers 創建連接池
SockIOPool pool = SockIOPool.GetInstance();
//設置服務器列表
pool.SetServers(serverlist);
//初始化
pool.InitConnections = 3;
pool.MinConnections = 3;
pool.MaxConnections = 5;
pool.SocketConnectTimeout = 1000;
pool.SocketTimeout = 3000;
pool.MaintenanceSleep = 30;
pool.Failover = true;
pool.Nagle = false;
pool.Initialize();
// initialize the pool for memcache servers 全屬性注入
// SockIOPool pool = SockIOPool.Instance;
// pool.Servers = serverlist; //屬性方式配置//
// pool.InitConn = 5;
// pool.MinConn = 5;
// pool.MaxConn = 50;
// pool.MaintSleep = 30;
// pool.SocketTO = 1000;//
// pool.Nagle = false;
// pool.Initialize();
// // get client instance
MemcachedClient mc = new MemcachedClient();
mc.EnableCompression = false; //是否啟用壓縮(通過ICSharpCode.SharpZipLib對存儲的數據壓縮)
// MemcachedClient mc = new MemcachedClient();
// mc.CompressEnable = false;
// mc.CompressThreshold = 0;
// mc.Serialize = true; //新的類中已沒有此屬性了,是默認幫你序列了?還是要自己實現呢?
string keyBase = "testKey";
string obj = "This is a test of an object blah blah es, serialization does not seem to slow things down so much. The gzip compression is horrible horrible performance, so we only use it for very large objects. I have not done any heavy benchmarking recently";
//循環記時往服務器緩存上插入數據 等會我們要觀察一下數據都存到哪個服務器上的Memcached server上了
long begin = DateTime.Now.Ticks;
for(int i = start; i < start+runs; i++)
{
mc.Set(keyBase + i, obj);
}
long end = DateTime.Now.Ticks;
long time = end - begin;
//計算存儲這些數據花了多長時間
Console.WriteLine(runs + " sets: " + new TimeSpan(time).ToString() + "ms");
//開始取數據,并記時
begin = DateTime.Now.Ticks;
int hits = 0;
int misses = 0;
for(int i = start; i < start+runs; i++)
{
string str = (string) mc.Get(keyBase + i);
if(str != null)
++hits; //成功取到數據
else
++misses; //丟失次數
}
end = DateTime.Now.Ticks;
time = end - begin;
//獲取這些數據花了多長時間
Console.WriteLine(runs + " gets: " + new TimeSpan(time).ToString() + "ms");
Console.WriteLine("Cache hits: " + hits.ToString());
Console.WriteLine("Cache misses: " + misses.ToString());
Console.WriteLine("--------------------------------------------------------\r\n");
Console.WriteLine("各服務器狀態:");
Console.WriteLine("-------------------------------------------------------");
IDictionary stats = mc.Stats();
foreach(string key1 in stats.Keys)
{
Console.WriteLine(key1);
Hashtable values = (Hashtable)stats[key1];
foreach(string key2 in values.Keys)
{
Console.WriteLine(key2 + ":" + values[key2]);
}
Console.WriteLine("-------------------------------------------------------");
}
//從這里可以看出SockIOPool應該建立了一張HashTable去管理所有連接池實例
SockIOPool.GetInstance().Shutdown();
Console.ReadLine();
}
分別設置了3臺,4臺,5臺服務器測試了3次,測試結果如下:
?
100條數據都確實存上去成功了,但是取數據命中率會隨著服務器增多急劇下降!才幾臺測試服務器,結果就如此差!問題出在哪里了呢? 服務器的memcached.exe太老了? 還是看一下memcached的實現原理了
這里有我之前下載的一版memcached的原理介紹 下載
里面提到查找服務器端數據的算法 是求余算法 ,而這中算法的命中率很差,并且隨便服務器節點的變動(增加或刪除節點)命中率急劇下降。
難道是這個原因? 了解到memcached的客戶端算法已經修改為Consistent Hashing算法,難道是我下載的客戶端版本確實很老了? 順便說一下這個Consistent Hashing算法是將服務器按環形分布在一個圓上,按我個人理解,服務器數量越多,環形分布越相對穩定,這個時候增刪服務器對定位的影響都比較小。在之后兩個客戶端的版本再測試一次看看結果,這節就到這里吧。附一張用MemcacheD Manager監控圖
Memcached分布式原理由于測試讀取數據的命中率太差,去查閱了一下Memcached的分布式原理。
先看一下應用場景
?
?第一次訪問先從數據庫中得到數據并保存到緩存中,第二次再讀數據就從緩存中獲取,這是正常情情,當第二次沒有命中數據?這個時候你是否回數據庫中讀取數據呢?讀取數據后,你是否還要保存到緩存中呢,但這個數據緩存中又是存在的,如何處理呢? 這就是Memcached客戶端沒有命中數據導致的后果。
我們來看一下Memcached的原理:
memcached雖然稱為“分布式”緩存服務器,但服務器端并沒有“分布式”功能,而是完全由客戶端程序庫實現的。服務端之間沒有任何聯系,數據存取都是通過客戶端的算法實現的。客戶端初始化的獲取所有服務器的哈希列表,當需要存取數據就會檢索這個哈希列表查找到對應的服務器。看下圖
當客戶端要存取數據時,首先會通過算法查找自己維護到的服務器哈希列表,找到對應的服務器后,再將數據存往指定服務器。這里關鍵點是使用了什么算法!
這個問題也不追查,接著往下看,我來再去取原先這個數據
查找數據的原理和存取的原理是一樣,首先通過算法在維護的哈希列表查到對應服務器,然后再去指定服務器讀取數據。那問題來了,他是如何準確的找到這臺服務器的呢?算法,算法就是他的原因,只要你在存和取的時候使用的算法是一樣的,那算法計算的結果也是一致的,所以就可以正確的找到服務器了。
那為什么我們在第三節的測試中,命中率會如此之差呢?
我們使用的Memcachedonet client 老版本使用的是求余算法,我們來看看這個求余算法的定義--“根據服務器臺數的余數進行分散”。即求得鍵的整
數哈希值,再除以服務器臺數,根據其余數來選擇服務器。我們在存數據的時候,計算出這個數據鍵的CRC值,用這個值除以服務器臺數求得余數來存往指定的服務器。那反過來取數據依然是這個算法,那結果肯定是一致的。問題是,為什么不同臺數的服務器測試中,命中率會變化這么大呢。余數計算的方法簡單,數據的分散性也相當優秀,但也有其缺點。那就是當添加或移除服務器時,緩存重組的代價相當巨大。添加服務器后,余數就會產生巨變,這樣就無法獲取與保存時相同的服
務器,從而影響緩存的命中率。因為增刪服務器后,數據鍵的CRC值是不變的,但是服務器的臺數變了,導致求余的結果也發生變化了,從而影響了命中率。
我們再來看一下改進的Consistent Hashing算法,可以確定是的,Memcachedonet的版本是沒有采用這個算法。
Consistent Hashing如下所示:首先求出memcached服務器(節點)的哈希值,并將其配置到0~2的32次方的圓(continuum)上。然后用同樣的方法求出存儲數據的鍵的哈希值,并映射到圓上。然后從數據映射到的位置開始順時針查找,將數據保存到找到的第一個服務器上。如果超過2的32次方仍然找不到服務器,就會保存到第一臺memcached服務器上。
當從上圖的狀態中添加一臺memcached服務器。余數分布式算法由于保存鍵的服務器會發生巨大變化而影響緩存的命中率,但Consistent Hashing中,只有在continuum上增加服務器的地點逆時針方向的第一臺服務器上的鍵會受到影響。如下圖
?從上圖可以看到,添加新的節點5時并不會重新分布所有節點,而是在之前的基礎上某個位置插入新的節點,這樣保證了整體的分布沒有發生太大變化,并且順時針方向的沒有影響,逆時針方向的從第一臺就開始有影響了。因此,Consistent Hashing最大限度地抑制了鍵的重新分布。但是這樣的誤差還是有的,因為根據服務器的哈希值來分布本身就是不均勻的。后面有提到改進的Consistent Hashing算法,即在圓環上預先分布為每臺服務器分布一定數量的虛定擬節點,相當于我們均勻分布了圓環上的節點,當有節點增加或刪除時都是在指定的位置上進行的就抑制了分布不均勻,最大限度地減小服務器增減時的緩存重新分。使用Consistent Hashing算法的memcached客戶端函數庫進行測試的結果是,由服務器臺數(n)和增加的服務器臺數(m)計算增加服務器后的命中率計算公式如下:(1 n/(n+m)) * 100
(參考之前提供下載的PDF原理一文)
???? memcachedonet 使用的是余數算法,可能是導致誤差的原因。在下一節中,我們來學習一下enyim.client(memcachedproviders),并進行相關測試。
轉載于:https://www.cnblogs.com/aaa6818162/archive/2011/11/20/2255820.html
總結
以上是生活随笔為你收集整理的第一节 Memcached分布式缓存入门的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: CorelDRAWX4的VBA插件开发(
- 下一篇: OneNote 安装代码高亮插件 Not