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持久机制
  1. session绑定,基于IP或session cookie的。其部署简单,尤其基于session黏性的方式,粒度小,
    对负载均衡影响小。但一旦后端服务器有故障,其上的session丢失。
  2. session复制集群,基于tomcat实现多个服务器内共享同步所有session。此方法可以保证任意一
    台后端服务器故障,其余各服务器上还都存有全部session,对业务无影响。但是它基于多播实现
    心跳,TCP单播实现复制,当设备节点过多,这种复制机制不是很好的解决方案。且并发连接多的
    时候,单机上的所有session占据的内存空间非常巨大,甚至耗尽内存。
  3. session服务器,将所有的session存储到一个共享的内存空间中,使用多个冗余节点保存
    session,这样做到session存储服务器的高可用,且占据业务服务器内存较小。是一种比较好的解
    决session持久的解决方案。

以上的方法都有其适用性。生产环境中,应根据实际需要合理选择。
不过以上这些方法都是在内存中实现了session的保持,可以使用数据库或者文件系统,把session数据
存储起来,持久化。这样服务器重启后,也可以重新恢复session数据。不过session数据是有时效性
的,是否需要这样做,视情况而定。

posted @ 2020-12-25 15:33  刘新元  阅读(199)  评论(0编辑  收藏  举报