memcache面试题
简介
Memcached 是一个开源的分布式缓存系统
提供键值类型的数据存储
特点:
提供内存存储,不提供磁盘存储
只支持单一的整体查询,不支持部分字段查询
不支持模糊查询,条件查找,也没有各种聚合函数对数据进行聚合查询
数据不能备份
memcache缓存最长有效期为30天,如果设置时间超过30天数据会添加不进去
memcache的单个命令是完全原子的。
memcache是多线程处理客户端请求(redis是单线程)
利用hash表实现存储
说明:
set命令指定失效时间为0代表永久存储。但空间不够时根据LRU算法可能会被删除
memcache最大的优势
Memcached 最大的好处就是它带来了极佳的水平可扩展性
memcached 之间没有相互通信,因此不会增加 memcached 的负载;
redis和memcache对比:
redis和memcache的单个命令都是原子的
redis单线程,memcache是多线程接收用户请求
redis支持多种数据类型,memcache只支持value的整个存储
reids支持持久哈,memcache不支持持久化
Memcache 可以使用 Magent 在客户端进行一致性 hash 做分布式。Redis 支
持在服务器端做分布式
memcache身份认证
没有身份认证机制!memcached 是运行在应用下层的软件(身份验证应该是应用
上层的职责)。
memcache多线程
命令解析(memcached 在这里花了大部分时间)可以运行在多
线程模式下。memcached 内部对数据的操作是基于很多全局锁的(因此这部分工
作不是多线程的)。
Memcache高性能原因
1.两阶段哈希结构:
- 第一阶段在客户端,通过 Hash算法根据Key值算出一个节点;
- 第二阶段在服务端,通过一个内部的Hash算法,查找真正的item并返回给客户端。从实现的角度看,MemCache是一个非阻塞的、基于事件的服务器程序
- 读写都是对内存操作
3、使用多路复用I/O模型,还使用多线程可以同时处理多个请求。
(redis也使用了多路复用io模型,不过是单线程处理客户端请求)
memcache查询过程
在一个memcached的查询中,Client先通过计算key的hash值来确定kv对所处在的Server位置。当Server确定后,客户端就会发送一个查询请求给对应的Server,让它来查找确切的数据。
memcache写缓存过程
1、应用程序输入需要写缓存的数据
2、API将Key输入路由算法模块,路由算法根据Key和MemCache集群服务器列表得到一台服务器编号
3、由服务器编号得到MemCache及其的ip地址和端口号
- API调用通信模块和指定编号的服务器通信,将数据写入该服务器,完成一次分布式缓存的写操作
memcache如何处理容错
- 启动热备节点,接管失效节点所占用的 IP。这样可以防止哈希紊乱
- 一致性hash减少哈希紊乱
memcache主从
Memcache集群
memcached尽管是“分布式”缓存服务器,但服务器端并没有分布式功能,各个memcached不会互相通信以共享数据,这完全取决memcached api的客户端所使用的路由算法;
通过客户端的算法把数据保存在不同的memcached中
Memcached常见分布式算法
1.余数Hash
将传入的key转换为Hash值
获取服务器数量列表
取余:Hash值%服务器数量
通过余数来选择具体存放/查询的服务器
优缺点:简便易理解、增加/减少节点会造成灾难
2.一致性Hash
将服务器列表+虚拟节点分布在0-2的32次方的一个圆上
将传入的key转换为Hash值
获取服务器数量列表
取余:Hash值%服务器数量
通过余数来选择具体存放/查询的服务器
如果余数命中虚拟节点,则会顺时针寻找真实Memcached服务

