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客户端如何把缓存数据分布到多个服务器上的更多相关文章

  1. php memcache 缓存与memcached 客户端的详细步骤

    缓存服务器有Memcache.Redis,我主要介绍了PHP中的Memcache,从Memcache简介开始,详细讲解了如Memcache和memcached的区别.PHP的 Memcache所有操作 ...

  2. 详细分析Memcached缓存与Mongodb数据库的优点与作用

    http://www.mini188.com/showtopic-1604.aspx 本文详细讲下Memcached和Mongodb一些看法,以及结合应用有什么好处,希望看到大家的意见和补充. Mem ...

  3. ASP.Net MVC4+Memcached+CodeFirst实现分布式缓存

    ASP.Net MVC4+Memcached+CodeFirst实现分布式缓存 part 1:给我点时间,允许我感慨一下2016年 正好有时间,总结一下最近使用的一些技术,也算是为2016年画上一个完 ...

  4. memcached客户端的使用

    一. 概念 Memcached是danga.com(运营LiveJournal的技术团队)开发的一套分布式内存对象缓存系统,用于在动态系统中减少数据库负载,提升性能. 二. 适用场合 1. 分布式应用 ...

  5. Windows下Memcached在.Net程序中的实际运用(从Memcached客户端Enyim的库的编译到实际项目运用)

    1.一点基础概念 2.获取EnyimMemcached客户端的源代码并编译出动态库 3.Memcached的服务器安装(windows server) 4.在web项目中实战 一.基础概念 memca ...

  6. Memcached源代码分析 - Memcached源代码分析之消息回应(3)

    文章列表: <Memcached源代码分析 - Memcached源代码分析之基于Libevent的网络模型(1)> <Memcached源代码分析 - Memcached源代码分析 ...

  7. Python并发编程-Memcached (分布式内存对象缓存系统)

    一.Memcached Memcached 是一个高性能的分布式内存对象缓存系统,用于动态Web应用以减轻数据库负载.它通过在内存中缓存数据和对象来减少读取数据库的次数,从而提高动态.数据库驱动网站的 ...

  8. Spring学习(六)——集成memcached客户端

    memcached是高性能的分布式内存缓存服务器.许多Web应用都将数据保存到RDBMS中,应用服务器从中读取数据并在浏览器中显示. 但随着数据量的增大.访问的集中,就会出现RDBMS的负担加重.数据 ...

  9. Hadoop源码分析之客户端向HDFS写数据

    转自:http://www.tuicool.com/articles/neUrmu 在上一篇博文中分析了客户端从HDFS读取数据的过程,下面来看看客户端是怎么样向HDFS写数据的,下面的代码将本地文件 ...

随机推荐

  1. [TopCoder8600]MagicFingerprint

    题目大意: 定义magic(x)为将x按十进制顺序写下来,依次对相邻两个数写下差的绝对值,并去除前导0得到的新数. 若对得到的magic(x)重复进行多次magic,最后会变成一个一位数. 若最后变成 ...

  2. 解决android客户端使用soap与服务器通讯错误415

    在编写一个android client与服务器使用soap通讯,虽然能连上但不是正常的200代码,而是415,经查询是"HTTP 415 错误 – 不 支持的媒体类型(Unsupported ...

  3. Windows下将ISO镜像制作成U盘启动的工具(U盘启动工具/UltraISO/Rufus/Universal-USB)

    说明:基于Windows的U盘启动制作都是非常的简单,在软件上指定ISO文件之后,一般都是选择写入到哪个U盘即可. 1.UltraISO 2.Rufus 3.Universal-USB 4.大白菜

  4. linux命令详解:tr命令

    转:http://www.cnblogs.com/lwgdream/archive/2013/11/05/3407809.html 前言 通过tr命令来转化数据,比如大小写的转换:用转换成另外一种字符 ...

  5. IOS设置UIView的边框为圆角

    iOS 系统自带的 View 组件都是正方形的,看起来都太生硬,有时候我需要变成圆角形式,如下图:    具体的实现是使用QuartzCore库,下面我具体的描述一下实现过程:    •    首先 ...

  6. maven自己主动编译,解决你每次代码改动须要又一次编译的繁琐

    maven结构的项目,我们在每次改动代码后都会须要手动编译,以下命令能够解决此问题.仅仅要代码改动.会自己主动帮你编译. 进入项目文件夹运行:mvn -U eclipse:clean eclipse: ...

  7. 什么是HotSpot VM & 深入理解Java虚拟机 JVM

    参考 http://book.2cto.com/201306/25434.html 另外,这篇文章也是从一个系列中得出的: <深入理解Java虚拟机:JVM高级特性与最佳实践(第2版)> ...

  8. ElasticSearch 组合过滤器

    1.布尔过滤器 前篇文章中(term精确查找)的两个例子都是单个过滤器(filter)的使用方式. 在实际应用中,我们很有可能会过滤多个值或字段.比方说,怎样用 Elasticsearch 来表达下面 ...

  9. win10 如何配置 java jdk1.8环境变量(2017.8.17 )jdk1.8.0_144

    win10 如何配置 java jdk 环境变量 2017.8.17 本篇还适用于 windows server 2012. windows server 2014+ 一.安装 下载 jdk 64位 ...

  10. C#程序不包含适合于入口点的静态“Main”方法怎么办

    如下图所示,一般程序上次运行还好好的,而且不管你复制粘贴再简单的程序也出现这种错误提示.   先点击右侧的显示所有文件,下面列举了所有CS文件,右击点击包括在项目中,则该文件呈现绿色,再运行即可.不过 ...