閱讀目錄: redis
以前有童鞋問到關於首次爲空的問題,這裏簡單補充下:windows
若是緩存數據量大的狀況下,預熱就麻煩些。好比LZ公司單在內存中的緩存大小都過G,每次預熱都須要數分鐘,假設放在應用進程內,對運維工做很是不方便的。若是有意外致使進程池回收,對用戶來講就是災難性的。因此須要把應用進程的數據緩存給單獨抽離出來存放,與應用解耦。瀏覽器
關於高併發的解決方案包括緩存更新策略可參見前幾篇博客的介紹。緩存
在網站架構演化中,這個階段就須要引入分佈式緩存了,好比memcached、redis。好處就很少講了,壞處就是速度慢。這裏速度慢是與本機內存緩存相比,跨機器通訊跟直接讀內存差的不是一數量級,對於併發量高、操做頻繁的數據就不適用了。網絡
因此把應用進程緩存的數據抽離出來,放在單獨進程中,給應用提供一層緩存。緩存的業務邏輯、併發處理在獨立進程中作,使用進程通訊進行交互。這樣不但解決了數據量大預熱的麻煩,還能解耦部分應用的業務。架構
另外單獨的進程也能夠供外部使用,好比以WCF服務的方式提供給其餘子系統使用。併發
缺點是跨進程讀取的速度比進程內讀取要稍慢。app
獨立進程與應用進程的幾種常見通訊方式:負載均衡
Namedpipe一種相對高效的進程通訊方式,支持局域網內通訊。運維
Service端:
var txt = File.ReadAllText("b.txt"); ServerPipeConnection PipeConnection = new ServerPipeConnection("MyPipe", 512, 512, 5000, false); Console.WriteLine("listening.."); while (true) { try { PipeConnection.Disconnect(); PipeConnection.Connect(); string request = PipeConnection.Read(); if (!string.IsNullOrEmpty(request)) { PipeConnection.Write(txt); if (request.ToLower() == "break") break; } } catch (Exception ex) { Console.WriteLine(ex.Message); break; } } PipeConnection.Dispose(); Console.Write("press any key to exit.."); Console.Read();
client端:
IInterProcessConnection clientConnection = new ClientPipeConnection("MyPipe", ".");
clientConnection.Connect();
var val = clientConnection.Read();
clientConnection.Close();
Wcf在原生namedpipe包裝了一下,使用起來更爲簡單方便。
Service端:
ServiceHost host = new ServiceHost( typeof (CacheService));
var NamePipe = new NetNamedPipeBinding();
host.AddServiceEndpoint(typeof(ICacheService), NamePipe, "net.pipe://localhost/CacheService");
host.Open();
Console.WriteLine("服務可用");
Console.ReadLine();
host.Close();
Client端:
ChannelFactory pipeFactory = new ChannelFactory(new NetNamedPipeBinding(), new EndpointAddress("net.pipe://localhost/CacheService")); ICacheService pipeProxy = pipeFactory.CreateChannel(); var obj=pipeProxy.GetVal();
共享內存是進程間通訊最快的一種方式,數據無需在進程間複製傳輸,直接開闢一塊公共內存,供其餘進程進行讀寫。
service端:
var mmf = MemoryMappedFile.CreateFromFile(@"a.txt", FileMode.Open, "cachea"); Console.ReadLine(); mmf.Dispose();
Client端:
var mmf = MemoryMappedFile.OpenExisting("cachea"); var accessor = mmf.CreateViewAccessor(0, 2000000);
accessor.ReadChar(1000); accessor.Dispose(); mmf.Dispose();
使用WcfTcp的方式,能夠供外部網絡使用。
Service端:
var ServiceHost host = new ServiceHost( typeof (CacheService)); host.AddServiceEndpoint(typeof (ICacheService), new NetTcpBinding(), "net.tcp://192.168.0.115:8057/CacheService/"); host.Open(); Console.WriteLine("服務可用"); Console.ReadLine(); host.Close();
Client端:
ChannelFactory NetcpFactory = new ChannelFactory(netTcpBindingBinding,new EndpointAddress("net.tcp://192.168.0.115:8057/CacheService/")); ICacheService tcpProxy= NetcpFactory.CreateChannel(); var obj=tcpProxy.GetVal();
上圖是在windows7 i5-3230CPU上跑的,13M和1M文本數據各100次傳輸測試的均值。
其中原生namedpipe相較已經很是快了,在能夠接受的範圍,共享內存的方式速度會更快些。
測試結果代表Wcf的namedpipe要慢於wcf-tcp的方式,這個讓人有些意外。
WcfTcp綁的是保留地址:
new ChannelFactory(netTcpBindingBinding, new EndpointAddress("net.tcp://192.168.0.115:8057/CacheService/"));
WcfTcp localhost綁的是127.0.0.1:
new ChannelFactory(netTcpBindingBinding, new EndpointAddress("net.tcp://localhost:8057/CacheService/"));
在大型網站開發中,緩存是個永遠避免不了的話題,也不存在一種方案能解決全部的問題。
而緩存開發過程常常碰到的問題:過時策略(惰性)、緩存更新(獨立)、多級緩存、分佈 式緩存(分片)、高可用(單點)、高併發(雪崩)、命中率(穿透)、緩存淘汰(LRU)等。
其多級緩存方案的層級關係大都是由瀏覽器->cdn->反向代理緩存->線程級->內存級->進程級->文件(靜態資源)->分佈式(redis)->Db結果。
多數內容在LZ前面博文中有過介紹,有興趣的童鞋能夠看看。
[1] http://www.codeproject.com/Articles/7176/Inter-Process-Communication-in-NET-Using-Named-Pip