主流的是使用一致性hash算法来路由到memcache服务器
一致性hash的实现
java中使用treeMap
Memcache原理
Memcached 进程运行之后,会预申请一块较大的内存空间,自己进行管理,用完之后再申请一块,而不是每次需要的时候去向操作系统申请。Memcached将对象保存在一个巨大的Hash表中(这个hash表是还是用数组+链表的方式来实现的,数据量达到一定值也会进行扩容,迁移数据)
memcache过期机制
Memcache删除机制
空间不足的时候,Memcached会优先使用已经过期的数据空间,如果还不够,那么就会把最近最少使用的对象的空间释放出来使用。当某个单元被请求时,维护一个计数器,通过计数器来判断最近谁最少使用,就把谁踢出去。所以也有可能删除一些尚未过期或者永久有效的数据。
MemCache的LRU算法不是针对全局的,是针对slab的
懒惰删除机制
1.4.25及以前版本使用 惰性删除机制,不会自动清理,作删除标记,下次分配的时候直接使用
之后版本会隔指定时间进行查找是否有过期item,如果有过期会进行删除处理。
memcache的LRU:
LRU策略不是针对所有的slabs,而是只针对新数据应该被放入的slab,当数据应该放的chunk所在的slabs内存不够的时候就会使用LRU
LRU原理是根据访问时间把key放入一张链表,不断更新,这样队尾就是最长时间没有使用的。
memcache的LRU可以禁止,启动时添加-M参数就行,内存用尽时memcached会返回错误
memcache连接限制
最大连接数限制为1024
Memcache内存使用原理
MemCache内存分配的方式称为allocator
Memcache的存储涉及到slab_class,slab,page,chunk四个概念
1、MemCache将内存空间分为一组slab
2、每个slab下又有若干个page,每个page默认是1M,如果一个slab占用100M内存的话,那么这个slab下应该有100个page
3、每个page里面包含一组chunk,chunk是真正存放数据的地方,同一个slab里面的chunk的大小是固定的,chunk的最小尺寸可以通过memcache的启动参数指定,page固定为1m,所以chunk最大不能超过1m。
4、有相同大小chunk的slab被组织在一起,称为slab_class
MemCache中的value过来存放的地方是由value的大小决定 的,value总是会被存放到与chunk大小最接近的一个slab中,比如slab[1]的chunk大小为80字节、slab[2]的chunk大小 为100字节、slab[3]的chunk大小为128字节(相邻slab内的chunk基本以1.25为比例进行增长,MemCache启动时可以用-f指定这个比例), 那么过来一个88字节的value,这个value将被放到2号slab中。放slab的时候,首先slab要申请内存,申请内存是以page为单位的, 所以在放入第一个数据的时候,无论大小为多少,都会有1M大小的page被分配给该slab。申请到page后,slab会将这个page的内存按 chunk的大小进行切分,这样就变成了一个chunk数组,最后从这个chunk数组中选择一个用于存储数据。
如果这个slab中没有chunk可以分配了怎么办,如果MemCache启动没有追加-M(禁止LRU,这种情况下内存不够会报Out Of Memory错误),那么MemCache会把这个slab中最近最少使用的chunk中的数据清理掉,然后放上最新的数据。

