1. key值最大长度?
memcached的key的最大长度是250个字符。
注意250是memcached服务器端内部的限制(可以修改)
如果您使用的客户端支持"key的前缀"或类似特性,那么key(前缀+原始key)的最大长度是可以超过250个字符的。
我们推荐使用使用较短的key,因为可以节省内存和带宽。
key只要不重复就行,如果太大浪费内存。
2.key 不能有空格和控制字符
the key must not include control characters or whitespace.
- 对item的过期时间限制?
过期时间最大30天。
如果不注意这个细节,过期时间设置大于了30天,值会设置不进缓存
- 最大能存储多大的单个item?
1MB
如果你的数据大于1MB,可以考虑在客户端压缩或拆分到多个key中。
memcached参数中文解释
memcached 1.4.2
-p <num> 监听的TCP端口(默认: 11211) -U <num> 监听的UDP端口(默认: 11211, 0表示不监听) -s <file> 用于监听的UNIX套接字路径(禁用网络支持) -a <mask> UNIX套接字访问掩码,八进制数字(默认:0700) -l <ip_addr> 监听的IP地址。(默认:INADDR_ANY,所有地址) -d 作为守护进程来运行。 -r 最大核心文件限制。 -u <username> 设定进程所属用户。(只有root用户可以使用这个参数) -m <num> 所有slab class可用内存的上限,以MB为单位。(默认:64MB) (译者注:也就是分配给该memcached实例的内存大小。) -M 内存用光时报错。(不会删除数据) -c <num> 最大并发连接数。(默认:1024) -k 锁定所有内存页。注意你可以锁定的内存上限。 试图分配更多内存会失败的,所以留意启动守护进程时所用的用户可分配的内存上限。 (不是前面的 -u <username> 参数;在sh下,使用命令"ulimit -S -l NUM_KB"来设置。) -v 提示信息(在事件循环中打印错误/警告信息。) -vv 详细信息(还打印客户端命令/响应) -vvv 超详细信息(还打印内部状态的变化) -h 打印这个帮助信息并退出。 -i 打印memcached和libevent的许可。 -P <file> 保存进程ID到指定文件,只有在使用 -d 选项的时候才有意义。 -f <factor> 不同slab class里面的chunk大小的增长倍率。(默认:1.25) (译者注:每个slab class里面有相同数量个slab page,每个slab page里面有chunk,且在当前slab class内的chunk大小固定。 而不同slab class里的chunk大小不一致,具体差异就是根据这个参数的倍率在增长,直到分配的内存用尽。) -n <bytes> chunk的最小空间(默认:48) (译者注:chunk数据结构本身需要消耗48个字节,所以一个chunk实际消耗的内存是n+48。) -L 尝试使用大内存页(如果可用的话)。提高内存页尺寸可以减少"页表缓冲(TLB)"丢失次数,提高运行效率。 为了从操作系统获得大内存页,memcached会把全部数据项分配到一个大区块。 -D <char> 使用 <char> 作为前缀和ID的分隔符。 这个用于按前缀获得状态报告。默认是":"(冒号)。 如果指定了这个参数,则状态收集会自动开启;如果没指定,则需要用命令"stats detail on"来开启。 -t <num> 使用的线程数(默认:4) -R 每个连接可处理的最大请求数。 -C 禁用CAS。 -b 设置后台日志队列的长度(默认:1024) -B 绑定协议 - 可能值:ascii,binary,auto(默认) -I 重写每个数据页尺寸。调整数据项最大尺寸。
Memcached.ClientLibrary的key-server映射比较简单,基本原理就是对key求hash值,用hash值对服务器数量进行模运算,该key值被分配到模运算结果为索引的那台server上
Load Balance配置
通过SocketIOPool的Weights属性设置。假如有server A、B、C,根据其机器配置决定负载分别为40%、30%、30%,则如下配置即可:
pool.SetServers(new string[] { "A", "B", "C" });
pool.SetWeights(new int[] { 4, 3, 3 });
SocketIOPool的私有属性_buckets用于存放key-server映射的索引,内容为server的地址。为实现负载均衡的设置,key-server映射时不是直接对服务器数量进行模运算,而是对_buckets的count取模。如果某个服务器的Weights被设置为2,则该服务器在_buckets中会放2条记录,以这样的方式实现各服务器之间的负载分配
需要注意,如果设置了Weights,会给socket pool的设置带来影响。比如socket pool设置初始化连接数为5,按照上面Weights的设置,初始化时服务器A会创建4*5=20个连接,而B和C会分别创建15个连接。但是有的情况下又是以server为单位进行控制的,例如维护线程在检查最小连接数、最大连接数时,不管Weights如何设置,均以server为单位做检查。这是代码处理上不一致的问题
压缩
启用数据压缩,需要设置MemcachedClient对象的EnableCompression属性,并设置CompressionThreshold值
CompressionThreshold是启用压缩的阀值,默认为15k,即数据超过15k大小时将使用ICSharpCode.SharpZipLib对数据进行压缩
memcached 的通讯协议中,存数据时可以为每个数据项提供一个16位的flag,用以对数据进行特殊标记,取数据时memcached将该标记原样返回。 Memcached.ClientLibrary使用flag记录数据是否有压缩、是否使用了序列化等,读取服务器返回的数据时,如果flag表明该数据有压缩,则使用ICSharpCode.SharpZipLib对其解压
key的hash算法支持
因为Memcached.ClientLibrary直接使用hash值进行key-server映射,因此hash算法起的作用比较大。内部支持3种hash算法
HashingAlgorithm.Native: 即使用.NET本身的hash算法,速度快,但与其他client可能不兼容,例如需要和java、ruby的client共享缓存的情况
HashingAlgorithm.OldCompatibleHash: 可以与其他客户端兼容,但速度慢
HashingAlgorithm.NewCompatibleHash: 可以与其他客户端兼容,据称速度快
他允许使用其他hash算法,使用方式是MemcachedClient对象的Get、Set等方法,都有提供hash值的重载版本,client自己使用其他hash算法对key求hash值,然后传给MemcachedClient
同时使用多个SocketIOPool
比如已有系统A、B,分别使用自己的memcached server,之间不共享,现在开发系统C需要同时使用A、B的memcached server,则系统C中可以创建2个SocketIOPool;又比如,在系统中希望使用2个独立的memcached server,1个用于存放一些readonly、特殊的缓存数据,另一部分存放其他正常缓存数据等;比如web server上专门用一组memcached server存放用户session状态数据,用另一组存放应用层缓存数据等等
使用方法:可以对SocketIOPool设置名称,创建MemcachedClient对象时指定SocketIOPool的名称
代码结构、处理方式
只有3个类完成主要功能
SockIO: 负责socket通讯,例如创建socket对象、建立连接、读、写等。socket对象也是一直保持连接状态的
连接超时的管理:
他提供了连接超时的配置选项,这在高并发的情况下遇到server不可用时,可以用来防止大量socket连接阻塞执行线程(windows自身的连接超时时间以秒为单位)
windows的socket连接超时通过注册表配置,运用于整个windows,而API在建立socket连接时并没有连接超时时间设置
Memcached.ClientLibrary 的实现方式为,如果配置了连接超时时间,每次创建socket连接时新开一个线程,用他创建sokcet对象并进行连接,执行线程则不停的sleep并检查新线程是否连接成功,如果连接成功则返回socket连接,否则达到超时时间时,主线程直接返回,新线程则交由.NET和windows进行释放
其实现上仍存在一个待处理问题,即需要对新开线程的数量进行管理,否则虽然执行线程没有被阻塞,还是会浪费大量线程资源尝试socket连接
SockIOPool:
1. socket pool的管理
2. 服务器节点状态管理
3. key-server映射管理
4. failover处理
5. 负载均衡的实现
socket pool管理
1. SocketPool的私有属性_availPool存放空闲的socket列表,_busyPool存放正在作业的socket列表
_availPool和_busyPool都是HashTable,key为server的string,值为一个HashTable,存放 SocketIO实例(这个HashTable的key为SocketIO实例对象,值为加入pool的时间,这个加入时间将用于最大空闲时间、最大工作时间的控制)
2. SocketPool.Initialize时,为每个server创建InitConnections数量的socket连接,放入空闲列表中
如前面所说,实际是针对每个Weights单位创建初始化连接数量的
3. 处理请求时,如果空闲列表中存在,则从空闲列表取出socket,放入工作列表,并返回给请求者;作业结束后如果socket仍然是连接状态,则从工作列表中删除,放回空闲列表
如果空闲列表中没有可用socket,则创建socket对象并返回给请求者
创建过程的处理:并不是每次仅仅创建一个socket对象,第一次遇到socket不够用时将创建1个,第二次创建2个,第三次4个,每次创建数量将增倍,单次创建的最大数量为MinConnections/4(MinConnections小于4时取MinConnections)。多创建的 socket放入空闲列表,最后一个放入工作列表并返回给请求者。SocketIOPool的_createShift存放下次创建时的倍数,key为 server的string,值为倍数,维护线程在释放空闲列表中多余的socket之后会重置这个倍数
这样的处理方式,有利于某时间段内请求快速上升时的处理性能
4. 处理请求时如果发生socket通讯异常,socket对象被真正释放掉,并从工作列表中移除
如果发生其他类型异常,则将socket从工作列表移除并放入空闲列表
5. 如果有设置MaintenanceSleep,则每个socket pool会开一个维护线程,每间隔MaintenanceSleep时间执行一次维护工作
维护内容包括:最小连接数、最大连接数、最长空闲时间、最长作业时间的检查控制。最小连接数和最大连接数是以空闲队列的数量做控制的,并不包含当前作业的 socket数量。最长空闲时间、最长作业时间以_availPool、_busyPool中记录的时间为基准,socket对象每次加入 _availPool和_busyPool时都记录了加入时间,socket作业时间如果超过最长作业时间设置,该socket会被强行中断掉。 socket超过最大连接数设置时,并不是一次全部把超过的数量全部释放掉,类似于创建连接时的处理方式,也是逐次递减的释放socket对象,直到等于最大连接数设置
节点状态管理
1. SocketIOPool的私有属性_hostDead存放死节点
key为server的string,值为加入_hostDead的时间;_hostDeadDuration存放下次尝试连接死节点的时间间隔,key为server的string,值为间隔时间
2. 如前面Load Balance配置中提到的,_buckets存放了当前所有节点,并且根据Weights的设置进行分配。节点变成dead server时也不会从_buckets中移除
3. 某个时间点某个server变得不可用时:
作业中的socket将发生异常,直接被释放掉
空闲队列中的socket仍会被分配给后续的请求,但这些请求将发生异常,将socket释放,请求的处理失败
最后该server相关的socket会全部被释放掉,新的请求将尝试创建新的socket连接
4. 任何时候创建新的socket连接时:
如果发生socket异常,则该节点被添加到_hostDead中,_hostDeadDuration的初始化值设置为100ms
后续针对dead server的创建请求,依赖于failover的设置
如果处理结果为节点可用了,则将该节点从_hostDead和_hostDeadDuration中移除,该节点恢复为正常工作节点
failover处理
用于在节点发生故障变成死节点时,提供后续的处理机制
启用failover(设置为true)时:
每隔一定时间间隔才尝试重新连接该节点,期间原来映射到该节点的key将被重新映射到其他可用节点上,该节点恢复之后,这些key会重新映射回该节点
具体处理过程为:
新的请求被映射到dead server时,检查_hostDeadDuration
如果还没有达到设定的时间间隔,则重新将key映射到其他可用server进行处理
如果时间间隔已经到达,则尝试重新连接,连接成功会将该节点从_hostDead中移除,连接失败则将_hostDeadDuration中对应的间隔时间翻倍,即下次将等待更长的时间再尝试连接
禁用failover时:
任何时候新的请求被映射到dead server上,都尝试重新建立socket连接,如果连接建立失败,给客户端返回null值(get、gets等命令)或者是操作失败(返回false值,对于set、add等命令)
MemcachedClient: 为客户端提供各种操作,负责各种命令的实现。也包括压缩、解压的处理,序列化、反序列化等。
基于.NET平台的客户端了:
据我总结,大概常见的有三四种吧。必要的类库或者源码,我都将提供给大家下载。
1).NET memcached client library
Memcached .NET客户端的类库,目前大概只支持.NET1.0和.NET2.0,笔者没仔细研究这个,估计这个已经过时啦。
2)enyim.com Memcached Client
源码地址:点击下载源码 (开源项目,可提供研究学习)
Enyim也是应用比较广泛的Memcached .net客户端,和之前的Memchachedonet 客户端相比,分布式算法应该做了相应优化
3)Memcached Providers
下载地址:点击下载
Memcached Providers的官网上有一份PDF的文档,是教你怎么配置的。
4) BeIT Memcached