分布式缓存学习总结

一、分布式缓存简图

二、为什么使用Memcached分布式缓存呢?

三、Memcached基础原理

四、Memcache下载与安装

五、MencacheHelper.cs 示例使用 结合Session与项目配置缓存

六、Redis和Memcache的区别总结


一、分布式缓存简图



二、为什么使用Memcached分布式缓存呢?

首先先讲讲为何要缓存,在数据驱动的web开发中,经常要重复从数据库中取出相同的数据,这种重复极大的增加了数据库负载。缓存是解决这个问题的好办法。但是ASP.NET中的虽然已经可以实现对页面局部进行缓存,但还是不够灵活。Memcached应运而生。


1、高并发访问数据库的痛楚:死锁!

2、磁盘IO之痛,数据库读写说白了就是跟磁盘打交道,磁盘读取速度是有限制的,一般高点也就7200转

3、多客户端共享缓存

4、Net+Memory  >> IO

5、读写性能完美 1s 读取可以达到1w次 写:10w次

6、超简单集群搭建 Clister

7、开源 Open Source

8、没有提供主从赋值功能,也没提供容灾等功能(容灾:即数据备份能使意外发生后恢复数据,Memcached不会进行备份,由于是缓存在内存中的,一断电就会失去数据


),所以所有的代码基本都只考虑性能最佳。如要考虑容灾,则可使用Redis分布式缓存

9、学习成本非常低,入门非常容易

10、丰富的成功的案例。很多大型公司都是用这个来做分布式缓存

注:Memcached在企业中一般都是在linux下跑,才能达到性能最佳。


三、Memcached基础原理

底层通信是使用Socket

可以将缓存服务器理解为Socket服务端,将WEB服务器理解为客户端。


四、Memcache下载与安装

下载,百度一下或者直接在csdn上搜一下windows Memcache稳定版就行,0积分。

1、下载完后,就这么个exe


2、安装,敲几行cmd命令就行,截图如下,左边是我们计算机服务列表,可以看到,已经启动了我们的Memcached(Memcache是这个开源项目的名称,加个d,Memcached是具体这个应用程序,也就是这个exe的名称)


3、现在已经启动服务了,且将其安装到windows服务上了,这样一来,就不用每次手动去启动了,随电脑而启动。


现在来测试下,随便新建个控制台应用程序

