Memcached缓存
1. 简介
Memcached只支持能序列化的数据类型,不支持持久化,基于Key-Value的内存缓存系统。
1.2 内存分配机制
应用程序运行需要使用内存存储数据,但对于一个缓存系统来说,申请内存、释放内存将十分频繁,非
常容易导致大量内存碎片,最后导致无连续内存空间可用。
Memcached采用了Slab Allocator机制来分配、管理内存
- Page:分配给Slab的内存空间,默认为1MB,分配后就得到一个Slab。Slab分配之后内存按照固
定字节大小等分成chunk。 - Chunk:用于缓存记录kv值的内存空间。Memcached会根据数据大小选择存到哪一个chunk中,
假设chunk有128bytes、64bytes,数据只有100bytes存储在128bytes中,存在些浪费。- Chunk最大就是Page的大小,即一个Page中就一个Chunk
- Slab Class:Slab按照大小分组,就组成不同的Slab Class
如果有100bytes要存,那么Memcached会选择上图中Slab Class 2存储,因为它是120bytes的
Chunk。
Slab之间的差异可以使用Growth Factor控制,默认1.25。
1.3 懒过期Lazy Expiration
memcached不会监视数据是否过期,而是在取数据时才看是否过期,过期的把数据有效期限标识为0,
并不清除该数据。以后可以覆盖该位置存储其它数据。
1.4 LRU
当内存不足时,memcached会使用LRU(Least Recently Used)机制来查找可用空间,分配给新纪录
使用。
1.5 集群
Memcached集群,称为基于客户端的分布式集群。
Memcached集群内部并不互相通信,一切都需要客户端连接到Memcached服务器后自行组织这些节
点,并决定数据存储的节点。
2. 安装
# yum install memcached
# rpm -ql memcached
/etc/sysconfig/memcached
/usr/bin/memcached
/usr/bin/memcached-tool
/usr/lib/systemd/system/memcached.service
/usr/share/doc/memcached-1.4.15
/usr/share/doc/memcached-1.4.15/AUTHORS
/usr/share/doc/memcached-1.4.15/CONTRIBUTORS
/usr/share/doc/memcached-1.4.15/COPYING
/usr/share/doc/memcached-1.4.15/ChangeLog
/usr/share/doc/memcached-1.4.15/NEWS
/usr/share/doc/memcached-1.4.15/README.md
/usr/share/doc/memcached-1.4.15/protocol.txt
/usr/share/doc/memcached-1.4.15/readme.txt
/usr/share/doc/memcached-1.4.15/threads.txt
/usr/share/man/man1/memcached-tool.1.gz
/usr/share/man/man1/memcached.1.gz
# cat /usr/lib/systemd/system/memcached.service
[Service]
Type=simple
EnvironmentFile=-/etc/sysconfig/memcached
ExecStart=/usr/bin/memcached -u $USER -p $PORT -m $CACHESIZE -c $MAXCONN $OPTIONS
# cat /etc/sysconfig/memcached
PORT="11211"
USER="memcached"
MAXCONN="1024"
CACHESIZE="64"
OPTIONS=""
前台显示看看效果
# memcached -u memcached -p 11211 -f 1.25 -vv
# systemctl start memcached
修改memcached运行参数,可以使用下面的选项修改/etc/sysconfifig/memcached文件
- -u username memcached运行的用户身份,必须普通用户
- -p 绑定的端口,默认11211
- -m num 最大内存,单位MB,默认64MB
- -c num 最大连接数,缺省1024
- -d 守护进程方式运行
- -f 增长因子Growth Factor,默认1.25
- -v 详细信息,-vv能看到详细信息
- -M 内存耗尽,不许LRU
- -U 设置UDP监听端口,0表示禁用UDP
协议
查看/usr/share/doc/memcached-1.4.15/protocol.txt
# yum install telnet
# telnet localhost 11211
stats
add mykey 1 60 4
test
STORED
get mykey
VALUE mykey 1 4
test
END
set mykey 1 60 5
test1
STORED
get mykey
VALUE mykey 1 5
test1
END
3. session共享服务器
3.1 msm
msm(memcached session manager)提供将Tomcat的session保持到memcached或redis的程序,
可以实现高可用。
目前项目托管在Github,https://github.com/magro/memcached-session-manager
支持Tomcat的6.x、7.x、8.x、9.x。
Tomcat的Session管理类,Tomcat版本不同
- memcached-session-manager-2.3.2.jar
- memcached-session-manager-tc8-2.3.2.jar
Session数据的序列化、反序列化类
- 官方推荐kyro
- 在webapp中WEB-INF/lib/下
驱动类
- memcached(spymemcached.jar)
Redis(jedis.jar)
3.2 安装
https://github.com/magro/memcached-session-manager/wiki/SetupAndConfifiguration
将spymemcached.jar、memcached-session-manage、kyro相关的jar文件都放到Tomcat的lib目录中
去,这个目录是 $CATALINA_HOME/lib/ ,对应本次安装就是/usr/local/tomcat/lib。
asm-5.2.jar
kryo-3.0.3.jar
kryo-serializers-0.45.jar
memcached-session-manager-2.3.2.jar
memcached-session-manager-tc8-2.3.2.jar
minlog-1.3.1.jar
msm-kryo-serializer-2.3.2.jar
objenesis-2.6.jar
reflectasm-1.11.9.jar
spymemcached-2.12.3.jar
3.3 sticky模式
-
原理
当请求结束时Tomcat的session会送给memcached备份。即Tomcat session为主session,
memcached session为备session,使用memcached相当于备份了一份Session。
查询Session时Tomcat会优先使用自己内存的Session,Tomcat通过jvmRoute发现不是自己的
Session,便从memcached中找到该Session,更新本机Session,请求完成后更新memcached。 -
部署
<t1> <t2>
. \ / .
. X .
. / \ .
<m1> <m2>
t1和m1部署在一台主机上,t2和m2部署在同一台。
- 配置
放到 $CATALINA_HOME/conf/context.xml 中
特别注意,t1配置中为failoverNodes="n1", t2配置为failoverNodes="n2"
以下是sticky的配置
<Context>
...
<Manager className="de.javakaffee.web.msm.MemcachedBackupSessionManager"
memcachedNodes="n1:192.168.142.152:11211,n2:192.168.142.153:11211"
failoverNodes="n1"
requestUriIgnorePattern=".*\.(ico|png|gif|jpg|css|js)$"
transcoderFactoryClass="de.javakaffee.web.msm.serializer.kryo.KryoTranscoderFactory"
/>
</Context>
memcachedNodes="n1:host1.yourdomain.com:11211,n2:host2.yourdomain.com:11211"
memcached的节点们;n1、n2只是别名,可以重新命名。
failoverNodes故障转移节点,n1是备用节点,n2是主存储节点。另一台Tomcat将n1改为n2,其主节
点是n1,备用节点是n2。
- 实验
如果配置成功,可以在logs/catalina.out中看到下面的内容
信息 [t1.magedu.com-startStop-1]
de.javakaffee.web.msm.MemcachedSessionService.startInternal --------
- finished initialization:
- sticky: true
- operation timeout: 1000
- node ids: [n2]
- failover node ids: [n1]
- storage key prefix: null
- locking mode: null (expiration: 5s)
配置成功后,网页访问以下,页面中看到了Session。然后运行下面的Python程序,就可以看到是否存
储到了memcached中了。
import memcache # pip install python-memcached
mc = memcache.Client(['192.168.142.152:11211', '192.168.142.153:11211'], debug=True)
stats = mc.get_stats()[0]
print(stats)
for k,v in stats[1].items():
print(k, v)
print('-' * 30)
# 查看全部key
print(mc.get_stats('items')) # stats items 返回 items:5:number 1
print('-' * 30)
for x in mc.get_stats('cachedump 5 0'):# stats cachedump 5 0 # 5和上面的items返回的值有
关;0表示全部
print(x)
t1、t2、n1、n2依次启动成功,分别使用http://t1.magedu.com:8080/ 和http://t2.magedu.com:808
0/ 观察。
看起负载均衡调度器,通过http://t0.magedu.com来访问看看效果
On tomcats
192.168.142.153:8080
SessionID = 2A19B1EB6D9649C9FED3E7277FDFD470-n2.Tomcat1
Wed Jun 26 16:32:11 CST 2019
On tomcats
192.168.142.152:8080
SessionID = 2A19B1EB6D9649C9FED3E7277FDFD470-n1.Tomcat2
Wed Jun 26 16:32:36 CST 2019
可以看到浏览器端被调度到不同Tomcat上,但是都获得了同样的SessionID。
停止t2、n2看看效果,恢复看看效果。
3.4 non-sticky模式
-
原理
从msm 1.4.0之后开始支持non-sticky模式。
Tomcat session为中转Session,如果n1为主session,n2为备session。产生的新的Session会发送给
主、备memcached,并清除本地Session。
n1下线,n2转正。n1再次上线,n2依然是主Session存储节点。 -
memcached配置
放到 $CATALINA_HOME/conf/context.xml 中
<Context>
...
<Manager className="de.javakaffee.web.msm.MemcachedBackupSessionManager"
memcachedNodes="n1:192.168.142.152:11211,n2:192.168.142.153:11211"
sticky="false"
sessionBackupAsync="false"
lockingMode="uriPattern:/path1|/path2"
requestUriIgnorePattern=".*\.(ico|png|gif|jpg|css|js)$"
transcoderFactoryClass="de.javakaffee.web.msm.serializer.kryo.KryoTranscoderFactory"
/>
</Context>
- redis配置
下载jedis.jar,放到 $CATALINA_HOME/lib/ ,对应本次安装就是/usr/local/tomcat/lib
# yum install redis
# vim /etc/redis.conf
bind 0.0.0.0
# systemctl start redis
放到 $CATALINA_HOME/conf/context.xml 中
<Context>
...
<Manager className="de.javakaffee.web.msm.MemcachedBackupSessionManager"
memcachedNodes="redis://192.168.142.152:6379"
sticky="false"
sessionBackupAsync="false"
lockingMode="uriPattern:/path1|/path2"
requestUriIgnorePattern=".*\.(ico|png|gif|jpg|css|js)$"
transcoderFactoryClass="de.javakaffee.web.msm.serializer.kryo.KryoTranscoderFactory"
/>
</Context>
4. 总结
- 通过多组实验,使用不同技术实现了session持久机制
- session绑定,基于IP或session cookie的。其部署简单,尤其基于session黏性的方式,粒度小,
对负载均衡影响小。但一旦后端服务器有故障,其上的session丢失。 - session复制集群,基于tomcat实现多个服务器内共享同步所有session。此方法可以保证任意一
台后端服务器故障,其余各服务器上还都存有全部session,对业务无影响。但是它基于多播实现
心跳,TCP单播实现复制,当设备节点过多,这种复制机制不是很好的解决方案。且并发连接多的
时候,单机上的所有session占据的内存空间非常巨大,甚至耗尽内存。 - session服务器,将所有的session存储到一个共享的内存空间中,使用多个冗余节点保存
session,这样做到session存储服务器的高可用,且占据业务服务器内存较小。是一种比较好的解
决session持久的解决方案。
以上的方法都有其适用性。生产环境中,应根据实际需要合理选择。
不过以上这些方法都是在内存中实现了session的保持,可以使用数据库或者文件系统,把session数据
存储起来,持久化。这样服务器重启后,也可以重新恢复session数据。不过session数据是有时效性
的,是否需要这样做,视情况而定。