为什么有的时候从memcached宕机 读取慢中读取数据的时间超过了1秒

& 利用Memcache解决数据库高并发访问的瓶颈问题
利用Memcache解决数据库高并发访问的瓶颈问题
  对于高并发高访问的Web应用程序来说,数据库存取瓶颈一直是个令人头疼的问题。特别当你的程序架构还是建立在单数据库模式,而一个数据池连接数峰值已经达到500的时候,那你的程序运行离崩溃的边缘也不远了。很多小网站的开发人员一开始都将注意力放在了产品需求设计上,缺忽视了程序整体性能,可扩展性等方面的考虑,结果眼看着访问量一天天网上爬,可突然发现有一天网站因为访问量过大而崩溃了,到时候哭都来不及。所以我们一定要未雨绸缪,在数据库还没罢工前,想方设法给它减负,这也是这篇文章的主要议题。  大家都知道,当有一个request过来后,web服务器交给app服务器,app处理并从db中存取相关数据,但db存取的花费是相当高昂的。特别是每次都取相同的数据,等于是让数据库每次都在做高耗费的无用功,数据库如果会说话,肯定会发牢骚,你都问了这么多遍了,难道还记不住吗?是啊,如果app拿到第一次数据并存到内存里,下次读取时直接从内存里读取,而不用麻烦数据库,这样不就给数据库减负了?而且从内存取数据必然要比从数据库媒介取快很多倍,反而提升了应用程序的性能。  因此,我们可以在web/app层与db层之间加一层cache层,主要目的:1.减少数据库读取负担;2.提高数据读取速度。而且,cache存取的媒介是内存,而一台服务器的内存容量一般都是有限制的,不像硬盘容量可以做到TB级别。所以,可以考虑采用分布式的cache层,这样更易于破除内存容量的限制,同时又增加了灵活性。  Memcached介绍  Memcached是开源的分布式cache系统,现在很多的大型web应用程序包括,youtube,wikipedia,等等都在使用memcached来支持他们每天数亿级的页面访问。通过把cache层与他们的web架构集成,他们的应用程序在提高了性能的同时,还大大降低了数据库的负载。  具体的memcached资料大家可以直接从它的官方网站上得到。这里我就简单给大家介绍一下memcached的工作原理:  Memcached处理的原子是每一个(key,value)对(以下简称kv对),key会通过一个hash算法转化成hash-key,便于查找、对比以及做到尽可能的散列。同时,memcached用的是一个二级散列,通过一张大hash表来维护。  Memcached有两个核心组件组成:服务端(ms)和客户端(mc),在一个memcached的查询中,mc先通过计算key的hash值来确定kv对所处在的ms位置。当ms确定后,客户端就会发送一个查询请求给对应的ms,让它来查找确切的数据。因为这之间没有交互以及多播协议,所以memcached交互带给网络的影响是最小化的。  举例说明:考虑以下这个场景,有三个mc分别是X,Y,Z,还有三个ms分别是A,B,C:  设置kv对  X想设置key=&foo&,value=&seattle&  X拿到ms列表,并对key做hash转化,根据hash值确定kv对所存的ms位置  B被选中了  X连接上B,B收到请求,把(key=&foo&,value=&seattle&)存了起来  获取kv对  Z想得到key=&foo&的value  Z用相同的hash算法算出hash值,并确定key=&foo&的值存在B上  Z连接上B,并从B那边得到value=&seattle&  其他任何从X,Y,Z的想得到key=&foo&的值的请求都会发向B  Memcached服务器(ms)  内存分配  默认情况下,ms是用一个内置的叫&块分配器&的组件来分配内存的。舍弃标准的malloc/free的内存分配,而采用块分配器的主要目的是为了避免内存碎片,否则操作系统要花费更多时间来查找这些逻辑上连续的内存块(实际上是断开的)。用了块分配器,ms会轮流的对内存进行大块的分配,并不断重用。当然由于块的大小各不相同,当数据大小和块大小不太相符的情况下,还是有可能导致内存的浪费。  同时,ms对key和data都有相应的限制,key的长度不能超过250字节,data也不能超过块大小的限制---1MB。  因为mc所使用的hash算法,并不会考虑到每个ms的内存大小。理论上mc会分配概率上等量的kv对给每个ms,这样如果每个ms的内存都不太一样,那可能会导致内存使用率的降低。所以一种替代的解决方案是,根据每个ms的内存大小,找出他们的最大公约数,然后在每个ms上开n个容量=最大公约数的instance,这样就等于拥有了多个容量大小一样的子ms,从而提供整体的内存使用率。  缓存策略  当ms的hash表满了之后,新的插入数据会替代老的数据,更新的策略是LRU(最近最少使用),以及每个kv对的有效时限。Kv对存储有效时限是在mc端由app设置并作为参数传给ms的。  同时ms采用是偷懒替代法,ms不会开额外的进程来实时监测过时的kv对并删除,而是当且仅当,新来一个插入的数据,而此时又没有多余的空间放了,才会进行清除动作。  缓存数据库查询  现在memcached最流行的一种使用方式是缓存数据库查询,下面举一个简单例子说明:  App需要得到userid=xxx的用户信息,对应的查询语句类似:  &SELECT*FROMusersWHEREuserid=xxx&  App先去问cache,有没有&user:userid&(key定义可预先定义约束好)的数据,如果有,返回数据;如果没有,App会从数据库中读取数据,并调用cache的add函数,把数据加入cache中。  当取的数据需要更新,app会调用cache的update函数,来保持数据库与cache的数据同步。  从上面的例子我们也可以发现,一旦数据库的数据发现变化,我们一定要及时更新cache中的数据,来保证app读到的是同步的正确数据。当然我们可以通过定时器方式记录下cache中数据的失效时间,时间一过就会激发事件对cache进行更新,但这之间总会有时间上的延迟,导致app可能从cache读到脏数据,这也被称为狗洞问题。(以后我会专门描述研究这个问题)  数据冗余与故障预防  从设计角度上,memcached是没有数据冗余环节的,它本身就是一个大规模的高性能cache层,加入数据冗余所能带来的只有设计的复杂性和提高系统的开支。  当一个ms上丢失了数据之后,app还是可以从数据库中取得数据。不过更谨慎的做法是在某些ms不能正常工作时,提供额外的ms来支持cache,这样就不会因为app从cache中取不到数据而一下子给数据库带来过大的负载。  同时为了减少某台ms故障所带来的影响,可以使用&热备份&方案,就是用一台新的ms来取代有问题的ms,当然新的ms还是要用原来ms的IP地址,大不了数据重新装载一遍。  另外一种方式,就是提高你ms的节点数,然后mc会实时侦查每个节点的状态,如果发现某个节点长时间没有响应,就会从mc的可用server列表里删除,并对server节点进行重新hash定位。当然这样也会造成的问题是,原本key存储在B上,变成存储在C上了。所以此方案本身也有其弱点,最好能和&热备份&方案结合使用,就可以使故障造成的影响最小化。  Memcached客户端(mc)  Memcached客户端有各种语言的版本供大家使用,包括java,c,php,.net等等。  大家可以根据自己项目的需要,选择合适的客户端来集成。& & & &缓存式的Web应用程序架构  有了缓存的支持,我们可以在传统的app层和db层之间加入cache层,每个app服务器都可以绑定一个mc,每次数据的读取都可以从ms中取得,如果没有,再从db层读取。而当数据要进行更新时,除了要发送update的sql给db层,同时也要将更新的数据发给mc,让mc去更新ms中的数据。  假设今后我们的数据库可以和ms进行通讯了,那可以将更新的任务统一交给db层,每次数据库更新数据的同时会自动去更新ms中的数据,这样就可以进一步减少app层的逻辑复杂度。如下图:  不过每次我们如果没有从cache读到数据,都不得不麻烦数据库。为了最小化数据库的负载压力,我们可以部署数据库复写,用slave数据库来完成读取操作,而master数据库永远只负责三件事:1.更新数据;2.同步slave数据库;3.更新cache。如下图:  以上这些缓存式web架构在实际应用中被证明是能有效并能极大地降低数据库的负载同时又能提高web的运行性能。当然这些架构还可以根据具体的应用环境进行变种,以达到不同硬件条件下性能的最优化。  未来的憧憬  Memcached的出现可以说是革命性的,第一次让我们意识到可以用内存作为存储媒介来大规模的缓存数据以提高程序的性能。不过它毕竟还是比较新的东西,还需要很多有待优化和改进的地方,例如:  如何利用memcached实现cache数据库,让数据库跑在内存上。这方面,tangentsoftware开发的memcached_engine已经做了不少工作,不过现在的版本还只是处于实验室阶段。  如何能方便有效的进行批量key清理。因为现在key是散列在不同的server上的,所以对某类key进行大批量清理是很麻烦的。因为memcached本身是一个大hash表,是不具备key的检索功能的。所以memcached是压根不知道某一类的key到底存了多少个,都存在哪些server上。而这类功能在实际应用中却是经常用到。
