摘要:余数分布式算法就是根据服务器台数的余数进行分散。余数分布式算法由于保存键的服务器会发生巨大变化,而影响缓存的命中率,但中,只有在上增加服务器的地点逆时针方向的第一台服务器上的键会受到影响。
WHAT is Memcache?
Free & open source, high-performance, distributed memory object caching system, generic in nature, but intended for use in speeding up dynamic web applications by alleviating database load.
memcached是一个免费开源、高性能、分布式的内存对象缓存系统,本质上是通用的,但旨在通过加速动态Web应用程序来减轻数据库负载。
Memcache是一款开发工具,其设计思想主要反映以下几个方面:
简单的key/value存储:服务器不关心数据本身意义及结构,主要是可序列化数据即可。
功能实现一半依赖与客户端,一半基于服务器端。
各服务器间彼此无视,不在服务器间进行数据同步。
O(1)的执行效率。
内存空间的再利用,Lazy Expiration + LRU 机制。
Memcache 与 memcached的区别1.客户端两者区别:
两个不同版本PHP的memcached的客户端
memcache是原生版本,完全是在PHP框架内开发的,支持OO和非OO两套接口并存;而memcached是建立在libmemcached的基础上,只支持OO接口。
其他一些实现和支持方面的不同等。
2.服务器端两者区别:
Memcache 是项目名称
Memcached 是Memcache服务器端可执行文件的名称,Memcached是以守护程序(监听)方式运行于一个或多个服务器中,随时会接收客户端的连接和操作。
ps:本文说明的内容是关于memcache服务器的,请不要跟客户端的叫法混淆。
Memcached内置内存存储方式1. Memcached 的高性能
首先从内存模型来研究memcached:C++里分配内存有两种方式,预先分配和动态分配内存,显然预先分配内存会使程序比较快,但是它的缺点是不能有效利用内存;而动态分配可以有效利用内存,但是会使程序运行效率下降,memcached的内存分配就是基于以上原理,显然为了获得更快的速度,有时候我们不得不以空间换时间。
Memcached的高性能源于两阶段哈希(two-stage-hash)结构。Memcached就像一个巨大的、存储了很多
为了提高性能,memcacahed中保存的数据都存储在memcached内置的内存存储空间中。由于数据仅存在于内存中,因此重启memcached、重启操作系统会导致全部数据丢失。另外,内存容量达到指定值之后,就基于LRU(Least Recently Used)算法自动删除不使用的缓存。memcached本身是为了缓存而设计的服务器,因此并没有过多考虑数据的永久性问题。
2. Slab Allocator 内存分配、管理机制
1.在该机制出现以前,内存的分配是通过对所有记录简单地进行malloc和free 来进行的。但是,这种方式会导致内存碎片,加重操作系统内存管理器的负担,最坏的情况下,会导致操作系统比memcached 进程本身还慢。Slab Allocator 就是为解决该问题而诞生的, 它按照预先规定的大小,将分配的内存分割成特定长度的块,以完成解决内存碎片的问题。存储结构图如下:
Memcached的存储涉及到slab、page、chunk三个概念
chunk:固定大小的内存空间,用于缓存记录,默认为88Byte。
page:分配给Slab的内存空间,默认是1M。分配给Slab之后根据Slab的大小切成chunk。
slab:同样大小的chunk组成一类slab。
2.在Slab中缓存记录的原理
memcached 根据收到的数据大小,选择最适合数据大小的Slab,memcached中保存着Slab内空闲chunk的列表,根据该列表选择chunk,然后将数据缓存其中。Slab allocator分配的内存不会释放,而是重复利用。
3.Slab Allocator 的缺点
由于分配的是特定长度的内存,因此无法有效的利用分配的内存。对与该问题没有完美的解决方案,但可以调节slab class的大小差别来减少空间浪费。
4.使用Growth Factor进行调优
memcached在启动时制定Growth Factor因子(通过f选项),就可以在某种程度上控制slab之间的差异。默认值时1.25.
memcached是缓存,不需要永久的保存到服务器上,下面介绍它的删除机制:
1.Lazy Expiration
memcached 不会释放已经分配的内存,记录过期后,客户端无法在看到这条记录,其存储空间可以再利用。memcached内部不会监视记录是否过期,而是在get时查看记录的时间戳,检查记录是否过期。这种技术被称为Lazy Expiration。因此,memcached不会在过期监视上耗费CPU时间。
2.LRU(Least Recently Used)
memcached会优先使用已超时的记录空间,但即使如此,也会发生追加新记录时空间不足的情况,此时就要使用名为LRU机制来分配空间。顾名思义,这是删除“最近最少使用”记录的机制。因此,当memcahced的内存空间不足时(无法从slab class获取新的空间时),就从最近未被使用的记录中搜索,并将其空间分配给新的记录。
1.Memcached "分布式"
特别澄清一个问题:MemCache虽然被称为"分布式缓存",但是MemCache本身完全不具备分布式的功能,Memcache集群之间不会相互通信(与之形成对比的,比如JBoss Cache,某台服务器有缓存数据更新时,会通知集群中其他机器更新缓存或清除缓存数据),所谓的"分布式",完全依赖于客户端程序的实现。前面已经讲过memcached的两段哈希了,数据的保存和获取都使用相同的算法。这样将不同的键保存到不同的服务器上,就实现了memcached的分布式。Memcached服务器增多后,键就会分散,即使一台memcached服务器发生故障无法连接,也不会影响其他的缓存,系统依然能继续进行。
2.余数分布式算法
就是“根据服务器台数的余数进行分散”。求得键的整数哈希值,再除以服务器台数,根据其余数来选择服务器。
余数算法的缺点:余数计算的方法简单,数据的分散性也相当优秀,但也有其缺点。那就是当添加或移除服务器时,缓存重组的代价相当巨大。添加服务器后,余数就会产生巨变,这样就无法获取与保存时相同的服务器,从而影响缓存的命中率。
3.Consistent hashing(一致哈希)
首先求出memcached 服务器(节点)的哈希值,并将其配置到0~2^32-1 的圆(continuum)上。然后用同样的方法求出存储数据的键的哈希值,并映射到圆上。然后从数据映射到的位置开始顺时针查找,将数据保存到找到的第一个服务器上。如果超过2^32-1仍然找不到服务器,就会保存到第一台memcached 服务器上。
从上图的状态中添加一台Memcached 服务器。余数分布式算法由于保存键的服务器会发生巨大变化,而影响缓存的命中率,但Consistent Hashing中,只有在continuum 上增加服务器的地点逆时针方向的第一台服务器上的键会受到影响。
Consistent Hashing(添加服务器):
因此,Consistent Hashing 最大限度地抑制了键的重新分布。而且,有的Consistent Hashing 的实现方法还采用了虚拟节点的思想。使用一般的hash函数的话,服务器的映射地点的分布非常不均匀。因此,使用虚拟节点的思想,为每个物理节点(服务器)在continum上分配100~200 个点。这样就能抑制分布不均匀,最大限度地减小服务器增减时的缓存重新分布。
通过上文中介绍的使用Consistent Hashing 算法的Memcached 客户端函数库进行测试的结果是,由服务器台数(n)和增加的服务器台数(m)计算增加服务器后的命中率计算公式: (1 -m/(n+m)) * 100
1.存储及删除命令,简单易用,使用语法如下:
command
参数说明如下:
command set/add/replace
key key 用于查找缓存值
flags 可以包括键值对的整型参数,客户机使用它存储关于键值对的额外信息
expiration time 在缓存中保存键值对的时间长度(以秒为单位,0 表示永远)
bytes 在缓存中存储的字节数
value 存储的值(始终位于第二行)
set 命令用于向缓存添加新的键值对,如果已经存在,则之前的值将被替换。设置成功,服务器会使用单词STORED进行响应。
add 仅当缓存中不存在键时,add 命令才会向缓存中添加一个键值对。如果缓存中已经存在键,则之前的值将仍然保持相同,并且您将获得响应 NOT_STORED。
replace 仅当键已经存在时,replace 命令才会替换缓存中的键。如果缓存中不存在键,那么您将从 memcached 服务器接受到一条 NOT_STORED 响应。
delete 删除命令的语法:command
2.读取命令
get 命令用于检索与之前添加的键值对相关的值。当使用一个键来调用 get,如果这个键存在于缓存中,则返回相应的值。如果不存在,则不返回任何内容。get命令的key可以表示一个或者多个键,键之间以空格隔开。
gets 命令比普通的get命令多返回一个数字。这个数字可以检查数据是否发生变化:当key对应的数据变化时,这个数字也会改变。
cas 即check and set,只有当最后一个参数和gets所获取的参数匹配时才能存储,否则返回“EXISTS”。
3.统计命令
stats 显示服务器信息、统计数据
stats settings 显示所有的参数设置
stats slabs 显示各个slab的信息,包括chunk的大小、数目、使用情况等
stats items 显示各个slab的item信息
stats cachedump slab_id limit_num 查看指定slab前limit_num个item,[key,expiration_time]
flush_all 用于清理缓存中所有键值对
stats reset 清空统计数据
运行状态分析1.stats指令解读
stats是一个比较重要的指令,用于列出当前MemCache服务器的状态,返回的参数反映着Memcache服务器的基本信息,他们的意思是:
参 数 名 | 作 用 |
---|---|
pid | MemCache服务器的进程id |
uptime | 服务器已经运行的秒数 |
time | 服务器当前的UNIX时间戳 |
version | MemCache版本 |
pointer_size | 当前操作系统指针大小,反映了操作系统的位数,64意味着MemCache服务器是64位的 |
rusage_user | 进程的累计用户时间 |
rusage_system | 进程的累计系统时间 |
curr_connections | 当前打开着的连接数 |
total_connections | 当服务器启动以后曾经打开过的连接数 |
connection_structures | 服务器分配的连接构造数 |
cmd_get | get命令总请求次数 |
cmd_set | set命令总请求次数 |
cmd_flush | flush_all命令总请求次数 |
get_hits | 总命中次数,重要,缓存最重要的参数就是缓存命中率,以get_hits / (get_hits + get_misses)表示,比如这个缓存命中率就是99.2% |
get_misses | 总未命中次数 |
auth_cmds | 认证命令的处理次数 |
auth_errors | 认证失败的处理次数 |
bytes_read | 总读取的字节数 |
bytes_written | 总发送的字节数 |
limit_maxbytes | 分配给MemCache的内存大小(单位为字节) |
accepting_conns | 是否已经达到连接的最大值,1表示达到,0表示未达到 |
listen_disabled_num | 统计当前服务器连接数曾经达到最大连接的次数,这个次数应该为0或者接近于0,如果这个数字不断增长, 就要小心我们的服务了 |
threads | 当前MemCache总线程数,由于MemCache的线程是基于事件驱动机制的,因此不会一个线程对应一个用户请求 |
bytes | 当前服务器存储的items总字节数 |
current_items | 当前服务器存储的items总数量 |
total_items | 自服务器启动以后存储的items总数量 |
比较关注的点:get_hits 和 get_misses,命中率:get_hits/(get_hits + get_misses) 是衡量memcache服务器的一个重要指标。
2.stats slabs 指令解读
参 数 名 | 作 用 |
---|---|
chunk_size | 当前slab每个chunk的大小,单位为字节 |
chunks_per_page | 每个page可以存放的chunk数目,由于每个page固定为1M即10241024字节,所以这个值就是(10241024/chunk_size) |
total_pages | 分配给当前slab的page总数 |
total_chunks | 当前slab最多能够存放的chunk数,这个值是total_pages*chunks_per_page |
used_chunks | 已经被分配给存储对象的chunks数目 |
free_chunks | 曾经被使用过但是因为过期而被回收的chunk数 |
free_chunks_end | 新分配但还没有被使用的chunk数,这个值不为0则说明当前slab从来没有出现过容量不够的时候 |
mem_requested | 当前slab中被请求用来存储数据的内存空间字节总数,(total_chunks*chunk_size)-mem_requested表示有多少内存在当前slab中是被闲置的,这包括未用的slab+使用的slab中浪费的内存 |
get_hits | 当前slab中命中的get请求数 |
cmd_set | 当前slab中接收的所有set命令请求数 |
delete_hits | 当前slab中命中的delete请求数 |
incr_hits | 当前slab中命中的incr请求数 |
decr_hits | 当前slab中命中的decr请求数 |
cas_hits | 当前slab中命中的cas请求数 |
cas_badval | 当前slab中命中但是更新失败的cas请求数 |
通过此命令返回的信息,可以查看slab class的分布情况,以及每个slab中chunk使用情况;根据slab的分布,可以判断增长因子的设置的是否合理等。
3.stats items 命令解读
参数名 | 作用 |
---|---|
outofmemory | slab class为新item分配空间失败的次数。这意味着你运行时带上了-M或者移除操作失败 |
number | 存放的数据总数 |
age | 存放的数据中存放时间最久的数据已经存在的时间,以秒为单位 |
evicted | 不得不从LRU中移除未过期item的次数 |
evicted_time | 自最后一次清除过期item起所经历的秒数,即最后被移除缓存的时间,0表示当前就有被移除,用这个来判断数据被移除的最近时间 |
evicted_nonzero | 没有设置过期时间(默认30天),但不得不从LRU中清除该未过期的item的次数 |
因为memcached的内存分配策略导致一旦memcached的总内存达到了设置的最大内存,表示所有的slab能够使用的page都已经固定,这时如果还有数据放入,将导致memcached使用LRU策略剔除数据。而LRU策略不是针对所有的slabs,而是只针对新数据应该被放入的slab,例如有一个新的数据要被放入slab 3,则LRU只对slab 3进行,通过stats items就可以观察到这些剔除的情况。
注意evicted_time:并不是发生了LRU就代表memcached负载过载了,因为有些时候在使用cache时会设置过期时间为0,这样缓存将被存放30天,如果内存满了还持续放入数据,而这些为过期的数据很久没有被使用,则可能被剔除。把evicted_time换算成标准时间看下是否已经达到了你可以接受的时间,例如:你认为数据被缓存了2天是你可以接受的,而最后被剔除的数据已经存放了3天以上,则可以认为这个slab的压力其实可以接受的;但是如果最后被剔除的数据只被缓存了20秒,不用考虑,这个slab已经负载过重了。
memcache已经分配的内存不会再主动清理。
memcache分配给某个slab的内存页不能再分配给其他slab。
flush_all不能重置memcache分配内存页的格局,只是给所有的item置为过期。
memcache最大存储的item(key+value)大小限制为1M,这由page大小1M限制
由于memcache的分布式是客户端程序通过hash算法得到的key取模来实现,不同的语言可能会采用不同的hash算法,同样的客户端程序也有可能使用相异的方法,因此在多语言、多模块共用同一组memcached服务时,一定要注意在客户端选择相同的hash算法
启动memcached时可以通过-M参数禁止LRU替换,在内存用尽时add和set会返回失败
memcached启动时指定的是数据存储量,没有包括本身占用的内存、以及为了保存数据而设置的管理空间。因此它占用的内存量会多于启动时指定的内存分配量,这点需要注意。
memcache存储的时候对key的长度有限制,php和C的最大长度都是250
参考文档https://www.cnblogs.com/xrq73...
http://zhihuzeye.com/archives...
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/61738.html
摘要:丰富的特性具有丰富的特性,比如可以用作分布式锁可以持久化数据可以用作消息队列排行榜计数器还支持通知过期等等。比如利用布隆过滤器,内部维护一系列合法有效的,迅速判断出请求所携带的是否合法有效。 showImg(https://segmentfault.com/img/remote/1460000019070847?w=750&h=300); 场景:Redis面试 showImg(http...
摘要:丰富的特性具有丰富的特性,比如可以用作分布式锁可以持久化数据可以用作消息队列排行榜计数器还支持通知过期等等。比如利用布隆过滤器,内部维护一系列合法有效的,迅速判断出请求所携带的是否合法有效。 showImg(https://segmentfault.com/img/remote/1460000019070847?w=750&h=300); 场景:Redis面试 showImg(http...
阅读 1037·2021-11-24 10:27
阅读 3311·2021-11-18 10:02
阅读 2378·2021-11-16 11:45
阅读 3143·2021-11-15 18:10
阅读 803·2021-09-22 15:23
阅读 1512·2019-08-30 15:53
阅读 3000·2019-08-30 13:20
阅读 1652·2019-08-30 12:53