阅读目录: 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