除非特别注明,文章均为原创
转载请标明本文地址:
作者:鸡啄米
&&( 21:46:49)&&( 21:50:42)
纯技术文啊,看不懂。
学习下。。
好深奥哦,不懂···
牛文章。。。。
支持下博主 谢谢博主分享
这篇文章比较实用呢 博主辛苦了~
给力支持!
文章不错哈!给力支持!
赞一个 加油啊
完全随机文章分布式缓存出于如下考虑,首先是缓存本身的水平线性扩展问题,其次是缓存大并发下的本身的性能问题,再次避免缓存的单点故障问题(多副本和副本一致性)。分布式缓存的核心技术包括首先是内存本身的管理问题,包括了内存的分配,管理和回收机制。其次是分布式管理和分布式算法,其次是缓存键值管理和路由。
什么是Memcached 许多Web 应用程序都将数据保存到RDBMS中,应用服务器从中读取数据并在浏览器中显示。但随着数据量的增大,访问的集中,就会出现REBMS的负担加重,数据库响应恶化,网站显示延迟等重大影响。Memcached是高性能的分布式内存缓存服务器。一般的使用目的是通过缓存数据库查询结果,减少数据库的访问次数,以提高动态Web 应用的速度、提高扩展性。
Memcached作为高速运行的分布式缓存服务器具有以下特点。
协议简单:memcached的服务器客户端通信并不使用复杂的MXL等格式,而是使用简单的基于文本的协议。
基于libevent的事件处理:libevent是个程序库,他将Linux 的epoll、BSD类操作系统的kqueue等时间处理功能封装成统一的接口。memcached使用这个libevent库,因此能在Linux、BSD、Solaris等操作系统上发挥其高性能。
内置内存存储方式:为了提高性能,memcached中保存的数据都存储在memcached内置的内存存储空间中。由于数据仅存在于内存中,因此重启memcached,重启操作系统会导致全部数据消失。另外,内容容量达到指定的值之后memcached回自动删除不适用的缓存。
Memcached不互通信的分布式:memcached尽管是“分布式”缓存服务器,但服务器端并没有分布式功能。各个memcached不会互相通信以共享信息。他的分布式主要是通过客户端实现的。
Memcached的内存管理
最近的memcached默认情况下采用了名为Slab Allocatoion的机制分配,管理内存。在改机制出现以前,内存的分配是通过对所有记录简单地进行malloc和free来进行的。但是这中方式会导致内存碎片,加重操作系统内存管理器的负担。
Slab Allocator的基本原理是按照预先规定的大小,将分配的内存分割成特定长度的块,已完全解决内存碎片问题。Slab Allocation&&的原理相当简单。将分配的内存分割成各种尺寸的块(chucnk),并把尺寸相同的块分成组(chucnk的集合)。
Memcached删除数据时数据不会真正从memcached中消失。Memcached不会释放已分配的内存。记录超时后,客户端就无法再看见该记录(invisible 透明),其存储空间即可重复使用。
Lazy Expriationmemcached内部不会监视记录是否过期,而是在get时查看记录的时间戳,检查记录是否过期。这种技术称为lazy expiration.因此memcached不会再过期监视上耗费CPU时间。
对于缓存存储容量满的情况下的删除需要考虑多种机制,一方面是按队列机制,一方面应该对应缓存对象本身的优先级,根据缓存对象的优先级进行对象的删除。
LRU:从缓存中有效删除数据的原理:
Memcached会优先使用已超时的记录空间,但即使如此,也会发生追加新纪录时空间不足的情况。此时就要使用名为Least Recently Used (LRU)机制来分配空间。这就是删除最少使用的记录的机制。因此当memcached的内存空间不足时(无法从slab class)获取到新空间时,就从最近未使用的记录中搜索,并将空间分配给新的记录。
缓存多副本主要是用于在缓存数
存储缓存数
据的多个副
缓存失效。缓存失
效发生在以
下几种情况:
1.&&&&缓存超时被移除(正常失效)
2.&&&&缓存由于存储空间限制被移除(异常失效)
3.&&&&由于缓存节点变化而导致的缓存失效(异常失效)
在缓存多副本的情况下,需要重新考虑缓存的分布式分布策略。其次缓存的多个
副本实际本身是可能的多个读的节点,可以做为分布式的并行读,这是另外一个可以考虑的问题。
缓存数据的一致性问题
缓存数据尽量只读,因此缓存本身是不适合大
量写和更新
据场景的。对
于读的情况下,如果存在数据变化,一种是同时更新缓存和数据库。一种是直接对缓
存数据进行失效
1、客户端在与 memcached 服务建立连接之后,进行存取对象的操作,每个被存取的对象都有一个唯一的标识符 key,存取操作均通过这个 key 进行,保存到 memcached 中的对象实际上是放置内存中的,并不是保存在 cache 文件中的,这也是为什么 memcached 能够如此高效快速的原因。注意,这些对象并不是持久的,服务停止之后,里边的数据就会丢失。
2、当存入cached的数据超过了cached的容量后会将最长时间没调用的对象挤出,这正好应征了cached的特征。
3、利用memcached常用的做法:在每取得一次cached对象后,重新设置这个对象的cache时间,这样能够使得经常被调用的对象可以长期滞留在缓存中,使得效率增倍。
& 原文链接:你可能喜欢
12345678910
关于本站 本站以分享运维技术为主,欢迎大家参与技术分享,同时也欢迎大家吐槽,本站提供以下交流圈:QQ群①:*****(满)QQ群②:6690706 QQ群③: QQ群④:(新) 微信公众号:ttlsacom
您还未添加分享代码,请到主题选项中,添加百度分享代码!分析Memcached客户端如何把缓存数据分布到多个服务器上 - CSDN博客
Memcached客户端可以设多个memcached服务器,它是如何把数据分发到各个服务器上,而使各个服务器负载平衡的呢?
可以看看.net版中的客户端中的源码,就可以知道&先看代码:
&&1&///&&summary&
&&2&&&&&&&&&///&Returns&appropriate&SockIO&object&given
&&3&&&&&&&&&///&string&cache&key&and&optional&hashcode.
&&4&&&&&&&&&///&
&&5&&&&&&&&&///&Trys&to&get&SockIO&from&pool.&&Fails&over
&&6&&&&&&&&&///&to&additional&pools&in&event&of&server&failure.
&&7&&&&&&&&&///&&/summary&
&&8&&&&&&&&&///&&param&name=&key&&hashcode&for&cache&key&/param&
&&9&&&&&&&&&///&&param&name=&hashCode&&if&not&null,&then&the&int&hashcode&to&use&/param&
&10&&&&&&&&&///&&returns&SockIO&obj&connected&to&server&/returns&
&11&&&&&&&&&public&SockIO&GetSock(string&key,&object&hashCode)
&12&&&&&&&&&{
&13&&&&&&&&&&&&&string&hashCodeString&=&&&null&&;
&14&&&&&&&&&&&&&if(hashCode&!=&null)
&15&&&&&&&&&&&&&&&&&hashCodeString&=&hashCode.ToString();
&17&&&&&&&&&&&&&if(Log.IsDebugEnabled)
&18&&&&&&&&&&&&&{
&19&&&&&&&&&&&&&&&&&Log.Debug(GetLocalizedString(&cache&socket&pick&).Replace(&$$Key$$&,&key).Replace(&$$HashCode$$&,&hashCodeString));
&20&&&&&&&&&&&&&}
&22&&&&&&&&&&&&&if&(key&==&null&||&key.Length&==&0)
&23&&&&&&&&&&&&&{
&24&&&&&&&&&&&&&&&&&if(Log.IsDebugEnabled)
&25&&&&&&&&&&&&&&&&&{
&26&&&&&&&&&&&&&&&&&&&&&Log.Debug(GetLocalizedString(&null&key&));
&27&&&&&&&&&&&&&&&&&}
&28&&&&&&&&&&&&&&&&&return&null;
&29&&&&&&&&&&&&&}
&31&&&&&&&&&&&&&if(!_initialized)
&32&&&&&&&&&&&&&{
&33&&&&&&&&&&&&&&&&&if(Log.IsErrorEnabled)
&34&&&&&&&&&&&&&&&&&{
&35&&&&&&&&&&&&&&&&&&&&&Log.Error(GetLocalizedString(&get&socket&from&uninitialized&pool&));
&36&&&&&&&&&&&&&&&&&}
&37&&&&&&&&&&&&&&&&&return&null;
&38&&&&&&&&&&&&&}
&40&&&&&&&&&&&&&//&if&no&servers&return&null
&41&&&&&&&&&&&&&if(_buckets.Count&==&0)
&42&&&&&&&&&&&&&&&&&return&null;
&44&&&&&&&&&&&&&//&if&only&one&server,&return&it
&45&&&&&&&&&&&&&if(_buckets.Count&==&1)
&46&&&&&&&&&&&&&&&&&return&GetConnection((string)_buckets[0]);
&48&&&&&&&&&&&&&int&tries&=&0;
&50&&&&&&&&&&&&&//&generate&hashcode
&51&&&&&&&&&&&&&int&
&52&&&&&&&&&&&&&if(hashCode&!=&null)
&53&&&&&&&&&&&&&{
&54&&&&&&&&&&&&&&&&&hv&=&(int)hashC
&55&&&&&&&&&&&&&}
&56&&&&&&&&&&&&&else
&57&&&&&&&&&&&&&{
&59&&&&&&&&&&&&&&&&&//&NATIVE_HASH&=&0
&60&&&&&&&&&&&&&&&&&//&OLD_COMPAT_HASH&=&1
&61&&&&&&&&&&&&&&&&&//&NEW_COMPAT_HASH&=&2
&62&&&&&&&&&&&&&&&&&switch(_hashingAlgorithm)
&63&&&&&&&&&&&&&&&&&{
&64&&&&&&&&&&&&&&&&&&&&&case&HashingAlgorithm.Native:
&65&&&&&&&&&&&&&&&&&&&&&&&&&hv&=&key.GetHashCode();
&66&&&&&&&&&&&&&&&&&&&&&&&&&break;
&68&&&&&&&&&&&&&&&&&&&&&case&HashingAlgorithm.OldCompatibleHash:
&69&&&&&&&&&&&&&&&&&&&&&&&&&hv&=&OriginalHashingAlgorithm(key);
&70&&&&&&&&&&&&&&&&&&&&&&&&&break;
&72&&&&&&&&&&&&&&&&&&&&&case&HashingAlgorithm.NewCompatibleHash:
&73&&&&&&&&&&&&&&&&&&&&&&&&&hv&=&NewHashingAlgorithm(key);
&74&&&&&&&&&&&&&&&&&&&&&&&&&break;
&76&&&&&&&&&&&&&&&&&&&&&default:
&77&&&&&&&&&&&&&&&&&&&&&&&&&//&use&the&native&hash&as&a&default
&78&&&&&&&&&&&&&&&&&&&&&&&&&hv&=&key.GetHashCode();
&79&&&&&&&&&&&&&&&&&&&&&&&&&_hashingAlgorithm&=&HashingAlgorithm.N
&80&&&&&&&&&&&&&&&&&&&&&&&&&break;
&81&&&&&&&&&&&&&&&&&}
&82&&&&&&&&&&&&&}
&84&&&&&&&&&&&&&//&keep&trying&different&servers&until&we&find&one
&85&&&&&&&&&&&&&while(tries++&&=&_buckets.Count)
&86&&&&&&&&&&&&&{
&87&&&&&&&&&&&&&&&&&//&get&bucket&using&hashcode&
&88&&&&&&&&&&&&&&&&&//&get&one&from&factory
&89&&&&&&&&&&&&&&&&&int&bucket&=&hv&%&_buckets.C
&90&&&&&&&&&&&&&&&&&if(bucket&&&0)
&91&&&&&&&&&&&&&&&&&&&&&bucket&+=&_buckets.C
&93&&&&&&&&&&&&&&&&&SockIO&sock&=&GetConnection((string)_buckets[bucket]);
&95&&&&&&&&&&&&&&&&&if(Log.IsDebugEnabled)
&96&&&&&&&&&&&&&&&&&{
&97&&&&&&&&&&&&&&&&&&&&&Log.Debug(GetLocalizedString(&cache&choose&).Replace(&$$Bucket$$&,&_buckets[bucket].ToString()).Replace(&$$Key$$&,&key));
&98&&&&&&&&&&&&&&&&&}
100&&&&&&&&&&&&&&&&&if(sock&!=&null)
101&&&&&&&&&&&&&&&&&&&&&return&
103&&&&&&&&&&&&&&&&&//&if&we&do&not&want&to&failover,&then&bail&here
104&&&&&&&&&&&&&&&&&if(!_failover)
105&&&&&&&&&&&&&&&&&&&&&return&null;
107&&&&&&&&&&&&&&&&&//&if&we&failed&to&get&a&socket&from&this&server
108&&&&&&&&&&&&&&&&&//&then&we&try&again&by&adding&an&incrementer&to&the
109&&&&&&&&&&&&&&&&&//&current&key&and&then&rehashing&
110&&&&&&&&&&&&&&&&&switch(_hashingAlgorithm)
111&&&&&&&&&&&&&&&&&{
112&&&&&&&&&&&&&&&&&&&&&case&HashingAlgorithm.Native:
113&&&&&&&&&&&&&&&&&&&&&&&&&hv&+=&((string)(&&&+&tries&+&key)).GetHashCode();
114&&&&&&&&&&&&&&&&&&&&&&&&&break;
116&&&&&&&&&&&&&&&&&&&&&case&HashingAlgorithm.OldCompatibleHash:
117&&&&&&&&&&&&&&&&&&&&&&&&&hv&+=&OriginalHashingAlgorithm(&&&+&tries&+&key);
118&&&&&&&&&&&&&&&&&&&&&&&&&break;
120&&&&&&&&&&&&&&&&&&&&&case&HashingAlgorithm.NewCompatibleHash:
121&&&&&&&&&&&&&&&&&&&&&&&&&hv&+=&NewHashingAlgorithm(&&&+&tries&+&key);
122&&&&&&&&&&&&&&&&&&&&&&&&&break;
124&&&&&&&&&&&&&&&&&&&&&default:
125&&&&&&&&&&&&&&&&&&&&&&&&&//&use&the&native&hash&as&a&default
126&&&&&&&&&&&&&&&&&&&&&&&&&hv&+=&((string)(&&&+&tries&+&key)).GetHashCode();
127&&&&&&&&&&&&&&&&&&&&&&&&&_hashingAlgorithm&=&HashingAlgorithm.N
128&&&&&&&&&&&&&&&&&&&&&&&&&break;
129&&&&&&&&&&&&&&&&&}
130&&&&&&&&&&&&&}
132&&&&&&&&&&&&&return&null;
133&&&&&&&&&}
上面代码是代码文件SockIOPool.cs中的一个方法,从方法签名上可以看出,获取一个socket连接是根据需要缓存数据的唯一键和它的哈希值,因为缓存的数据的键值是唯一的,所以它的哈希代码也是唯一的;
&&&&&&&再看看上面方法中的以下代码:
&&&&&& &&int&bucket = hv % _buckets.C
&&&&&&&&&&&&&&&&if(bucket & 0)
&&&&&&&&&&&&&&&&&&& bucket += _buckets.C
&&&&&&&&&&&&&&&&SockIO&sock = GetConnection((string)_buckets[bucket]);
&&具体的选择服务器的算法是:唯一键值的哈希值与存放服务器列表中服务器(服务器地址记录不是唯一的)的数量进行模数运算来选择服务器的地址的。所以数据缓存在那台服务器取决于缓存数据的唯一键值所产生的哈希值和存放服务器列表中服务器的数量值,所以访问memcached服务的所有客户端操作数据时都必须使用同一种哈希算法和相同的服务器列表配置,否则就会或取不到数据或者重复存取数据。由于不同数据的唯一键所对应的哈希值不同,所以不同的数据就有可能分散到不同的服务器上,达到多个服务器负载平衡的目的。
&&&&如果几台服务器当中,负载能力各不同,想根据具体情况来配置各个服务器负载作用,也是可以做到的。看上面代码,可以知道程序是从_buckets中获取得服务器地址的,_buckets存放着服务器的地址信息,服务器地址在_bucket列表中并不是唯一的,它是可以有重复记录的。相同的服务器地址在_bucket重复记录越多,它被选中的机率就越大,相应负载作用也就越大。
&&&怎么设置服务器让它发挥更大的负载作用,如下面代码:&&&&&&& &&&&
&&&&&&& String[] serverlist = {&192.168.1.2:11211&, &192.168.1.3:11211&};
&& &&&&&int[] weights&& = new int[]{5, 2};&
&&&&&&& SockIOPool pool = SockIOPool.GetInstance();
&&&&&&& pool.SetServers(serverlist);
&&&&&&& pool.SetWeights(weights);&&&
&&& &&&& pool.Initialize();
&&&&pool.SetWeights(weights)方法就是设配各个服务器负载作用的系数,系数值越大,其负载作用也就越大。如上面的例子,就设服务器192.168.1.2的负载系数为5,服务器192.168.1.3的负载系数为2,也就说服务器192.168.1.2&比192.168.1.3的负载作用大。&&&&&&
程序中根据缓存数据中的唯一键标识的哈希值跟服务器列表中服务器记录数量求模运算来确定数据的缓存的位置的方法,算法的优点:能够把数据匀均的分散到各个服务器上数据服务器负载平衡,当然也可以通过配置使不同服务器有不同的负载作用。但也有缺点:使同类的数据过于分散,同个模块的数据都分散到不同的数据,不好统一管理和唯护;比如:现在有A、B、C、D四台服务器一起来做缓存服务器,数月后C台服务器突然死掉不可用啦,那么按算法缓存在C台服务器的数据都不可用啦,但客户端还是按原来的四台服务器的算法来取操作数据,所以分布在C服务上的数据在C服务器恢复可用之前都不可用,都必须从数据库中读取数据,并且不能添加到缓存中,因为只要缓存数据的Key不变,它还是会被计算分配到C服务器上。如果想把分配到C服务器就必须全部初始化A、B、D三台服务器上的所有数据,并把C服务器从服务器列表中移除。
如果我们能够把数据分类分布到各个服务器中,同类型的数据分布到相同的服务器;比如说,A服务器存放用户日志模块信息,B服务器存放用户相册模块信息,C服务器存放音乐模块信息,D服务器存放用户基础信息。如果C服务器不可用后,就可以更改下配置使它存放在其它服务器当中,而且并不影响其它服务器的缓存信息。
解决方法1:不同的模块使用不同memcached客户端实例,这样不同模块就可以配置不同的服务器列表,这样不同模块的数据就缓存到了不同的服务器中。这样,当某台服务器不可用后,只会影响到相应memcached客户端实例的数据,而不会影响到其它客户端实例的数据。
解决方法2:修改或添加新的算法,并在数据唯一键中添加命名空间,算法根据配置和数据唯一键中命名空间来选择不同的Socket连接,也就是服务器啦。
数据项唯一键(key)的定义:命名空间.数据项ID,就跟编程中的”&命名空间”一样,经如说用户有一篇日志的ID是”999999”,&那么这条篇日志的唯一键就是:Sns.UserLogs.Log.999999,当然我们存贮的时候考虑性能问题,可以用一个短的数值来代替命名空间。这样在选择Socket的时候就可以根据数据项中的唯一键来选择啦。
刚入门,请各位大佬多多指导!}

我要回帖

更多关于 有的时候 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信