一、基础知识
1.1 什么是Memcached
Memcached:是一个免费开源的、高性能的、具有分布式内存对象的缓存系统,它通过减轻数据库负载加速动态Web应用;
Memcached的特性:
本质上就是一个内存key-value缓存;
协议简单,使用的是基于文本行的协议;
不支持数据的持久化,服务器关闭之后数据全部丢失;
Memcached简洁而强大,便于快速开发,上手较为容易;
互不通信的Memcached之间具有分布特征(节点与节点之间不做任何通信) ;
没有安全机制
1.2 使用场景
适合:
变化频繁,查询频繁,但不需要入库的场景
变化不频繁,查询频繁
读多邪少的场景中用于页面缓存
不适合:
pv值不高(就是page view页面展示次数不多),不考虑使用Memcached
变化频繁且需要入库(因为Memcached不能持久化,所以入库的场景不用考虑Memcached)
过大的数据不宜放在Memcached中(因为过大的数据本身就不宜放在内存中)
1.3 与Redis对比
首先来看下线程模型,Redis是单进程单线程的模式,而memcached是单进程多线程,这肯定memcached性能比redis要好那么一点,这样的差距反应在QPS/TPS的比较中,不过这个差别也不是特别的大。没错,这么一比较memcached也并不是一无是处,但这也就是memcached唯一的可圈可点之处了。其他的基本redis超过memcached一大截。
Redis集群与Memcached集群比较
redis集群,不管是redis中的哨兵还是cluster集群,服务与服务之间是可以有数据的同步的,master的节点数据会通过slaveof的配置参数进行同步
首先会通过一个Memcached的“应用程序”去访问客户端(中间那一块),这个客户端就是我们的java代码,是这个客户端负责和各个节点之间进行通信的,节点与节点之间是不进行通信的,所以它不支持高可用。
1.4 安装
1.4.1 单机安装
第一步:准备工作
在linux根目录创建soft文件夹(根据自己习惯),输入命令 mkdir /soft
在soft目录里面上传课件里面的两文件 libevent-2.1.8-stable.tar.gz和memcached-1.5.12.tar.gz
第二步:安装libevent
安装Memcached应该先安装好libevent依赖,在soft目录里面执行命tar -xzvf libevent-2.1.8-stable.tar.gz
进入libevent的目录,开始安装libevent,输入以下三条命令
./configure -prefix=/soft/libevent
make
make install
通过上述命令,libevent已经安装到/soft/libevent目录了
第三步:安装Memcached
在soft目录解压上传的memcached,输入命令tar -zxvf memcached-1.5.12.tar.gz
注意:编译的时候需要指定动态链接库,需要linux把libevent/lib目录加载进来,下面的步骤特别重要
vi /etc/ld.so.conf
在ld.so.conf目录中增加libevent/lib所在目录,wq保存退出
增加(请根据libevent实际安装目录设置)
/soft/libevent/lib
执行下面命令让上面的修改生效
ldconfig
下面可以正式安装memcached,需要指定libevent的安装位置
./configure -prefix=/soft/memcached --with-libevent=/soft/libevent
make
make install
测试是否安装成功
进入memcached的安装目录下的bin目录
执行:
./memcached -h
发现有如上界面说明memcached 已经安装成功
Memcached的启动
进入memcached的安装目录下的bin目录
输入以下命令
./memcached -m 16 -p 11211 -d -c 1024 -u root
-d 选项是启动一个守护进程,
-m 是分配给Memcache使用的内存数量,单位是MB,这里是1024MB,默认是64MB
-u 是运行Memcache的用户,这里是root
-l 是监听的服务器IP地址,默认应该是本机
-p 是设置Memcache监听的端口,默认是11211,最好是1024以上的端口
-c 选项是最大运行的并发连接数,默认是1024,这里设置了1024,按照你服务器的负载量来设定
-P 是设置保存Memcache的pid文件位置
-h 打印帮助信息
-v 输出警告和错误信息
-vv 打印客户端的请求和返回信息
查看Memcached是否启动成功,输入命令 ps -ef | grep memcached 查看
1.4.2 集群安装
memcached 可以安装到多台机器上,安装方式与上面一样。这里就不分别安装了,就在当前的节点上启动多个memcached 实例。
memcached -m 16 -p 11212 -d -c 1024 -u root
memcached -m 16 -p 11213 -d -c 1024 -u root
通过上面两条命令,实际又启动了2个memcached实例,加上上面启动的,总共启动了3个memcached实例
ps -ef | grep memcached 查看
停止Memcached
Kill -9 进程号
例如现在我要杀掉上图的端口号为11211的Memcached,那么命令是Kill -9 10763
二、客户端使用
2.1 telnet
2.1.1 安装Telnet
安装telnet部分转自https://www.cnblogs.com/sz-jack/p/9760030.html
[root@iZ8vb4ukto7mbo5xsnb2ecZ ~]# rpm -qa xinetd #检查是否安装过
xinetd-2.3.15-13.el7.x86_64
[root@iZ8vb4ukto7mbo5xsnb2ecZ ~]# rpm -qa telnet-server #检查是否安装过
telnet-server-0.17-64.el7.x86_64
[root@iZ8vb4ukto7mbo5xsnb2ecZ ~]# rpm -e --nodeps xinetd-2.3.15-13.el7.x86_64 telnet-server-0.17-64.el7.x86_64 #卸载已经存在的安装文件
[root@iZ8vb4ukto7mbo5xsnb2ecZ ~]# yum list |grep telnet
dcap-tunnel-telnet.x86_64 2.47.12-4.el7 epel
libguac-client-telnet.x86_64 1:0.9.14-1.el7 epel
libtelnet.x86_64 0.21-5.el7 epel
libtelnet-devel.x86_64 0.21-5.el7 epel
libtelnet-utils.x86_64 0.21-5.el7 epel
telnet.x86_64 1:0.17-64.el7 base
telnet-server.x86_64 1:0.17-64.el7 base
[root@iZ8vb4ukto7mbo5xsnb2ecZ ~]# yum list |grep xinetd
xinetd.x86_64 2:2.3.15-13.el7 base
3,执行安装语句
yum -y install telnet-server.x86_64
yum -y install telnet.x86_64
yum -y install xinetd.x86_64
4,设置开机自启:
systemctl enable xinetd.service
systemctl enable telnet.socket#这个命名如果第一次执行报错,再执行下即可。
5,开启service:
systemctl start telnet.socket
systemctl start xinetd
2.1.2 使用telnet操作Memcached
1,连接Memcached(注意在telnet中删除是要按着ctrl键进行删除的看):
命令telnet ip 端口
例如 telnet 127.0.0.1 11211
输入telnet命令之后回车然后输入stats再回车
2,Memcached的命令:
例如存储命令语法格式举例:
set key flags exptime bytes [noreply]
value
参数解释(这些参数不仅适用于set命令):
key:键值 key-value 结构中的 key,用于查找缓存值。
flags:可以包括键值对的**整型**参数,客户机使用它存储关于键值对的额外信息 。
exptime:在缓存中保存键值对的时间长度(以秒为单位,0 表示永远)
bytes:在缓存中存储的字节数
noreply(可选): 该参数告知服务器不需要返回数据
value:存储的值(始终位于第二行)(可直接理解为key-value结构中的value)
输出信息:
STORED:保存成功后输出。
ERROR:保存出错或语法错误。
EXISTS:在最后一次取值后另外一个用户也在更新该数据。
NOT_FOUND:Memcached 服务上不存在该键值
例如
replace,如果不存在此key,则失败
set,如果存在此key则是修改,不存在则新增
轻量级的所机制CAS机制(本质就是一个乐观锁)
解释:Check and set,即保存之前进行版本检查,memcache1.2.4新增的特性
有了版本号之后就可以用CAS更新了
查找相关命令
2.2 Java客户端
2.2.1 Memcached-Java-Client
2.2.2 spymemcach
2.2.3 XMencached
2.2.4 Spring Cache集成实战
三、原理
3.1 一致性Hash算法(重点)
3.1.1 Hash算法
如果不是在分布式环境下就不要选择一致性Hash。memcached的单节点是有存储局限的,所以有时候需要用到多节点,那么集群memcached就有一个分布式存储与分布式读取的问题,不管是写入还是读取,肯定要通过某种算法来把写入或读取操作定位到某个固定的节点。
3.1.2 余数分散(普通Hash)
整个过程可以看出公式
公式:m = hash(o) mod n
3.1.3 一致性Hash算法
一致性hash是为了解决普通hash的问题,使用一个环状结构,具体可以分层4步骤。
步骤1:构建环形hash空间
说明:
一致性hash算法通过一个叫作一致性hash环的数据结构实现
这个环的起点是0,终点是2^32 - 1,并且起点与终点连接,环的中间的整数按逆时针分布
这个环的整数分布范围是[0, 2^32-1]
步骤二:把对象映射到环形hash空间
假设现在我们有4个对象,他们的key分别为o1,o2,o3,o4,通过这些key可以找到对应的对象,
使用hash函数计算这4个对象的hash值(范围为0 ~ 2^32-1)
步骤三:把cache节点映射到hash空间
使用同样的hash函数,我们将机器也放置到hash环上。
假设我们有三台缓存机器,分别为 c1,c2,c3,一般使用节点对应的ip作为c1,c2,c3
使用hash函数计算这3台机器的hash值
步骤四:对象映射到cache节点
将对象和机器都放置到同一个hash环后
在hash环上顺时针查找距离这个对象的hash值最近的机器,即是这个对象所属的机器。
步骤五:增加一个节点的情况
增加机器c4的部署并将机器c4加入到hash环的机器c3与c2之间。
只有对象o4被重新分配到了c4
其他对象仍在原有机器上
步骤六:删除一个节点的情况
将机器c1下线(当然,也有可能是机器c1宕机)
只有对象o2被重新分配到机器c3
其他对象仍在原有机器上
步骤七:虚拟节点
仅仅使用真实的节点来形成环的结构可能会导致数据的倾斜,为了解决这种数据不对称的现象,可以在原理缓存的机器的基础上,增加相应的虚拟节点,这样数据就会均匀的打散到其他节点中。
这个时候客户端进行数据存取的时候找的就是虚拟节点,而不是真实的物理节点服务器。
这样增加节点会删除节点虽然命中率会降低,却很好的解决了数据倾斜问题。
3.2 内存管理策略
Memcached采用Slab Allocator(Slab分配器)进行内存管理
3.2.1 Slab
内存被拆分为多个SlabClass
每个Slab Class中有多个Slab 每个Slab=1M
每个Slab下有多个大小相等的Chunk
不同Slab中的Chunk大小不等
数据存储在Chunk中
3.2.2 增长因子
步骤一:启动Memcached,启动时加上-vv参数
memcached -p 11211 -d -u root -vv
其中-vv显示memcached的内存分配情况,如下图所示
这里会显示memcached内存会分配的情况。
每一行的显示如下
slab class 1: chunk size 96 perslab 10922
其中chunk size 为96,总共有10922个块
96*10922=1048512/1024/1024 = 0.9999 M
步骤二:客户端测试
使用telnet 连接上服务端
telnet 127.0.0.1 11211
查看内存分布情况
stats slabs
可以看到激活的slabs的数目为0,可以分配的内存也是0
新增一个数据
add k1 0 0 10
1234567890
在使用stats查看内存分布情况
再新增一个数据
add k2 0 0 10
1234567890
这个时候发现已经用了2个块。
新增一个数据
add k3 0 0 100
1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
启动时指定增长-f(growth factor)因子,就可以在某种程度上控制slab之间的差异,默认值为1.25 命令
memcached -p 11211 -f 2 -d -u root -vv
注意:真实项目中,要均衡数据的大小,如果数据之间大小差别不大建议增长因子设置比较小,而数据之间大小悬殊,数据的增长因子可以考虑增大。
3.3 缓存过期策略
MC不会主动删除过期数据,而是采用lazy策略
Memcached不会释放已分配的内存,其存储空间可以重复使用
Memcached内部不会监视数据是否过期,而是在get时查看数据的时间戳,查看数据是否过期。被称为lazy expiration(惰性过期)
Memcached内存空间不足,即无法从slab class中获取到新的空间时,就从最近未被使用的数据中搜索,将其空间分配给新的数据。(如果要禁用LRU,使用-M参数,超出会报错)
以上内容来自“腾讯享学课堂”笔记整理 | 转载请保留此段文字