分析Memcached客户端如何把缓存数据分布到多个服务器上
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(); 16 17 if(Log.IsDebugEnabled) 18 { 19 Log.Debug(GetLocalizedString("cache socket pick").Replace("$$Key$$", key).Replace("$$HashCode$$", hashCodeString)); 20 } 21 22 if (key == null || key.Length == 0) 23 { 24 if(Log.IsDebugEnabled) 25 { 26 Log.Debug(GetLocalizedString("null key")); 27 } 28 return null; 29 } 30 31 if(!_initialized) 32 { 33 if(Log.IsErrorEnabled) 34 { 35 Log.Error(GetLocalizedString("get socket from uninitialized pool")); 36 } 37 return null; 38 } 39 40 // if no servers return null 41 if(_buckets.Count == 0)
42 return null;
43
44 // if only one server, return it
45 if(_buckets.Count == 1)
46 return GetConnection((string)_buckets[0]);
47
48 int tries = 0;
49
50 // generate hashcode
51 int hv;
52 if(hashCode != null)
53 {
54 hv = (int)hashCode;
55 }
56 else
57 {
58
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;
67
68 case HashingAlgorithm.OldCompatibleHash:
69 hv = OriginalHashingAlgorithm(key);
70 break;
71
72 case HashingAlgorithm.NewCompatibleHash:
73 hv = NewHashingAlgorithm(key);
74 break;
75
76 default:
77 // use the native hash as a default
78 hv = key.GetHashCode();
79 _hashingAlgorithm = HashingAlgorithm.Native;
80 break;
81 }
82 }
83
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.Count;
90 if(bucket < 0)
91 bucket += _buckets.Count;
92
93 SockIO sock = GetConnection((string)_buckets[bucket]);
94
95 if(Log.IsDebugEnabled)
96 {
97 Log.Debug(GetLocalizedString("cache choose").Replace("$$Bucket$$", _buckets[bucket].ToString()).Replace("$$Key$$", key));
98 }
99
100 if(sock != null)
101 return sock;
102
103 // if we do not want to failover, then bail here
104 if(!_failover)
105 return null;
106
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;
115
116 case HashingAlgorithm.OldCompatibleHash:
117 hv += OriginalHashingAlgorithm("" + tries + key);
118 break;
119
120 case HashingAlgorithm.NewCompatibleHash:
121 hv += NewHashingAlgorithm("" + tries + key);
122 break;
123
124 default:
125 // use the native hash as a default
126 hv += ((string)("" + tries + key)).GetHashCode();
127 _hashingAlgorithm = HashingAlgorithm.Native;
128 break;
129 }
130 }
131
132 return null;
133 }
134
上面代码是代码文件SockIOPool.cs中的一个方法,从方法签名上可以看出,获取一个socket连接是根据需要缓存数据的唯一键和它的哈希值,因为缓存的数据的键值是唯一的,所以它的哈希代码也是唯一的;
再看看上面方法中的以下代码:
int bucket = hv % _buckets.Count;
if(bucket < 0)
bucket += _buckets.Count;
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的时候就可以根据数据项中的唯一键来选择啦。
分析Memcached客户端如何把缓存数据分布到多个服务器上的更多相关文章
- php memcache 缓存与memcached 客户端的详细步骤
缓存服务器有Memcache.Redis,我主要介绍了PHP中的Memcache,从Memcache简介开始,详细讲解了如Memcache和memcached的区别.PHP的 Memcache所有操作 ...
- 详细分析Memcached缓存与Mongodb数据库的优点与作用
http://www.mini188.com/showtopic-1604.aspx 本文详细讲下Memcached和Mongodb一些看法,以及结合应用有什么好处,希望看到大家的意见和补充. Mem ...
- ASP.Net MVC4+Memcached+CodeFirst实现分布式缓存
ASP.Net MVC4+Memcached+CodeFirst实现分布式缓存 part 1:给我点时间,允许我感慨一下2016年 正好有时间,总结一下最近使用的一些技术,也算是为2016年画上一个完 ...
- memcached客户端的使用
一. 概念 Memcached是danga.com(运营LiveJournal的技术团队)开发的一套分布式内存对象缓存系统,用于在动态系统中减少数据库负载,提升性能. 二. 适用场合 1. 分布式应用 ...
- Windows下Memcached在.Net程序中的实际运用(从Memcached客户端Enyim的库的编译到实际项目运用)
1.一点基础概念 2.获取EnyimMemcached客户端的源代码并编译出动态库 3.Memcached的服务器安装(windows server) 4.在web项目中实战 一.基础概念 memca ...
- Memcached源代码分析 - Memcached源代码分析之消息回应(3)
文章列表: <Memcached源代码分析 - Memcached源代码分析之基于Libevent的网络模型(1)> <Memcached源代码分析 - Memcached源代码分析 ...
- Python并发编程-Memcached (分布式内存对象缓存系统)
一.Memcached Memcached 是一个高性能的分布式内存对象缓存系统,用于动态Web应用以减轻数据库负载.它通过在内存中缓存数据和对象来减少读取数据库的次数,从而提高动态.数据库驱动网站的 ...
- Spring学习(六)——集成memcached客户端
memcached是高性能的分布式内存缓存服务器.许多Web应用都将数据保存到RDBMS中,应用服务器从中读取数据并在浏览器中显示. 但随着数据量的增大.访问的集中,就会出现RDBMS的负担加重.数据 ...
- Hadoop源码分析之客户端向HDFS写数据
转自:http://www.tuicool.com/articles/neUrmu 在上一篇博文中分析了客户端从HDFS读取数据的过程,下面来看看客户端是怎么样向HDFS写数据的,下面的代码将本地文件 ...
随机推荐
- Union与UnionAll
UNION指令的目的是将两个SQL语句的结果合并起来.从这个角度来看, 我们会产生这样的感觉,UNION跟JOIN似乎有些许类似,因为这两个指令都可以由多个表格中撷取资料. UNION的一个限制是两个 ...
- Java中堆和栈有什么区别
stack 和 heep 都是内存的一部分stack 空间小,速度比较快, 用来放对象的引用heep 大,一般所有创建的对象都放在这里. 栈(stack):是一个先进后出的数据结构,通常用于保存方法( ...
- highcharts 图例详解
highcharts 图例 tooltip: { }, legend: { ...
- 集合框架(中):Map
Map接口: Map提供了一种映射关系,其中的元素就是以键值对(key-value)的形式存储的,能够实现根据key快速查找value Map中的键值对以Entry类型的对象实例形式存在 键(key值 ...
- 【MySQL】undo,redo,2PC,恢复思维导图
http://blog.itpub.net/22664653/viewspace-2131353/
- 【IntellJ IDEA】idea启动测试类报错Error running 'Test1.test': Command line is too long. Shorten command line for Test1.test or also for JUnit default configuration.
idea启动测试类报错 Error running 'Test1.test': Command line is too long. Shorten command line for Test1.tes ...
- 如何评价 GitHub 发布的文本编辑器 Atom?
这里是HN上的讨论:GitHub's new text editor leaked on Twitter这里是github page:Atom · GitHub 好多repo啊我不知道有没有知友了解更 ...
- 获得Oracle当前日期的年或月的第一天和最后一天
.当前日期的年份第一天和最后一天 第一天 select trunc(sysdate,'y') FROM DUAL; select trunc(sysdate,'yy') FROM DUAL; sele ...
- DatagramPacket,DatagramSocket
package test; import java.io.IOException; import java.net.DatagramPacket; import java.net.DatagramSo ...
- Nodejs扩展,实现消息弹窗
參考https://github.com/olalonde/node-notify的实现 模块的C++代码 node_gtknotify.cc #include <v8.h> #inclu ...