总结:
memcache存储数据的最小单位是chunk,大小相等的chunk组成了page,page默认大小是1M,多个page组成了slab;相同大小chunk的slab被组织在一起,称为slab_class
同一个slab中的chunk大小都是一样的,value过来后会被存放到与chunk大小最接近的一个slab中
内存删除策略是针对slab的
为什么这样使用
避免浪费内存
memcached键值大小限制
Memcached是键值一一对应,key默认最大不能超过250个字节,value默认大小是1M
在memcached.h中定义key的长度,超过该长度无法存储
Redis 的 Key 长度支持到 512k。
为什么限制key的长度
主要是节省内存,节省带宽,而且可以存储到更加高效的slab class
key为什么限制250字节
限制key的长度
- 可以使用缩写来减少长度
- 使用base64编码来缩短key
- 使用二进制协议序列化
数据大于1M的问题
如果数据大小大于1M,数据会添加失败
Memcahce默认的page大小为1M,可以启动的时候指定大小,由于数据是存放在page中的chunk中的,所以chunk的大小最大就是page的大小,所以数据默认最大限制为1M
真的要存大于1M的怎么办
可以考虑在客户端压缩或拆分到多个key中。
memcache高可用
由于memcache本身服务器之间无法进行通信所以无法做主从,可以通过magent软件来实现
magent是一款开源的代理服务软件,我们可以通过他来实现缓存数据的同步,当然这里说的同步不是说memcached之间就能互相通讯了,而是magent可以备份数据,而magent可以同时连接多个memcached节点,当memcached重启或者宕机恢复后可以从magent指定的memcached的备份节点中恢复丢失的缓存数据。
memcache扩容
只需要添加额外的服务并修改客户端配置。
memcache缓存30天
memcached的过期时间,有一个最大时限就是30天,设置时若超过30天,存储时返回true,但是在获取数据的时候取不到
memcache常用命令
运行参数
-p 监听的端口
-l 连接的IP地址, 默认是本机
-d start 启动memcached服务
-d restart 重起memcached服务
-d stop|shutdown 关闭正在运行的memcached服务
-d install 安装memcached服务
-d uninstall 卸载memcached服务
-u 以的身份运行 (仅在以root运行的时候有效)
-m 最大内存使用,单位MB。默认64MB
-M 内存耗尽时返回错误,而不是删除项
-c 最大同时连接数,默认是1024
-f 块大小增长因子,默认是1.25
-n 最小分配空间,key+value+flags默认是48
-h 显示帮助
如:
Memcached.exe –d -m 50 –l 127.0.0.1 -p 11211 start
其他命令
|
Command |
Description |
Example |
|
get |
返回Key对应的Value值 |
get mykey |
|
set |
无条件地设置一个Key值,没有就增加,有就覆盖,操作成功提示STORED |
set mykey 0 60 5 |
|
add |
Add a new key |
add newkey 0 60 5 |
|
replace |
按照相应的Key值替换数据,如果Key值不存在则会操作失败 |
replace key 0 60 5 |
|
append |
Append data to existing key |
append key 0 60 15 |
|
prepend |
Prepend data to existing key |
prepend key 0 60 15 |
|
incr |
Increments numerical key value by given number |
incr mykey 2 |
|
decr |
Decrements numerical key value by given number |
decr mykey 5 |
|
delete |
Deletes an existing key |
delete mykey |
|
flush_all |
清空所有键值,但不会删除items,所以此时MemCache依旧占用内存 |
flush_all |
|
Invalidate all items in n seconds |
flush_all 900 |
|
|
stats |
返回MemCache通用统计信息 |
stats |
|
返回MemCache运行期间创建的每个slab的信息 |
stats slabs |
|
|
Prints memory statistics |
stats malloc |
|
|
返回各个slab中item的数目和最老的item的年龄(最后一次访问距离现在的秒数) |
stats items |
|
|
|
stats detail |
|
|
|
stats sizes |
|
|
Resets statistics |
stats reset |
|
|
version |
返回当前MemCache版本号 |
version |
|
verbosity |
Increases log level |
verbosity |
|
quit |
关闭连接 |
quit |
stats命令
stats
STAT pid 1162
STAT uptime 5022
STAT time 1415208270
STAT version 1.4.14
STAT libevent 2.0.19-stable
STAT pointer_size 64
STAT rusage_user 0.096006
STAT rusage_system 0.152009
STAT curr_connections 5
STAT total_connections 6
STAT connection_structures 6
STAT reserved_fds 20
STAT cmd_get 6
STAT cmd_set 4
STAT cmd_flush 0
STAT cmd_touch 0
STAT get_hits 4
STAT get_misses 2
STAT delete_misses 1
STAT delete_hits 1
STAT incr_misses 2
STAT incr_hits 1
STAT decr_misses 0
STAT decr_hits 1
STAT cas_misses 0
STAT cas_hits 0
STAT cas_badval 0
STAT touch_hits 0
STAT touch_misses 0
STAT auth_cmds 0
STAT auth_errors 0
STAT bytes_read 262
STAT bytes_written 313
STAT limit_maxbytes 67108864
STAT accepting_conns 1
STAT listen_disabled_num 0
STAT threads 4
STAT conn_yields 0
STAT hash_power_level 16
STAT hash_bytes 524288
STAT hash_is_expanding 0
STAT expired_unfetched 1
STAT evicted_unfetched 0
STAT bytes 142
STAT curr_items 2
STAT total_items 6
STAT evictions 0
STAT reclaimed 1
END
这里显示了很多状态信息,下边详细解释每个状态项:
pid: memcache服务器进程ID
uptime:服务器已运行秒数
time:服务器当前Unix时间戳
version:memcache版本
pointer_size:操作系统指针大小
rusage_user:进程累计用户时间
rusage_system:进程累计系统时间
curr_connections:当前连接数量
total_connections:Memcached运行以来连接总数
connection_structures:Memcached分配的连接结构数量
cmd_get:get命令请求次数
cmd_set:set命令请求次数
cmd_flush:flush命令请求次数
get_hits:get命令命中次数
get_misses:get命令未命中次数
delete_misses:delete命令未命中次数
delete_hits:delete命令命中次数
incr_misses:incr命令未命中次数
incr_hits:incr命令命中次数
decr_misses:decr命令未命中次数
decr_hits:decr命令命中次数
cas_misses:cas命令未命中次数
cas_hits:cas命令命中次数
cas_badval:使用擦拭次数
auth_cmds:认证命令处理的次数
auth_errors:认证失败数目
bytes_read:读取总字节数
bytes_written:发送总字节数
limit_maxbytes:分配的内存总大小(字节)
accepting_conns:服务器是否达到过最大连接(0/1)
listen_disabled_num:失效的监听数
threads:当前线程数
conn_yields:连接操作主动放弃数目
bytes:当前存储占用的字节数
curr_items:当前存储的数据总数
total_items:启动以来存储的数据总数
evictions:LRU释放的对象数目
reclaimed:已过期的数据条目来存储新数据的数目
memcache的操作是原子的吗
memcached的单个命令是完全原子的
memcache的incr操作也是原子操作,如果对应的key不存在,会报错
memcache配置
服务器端配置
memcache启动命令指定配置内容,没有配置文件
如:memcached -m 512 -u root -d -l 127.0.0.1 -p 11211
-d # 以后台守护进程的方式运行,等于--daemon参数,默认是关闭了的
-u # 指定以哪个用户来运行,等于--user参数,默认是root用户
-l # 指定监听的IP地址,等于--listen参数,默认监听的是0.0.0.0 即所有IP地址
-p # 指定监听的端口,等于--port参数,默认监听的是11211,具体用啥看你的规划
-t # 指定线程数,等于--threads参数,默认是两个;
-P #(大写P) 生成pid文件,并指定pid文件保存的位置,等于--pidfile参数,默认是不会生成的;
-s # 生成socket文件,并指定socket文件保存的午饭了,等于--socket参数,默认是不会生成的;
-c # 指定最大并发连接数,等于--conn-limit参数,默认是1024;
-------------------------------------------------------------------------------------------------------------------
-m # 指定分配多少内存,单位是M,等于--memory-limit参数,默认值是64,那就是64M
应用端配置
服务器ip及端口列表
servers host1:11211,host2:11211,host3:11211
memcache做集群
1程序端进行使用路由算法路由服务器
2使用负载均衡器
为什么这样做集群
这种MemCache集群的方式也是从分区容错性的方面考虑的,假如Node2宕机了,那么Node2上面存储的数据都不可用了,此时由于集群中Node0和Node1还存在,下一次请求Node2中存储的Key值的时候,肯定是没有命中的,这时先从数据库中拿到要缓存的数据,然后路由算法模块根据Key值在Node0和Node1中选取一个节点,把对应的数据放进去,这样下一次就又可以走缓存了,这种集群的做法很好,但是缺点是成本比较大。
Magent
Magent是一款开源的Memcached代理服务器软件,使用它可以搭建高可用性的集群应用的Memcached服务
采用一致性hash路由算法
Libevent和memcache
其他
MemCached和MemCache
MemCache是项目的名称
MemCached是MemCache服务器端可以执行文件的名称

浙公网安备 33010602011771号