1using Memcached.ClientLibrary; 2using System; 3using System.Collections.Generic; 4using System.Linq; 5using System.Text; 6using System.Threading.Tasks; 7 8namespace 测试 9{10publicclass MemcacheTset11    {12publicstaticvoid Test()13        {14string[] serverlist = {"127.0.0.1:11211"};//服务器列表,可多个 用逗号隔开    1516//初始化池17SockIOPool pool = SockIOPool.GetInstance();1819//根据实际情况修改下面参数20            pool.SetServers(serverlist);21pool.InitConnections =3;22pool.MinConnections =3;23pool.MaxConnections =5;24pool.SocketConnectTimeout =1000;25pool.SocketTimeout =3000;26pool.MaintenanceSleep =30;27pool.Failover =true;28pool.Nagle =false;29pool.Initialize();// initialize the pool for memcache servers  3031//获得客户端实例32MemcachedClient mc =newMemcachedClient();//初始化一个客户端 33mc.EnableCompression =false;3435Console.WriteLine("---------测试----------");36mc.Set("test","my value");//存储数据到缓存服务器,这里将字符串"my value"缓存,key3738if(mc.KeyExists("test"))//测试缓存存在key为test的项目39            {40Console.WriteLine("test is Exists");41Console.WriteLine(mc.Get("test").ToString());//在缓存中获取key为test的项目42            }43else44            {45Console.WriteLine("test not Exists");46            }4748            Console.ReadLine();4950mc.Delete("test");//移除缓存中key为test的项目5152if(mc.KeyExists("test"))53            {54Console.WriteLine("test is Exists");55Console.WriteLine(mc.Get("test").ToString());56            }57else58            {59Console.WriteLine("test not Exists");60            }6162            Console.ReadLine();6364SockIOPool.GetInstance().Shutdown();//关闭池,关闭sockets65        }66    }67}

如果程序运行正常,说明我们的Memcache服务已启动且运行正常。

有一点,别忘咯,就是我们Memcache的驱动,同样,百度C# Memcache安装就OK。

好了,现在我们就实际来应用下吧。

五、MencacheHelper.cs示例使用 结合项目配置缓存

对于什么是项目配置,相信大家肯定都熟悉的,就是将业务中不经常更改的数据如系统邮件地址,将其存在数据库中,方便更改。

然后,回头看这几个字,“不经常更改”,我们就得注意了,这样的数据,我们就得想到缓存了,缓存就是用来管理这样的数据。然后呢,我们就可以使用我们的Memcache来管理它了。

项目中,我们可以新建个MemcacheHelper类来封装下代码,我写了个最简单的存取删除。

1using Memcached.ClientLibrary; 2using System; 3using System.Collections.Generic; 4using System.Linq; 5using System.Text; 6using System.Threading.Tasks; 7 8namespace JOEY.BookShop.Common 9{10publicclass MemcacheHelper11    {12privatestaticreadonly MemcachedClient mc;13static MemcacheHelper()14        {15string[] serverlist = {"127.0.0.1:11211"};//服务器列表,可多个 用逗号隔开    1617//初始化池18SockIOPool pool = SockIOPool.GetInstance();1920//根据实际情况修改下面参数21            pool.SetServers(serverlist);22pool.InitConnections =3;23pool.MinConnections =3;24pool.MaxConnections =5;25pool.SocketConnectTimeout =1000;26pool.SocketTimeout =3000;27pool.MaintenanceSleep =30;28pool.Failover =true;29pool.Nagle =false;30pool.Initialize();// initialize the pool for memcache servers  3132//获得客户端实例33mc =newMemcachedClient();//初始化一个客户端 34mc.EnableCompression =false;35        }3637///38/// 存39///40///41///42publicstaticvoidSet(stringkey,object value)43        {44            mc.Set(key, value);45        }4647publicstaticvoidSet(stringkey,object value, DateTime time)48        {49            mc.Set(key, value, time);50        }5152///53/// 取54///55///56///57publicstaticobjectGet(string key)58        {59if (mc.KeyExists(key))60            {61return mc.Get(key);62            }63else64            {65returnnull;66            }6768        }6970///71/// 删除72///73///74///75publicstaticboolDelete(string key)76        {77if (mc.KeyExists(key))78            {79                mc.Delete(key);80returntrue;81            }82returnfalse;83        }84    }85}


1varsetting =this.DbSession.SettingsDal.LoadEntities(c => c.Name =="系统邮件地址").FirstOrDefault();2stringvalue = setting.Value.Trim();3MemcacheHelper.Set("setting_"+ key, value);

这样就将我们的从数据库中取出的系统邮件地址存储到了Memcache中,很方便吧。取的话就是:

objectobj = MemcacheHelper.Get("setting_"+"系统邮件地址");

这里由于存取的数据均为字符串,不存在序列化的问题,如果存取的对象类型不是字符串,如某个表Model,那么就得通过序列化来进行操作,对于序列化,本人是使用Json.Net来操作。

再来个辅助类吧。

1using Newtonsoft.Json; 2using System; 3using System.Collections.Generic; 4using System.Linq; 5using System.Text; 6using System.Threading.Tasks; 7 8namespace JOEY.BookShop.Common 9{10///11/// Json.Net 序列化,对于由于相互引用类型导致的序列化死循环,可在该对象上加个特性标签[JsonIgnore] 如在Model中有外键,两个模型间相互引用即造成该问题12///13publicclass SerializeHelper14    {15///16/// 传入对象,序列化成字符串返回17///18///19///20publicstaticstringSerializeToString(object obj)21        {22return JsonConvert.SerializeObject(obj);23        }24///25/// 传入序列化字符串,反序列化成对应对象返回26///27///泛型,对应对象类型28///序列化后的字符串29///30publicstaticT DeserializeToObject(string serializeStr)31        {32returnJsonConvert.DeserializeObject(serializeStr);33        }34    }35}

很容易就能看懂,对吧。当然驱动也是需要的。同样百度哦。

这里有个小问题,这个程序集,Newtonsoft.Json在我的MVC项目中本身就存在,而我在其他项目(即项目Common)中用的时候用的网上下的,选的版本是4.5,由于MVC项目引用了Common,这样貌似就出现了版本不一致的情况,貌似是这样,会提示错误。于是我把MVC中的dll给删除了,重新加载Common下的dll(现在想想我为什么不把Common下的删了,去引用MVC下这个呢- -),这样一来,又出现一个问题,未能加载文件或程序集“Newtonsoft.Json,Version=4.5.0.0。估计是配置项的原因,于是,百度了下,在web.config runtime节点下添加了这么几行,修改后为:

                     

8.0.0.0是当前这个dll的版本,估计是版本更新通知吧。具体为何这样做是有点迷糊的。谁能指点下呢,感激~~~

六、Redis和Memcache的区别总结(摘自百度知道)

1. Redis是什么

这个问题的结果影响了我们怎么用Redis。如果你认为Redis是一个key value store, 那可能会用它来代替MySQL;如果认为它是一个可以持久化的cache, 可能只是它保存一些频繁访问的临时数据。Redis是REmote DIctionary Server的缩写,在Redis在官方网站的的副标题是A persistent key-value database with built-in net interface written in ANSI-C for Posix systems,这个定义偏向key value store。还有一些看法则认为Redis是一个memory database,因为它的高性能都是基于内存操作的基础。另外一些人则认为Redis是一个data structure server,因为Redis支持复杂的数据特性,比如List, Set等。对Redis的作用的不同解读决定了你对Redis的使用方式。

互联网数据目前基本使用两种方式来存储,关系数据库或者key value。但是这些互联网业务本身并不属于这两种数据类型,比如用户在社会化平台中的关系,它是一个list,如果要用关系数据库存储就需要转换成一种多行记录的形式,这种形式存在很多冗余数据,每一行需要存储一些重复信息。如果用key value存储则修改和删除比较麻烦,需要将全部数据读出再写入。Redis在内存中设计了各种数据类型,让业务能够高速原子的访问这些数据结构,并且不需要关心持久存储的问题,从架构上解决了前面两种存储需要走一些弯路的问题。

2. Redis不可能比Memcache快

很多开发者都认为Redis不可能比Memcached快,Memcached完全基于内存,而Redis具有持久化保存特性,即使是异步的,Redis也不可能比Memcached快。但是测试结果基本是Redis占绝对优势。一直在思考这个原因,目前想到的原因有这几方面。

Libevent。和Memcached不同,Redis并没有选择libevent。Libevent为了迎合通用性造成代码庞大(目前Redis代码还不到libevent的1/3)及牺牲了在特定平台的不少性能。Redis用libevent中两个文件修改实现了自己的epoll event loop(4)。业界不少开发者也建议Redis使用另外一个libevent高性能替代libev,但是作者还是坚持Redis应该小巧并去依赖的思路。一个印象深刻的细节是编译Redis之前并不需要执行./configure。

CAS问题。CAS是Memcached中比较方便的一种防止竞争修改资源的方法。CAS实现需要为每个cache key设置一个隐藏的cas token,cas相当value版本号,每次set会token需要递增,因此带来CPU和内存的双重开销,虽然这些开销很小,但是到单机10G+ cache以及QPS上万之后这些开销就会给双方相对带来一些细微性能差别(5)。

3.单台Redis的存放数据必须比物理内存小

Redis的数据全部放在内存带来了高速的性能,但是也带来一些不合理之处。比如一个中型网站有100万注册用户,如果这些资料要用Redis来存储,内存的容量必须能够容纳这100万用户。但是业务实际情况是100万用户只有5万活跃用户,1周来访问过1次的也只有15万用户,因此全部100万用户的数据都放在内存有不合理之处,RAM需要为冷数据买单。

这跟操作系统非常相似,操作系统所有应用访问的数据都在内存,但是如果物理内存容纳不下新的数据,操作系统会智能将部分长期没有访问的数据交换到磁盘,为新的应用留出空间。现代操作系统给应用提供的并不是物理内存,而是虚拟内存(Virtual Memory)的概念。

基于相同的考虑,Redis 2.0也增加了VM特性。让Redis数据容量突破了物理内存的限制。并实现了数据冷热分离。

4. Redis的VM实现是重复造轮子

Redis的VM依照之前的epoll实现思路依旧是自己实现。但是在前面操作系统的介绍提到OS也可以自动帮程序实现冷热数据分离,Redis只需要OS申请一块大内存,OS会自动将热数据放入物理内存,冷数据交换到硬盘,另外一个知名的“理解了现代操作系统(3)”的Varnish就是这样实现,也取得了非常成功的效果。

作者antirez在解释为什么要自己实现VM中提到几个原因(6)。主要OS的VM换入换出是基于Page概念,比如OS VM1个Page是4K, 4K中只要还有一个元素即使只有1个字节被访问,这个页也不会被SWAP, 换入也同样道理,读到一个字节可能会换入4K无用的内存。而Redis自己实现则可以达到控制换入的粒度。另外访问操作系统SWAP内存区域时block进程,也是导致Redis要自己实现VM原因之一。

5.用get/set方式使用Redis

作为一个key value存在,很多开发者自然的使用set/get方式来使用Redis,实际上这并不是最优化的使用方法。尤其在未启用VM情况下,Redis全部数据需要放入内存,节约内存尤其重要。

假如一个key-value单元需要最小占用512字节,即使只存一个字节也占了512字节。这时候就有一个设计模式,可以把key复用,几个key-value放入一个key中,value再作为一个set存入,这样同样512字节就会存放10-100倍的容量。

这就是为了节约内存,建议使用hashset而不是set/get的方式来使用Redis,详细方法见参考文献(7)。

6.使用aof代替snapshot

Redis有两种存储方式,默认是snapshot方式,实现方法是定时将内存的快照(snapshot)持久化到硬盘,这种方法缺点是持久化之后如果出现crash则会丢失一段数据。因此在完美主义者的推动下作者增加了aof方式。aof即append only mode,在写入内存数据的同时将操作命令保存到日志文件,在一个并发更改上万的系统中,命令日志是一个非常庞大的数据,管理维护成本非常高,恢复重建时间会非常长,这样导致失去aof高可用性本意。另外更重要的是Redis是一个内存数据结构模型,所有的优势都是建立在对内存复杂数据结构高效的原子操作上,这样就看出aof是一个非常不协调的部分。

其实aof目的主要是数据可靠性及高可用性,在Redis中有另外一种方法来达到目的:Replication。由于Redis的高性能,复制基本没有延迟。这样达到了防止单点故障及实现了高可用。

在这里顺便给大家推荐一个架构交流群:617434785,里面会分享一些资深架构师录制的视频录像:有Spring,MyBatis,Netty源码分析,高并发、高性能、分布式、微服务架构的原理,JVM性能优化这些成为架构师必备的知识体系。还能领取免费的学习资源。相信对于已经工作和遇到技术瓶颈的码友,在这个群里会有你需要的内容。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 221,888评论 6 515
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 94,677评论 3 399
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 168,386评论 0 360
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 59,726评论 1 297
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,729评论 6 397
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 52,337评论 1 310
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,902评论 3 421
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,807评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 46,349评论 1 318
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,439评论 3 340
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,567评论 1 352
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 36,242评论 5 350
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,933评论 3 334
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,420评论 0 24
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,531评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,995评论 3 377
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,585评论 2 359

推荐阅读更多精彩内容

  • 1、memcache的概念? Memcache是一个高性能的分布式的内存对象缓存系统,通过在内存里维护一个统一的巨...
    桖辶殇阅读 2,243评论 2 12
  • 关于Mongodb的全面总结 MongoDB的内部构造《MongoDB The Definitive Guide》...
    中v中阅读 31,947评论 2 89
  • 一、MemCache简介 session MemCache是一个自由、源码开放、高性能、分布式的分布式内存对象缓存...
    李伟铭MIng阅读 3,821评论 2 13
  • 心烦,睡不着觉,总是半夜里从梦里惊醒,最近情绪极不稳定。我在实习期,带我的老师是副主任,比较忙,教的东西也不咋多,...
    心肌病阅读 182评论 0 2
  • 言吾小姐阅读 914评论 0 0