那些年咱們一塊兒追過的緩存寫法(四)

閱讀目錄: redis

  1. 介紹
  2. 進程緩存
  3. 通訊方式
  4. 速度對比
  5. 總結

介紹

以前有童鞋問到關於首次爲空的問題,這裏簡單補充下:windows

  • 通常來講併發量小、緩存數據量小的網站讓用戶自行觸發頁面讓其緩存便可。
  • 大點網站都會多臺部署,用負載均衡路由。常見的策略是在每臺機器發佈應用時,節點從負載均衡節點集合中移除,發佈結束後,首次訪問經過人工或自動請求下頁面讓其緩存,也包括預編譯。
  • 還有一種是併發量大,緩存數據量大的狀況,這也是本文的主題,下面會詳細介紹。

若是緩存數據量大的狀況下,預熱就麻煩些。好比LZ公司單在內存中的緩存大小都過G,每次預熱都須要數分鐘,假設放在應用進程內,對運維工做很是不方便的。若是有意外致使進程池回收,對用戶來講就是災難性的。因此須要把應用進程的數據緩存給單獨抽離出來存放,與應用解耦。瀏覽器

關於高併發的解決方案包括緩存更新策略可參見前幾篇博客的介紹。緩存

進程緩存

在網站架構演化中,這個階段就須要引入分佈式緩存了,好比memcached、redis。好處就很少講了,壞處就是速度慢。這裏速度慢是與本機內存緩存相比,跨機器通訊跟直接讀內存差的不是一數量級,對於併發量高、操做頻繁的數據就不適用了。網絡

因此把應用進程緩存的數據抽離出來,放在單獨進程中,給應用提供一層緩存。緩存的業務邏輯、併發處理在獨立進程中作,使用進程通訊進行交互。這樣不但解決了數據量大預熱的麻煩,還能解耦部分應用的業務。架構

另外單獨的進程也能夠供外部使用,好比以WCF服務的方式提供給其餘子系統使用。併發

缺點是跨進程讀取的速度比進程內讀取要稍慢。app

通訊方式

獨立進程與應用進程的幾種常見通訊方式:負載均衡

Namedpipe

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();  
View Code

client端:

IInterProcessConnection clientConnection = new ClientPipeConnection("MyPipe", ".");
clientConnection.Connect();
var val = clientConnection.Read();
clientConnection.Close();

Wcf Namedpipe

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();

SharedMemory

共享內存是進程間通訊最快的一種方式,數據無需在進程間複製傳輸,直接開闢一塊公共內存,供其餘進程進行讀寫。  

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();

WCF TCP方式

使用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

相關文章
相關標籤/搜索