200字
Memcached和会话保持的方案
2026-03-17
2026-03-17

Memcached

NoSQL介绍

NoSQL是对 Not Only SQL、非传统关系型数据库的统称。

NoSQL一词诞生于1998年,2009年这个词汇被再次提出指非关系型、分布式、不提供ACID的数据库设计模式。

随着互联网时代的到来,数据爆发式增长,数据库技术发展日新月异,要适应新的业务需求。

而随着移动互联网、物联网的到来,大数据的技术中NoSQL也同样重要。

数据库排名:https://db-engines.com/en/ranking

NoSQL 分类

  • Key-value Store k/v数据库
    • 性能好 O(1) , 如: redis、memcached
  • Document Store 文档数据库
    • mongodb、CouchDB
  • Column Store 列存数据库,Column-Oriented DB
    • HBase、Cassandra,大数据领域应用广泛
  • Graph DB 图数据库
    • Neo4j
  • Time Series 时序数据库
    • InfluxDB、Prometheus

Memcached

Memcached 只支持能序列化的数据类型,不支持持久化,基于Key-Value的内存缓存系统

Memcached 虽然没有像redis所具备的数据持久化功能,比如RDB和AOF都没有,但是可以通过做集群同步的方式,让各memcached服务器的数据进行同步,从而实现数据的一致性,即保证各memcached的数据是一样的,即使有任何一台 memcached 发生故障,只要集群中有一台 memcached 可用就不会出现数据丢失,当其他memcached 重新加入到集群的时候,可以自动从有数据的memcached 当中自动获取数据并提供服务。

Memcached 借助了操作系统的 libevent 工具做高效的读写。libevent是个程序库,它将Linux的epoll、BSD类操作系统的kqueue等事件处理功能封装成统一的接口。即使对服务器的连接数增加,也能发挥高性能。memcached使用这个libevent库,因此能在Linux、BSD、Solaris等操作系统上发挥其高性能

Memcached 支持最大的内存存储对象为1M,超过1M的数据可以使用客户端压缩或拆分报包放到多个key中,比较大的数据在进行读取的时候需要消耗的时间比较长,memcached 最适合保存用户的session实现session共享

Memcached存储数据时, Memcached会去申请1MB的内存, 把该块内存称为一个slab, 也称为一个page

Memcached 支持多种开发语言,包括:JAVA,C,Python,PHP,C#,Ruby,Perl等

Memcached 官网:http://memcached.org/

Memcached 和 Redis 比较

比较类别RedisMemcached
支持的数据结构哈希、列表、集合、有序集合纯 key-value
持久化支持
高可用支持支持集群功能,支持主从复制、读写分离;官方提供 Sentinel 工具,支持故障自动转移,对客户端透明。需要二次开发
存储 value 容量最大 512M最大 1M
内存分配临时申请空间,可能导致碎片预分配内存池管理内存,节省分配时间
虚拟内存使用有自己的 VM 机制,理论上可存储超过物理内存的数据,超量时会触发 swap 刷到磁盘。所有数据存储在物理内存里
网络模型非阻塞 IO 复用模型。支持复杂计算(排序、聚合),但复杂计算会阻塞 IO 调度。非阻塞 IO 复用模型
水平扩展支持Redis Cluster 可以横向扩展暂无
多线程Redis 6.0 之前只支持单线程支持多线程,CPU 利用方面优于 Redis
过期策略有专门线程,清除缓存数据懒淘汰机制:读取时通过 TTL 比较判断是否过期
单机 QPS约 10W约 60W
源代码可读性代码清爽简洁因考虑扩展性、多系统兼容性,代码较不清爽
适用场景复杂数据结构、有持久化、高可用需求、value 存储内容较大纯 KV,数据量非常大,并发量非常大的业务

Memcached 工作机制

内存分配机制

应用程序运行需要使用内存存储数据,但对于一个缓存系统来说,申请内存、释放内存将十分频繁,非常容易导致大量内存碎片,最后导致无连续可用内存可用。

Memcached采用了Slab Allocator机制来分配、管理内存。

  • Page:分配给Slab的内存空间,默认为1MB,分配后就得到一个Slab。Slab分配之后内存按照固定字节大小等分成chunk。
  • Chunk:用于缓存记录k/v值的内存空间。Memcached会根据数据大小选择存到哪一个chunk中,假设chunk有128bytes、64bytes等多种,数据只有100bytes存储在128bytes中,存在少许浪费。
    • Chunk最大就是Page的大小,即一个Page中就一个Chunk
  • Slab Class:Slab按照Chunk的大小分组,就组成不同的Slab Class, 第一个Chunk大小为 96B的Slab为Class1,Chunk 120B为Class 2,如果有100bytes要存,那么Memcached会选择下图中SlabClass 2 存储,因为它是120bytes的Chunk。Slab之间的差异可以使用Growth Factor 控制,默认1.25。

img

范例:查看Slab Class

#-f, --slab-growth-factor=<num> chunk size growth factor (default: 1.25)
[root@centos8 ~]#memcached -u memcached -f 2 -vv
slab class 1: chunk size 96 perslab 10922
slab class 2: chunk size 192 perslab 5461
slab class 3: chunk size 384 perslab 2730
slab class 4: chunk size 768 perslab 1365
slab class 5: chunk size 1536 perslab 682
slab class 6: chunk size 3072 perslab 341
slab class 7: chunk size 6144 perslab 170
slab class 8: chunk size 12288 perslab 85
slab class 9: chunk size 24576 perslab 42
slab class 10: chunk size 49152 perslab 21
slab class 11: chunk size 98304 perslab 10
slab class 12: chunk size 196608 perslab 5
slab class 13: chunk size 524288 perslab 2
<27 server listening (auto-negotiate)
<28 server listening (auto-negotiate)

懒过期 Lazy Expiration

memcached不会监视数据是否过期,而是在取数据时才看是否过期,如果过期,把数据有效期限标识为0,并不清除该数据。以后可以覆盖该位置存储其它数据。

LRU

当内存不足时,memcached会使用LRU(Least Recently Used)机制来查找可用空间,分配给新记录使用。

集群

Memcached集群,称为基于客户端 的分布式集群,即由客户端实现集群功能,即Memcached本身不支持集群

Memcached集群内部并不互相通信,一切都需要客户端连接到Memcached服务器后自行组织这些节点,并决定数据存储的节点。

安装和启动

官方安装说明

https://docs.memcached.org/serverguide/

包安装

范例: Ubuntu22.04

[root@ubuntu22.04 ~]#apt list memcached
正在列表... 完成
memcached/jammy,now 1.6.14-1 amd64
[root@ubuntu22.04 ~]#apt update;apt -y install memcached
[root@ubuntu22.04 ~]#dpkg -L memcached
/.
/etc
/etc/default
/etc/default/memcached
/etc/init.d
/etc/init.d/memcached
/lib
/lib/systemd
/lib/systemd/system
/lib/systemd/system/memcached.service
/usr
/usr/bin
/usr/bin/memcached
/usr/include
/usr/include/memcached
/usr/include/memcached/protocol_binary.h
/usr/include/memcached/xxhash.h
/usr/lib
/usr/lib/tmpfiles.d
/usr/lib/tmpfiles.d/memcached.conf
/usr/share
/usr/share/doc
/usr/share/doc/memcached
/usr/share/doc/memcached/NEWS.Debian.gz
/usr/share/doc/memcached/NEWS.gz
/usr/share/doc/memcached/README.Debian
/usr/share/doc/memcached/README.damemtop
/usr/share/doc/memcached/README.md
/usr/share/doc/memcached/changelog.Debian.gz
/usr/share/doc/memcached/copyright
/usr/share/doc/memcached/napi_ids.txt
/usr/share/doc/memcached/new_lru.txt
/usr/share/doc/memcached/protocol.txt.gz
/usr/share/doc/memcached/readme.txt
/usr/share/doc/memcached/storage.txt.gz
/usr/share/doc/memcached/threads.txt
/usr/share/doc/memcached/tls.txt.gz
/usr/share/man
/usr/share/man/man1
/usr/share/man/man1/memcached.1.gz
/usr/share/memcached
/usr/share/memcached/memcached.conf.default
/usr/share/memcached/scripts
/usr/share/memcached/scripts/damemtop
/usr/share/memcached/scripts/damemtop.yaml
/usr/share/memcached/scripts/memcached-tool
/usr/share/memcached/scripts/start-memcached
/usr/share/memcached/scripts/systemd-memcached-wrapper

[root@ubuntu22.04 ~]#memcached -V
memcached 1.6.14

[root@ubuntu22.04 ~]#ss -ntl|grep 11211
LISTEN 0 1024 127.0.0.1:11211 0.0.0.0:*

[root@ubuntu22.04 ~]#vim /etc/memcached.conf
#-l 127.0.0.1 注释此行

[root@ubuntu22.04 ~]#grep -Ev "#|^$" /etc/memcached.conf
-d
logfile /var/log/memcached.log
-m 128 #最大内存空间,默认64M
-p 11211
-u memcache
-c 10240 #最大并发连接,默认1024
-P /var/run/memcached/memcached.pid

[root@ubuntu22.04 ~]#systemctl restart memcached
[root@ubuntu22.04 ~]#ss -ntl|grep 11211
LISTEN 0 1024 0.0.0.0:11211 0.0.0.0:*
LISTEN 0 1024 [::]:11211 [::]:*

范例: CentOS 8 安装 memcached

[root@centos8 ~]#dnf info memcached
Last metadata expiration check: 0:16:45 ago on Wed 15 Jul 2020 03:07:47 PM CST.
Available Packages
Name : memcached
Version : 1.5.9
Release : 3.el8
Architecture : x86_64
Size : 132 k
Source : memcached-1.5.9-3.el8.src.rpm
Repository : AppStream
Summary : High Performance, Distributed Memory Object Cache
URL : https://www.memcached.org/
License : BSD
Description : memcached is a high-performance, distributed memory object
caching
: system, generic in nature, but intended for use in speeding up
dynamic
: web applications by alleviating database load.

[root@centos8 ~]#dnf -y install memcached
[root@centos8 ~]#rpm -ql memcached
/etc/sysconfig/memcached
/usr/bin/memcached
/usr/bin/memcached-tool
/usr/lib/.build-id
/usr/lib/.build-id/25
/usr/lib/.build-id/25/2528fb78bbe5b14596eb4ee8c88120b5cc6b59
/usr/lib/systemd/system/memcached.service
/usr/share/doc/memcached
/usr/share/doc/memcached/AUTHORS
/usr/share/doc/memcached/CONTRIBUTORS
/usr/share/doc/memcached/COPYING
/usr/share/doc/memcached/ChangeLog
/usr/share/doc/memcached/NEWS
/usr/share/doc/memcached/README.md
/usr/share/doc/memcached/new_lru.txt
/usr/share/doc/memcached/protocol.txt
/usr/share/doc/memcached/readme.txt
/usr/share/doc/memcached/storage.txt
/usr/share/doc/memcached/threads.txt
/usr/share/man/man1/memcached-tool.1.gz
/usr/share/man/man1/memcached.1.gz

[root@t1 ~]#cat /etc/sysconfig/memcached
PORT="11211" #监听端口
USER="memcached" #启动用户
MAXCONN="1024" #最大连接数
CACHESIZE="64" #最大使用内存
OPTIONS="-l 127.0.0.1,::1" #其他选项

[root@centos8 ~]#grep -Ev "^#|^$" /usr/lib/systemd/system/memcached.service
[Unit]
Description=memcached daemon
Before=httpd.service
After=network.target
[Service]
EnvironmentFile=/etc/sysconfig/memcached
ExecStart=/usr/bin/memcached -p ${PORT} -u ${USER} -m ${CACHESIZE} -c ${MAXCONN}
$OPTIONS
PrivateTmp=true
ProtectSystem=full
NoNewPrivileges=true
PrivateDevices=true
CapabilityBoundingSet=CAP_SETGID CAP_SETUID CAP_SYS_RESOURCE
RestrictAddressFamilies=AF_INET AF_INET6 AF_UNIX
[Install]
WantedBy=multi-user.target

[root@centos8 ~]#getent passwd memcached
memcached:x:992:989:Memcached daemon:/run/memcached:/sbin/nologin

[root@centos8 ~]#systemctl enable --now memcached
[root@centos8 ~]#pstree -p |grep memcached
|-memcached(25582)-+-{memcached}(25584)
| |-{memcached}(25585)
| |-{memcached}(25586)
| |-{memcached}(25587)
| |-{memcached}(25588)
| |-{memcached}(25589)
| |-{memcached}(25590)
| |-{memcached}(25591)
| `-{memcached}(25592)

[root@centos8 ~]#ss -ntlup|grep memcached
tcp LISTEN 0 128 127.0.0.1:11211 0.0.0.0:*
users:(("memcached",pid=25453,fd=27))
tcp LISTEN 0 128 [::1]:11211 [::]:*
users:(("memcached",pid=25453,fd=28))

#修改端口绑定的IP为当前主机的所有IP
[root@centos8 ~]#vim /etc/sysconfig/memcached
[root@centos8 ~]#cat /etc/sysconfig/memcached
PORT="11211"
USER="memcached"
MAXCONN="1024"
CACHESIZE="64"
#OPTIONS="-l 127.0.0.1,::1" #注释此行
OPTIONS=""
[root@centos8 ~]#systemctl restart memcached.service


[root@centos8 ~]#ss -ntul
Netid State Recv-Q Send-Q Local Address:Port Peer Address:Port
udp UNCONN 0 0 127.0.0.1:323 0.0.0.0:*
udp UNCONN 0 0 [::1]:323 [::]:*
tcp LISTEN 0 128 0.0.0.0:22 0.0.0.0:*
tcp LISTEN 0 100 127.0.0.1:25 0.0.0.0:*
tcp LISTEN 0 128 0.0.0.0:11211 0.0.0.0:*
tcp LISTEN 0 128 [::]:22 [::]:*
tcp LISTEN 0 100 [::1]:25 [::]:*
tcp LISTEN 0 128 [::]:11211 [::]:*

范例: CentOS 7 安装 memcached

[root@centos7 ~]#yum info memcached
Loaded plugins: fastestmirror
Loading mirror speeds from cached hostfile
* base:
Installed Packages
Name : memcached
Arch : x86_64
Version : 1.4.15
Release : 10.el7_3.1
Size : 176 k
Repo : installed
From repo : base
Summary : High Performance, Distributed Memory Object Cache
URL : http://www.memcached.org/
License : BSD
Description : memcached is a high-performance, distributed memory object caching
: system, generic in nature, but intended for use in speeding up
dynamic
: web applications by alleviating database load.

[root@centos7 ~]# yum install memcached
[root@centos7 ~]# 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

[root@centos7 ~]#getent passwd memcached
memcached:x:997:995:Memcached daemon:/run/memcached:/sbin/nologin
[root@centos7 ~]# 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
[root@centos7 ~]# cat /etc/sysconfig/memcached
PORT="11211"
USER="memcached"
MAXCONN="1024"
CACHESIZE="64"
OPTIONS=""

#前台显示看看效果
[root@centos7 ~]# memcached -u memcached -p 11211 -f 1.25 -vv

[root@centos7 ~]# systemctl start memcached
[root@centos7 ~]#ss -ntlpu|grep memcached
udp UNCONN 0 0 *:11211 *:* users:
(("memcached",pid=2591,fd=28))
udp UNCONN 0 0 [::]:11211 [::]:* users:
(("memcached",pid=2591,fd=29))
tcp LISTEN 0 128 *:11211 *:* users:
(("memcached",pid=2591,fd=26))
tcp LISTEN 0 128 [::]:11211 [::]:* users:
(("memcached",pid=2591,fd=27)) tcp LISTEN 0 100 [::1]:25
[::]:*

编译安装

范例:Ubuntu

[root@ubuntu2204 ~]#apt update && apt -y install gcc make libevent-dev
[root@ubuntu2204 ~]#wget http://memcached.org/files/memcached-1.6.17.tar.gz
[root@ubuntu2204 ~]#tar xf memcached-1.6.17.tar.gz
[root@ubuntu2204 memcached-1.6.17]#./configure --prefix=/apps/memcached
[root@ubuntu2204 memcached-1.6.17]#make && make install
[root@ubuntu2204 memcached-1.6.17]#tree /apps/memcached/
/apps/memcached/
├── bin
│ 	└── memcached
├── include
│ 	└── memcached
│ 		├── protocol_binary.h
│ 		└── xxhash.h
└── share
	└── man
		└── man1
			└── memcached.1
6 directories, 4 files

[root@ubuntu2204 ~]#ln -s /apps/memcached/bin/memcached /usr/local/bin

#不允许以root执行
[root@ubuntu2204 ~]#memcached
can't run as root without the -u switch

[root@ubuntu2204 ~]#useradd -r -s /sbin/nologin memcached

[root@ubuntu2204 ~]#memcached -u memcached -d -f 2 -vv
slab class 1: chunk size 96 perslab 10922
slab class 2: chunk size 192 perslab 5461
slab class 3: chunk size 384 perslab 2730
slab class 4: chunk size 768 perslab 1365
slab class 5: chunk size 1536 perslab 682
slab class 6: chunk size 3072 perslab 341
slab class 7: chunk size 6144 perslab 170
slab class 8: chunk size 12288 perslab 85
slab class 9: chunk size 24576 perslab 42
slab class 10: chunk size 49152 perslab 21
slab class 11: chunk size 98304 perslab 10
slab class 12: chunk size 196608 perslab 5
slab class 13: chunk size 524288 perslab 2
<22 server listening (auto-negotiate)
<23 server listening (auto-negotiate)

[root@ubuntu2204 ~]#ss -ntl |grep 11211
LISTEN 0 1024 0.0.0.0:11211 0.0.0.0:*
LISTEN 0 1024 [::]:11211 [::]:*

范例:红帽系统

[root@centos7 ~]#yum -y install gcc libevent-devel
[root@ubuntu1804 ~]#apt -y install gcc make libevent-dev
[root@centos7 ~]#wget http://memcached.org/files/memcached-1.6.6.tar.gz
[root@centos7 ~]#tar xvf memcached-1.6.6.tar.gz
[root@centos7 ~]#cd memcached-1.6.6/
[root@centos7 memcached-1.6.6]#./configure --prefix=/apps/memcached
[root@centos7 memcached-1.6.6]#make && make install

[root@centos7 ~]#tree /apps/memcached/
/apps/memcached/
├── bin
│ 	└── memcached
├── include
│ 	└── memcached
│ 		└── protocol_binary.h
└── share
    └── man
        └── man1
        	└── memcached.1
6 directories, 3 files
[root@centos7 ~]#echo 'PATH=/apps/memcached/bin:$PATH' > /etc/profile.d/memcached.sh
[root@centos7 ~]#. /etc/profile.d/memcached.sh

#准备用户
[root@centos7 ~]#useradd -r -s /sbin/nologin memcached

[root@centos7 ~]#cat /etc/sysconfig/memcached

PORT="11211"
USER="memcached"
MAXCONN="1024"
CACHESIZE="64"
OPTIONS="-l 127.0.0.1,::1"

#默认前台执行
[root@centos7 ~]#memcached -u memcached -m 2048 -c 65536 -f 2 -vv

#以后台方式执行
[root@centos7 ~]#memcached -u memcached -m 2048 -c 65536 -d

#准备service文件
[root@centos7 ~]#cat /lib/systemd/system/memcached.service
[Unit]
Description=memcached daemon
Before=httpd.service
After=network.target

[Service]
EnvironmentFile=/etc/sysconfig/memcached
ExecStart=/apps/memcached/bin/memcached -p ${PORT} -u ${USER} -m ${CACHESIZE} -c  ${MAXCONN} $OPTIONS

[Install]
WantedBy=multi-user.target

[root@centos7 ~]#systemctl daemon-reload
[root@centos7 ~]#systemctl enable --now memcached.service

[root@centos7 ~]#ss -ntl
State Recv-Q Send-Q Local Address:Port Peer Address:Port
LISTEN 0 128 127.0.0.1:11211 *:*
LISTEN 0 128 *:22 *:*
LISTEN 0 100 127.0.0.1:25 *:*
LISTEN 0 128 [::1]:11211 [::]:*
LISTEN 0 128 [::]:22 [::]:*
LISTEN 0 100 [::1]:25 [::]:*
[root@centos7 ~]#memcached --version
memcached 1.6.6

memcached 启动程序说明

修改memcached 运行参数,可以使用下面的选项修改/etc/sysconfig/memcached文件

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

范例:

[root@centos8 ~]#memcached -u memcached -p 11211 -f 2 -vv
slab class 1: chunk size 96 perslab 10922
slab class 2: chunk size 192 perslab 5461
slab class 3: chunk size 384 perslab 2730
slab class 4: chunk size 768 perslab 1365
slab class 5: chunk size 1536 perslab 682
slab class 6: chunk size 3072 perslab 341
slab class 7: chunk size 6144 perslab 170
slab class 8: chunk size 12288 perslab 85
slab class 9: chunk size 24576 perslab 42
slab class 10: chunk size 49152 perslab 21
slab class 11: chunk size 98304 perslab 10
slab class 12: chunk size 196608 perslab 5
slab class 13: chunk size 524288 perslab 2
<27 server listening (auto-negotiate)
<28 server listening (auto-negotiate)

[root@centos8 ~]#memcached -u memcached -p 11211 -f 1.25 -vv
slab class 1: chunk size 96 perslab 10922
slab class 2: chunk size 120 perslab 8738
slab class 3: chunk size 152 perslab 6898
slab class 4: chunk size 192 perslab 5461
slab class 5: chunk size 240 perslab 4369
slab class 6: chunk size 304 perslab 3449
slab class 7: chunk size 384 perslab 2730
slab class 8: chunk size 480 perslab 2184
slab class 9: chunk size 600 perslab 1747
slab class 10: chunk size 752 perslab 1394
slab class 11: chunk size 944 perslab 1110
slab class 12: chunk size 1184 perslab 885
slab class 13: chunk size 1480 perslab 708
slab class 14: chunk size 1856 perslab 564
slab class 15: chunk size 2320 perslab 451
slab class 16: chunk size 2904 perslab 361
slab class 17: chunk size 3632 perslab 288
slab class 18: chunk size 4544 perslab 230
slab class 19: chunk size 5680 perslab 184
slab class 20: chunk size 7104 perslab 147
slab class 21: chunk size 8880 perslab 118
slab class 22: chunk size 11104 perslab 94
slab class 23: chunk size 13880 perslab 75
slab class 24: chunk size 17352 perslab 60
slab class 25: chunk size 21696 perslab 48
slab class 26: chunk size 27120 perslab 38
slab class 27: chunk size 33904 perslab 30
slab class 28: chunk size 42384 perslab 24
slab class 29: chunk size 52984 perslab 19
slab class 30: chunk size 66232 perslab 15
slab class 31: chunk size 82792 perslab 12
slab class 32: chunk size 103496 perslab 10
slab class 33: chunk size 129376 perslab 8
slab class 34: chunk size 161720 perslab 6
slab class 35: chunk size 202152 perslab 5
slab class 36: chunk size 252696 perslab 4
slab class 37: chunk size 315872 perslab 3
slab class 38: chunk size 394840 perslab 2
slab class 39: chunk size 524288 perslab 2
<27 server listening (auto-negotiate)
<28 server listening (auto-negotiate)

使用 memcached

memcached 开发库和工具

与memcached通信的不同语言的连接器。libmemcached提供了C库和命令行工具。

范例: Ubuntu 安装相关工具包

[root@ubuntu2204 ~]#apt -y install libmemcached-tools

[root@ubuntu2204 ~]#dpkg -L libmemcached-tools
/.
/usr
/usr/bin
/usr/bin/memccapable
/usr/bin/memccat
/usr/bin/memccp
/usr/bin/memcdump
/usr/bin/memcerror
/usr/bin/memcexist
/usr/bin/memcflush
/usr/bin/memcparse
/usr/bin/memcping
/usr/bin/memcrm
/usr/bin/memcslap
/usr/bin/memcstat
/usr/bin/memctouch
/usr/share
/usr/share/doc
/usr/share/doc/libmemcached-tools
/usr/share/doc/libmemcached-tools/README.Debian
/usr/share/doc/libmemcached-tools/copyright
/usr/share/man
/usr/share/man/man1
/usr/share/man/man1/memcaslap.1.gz
/usr/share/man/man1/memccapable.1.gz
/usr/share/man/man1/memccat.1.gz
/usr/share/man/man1/memccp.1.gz
/usr/share/man/man1/memcdump.1.gz
/usr/share/man/man1/memcerror.1.gz
/usr/share/man/man1/memcexist.1.gz
/usr/share/man/man1/memcflush.1.gz
/usr/share/man/man1/memcparse.1.gz
/usr/share/man/man1/memcping.1.gz
/usr/share/man/man1/memcrm.1.gz
/usr/share/man/man1/memcslap.1.gz
/usr/share/man/man1/memcstat.1.gz
/usr/share/man/man1/memctouch.1.gz
/usr/share/doc/libmemcached-tools/changelog.Debian.gz

[root@ubuntu2204 ~]#/usr/bin/memcping --servers=10.0.0.200
[root@ubuntu2204 ~]#echo $?
0
[root@ubuntu2204 ~]#memcstat --servers=10.0.0.200
Server: 10.0.0.200 (11211)
pid: 33895
uptime: 7
time: 1670397802
version: 1.6.17
libevent: 2.1.12-stable
pointer_size: 64
rusage_user: 0.004382
rusage_system: 0.000000
max_connections: 1024
curr_connections: 2
total_connections: 3
rejected_connections: 0
connection_structures: 3
response_obj_oom: 0
response_obj_count: 1
response_obj_bytes: 16384
read_buf_count: 2
read_buf_bytes: 32768
read_buf_bytes_free: 0
read_buf_oom: 0
reserved_fds: 20
cmd_get: 0
cmd_set: 0
cmd_flush: 0
cmd_touch: 0
cmd_meta: 0
get_hits: 0
get_misses: 0
get_expired: 0
get_flushed: 0
delete_misses: 0
delete_hits: 0
incr_misses: 0
incr_hits: 0
decr_misses: 0
decr_hits: 0
cas_misses: 0
cas_hits: 0
cas_badval: 0
touch_hits: 0
touch_misses: 0
store_too_large: 0
store_no_memory: 0
auth_cmds: 0
auth_errors: 0
bytes_read: 17
bytes_written: 16
limit_maxbytes: 67108864
accepting_conns: 1
listen_disabled_num: 0
time_in_listen_disabled_us: 0
threads: 4
conn_yields: 0
hash_power_level: 16
ash_bytes: 524288
hash_is_expanding: 0
slab_reassign_rescues: 0
slab_reassign_chunk_rescues: 0
slab_reassign_evictions_nomem: 0
slab_reassign_inline_reclaim: 0
slab_reassign_busy_items: 0
slab_reassign_busy_deletes: 0
slab_reassign_running: 0
slabs_moved: 0
lru_crawler_running: 0
lru_crawler_starts: 1
lru_maintainer_juggles: 56
malloc_fails: 0
log_worker_dropped: 0
log_worker_written: 0
log_watcher_skipped: 0
log_watcher_sent: 0
log_watchers: 0
unexpected_napi_ids: 0
round_robin_fallback: 0
bytes: 0
curr_items: 0
total_items: 0
slab_global_page_pool: 0
expired_unfetched: 0
evicted_unfetched: 0
evicted_active: 0
evictions: 0
reclaimed: 0
crawler_reclaimed: 0
crawler_items_checked: 0
lrutail_reflocked: 0
moves_to_cold: 0
moves_to_warm: 0
moves_within_lru: 0
direct_reclaims: 0
lru_bumps_dropped: 0

范例: 查看memcached相关包

[root@centos8 ~]#yum list "*memcached*"
Last metadata expiration check: 0:09:46 ago on Thu 13 Feb 2020 07:14:15 PM CST.
Installed Packages
memcached.x86_64 1.5.9-2.el8 @AppStream
Available Packages
libmemcached.x86_64 1.0.18-15.el8 AppStream
libmemcached-libs.i686 1.0.18-15.el8 AppStream
libmemcached-libs.x86_64 1.0.18-15.el8 AppStream
perl-Cache-Memcached.noarch 1.30-21.el8 epel
python2-memcached.noarch 1.58-8.el8 epel
python3-memcached.noarch 1.58-8.el8 epel

[root@centos7 ~]#yum list "*memcached*"
Loaded plugins: fastestmirror
Loading mirror speeds from cached hostfile
* base:
Installed Packages
memcached.x86_64 1.4.15-10.el7_3.1
@base
Available Packages
libmemcached.i686 1.0.16-5.el7 base
libmemcached.x86_64 1.0.16-5.el7 base
libmemcached-devel.i686 1.0.16-5.el7 base
libmemcached-devel.x86_64 1.0.16-5.el7 base
memcached-devel.i686 1.4.15-10.el7_3.1 base
memcached-devel.x86_64 1.4.15-10.el7_3.1 base
opensips-memcached.x86_64 1.10.5-4.el7 epel
perl-Cache-Memcached.noarch 1.30-8.el7 epel
php-ZendFramework-Cache-Backend-Libmemcached.noarch 1.12.20-1.el7 epel
php-ZendFramework-Cache-Backend-Memcached.noarch 1.12.20-1.el7 epel
php-pecl-memcached.x86_64 2.2.0-1.el7 epel
python-memcached.noarch 1.48-4.el7 base
uwsgi-router-memcached.x86_64 2.0.17.1-2.el7 epel

协议

查看/usr/share/doc/memcached-1.4.15/protocol.txt

[root@centos8 ~]#dnf info libmemcached
Last metadata expiration check: 1:04:38 ago on Wed 15 Jul 2020 03:07:47 PM CST.
Available Packages
Name : libmemcached
Version : 1.0.18
Release : 15.el8
Architecture : x86_64
Size : 140 k
Source : libmemcached-1.0.18-15.el8.src.rpm
Repository : AppStream
Summary : Client library and command line tools for memcached server
URL : http://libmemcached.org/
License : BSD
Description : libmemcached is a C/C++ client library and tools for the
memcached server
: (http://memcached.org/). It has been designed to be light on
memory
: usage, and provide full access to server side methods.
:
: It also implements several command line tools:
:
: memaslap Load testing and benchmarking a server
: memcapable Checking a Memcached server capibilities and
compatibility
: memcat Copy the value of a key to standard output
: memcp Copy data to a server
: memdump Dumping your server
: memerror Translate an error code to a string
: memexist Check for the existance of a key
: memflush Flush the contents of your servers
: memparse Parse an option string
: memping Test to see if a server is available.
: memrm Remove a key(s) from the server
: memslap Generate testing loads on a memcached cluster
: memstat Dump the stats of your servers to standard output
: memtouch Touches a key
[root@centos8 ~]#dnf repoquery -l libmemcached
Last metadata expiration check: 1:05:59 ago on Wed 15 Jul 2020 03:07:47 PM CST.
/usr/bin/memaslap
/usr/bin/memcapable
/usr/bin/memcat
/usr/bin/memcp
/usr/bin/memdump
/usr/bin/memerror
/usr/bin/memexist
/usr/bin/memflush
/usr/bin/memparse
/usr/bin/memping
/usr/bin/memrm
/usr/bin/memslap
/usr/bin/memstat
/usr/bin/memtouch
/usr/lib/.build-id
/usr/lib/.build-id/1b
/usr/lib/.build-id/1b/be22224bfebeca90608feb39b80727ae54628e
/usr/lib/.build-id/38
/usr/lib/.build-id/38/5751e779437bb3a4081e7cfb4ef77088a07d97
/usr/lib/.build-id/42
/usr/lib/.build-id/42/b350284fa158955530a88eb8f96c1f870b4fe2
/usr/lib/.build-id/56
/usr/lib/.build-id/56/42b8e27074c76b9801e7719479084a600db691
/usr/lib/.build-id/59
/usr/lib/.build-id/59/9c9b9482f1c789b5b4446f1b97f5d7e52f30ab
/usr/lib/.build-id/72
/usr/lib/.build-id/72/493b49e4933a11db401650eb5de14a38e22c5b
/usr/lib/.build-id/78
/usr/lib/.build-id/78/c5db64ca4e70a9fd1ef5da96ad28db07946bfa
/usr/lib/.build-id/98
/usr/lib/.build-id/98/6fde24b289939e1bb1621f74c46e68329b140a
/usr/lib/.build-id/a9
/usr/lib/.build-id/a9/028d7389fc0be4422efaf38782416365d67969
/usr/lib/.build-id/dc
/usr/lib/.build-id/dc/d8bd345f28d55f95c5a510ac88e440c97778d3
/usr/lib/.build-id/de
/usr/lib/.build-id/de/0354325ffca355fc6682f3ac4207f111d42ec1
/usr/lib/.build-id/e0
/usr/lib/.build-id/e0/e81e353fdc4b4cfe6e44c20d65e1eb4740249c
/usr/lib/.build-id/e1
/usr/lib/.build-id/e1/91e088f007b253329756088bedb68948191166
/usr/lib/.build-id/e8
/usr/lib/.build-id/e8/b2f6d6a35c022c66e400c6f6db3d507be54dcd
/usr/share/man/man1/memaslap.1.gz
/usr/share/man/man1/memcapable.1.gz
/usr/share/man/man1/memcat.1.gz
/usr/share/man/man1/memcp.1.gz
/usr/share/man/man1/memdump.1.gz
/usr/share/man/man1/memerror.1.gz
/usr/share/man/man1/memexist.1.gz
/usr/share/man/man1/memflush.1.gz
/usr/share/man/man1/memparse.1.gz
/usr/share/man/man1/memping.1.gz
/usr/share/man/man1/memrm.1.gz
/usr/share/man/man1/memslap.1.gz
/usr/share/man/man1/memstat.1.gz
/usr/share/man/man1/memtouch.1.gz

#测试memcached是否可访问
[root@centos8 ~]#memping --servers=10.0.0.7
[root@centos8 ~]#echo $?
0
[root@centos8 ~]#memping --servers=10.0.0.77
Failed to ping 10.0.0.77:11211 SYSTEM ERROR

查看memcached状态
[root@centos8 ~]#memstat --servers=10.0.0.101
Server: 10.0.0.101 (11211)
pid: 25582
uptime: 648
time: 1594801017
version: 1.5.9
libevent: 2.1.8-stable
pointer_size: 64
rusage_user: 0.051100
rusage_system: 0.079158
max_connections: 1024
curr_connections: 3
total_connections: 4
rejected_connections: 0
connection_structures: 4
reserved_fds: 20
cmd_get: 0
cmd_set: 2
cmd_flush: 0
cmd_touch: 0
get_hits: 0
get_misses: 0
get_expired: 0
get_flushed: 0
delete_misses: 0
delete_hits: 0
incr_misses: 0
incr_hits: 0
decr_misses: 0
decr_hits: 0
cas_misses: 0
cas_hits: 0
cas_badval: 0
touch_hits: 0
touch_misses: 0
auth_cmds: 0
auth_errors: 0
bytes_read: 72
bytes_written: 1911
limit_maxbytes: 67108864
accepting_conns: 1
listen_disabled_num: 0
time_in_listen_disabled_us: 0
threads: 4
conn_yields: 0
hash_power_level: 16
hash_bytes: 524288
hash_is_expanding: 0
slab_reassign_rescues: 0
slab_reassign_chunk_rescues: 0
slab_reassign_evictions_nomem: 0
slab_reassign_inline_reclaim: 0
slab_reassign_busy_items: 0
slab_reassign_busy_deletes: 0
slab_reassign_running: 0
slabs_moved: 0
lru_crawler_running: 0
lru_crawler_starts: 1275
lru_maintainer_juggles: 1141
malloc_fails: 0
log_worker_dropped: 0
log_worker_written: 0
log_watcher_skipped: 0
log_watcher_sent: 0
bytes: 0
curr_items: 0
total_items: 2
slab_global_page_pool: 0
expired_unfetched: 2
evicted_unfetched: 0
evicted_active: 0
evictions: 0
reclaimed: 2
crawler_reclaimed: 0
crawler_items_checked: 0
lrutail_reflocked: 0
moves_to_cold: 1
moves_to_warm: 0
moves_within_lru: 0
direct_reclaims: 0
lru_bumps_dropped: 0
[root@centos8 ~]#

memcached 操作命令

帮助文档:

[root@centos8 ~]#cat /usr/share/doc/memcached/protocol.txt

五种基本 memcached 命令执行最简单的操作。这些命令和操作包括:

  • set
  • add
  • replace
  • get
  • delete
#前三个命令是用于操作存储在 memcached 中的键值对的标准修改命令,都使用如下所示的语法:
command <key> <flags> <expiration time> <bytes> <value>
#参数说明如下:
command set/add/replace
key 	key 用于查找缓存值
flags 	可以包括键值对的整型参数,客户机使用它存储关于键值对的额外信息
expiration time 	在缓存中保存键值对的时间长度(以秒为单位,0 表示永远)
bytes 	在缓存中存储的字节数
value 	存储的值(始终位于第二行)

#增加key,过期时间为秒,bytes为存储数据的字节数
add key flags exptime bytes

范例:

[root@centos8 ~]#systemctl start memcached
[root@centos8 ~]#telnet localhost 11211
Trying ::1...
Connected to localhost.
Escape character is '^]'.
stats
STAT pid 27208
STAT uptime 242
STAT time 1603035824
STAT version 1.5.9
STAT libevent 2.1.8-stable
STAT pointer_size 64
STAT rusage_user 0.004214
STAT rusage_system 0.040611
STAT max_connections 1024
STAT curr_connections 2
STAT total_connections 4
STAT rejected_connections 0
STAT connection_structures 3
STAT reserved_fds 20
STAT cmd_get 8
STAT cmd_set 4
STAT cmd_flush 1
STAT cmd_touch 0
STAT get_hits 5
STAT get_misses 3
STAT get_expired 0
STAT get_flushed 0
STAT delete_misses 0
STAT delete_hits 1
STAT incr_misses 0
STAT incr_hits 0
STAT decr_misses 0
STAT decr_hits 0
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 224
STAT bytes_written 3963
STAT limit_maxbytes 67108864
STAT accepting_conns 1
STAT listen_disabled_num 0
STAT time_in_listen_disabled_us 0
STAT threads 4
STAT conn_yields 0
STAT hash_power_level 16
STAT hash_bytes 524288
STAT hash_is_expanding 0
STAT slab_reassign_rescues 0
STAT slab_reassign_chunk_rescues 0
STAT slab_reassign_evictions_nomem 0
STAT slab_reassign_inline_reclaim 0
STAT slab_reassign_busy_items 0
STAT slab_reassign_busy_deletes 0
STAT slab_reassign_running 0
STAT slabs_moved 0
STAT lru_crawler_running 0
STAT lru_crawler_starts 765
STAT lru_maintainer_juggles 523
STAT malloc_fails 0
STAT log_worker_dropped 0
STAT log_worker_written 0
STAT log_watcher_skipped 0
STAT log_watcher_sent 0
STAT bytes 0
STAT curr_items 0
STAT total_items 4
STAT slab_global_page_pool 0
STAT expired_unfetched 0
STAT evicted_unfetched 0
STAT evicted_active 0
STAT evictions 0
STAT reclaimed 3
STAT crawler_reclaimed 0
STAT crawler_items_checked 1
STAT lrutail_reflocked 4
STAT moves_to_cold 5
STAT moves_to_warm 1
STAT moves_within_lru 0
STAT direct_reclaims 0
STAT lru_bumps_dropped 0
END

stats items #显示各个 slab 中 item 的数目和存储时长(最后一次访问距离现在的秒数)。
STAT items:1:number 2
STAT items:1:number_hot 0
STAT items:1:number_warm 0
STAT items:1:number_cold 2
STAT items:1:age_hot 0
STAT items:1:age_warm 0
STAT items:1:age 17
STAT items:1:evicted 0
STAT items:1:evicted_nonzero 0
STAT items:1:evicted_time 0
STAT items:1:outofmemory 0
STAT items:1:tailrepairs 0
STAT items:1:reclaimed 0
STAT items:1:expired_unfetched 0
STAT items:1:evicted_unfetched 0
STAT items:1:evicted_active 0
STAT items:1:crawler_reclaimed 0
STAT items:1:crawler_items_checked 0
STAT items:1:lrutail_reflocked 0
STAT items:1:moves_to_cold 2
STAT items:1:moves_to_warm 0
STAT items:1:moves_within_lru 0
STAT items:1:direct_reclaims 0
STAT items:1:hits_to_hot 0
STAT items:1:hits_to_warm 0
STAT items:1:hits_to_cold 1
STAT items:1:hits_to_temp 0
END
stats slabs #用于显示各个slab的信息,包括chunk的大小、数目、使用情况等
STAT 1:chunk_size 96
STAT 1:chunks_per_page 10922
STAT 1:total_pages 1
STAT 1:total_chunks 10922
STAT 1:used_chunks 1
STAT 1:free_chunks 10921
STAT 1:free_chunks_end 0
STAT 1:mem_requested 67
STAT 1:get_hits 1
STAT 1:cmd_set 3
STAT 1:delete_hits 0
STAT 1:incr_hits 0
STAT 1:decr_hits 0
STAT 1:cas_hits 0
STAT 1:cas_badval 0
STAT 1:touch_hits 0
STAT active_slabs 1
STAT total_malloced 1048576
END

#加
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

#删除
delete mykey
DELETED
get mykey
END

#清空
flush_all
OK
get mykey
END
quit

范例: 非交互式取信息

[root@rocky8 ~]#echo -e "stats\nquit" | nc 10.0.0.28 11211 |awk '/curr_connections/{print $NF}'
2

Python 语言连接 memcached

范例: python3 测试代码

#Ubuntu
[root@ubuntu2204 ~]#apt -y install python3 python3-memcache

#红帽系统
[root@centos8 ~]#yum -y install python3 python3-memcached
[root@centos8 ~]#cat m3.py
#!/usr/bin/python3
#coding:utf-8
import memcache
m = memcache.Client(['127.0.0.1:11211'], debug=True)
for i in range(10):
    m.set("key%d" % i,"v%d" % i)
    ret = m.get('key%d' % i)
    print("%s" % ret)

[root@centos8 ~]#chmod +x m3.py
[root@centos8 ~]#./m3.py
v0
v1
v2
v3
v4
v5
v6
v7
v8
v9

范例: Python2 测试代码

[root@centos7 ~]#yum -y install python-memcached

[root@centos7 ~]#cat m2.py
#!/usr/bin/env python
#coding:utf-8
import memcache
m = memcache.Client(['127.0.0.1:11211'], debug=True)
for i in range(10):
    m.set("key%d" % i,"v%d" % i)
    ret = m.get('key%d' % i)
    print ret

[root@centos7 ~]#python m2.py
v0
v1
v2
v3
v4
v5
v6
v7
v8
v9

[root@centos7 ~]#telnet 127.0.0.1 11211
Trying 127.0.0.1...
Connected to 127.0.0.1.
Escape character is '^]'.
get key1
VALUE key1 0 2
v1
END
get key9
VALUE key9 0 2
v9
END
get key10
END
quit
Connection closed by foreign host.
[root@centos7 ~]#

Session 共享服务器

MSM 介绍

图片-ZGHVjPVjNEXJETGENmZpSSgoUPrbOySA.png

MSM(memcached session manager)提供将Tomcat的session保持到memcached或Redis的程序,可以实现高可用。

项目早期托管在google code,目前在Github

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)

安装

参考链接: https://github.com/magro/memcached-session-manager/wiki/SetupAndConfiguration

将spymemcached.jar、memcached-session-manage、kyro相关的jar文件都放到Tomcat的lib目录中去,这个目录是$CATALINA_HOME/lib/,对应本次安装就是/usr/local/tomcat/lib。

kryo-3.0.3.jar
asm-5.2.jar
objenesis-2.6.jar
reflectasm-1.11.9.jar
minlog-1.3.1.jar
kryo-serializers-0.45.jar
msm-kryo-serializer-2.3.2.jar
memcached-session-manager-tc8-2.3.2.jar
spymemcached-2.12.3.jar
memcached-session-manager-2.3.2.jar

Sticky 模式

Sticky 模式工作原理

sticky 模式即前端tomcat和后端memcached有关联(粘性)关系

参考文档:https://github.com/magro/memcached-session-manager/wiki/SetupAndConfiguration

Tomcat-1 (t1) will primarily store it's sessions in memcached-2 (m2) which is
running on another machine (m2 is a regular node for t1). Only if m2 is not
available, t1 will store it's sessions in memcached-1 (m1, m1 is the failoverNode
for t1). With this configuration, sessions won't be lost when machine 1 (serving
t1 and m1) crashes. The following really nice ASCII art shows this setup.
Tomcat-1(t1)主要将其会话存储在另一台计算机上运行的memcached-2(m2)中(m2是t1的常规节点)。 仅当m2不可用时,t1才会将其会话存储在memcached-1中(m1,m1是t1的failoverNode)。 使用此配置,当计算机1(服务于t1和m1)崩溃时,会话不会丢失。 以下非常好的ASCII艺术显示了此设置。
<t1>  <t2>
. \   / .
.   X   .
. /   \ .
<m1>  <m2>

t1和m1部署可以在一台主机上,t2和m2部署也可以在同一台。

当新用户发请求到Tomcat1时, Tomcat1生成session返回给用户的同时,也会同时发给memcached2备份。即Tomcat1 session为主session,memcached2 session为备用session,使用memcached相当

如果Tomcat1发现memcached2 失败,无法备份Session到memcached2,则将Sessoin备份存放在memcached1中

配置过程

下载相关jar包

下载相关jar包,参考下面官方说明的下载链接

https://github.com/magro/memcached-session-manager/wiki/SetupAndConfiguration

tomcat和memcached相关包

序列化相关下载

修改tomcat配置

修改 $CATALINA_HOME/conf/context.xml

特别注意,t1配置中为failoverNodes="n1", t2配置为failoverNodes="n2"

#以下是sticky的配置
<Context>
    ...
    <Manager className="de.javakaffee.web.msm.MemcachedBackupSessionManager"
             memcachedNodes="n1:10.0.0.101:11211,n2:10.0.0.102: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中看到下面的内容

12-APR-2020 16:24:08.975 INFO [t1.wang.org-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中了。

准备测试msm的python脚本

范例:安装python环境准备python程序查看memcached中的SessionID

[root@centos8 ~]#yum -y install python3 python3-memcached
#或者执行下面两步
[root@centos8 ~]#dnf install python3 -y
[root@centos8 ~]#pip3 install python-memcached

#脚本内容
[root@centos8 ~]#cat showmemcached.py
#!/usr/bin/python3
import memcache
mc = memcache.Client(['10.0.0.101: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)
print(mc.get_stats('cachedump 5 0')) # stats cachedump 5 0 # 5和上面的items返回的值有关;0表示全部

t1、t2、n1、n2依次启动成功,分别使用http://t1.wang.org:8080/http://t2.wang.org:8080/ 观察。

开启负载均衡调度器,通过http://proxy.wang.org来访问看看效果

On tomcats
10.0.0.102:8080
SessionID = 2A19B1EB6D9649C9FED3E7277FDFD470-n2.Tomcat1
Wed Jun 26 16:32:11 CST 2019

On tomcats
10.0.0.101:8080
SessionID = 2A19B1EB6D9649C9FED3E7277FDFD470-n1.Tomcat2
Wed Jun 26 16:32:36 CST 2019

可以看到浏览器端被调度到不同Tomcat上,但是都获得了同样的SessionID。

停止t2、n2看看效果,恢复看看效果。

范例:访问tomcat,查看memcached中SessionID信息

[root@centos8 ~]#python3 showmemcached.py
.....
[('10.0.0.48:11211 (1)', {'8D0B801640CA0B1EB9AD4A4C221EA81A-n2.Tomcat1': '[97 b;
1581598952 s]'})]
#以上结果表示SessionID来自于memcached的n2节点,但是最终是由tomcat1返回的SessionID

实战案例 1 : tomcat和memcached集成在一台主机

图片-xMMjxzlebqOCsXdEdakkYBXmHYuvstUP.png

环境准备:

  • 时间同步,确保NTP或Chrony服务正常运行。
  • 防火墙规则
  • 禁用SELinux
  • 三台主机
IP主机名服务软件
10.0.0.100proxy调度器CentOS 8、Nginx、HTTPD
10.0.0.101t1tomcat1CentOS 8、JDK 8、Tomcat 8、Memcached
10.0.0.102t2tomcat2CentOS 8、JDK 8、Tomcat 8、Memcached

配置 Nginx 充当 Proxy

[root@proxy ~]#cat /etc/nginx/nginx.conf
http {
......
    upstream tomcat-server {
        #ip_hash;
        server t1.wang.org:8080;
        server t2.wang.org:8080;
    }
	server {
    	......
        location / {
        }
        location ~* \.(jsp|do)$ {
            proxy_pass http://tomcat-server;
            #proxy_set_header Host $http_host; #转发主机头至后端服务器
        }
        
[root@proxy ~]#cat /etc/hosts
10.0.0.100 proxy.wang.org proxy
10.0.0.101 t1.wang.org t1
10.0.0.102 t2.wang.org t2

配置 Memcached

在 tomcat1 上配置 memcached
[root@t1 ~]#dnf -y install memcached
[root@t1 ~]#vim /etc/sysconfig/memcached
[root@t1 ~]#cat /etc/sysconfig/memcached
PORT="11211"
USER="memcached"
MAXCONN="1024"
CACHESIZE="64"
#注释下面行
#OPTIONS="-l 127.0.0.1,::1"

[root@t1 ~]#systemctl enable --now memcached.service
在 tomcat2 上配置 memcached

配置和t1相同

[root@t2 ~]#dnf -y install memcached
[root@t2 ~]#vim /etc/sysconfig/memcached
[root@t2 ~]#cat /etc/sysconfig/memcached
PORT="11211"
USER="memcached"
MAXCONN="1024"
CACHESIZE="64"
#注释下面行
#OPTIONS="-l 127.0.0.1,::1"

[root@t2 ~]#systemctl enable --now memcached.service

配置 Tomcat

配置 tomcat1
[root@t1 tomcat]#vim conf/server.xml
<Engine name="Catalina" defaultHost="t1.wang.org" jvmRoute="Tomcat1">
            
            <Host name="t1.wang.org" 
                  appBase="/data/webapps" 
                  unpackWARs="true" 
                  autoDeploy="true">
                  
                </Host>
            
        </Engine>
        
    </Service>
    
</Server>
[root@t1 tomcat]#vim conf/context.xml
<Context>
	<Manager pathname="" />
	-->
###倒数第一行前,即</Context>行的前面,加下面内容
    <Manager className="de.javakaffee.web.msm.MemcachedBackupSessionManager"
             memcachedNodes="n1:10.0.0.101:11211,n2:10.0.0.102:11211"
             failoverNodes="n1"
             requestUriIgnorePattern=".*\.(ico|png|gif|jpg|css|js)$"
             transcoderFactoryClass="de.javakaffee.web.msm.serializer.kryo.KryoTranscoderFactory" />
    </Context>#最后一行
    
#将相关包传到lib/目录下,共10个文件
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

[root@t1 tomcat]#ls lib/ -t |tail
kryo-3.0.3.jar
asm-5.2.jar
objenesis-2.6.jar
reflectasm-1.11.9.jar
minlog-1.3.1.jar
kryo-serializers-0.45.jar
msm-kryo-serializer-2.3.2.jar
memcached-session-manager-tc8-2.3.2.jar
spymemcached-2.12.3.jar
memcached-session-manager-2.3.2.jar

[root@t1 tomcat]#systemctl restart tomcat

[root@t1 tomcat]#cat /data/webapps/ROOT/index.jsp
<%@ page import="java.util.*" %>
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>tomcat test</title>
</head>
<body>
<h1> tomcat website </h1>
<div>On <%=request.getServerName() %></div>
<div><%=request.getLocalAddr() + ":" + request.getLocalPort() %></div>
<div>SessionID = <span style="color:blue"><%=session.getId() %></span></div>
<%=new Date()%>
</body>
</html>

配置 tomcat2
#t2参考上面t1做配置
[root@t2 tomcat]#vim conf/server.xml
<Engine name="Catalina" defaultHost="t2.wang.org" jvmRoute="Tomcat2">
            
            <Host name="t2.wang.org" 
                  appBase="/data/webapps" 
                  unpackWARs="true" 
                  autoDeploy="true">
                  
                </Host>            
        </Engine>        
    </Service>
</Server>

[root@t2 tomcat]#vim conf/context.xml
<Context>
	<Manager pathname="" />
	-->
###倒数第一行前,即</Context>行的前面,加下面内容
    <Manager className="de.javakaffee.web.msm.MemcachedBackupSessionManager"
             memcachedNodes="n1:10.0.0.101:11211,n2:10.0.0.102:11211"
             failoverNodes="n2"	#只修改此行,和t1不同,其它都一样
             requestUriIgnorePattern=".*\.(ico|png|gif|jpg|css|js)$"
             transcoderFactoryClass="de.javakaffee.web.msm.serializer.kryo.KryoTranscoderFactory" />
    </Context>#最后一行
    
#将相关包传到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
[root@t2 tomcat]#ls lib/ -t |tail
kryo-3.0.3.jar
asm-5.2.jar
objenesis-2.6.jar
reflectasm-1.11.9.jar
minlog-1.3.1.jar
kryo-serializers-0.45.jar
msm-kryo-serializer-2.3.2.jar
memcached-session-manager-tc8-2.3.2.jar
spymemcached-2.12.3.jar
memcached-session-manager-2.3.2.jar
[root@t2 tomcat]#systemctl restart tomcat
[root@t2 tomcat]#cat /data/webapps/ROOT/index.jsp
<%@ page import="java.util.*" %>
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>tomcat test</title>
</head>
<body>
<h1> tomcat website </h1>
<div>On <%=request.getServerName() %></div>
<div><%=request.getLocalAddr() + ":" + request.getLocalPort() %></div>
<div>SessionID = <span style="color:blue"><%=session.getId() %></span></div>
<%=new Date()%>
</body>
</html>
查看tomcat日志
[root@t1 tomcat]#tail -n 20 logs/catalina.out
2020-07-13 09:00:28.580 INFO net.spy.memcached.MemcachedConnection: Setting
retryQueueSize to -1
2020-07-13 09:00:28.581 INFO net.spy.memcached.MemcachedConnection: Added {QA
sa=/10.0.0.101:11211, #Rops=0, #Wops=0, #iq=0, topRop=null, topWop=null,
toWrite=0, interested=0} to connect queue
2020-07-13 09:00:28.581 INFO net.spy.memcached.MemcachedConnection: Added {QA
sa=/10.0.0.102:11211, #Rops=0, #Wops=0, #iq=0, topRop=null, topWop=null,
toWrite=0, interested=0} to connect queue
13-Jul-2020 09:00:28.582 INFO [t1.wang.org-startStop-1]
de.javakaffee.web.msm.RequestTrackingHostValve.<init> Setting ignorePattern to
.*\.(ico|png|gif|jpg|css|js)$
13-Jul-2020 09:00:28.582 INFO [t1.wang.org-startStop-1]
de.javakaffee.web.msm.MemcachedSessionService.setLockingMode Setting lockingMode
to null
13-Jul-2020 09:00:28.582 INFO [t1.wang.org-startStop-1]
de.javakaffee.web.msm.MemcachedSessionService.createTranscoderFactory Creating
transcoder factory de.javakaffee.web.msm.serializer.kryo.KryoTranscoderFactory
13-Jul-2020 09:00:28.583 INFO [t1.wang.org-startStop-1]
de.javakaffee.web.msm.serializer.kryo.KryoTranscoder.<init> Starting with
initialBufferSize 102400, maxBufferSize 2048000 and defaultSerializerFactory
de.javakaffee.web.msm.serializer.kryo.DefaultFieldSerializerFactory
13-Jul-2020 09:00:28.583 INFO [t1.wang.org-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)
--------
13-Jul-2020 09:00:28.587 INFO [t1.wang.org-startStop-1]
org.apache.catalina.startup.HostConfig.deployDirectory Deployment of web
application directory [/data/webapps/ROOT] has finished in [160] ms
13-Jul-2020 09:00:28.596 INFO [main] org.apache.coyote.AbstractProtocol.start
Starting ProtocolHandler ["http-nio-8080"]
13-Jul-2020 09:00:28.619 INFO [main] org.apache.coyote.AbstractProtocol.start
Starting ProtocolHandler ["ajp-nio-0.0.0.0-8009"]
13-Jul-2020 09:00:28.621 INFO [main] org.apache.catalina.startup.Catalina.start
Server startup in 2097 ms
[root@t1 tomcat]#

Python测试脚本

在t1 上安装部署python3环境,访问memcached

[root@t1 ~]#dnf -y install python3 python3-memcached
#或者下面方式也可以安装
[root@t1 ~]#dnf -y install python3
[root@t1 ~]#pip3 install python-memcached

#准备python测试脚本
[root@t1 ~]#cat showmemcached.py
#!/usr/bin/python3
import memcache
mc = memcache.Client(['10.0.0.101:11211','10.0.0.102:11211'], debug=True)
print('-' * 30)
#查看全部 key
#for x in mc.get_stats('items'): # stats items 返回 items:5:number 1
#	 print(x)
#print('-' * 30)

for x in mc.get_stats('cachedump 5 0'): # stats cachedump 5 0 # 5和上面的items返回的值有关;0表示全部
	print(x)
[root@t1 ~]#chmod +x showmemcached.py
#运行python脚本
[root@t1 ~]#./showmemcached.py
('10.0.0.101:11211 (1)', {})
('10.0.0.102:11211 (1)', {})

浏览器访问

第一次刷新页面,可以看到显示

第一次运行脚本查看结果

[root@t1 ~]#./showmemcached.py
------------------------------
('10.0.0.101:11211 (1)', {})
('10.0.0.102:11211 (1)', {'3B4E6FB0934692150DD9944845830FCC-n2.Tomcat1': '[97 b;
1603970381 s]'})
#只有10.0.0.102上有信息,说明SessionID是由Tomcat1生成,并备份到n2,即t2上面的memcached

第二次刷新页面后,运行脚本可以查看到显示

第二次执行脚本

[root@t1 ~]#./showmemcached.py
------------------------------
('10.0.0.101:11211 (1)', {'3B4E6FB0934692150DD9944845830FCC-n1.Tomcat2': '[97 b;
1603970442 s]'})
('10.0.0.102:11211 (1)', {})

第三次刷新页面

第三次执行脚本

[root@t1 ~]#./showmemcached.py
------------------------------
('10.0.0.101:11211 (1)', {'3B4E6FB0934692150DD9944845830FCC-n1.Tomcat2': '[97 b;
1603970442 s]'})
('10.0.0.102:11211 (1)', {'3B4E6FB0934692150DD9944845830FCC-n2.Tomcat1': '[97 b;
1603970381 s]'})

第四次刷新页面

第四次执行脚本

[root@t1 ~]#./showmemcached.py
------------------------------
('10.0.0.101:11211 (1)', {'3B4E6FB0934692150DD9944845830FCC-n1.Tomcat2': '[97 b;
1603970442 s]'})
('10.0.0.102:11211 (1)', {'3B4E6FB0934692150DD9944845830FCC-n2.Tomcat1': '[97 b;
1603970381 s]'})

之后多次刷新页面,执行脚本后,session信息不在变化

故障访问

模拟tomcat故障
[root@t2 ~]#systemctl stop tomcat

刷新几次页面,看到下面SessionID显示不变

运行脚本看到下面结果

[root@t1 ~]#./showmemcached.py
------------------------------
('10.0.0.101:11211 (1)', {'items:5:number': '1', 'items:5:number_hot': '0',
'items:5:number_warm': '0', 'items:5:number_cold': '1', 'items:5:age_hot': '0',
'items:5:age_warm': '0', 'items:5:age': '1531', 'items:5:evicted': '0',
'items:5:evicted_nonzero': '0', 'items:5:evicted_time': '0',
'items:5:outofmemory': '0', 'items:5:tailrepairs': '0', 'items:5:reclaimed':
'0', 'items:5:expired_unfetched': '0', 'items:5:evicted_unfetched': '0',
'items:5:evicted_active': '0', 'items:5:crawler_reclaimed': '0',
'items:5:crawler_items_checked': '9', 'items:5:lrutail_reflocked': '0',
'items:5:moves_to_cold': '2', 'items:5:moves_to_warm': '0',
'items:5:moves_within_lru': '0', 'items:5:direct_reclaims': '0',
'items:5:hits_to_hot': '0', 'items:5:hits_to_warm': '0', 'items:5:hits_to_cold':
'1', 'items:5:hits_to_temp': '0'})
('10.0.0.102:11211 (1)', {})
------------------------------
('10.0.0.101:11211 (1)', {'4E92417BEFB38ED09E50433EF6F96DDF-n1.Tomcat2': '[97 b;
1594562924 s]'})
('10.0.0.102:11211 (1)', {})
模拟memcached故障
[root@t2 ~]#systemctl start tomcat
[root@t2 ~]#systemctl stop memcached.service

刷新几次页面可以看到只有一個n了

再次运行脚本

[root@t1 ~]#./showmemcached.py
------------------------------
MemCached: MemCache: inet:10.0.0.102:11211: connect: [Errno 111] Connection
refused. Marking dead.
('10.0.0.101:11211 (1)', {'items:5:number': '2', 'items:5:number_hot': '0',
'items:5:number_warm': '0', 'items:5:number_cold': '2', 'items:5:age_hot': '0',
'items:5:age_warm': '0', 'items:5:age': '60', 'items:5:evicted': '0',
'items:5:evicted_nonzero': '0', 'items:5:evicted_time': '0',
'items:5:outofmemory': '0', 'items:5:tailrepairs': '0', 'items:5:reclaimed':
'1', 'items:5:expired_unfetched': '1', 'items:5:evicted_unfetched': '0',
'items:5:evicted_active': '0', 'items:5:crawler_reclaimed': '0',
'items:5:crawler_items_checked': '11', 'items:5:lrutail_reflocked': '0',
'items:5:moves_to_cold': '13', 'items:5:moves_to_warm': '0',
'items:5:moves_within_lru': '0', 'items:5:direct_reclaims': '0',
'items:5:hits_to_hot': '0', 'items:5:hits_to_warm': '0', 'items:5:hits_to_cold':
'5', 'items:5:hits_to_temp': '0'})
------------------------------
('10.0.0.101:11211 (1)', {'63B8F0CE41AF8943351AB9B71DE174C3-n1.Tomcat1': '[97 b;
1594564819 s]', '63B8F0CE41AF8943351AB9B71DE174C3-n1.Tomcat2': '[97 b;
1594564785 s]'}

#看到只有10.0.0.101有信息,并且生成两个sessionID,说明当memcached2挂掉后,tomcat1只能将Session信息写入至memcached1做为备份

恢复memcached

[root@t2 ~]#systemctl start memcached.service
[root@t1 ~]#./showmemcached.py
------------------------------
('10.0.0.101:11211 (1)', {'items:5:number': '2', 'items:5:number_hot': '0',
'items:5:number_warm': '0', 'items:5:number_cold': '2', 'items:5:age_hot': '0',
'items:5:age_warm': '0', 'items:5:age': '23', 'items:5:evicted': '0',
'items:5:evicted_nonzero': '0', 'items:5:evicted_time': '0',
'items:5:outofmemory': '0', 'items:5:tailrepairs': '0', 'items:5:reclaimed':
'1', 'items:5:expired_unfetched': '1', 'items:5:evicted_unfetched': '0',
'items:5:evicted_active': '0', 'items:5:crawler_reclaimed': '0',
'items:5:crawler_items_checked': '13', 'items:5:lrutail_reflocked': '0',
'items:5:moves_to_cold': '20', 'items:5:moves_to_warm': '0',
'items:5:moves_within_lru': '0', 'items:5:direct_reclaims': '0',
'items:5:hits_to_hot': '0', 'items:5:hits_to_warm': '0', 'items:5:hits_to_cold':
'5', 'items:5:hits_to_temp': '0'})
('10.0.0.102:11211 (1)', {'items:5:number': '1', 'items:5:number_hot': '0',
'items:5:number_warm': '0', 'items:5:number_cold': '1', 'items:5:age_hot': '0',
'items:5:age_warm': '0', 'items:5:age': '20', 'items:5:evicted': '0',
'items:5:evicted_nonzero': '0', 'items:5:evicted_time': '0',
'items:5:outofmemory': '0', 'items:5:tailrepairs': '0', 'items:5:reclaimed':
'0', 'items:5:expired_unfetched': '0', 'items:5:evicted_unfetched': '0',
'items:5:evicted_active': '0', 'items:5:crawler_reclaimed': '0',
'items:5:crawler_items_checked': '0', 'items:5:lrutail_reflocked': '0',
'items:5:moves_to_cold': '2', 'items:5:moves_to_warm': '0',
'items:5:moves_within_lru': '0', 'items:5:direct_reclaims': '0',
'items:5:hits_to_hot': '0', 'items:5:hits_to_warm': '0', 'items:5:hits_to_cold':
'0', 'items:5:hits_to_temp': '0'})
------------------------------
('10.0.0.101:11211 (1)', {'63B8F0CE41AF8943351AB9B71DE174C3-n1.Tomcat2': '[97 b;
1594564785 s]', '63B8F0CE41AF8943351AB9B71DE174C3-n1.Tomcat1': '[97 b;
1594564819 s]'})
('10.0.0.102:11211 (1)', {'63B8F0CE41AF8943351AB9B71DE174C3-n2.Tomcat1': '[97 b;
1594564796 s]'})

实战案例 2 : tomcat和memcached 分别处于不同

图片-rZhhoAcAiKznxZxSCGikYvrUxNhAUnqU.png

环境准备:

  • 时间同步,确保NTP或Chrony服务正常运行。
  • 防火墙规则
  • 禁用SELinux
  • 五台主机
IP主机名服务软件
10.0.0.100proxy调度器CentOS8、Nginx、HTTPD
10.0.0.101t1tomcat1CentOS8、JDK8、Tomcat8
10.0.0.102t2tomcat2CentOS8、JDK8、Tomcat8
10.0.0.103m1memcached1CentOS8、memcached
10.0.0.104m2memcached2CentOS8、memcached

准备proxy主机的配置,利用nginx作为反向代理

[root@proxy ~]#cat /etc/nginx/nginx.conf
http {
        ......
        upstream tomcat-server {
        server t1.wang.org:8080;
        server t2.wang.org:8080;
}
	server {
        ......
        location / {
        }
        location ~* \.(jsp|do)$ {
        	proxy_pass http://tomcat-server;
			#proxy_set_header Host $http_host; #转发主机头至后端服务器
		}
}

[root@proxy ~]#cat /etc/hosts
10.0.0.100 proxy.wang.org proxy
10.0.0.101 t1.wang.org t1
10.0.0.102 t2.wang.org t2

#准备一台测试机(可选)
[root@centos7 ~]#cat /etc/hosts
127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4
centos7.ayaka.com
::1 localhost localhost.localdomain localhost6 localhost6.localdomain6
10.0.0.100 proxy.wang.org
[root@centos7 ~]#hostname -I
10.0.0.7

在m1和m2上分别配置memcached

#在m1和m2上做相同的配置
[root@m1 ~]#dnf -y install memcached
[root@m1 ~]#vim /etc/sysconfig/memcached
[root@m1 ~]#cat /etc/sysconfig/memcached
PORT="11211"
USER="memcached"
MAXCONN="1024"
CACHESIZE="64"
#OPTIONS="-l 127.0.0.1,::1"
OPTIONS=""
[root@m1 ~]#systemctl start memcached.service
#m2的配置和m1相同

在t1和t2上准备tomcat

t1 的配置

[root@t1 tomcat]#vim conf/server.xml
<Engine name="Catalina" defaultHost="t1.wang.org" jvmRoute="Tomcat1">
   ....         
            <Host name="t1.wang.org" 
                  appBase="/data/webapps" 
                  unpackWARs="true" 
                  autoDeploy="true">                  
                </Host>            
        </Engine>        
    </Service>
</Server>

[root@t1 tomcat]#vim conf/context.xml
<Context>
	<Manager pathname="" />
	-->
###倒数第一行前,即</Context>行的前面,加下面内容
    <Manager className="de.javakaffee.web.msm.MemcachedBackupSessionManager"
             memcachedNodes="n1:10.0.0.103:11211,n2:10.0.0.104:11211"
             failoverNodes="n1"
             requestUriIgnorePattern=".*\.(ico|png|gif|jpg|css|js)$"
             transcoderFactoryClass="de.javakaffee.web.msm.serializer.kryo.KryoTranscoderFactory" />
    </Context>#最后一行
    
#将相关包传到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

[root@t1 tomcat]#ls lib/ -t |tail
kryo-3.0.3.jar
asm-5.2.jar
objenesis-2.6.jar
reflectasm-1.11.9.jar
minlog-1.3.1.jar
kryo-serializers-0.45.jar
msm-kryo-serializer-2.3.2.jar
memcached-session-manager-tc8-2.3.2.jar
spymemcached-2.12.3.jar
memcached-session-manager-2.3.2.jar

[root@t1 tomcat]#cat /data/webapps/ROOT/index.jsp
<%@ page import="java.util.*" %>
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>tomcat test</title>
</head>
<body>
<div>On <%=request.getServerName() %></div>
<div><%=request.getLocalAddr() + ":" + request.getLocalPort() %></div>
<div>SessionID = <span style="color:blue"><%=session.getId() %></span></div>
<%=new Date()%>
</body>
</html>
[root@t1 ~]#systemctl restart tomcat

t2参考上面t1做类似的配置

[root@t2 tomcat]#vim conf/server.xml
<Engine name="Catalina" defaultHost="t2.wang.org" jvmRoute="Tomcat2">
            
            <Host name="t2.wang.org" 
                  appBase="/data/webapps" 
                  unpackWARs="true" 
                  autoDeploy="true">
                  
                </Host>            
        </Engine>        
    </Service>
</Server>

[root@t2 tomcat]#vim conf/context.xml

[root@t2 tomcat]#vim conf/context.xml
<Context>
	<Manager pathname="" />
	-->
###倒数第一行前,即</Context>行的前面,加下面内容
    <Manager className="de.javakaffee.web.msm.MemcachedBackupSessionManager"
             memcachedNodes="n1:10.0.0.103:11211,n2:10.0.0.104:11211"
             failoverNodes="n2"	#只修改此行,和t1不同,其它都一样
             requestUriIgnorePattern=".*\.(ico|png|gif|jpg|css|js)$"
             transcoderFactoryClass="de.javakaffee.web.msm.serializer.kryo.KryoTranscoderFactory" />
    </Context>#最后一行
    
#将相关包传到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
[root@t2 tomcat]#cat /data/webapps/ROOT/index.jsp
<%@ page import="java.util.*" %>
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>tomcat test</title>
</head>
<body>
<div>On <%=request.getServerName() %></div>
<div><%=request.getLocalAddr() + ":" + request.getLocalPort() %></div>
<div>SessionID = <span style="color:blue"><%=session.getId() %></span></div>
<%=new Date()%>
</body>
</html>
[root@t2 ~]#systemctl restart tomcat

查看日志

[root@t1 ~]#tail /usr/local/tomcat/logs/catalina.out
.......
...... INFO [t1.wang.org-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)

测试的python脚本

在proxy 上安装部署python3环境,访问memcached

[root@proxy ~]#dnf -y install python3 python3-memcached

#准备python测试脚本
[root@proxy ~]#cat showmemcached.py
#!/usr/bin/python3
import memcache
mc = memcache.Client(['10.0.0.103:11211','10.0.0.104:11211'], debug=True)
print('-' * 30)
for x in mc.get_stats('cachedump 5 0'): # stats cachedump 5 0 # 5和上面的items返回的值有关;0表示全部
	print(x)

[root@proxy ~]#chmod +x showmemcached.py

#运行python脚本
[root@proxy ~]#./showmemcached.py
------------------------------
('10.0.0.103:11211 (1)', {})
('10.0.0.104:11211 (1)', {})

浏览器访问测试

第一次刷新浏览器可以看到以下显示

运行脚本,可以看到只有m2上有SessionID信息

[root@proxy ~]#./showmemcached.py
------------------------------
('10.0.0.103:11211 (1)', {})
('10.0.0.104:11211 (1)', {'8F9B4782FFFE6F1840728C344A179EE8-n2.Tomcat1': '[97 b;
1594812395 s]'})

第二次刷新页面,可以看到主机轮询,SessionID不变,但SessionID来自别一个tomcat

多次刷新页面,可以看到主机轮询,SessionID不变,发现以下规律

当tomcat为t1,发现SessionID为n1.Tomcat2

当tomcat为t2,发现SessionID为n2.Tomcat1

运行脚本,可以看到m1和m2上都有了SessionID信息

[root@proxy ~]#./showmemcached.py
------------------------------
('10.0.0.103:11211 (1)', {'8F9B4782FFFE6F1840728C344A179EE8-n1.Tomcat2': '[97 b;
1594812654 s]'})
('10.0.0.104:11211 (1)', {'8F9B4782FFFE6F1840728C344A179EE8-n2.Tomcat1': '[97 b;
1594812396 s]'})
[root@proxy ~]#

模拟故障

[root@t2 ~]#systemctl stop tomcat

多次刷新页面,SessionID不变

[root@m2 ~]#systemctl stop memcached.service

多次刷新页面,SessionID不变

运行脚本

[root@proxy ~]#./showmemcached.py
------------------------------
MemCached: MemCache: inet:10.0.0.104:11211: connect: [Errno 111] Connection
refused. Marking dead.
('10.0.0.103:11211 (1)', {'F82C3A7C84B2E0D6B05E6E6F496F9FBC-n1.Tomcat2': '[97 b;
1594815951 s]', 'F82C3A7C84B2E0D6B05E6E6F496F9FBC-n1.Tomcat1': '[97 b;
1594815949 s]'}

Non-Sticky 模式

Non-Sticky 模式工作原理

non-sticky 模式即前端tomcat和后端memcached无关联(无粘性)关系

从msm 1.4.0之后版本开始支持non-sticky模式。

Tomcat session为中转Session,对每一个SessionID随机选中后端的memcached节点n1(或者n2)为主session,而另一个memcached节点n2(或者是n1)为备session。产生的新的Session会发送给主、备memcached,并清除本地Session。

后端两个memcached服务器对一个session来说是一个是主,一个是备,但对所有session信息来说每个memcached即是主同时也是备

如果n1下线,n2则转正。n1再次上线,n2依然是主Session存储节点。

Memcached 配置

放到$CATALINA_HOME/conf/context.xml

<Context>
    <Manager className="de.javakaffee.web.msm.MemcachedBackupSessionManager"
             memcachedNodes="n1:10.0.0.101:11211,n2:10.0.0.102: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 配置

图片-tpHosMudOVmndIOOozuzmSVVxlGmcSJW.png

支持将session存放在Redis中,但当前对Redis的支持不允许连接到多个Redis节点,可以通过Redis的集群服务实现防止redis的单点失败

参考文档 :
https://github.com/ran-jit/tomcat-cluster-redis-session-manager/wiki

https://github.com/magro/memcached-session-manager/wiki/SetupAndConfiguration#example-for-non-sticky-sessions--kryo--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://:password@redis.example.com:portnumber"
             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相关工具可以观察到redis中的信息

实战案例: memcached 实现non-sticky模式

环境准备:

  • 时间同步,确保NTP或Chrony服务正常运行。
  • 防火墙规则
  • 禁用SELinux
  • 三台主机
IP主机名服务组件/软件
10.0.0.100proxy调度器Nginx、HTTPD
10.0.0.101t1tomcat1JDK8、Tomcat8、memcached
10.0.0.102t2tomcat2JDK8、Tomcat8、memcached

修改tomcat配置

#在前面实验基础上修改,memcached配置不变,只需要修改tomcat配置
[root@t1 tomcat]#vim conf/context.xml
<Context>
    <Manager className="de.javakaffee.web.msm.MemcachedBackupSessionManager"
             memcachedNodes="n1:10.0.0.101:11211,n2:10.0.0.102:11211"
             sticky="false"	#下面三行和sticky模式不同
             sessionBackupAsync="false"
             lockingMode="uriPattern:/path1|/path2"
             requestUriIgnorePattern=".*\.(ico|png|gif|jpg|css|js)$"
             transcoderFactoryClass="de.javakaffee.web.msm.serializer.kryo.KryoTranscoderFactory" />

</Context>

[root@t1 tomcat]#systemctl restart tomcat

#查看日志
[root@t1 ~]#tail -f /usr/local/tomcat/logs/catalina.out
..... INFO [t1.wang.org-startStop-1]
de.javakaffee.web.msm.MemcachedSessionService.startInternal --------
- finished initialization:
- sticky: false
- operation timeout: 1000
- node ids: [n1, n2]
- failover node ids: []
- storage key prefix: null
- locking mode: uriPattern:/path1|/path2 (expiration: 5s)

#t2和t1相同操作
[root@t2 tomcat]#vim conf/context.xml
[root@t2 tomcat]#systemctl restart tomcat

#运行脚本查看key
[root@t1 ~]#cat ./showmemcached.py
#!/usr/bin/python3
import memcache
mc = memcache.Client(['10.0.0.101:11211','10.0.0.102:11211'], debug=True)
print('-' * 30)
for x in mc.get_stats('cachedump 5 0'): # stats cachedump 5 0 # 5和上面的items返回的值有关;0表示全部
	print(x)
[root@t1 ~]#./showmemcached.py
------------------------------
('10.0.0.101:11211 (1)', {})
('10.0.0.102:11211 (1)', {})
[root@t1 ~]#

通过浏览器访问

#再次运行脚本后可以看到,t2为memcached的主节点,t1为备份节点
[root@t1 ~]#./showmemcached.py
------------------------------
('10.0.0.101:11211 (1)', {'bak:D65D49C8BB068B0854F11BD1A7BFAE88-n2.Tomcat2':
'[97 b; 1594609275 s]'})
('10.0.0.102:11211 (1)', {'D65D49C8BB068B0854F11BD1A7BFAE88-n2.Tomcat2': '[97 b;
1594609274 s]'})

模拟故障

模拟t1的memcached 故障

[root@t1 ~]#systemctl stop memcached.service
[root@t1 ~]#./showmemcached.py
------------------------------
MemCached: MemCache: inet:10.0.0.101:11211: connect: [Errno 111] Connection
refused. Marking dead.
('10.0.0.102:11211 (1)', {'D65D49C8BB068B0854F11BD1A7BFAE88-n2.Tomcat2': '[97 b; 1594609274 s]'})

[root@t1 ~]#systemctl start memcached.service
[root@t1 ~]#./showmemcached.py
------------------------------
('10.0.0.101:11211 (1)', {})
('10.0.0.102:11211 (1)', {'D65D49C8BB068B0854F11BD1A7BFAE88-n2.Tomcat2': '[97 b;1594609274 s]'})


#刷新几次页面后,再运行脚本
[root@t1 ~]#./showmemcached.py
------------------------------
('10.0.0.101:11211 (1)', {'bak:D65D49C8BB068B0854F11BD1A7BFAE88-n2.Tomcat2':
'[97 b; 1594609854 s]'})
('10.0.0.102:11211 (1)', {'D65D49C8BB068B0854F11BD1A7BFAE88-n2.Tomcat2': '[97 b;1594609274 s]'}

模拟t2的memcached 故障

[root@t2 ~]#systemctl stop memcached.service
[root@t1 ~]#./showmemcached.py
------------------------------
MemCached: MemCache: inet:10.0.0.102:11211: connect: [Errno 111] Connection
refused. Marking dead.
('10.0.0.101:11211 (1)', {'bak:D65D49C8BB068B0854F11BD1A7BFAE88-n2.Tomcat2':
'[97 b; 1594609854 s]'})

再刷新页面

#运行脚本看到在t1上生成相同的SessionID,并成为memcached新主
[root@t1 ~]#./showmemcached.py
------------------------------
MemCached: MemCache: inet:10.0.0.102:11211: connect: [Errno 111] Connection
refused. Marking dead.
('10.0.0.101:11211 (1)', {'D65D49C8BB068B0854F11BD1A7BFAE88-n1.Tomcat2': '[97 b;1594610030 s]', 'bak:D65D49C8BB068B0854F11BD1A7BFAE88-n2.Tomcat2': '[97 b;1594609854 s]'}

[root@t2 ~]#systemctl start memcached.service
[root@t1 ~]#./showmemcached.py
------------------------------
('10.0.0.101:11211 (1)', {'D65D49C8BB068B0854F11BD1A7BFAE88-n1.Tomcat2': '[97 b;1594610030 s]', 'bak:D65D49C8BB068B0854F11BD1A7BFAE88-n2.Tomcat2': '[97 b;1594609854 s]'})
('10.0.0.102:11211 (1)', {})

#再刷新页,运行脚本看到t2成为备用节点
[root@t1 ~]#./showmemcached.py
------------------------------
('10.0.0.101:11211 (1)', {'D65D49C8BB068B0854F11BD1A7BFAE88-n1.Tomcat2': '[97 b;1594610030 s]', 'bak:D65D49C8BB068B0854F11BD1A7BFAE88-n2.Tomcat2': '[97 b;1594609854 s]'})
('10.0.0.102:11211 (1)', {'bak:D65D49C8BB068B0854F11BD1A7BFAE88-n1.Tomcat2':
'[97 b; 1594610367 s]'})

模拟t1的tomcat故障,刷新页面,可以看到SessionID不变

[root@t1 ~]#systemctl stop tomcat

实战案例: redis 实现 non-sticky 模式的msm

环境准备:

  • 时间同步,确保NTP或Chrony服务正常运行
  • 防火墙规则
  • 禁用SELinux
  • 四台主机
IP主机名服务软件包
10.0.0.100proxy调度器Nginx、HTTPD
10.0.0.101t1.wang.orgtomcat1JDK8、Tomcat8
10.0.0.102t2.wang.orgtomcat2JDK8、Tomcat8
10.0.0.103redis.wang.orgredisRedis

上传redis库到tomcat服务器

[root@t1 ~]#ll /usr/local/tomcat/lib/jedis-3.0.0.jar
-rw-r--r-- 1 root root 586620 Jun 26 2019 /usr/local/tomcat/lib/jedis-3.0.0.jar
[root@t2 ~]#ll /usr/local/tomcat/lib/jedis-3.0.0.jar
-rw-r--r-- 1 root root 586620 Jun 26 2019 /usr/local/tomcat/lib/jedis-3.0.0.jar

安装并配置 Redis 服务

[root@redis ~]#dnf -y install redis
[root@redis ~]#sed -i.bak 's/^bind.*/bind 0.0.0.0/' /etc/redis.conf
[root@redis ~]#systemctl enable --now redis
[root@redis ~]#ss -ntl
State Recv-Q Send-Q Local Address:Port Peer Address:Port
LISTEN 0 128 0.0.0.0:22 0.0.0.0:*
LISTEN 0 100 127.0.0.1:25 0.0.0.0:*
LISTEN 0 128 0.0.0.0:6379 0.0.0.0:*
LISTEN 0 128 [::]:22 [::]:*
LISTEN 0 100 [::1]:25 [::]:*

修改tomcat 配置指定redis服务器地址

[root@t1 tomcat]#vim conf/context.xml
<Context>
    <Manager className="de.javakaffee.web.msm.MemcachedBackupSessionManager"
             memcachedNodes="redis://10.0.0.103:6379"#和non-sticky的memcached相比,只修改此行
             sticky="false"	#下面三行和sticky模式不同
             sessionBackupAsync="false"
             lockingMode="uriPattern:/path1|/path2"
             requestUriIgnorePattern=".*\.(ico|png|gif|jpg|css|js)$"
             transcoderFactoryClass="de.javakaffee.web.msm.serializer.kryo.KryoTranscoderFactory" />

</Context>

[root@t1 ~]#systemctl restart tomcat
#查看日志
[root@t1 ~]#tail -f /usr/local/tomcat/logs/catalina.out
....., INFO [t1.wang.org-startStop-1]
de.javakaffee.web.msm.MemcachedSessionService.startInternal --------
- finished initialization:
- sticky: false
- operation timeout: 1000
- node ids: []
- failover node ids: []
- storage key prefix: null
- locking mode: uriPattern:/path1|/path2 (expiration: 5s)
.......

#t2和t1配置相同
[root@t2 ~]#vim /usr/local/tomcat/conf/context.xml
[root@t2 ~]#systemctl restart tomcat

测试访问

浏览器刷新访问多次,主机轮询,但SessionID不变

使用redis工具连接redis 查看SessionID

[root@redis ~]#redis-cli
127.0.0.1:6379> KEYS *
1) "4245D5D28B2CDAB292623A01DD5D2C83.Tomcat2"
2) "validity:4245D5D28B2CDAB292623A01DD5D2C83.Tomcat2"
127.0.0.1:6379> GET 4245D5D28B2CDAB292623A01DD5D2C83.Tomcat2
"\x00\x02\x00\\\x00\x00\x01sR\xf6\x8b@\x00\x00\x01sR\xf6\x8b@\x00\x00\a\b11\x00\
x00\x01sR\xf6\x8b@\x00\x00\x01sR\xf6\x8bA\x00(4245D5D28B2CDAB292623A01DD5D2C83.T
omcat2\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00"
127.0.0.1:6379>

模拟故障

模拟tomcat故障,查看是否SessionID变化
[root@t2 ~]#systemctl stop tomcat

刷新页面,可以看到SessinID不变

模拟Redis 故障

模拟Redis 故障,再刷新页面,可以看到SessionID不断变化,说明redis存在单点故障

[root@t1 ~]#systemctl start tomcat
[root@redis ~]#systemctl stop redis

使用 Redisson 利用 Redis 实现 Session共享

Redisson是Redis官方推荐的Java版的Redis客户端。它提供的功能非常多,也非常强大

Redisson 是基于redis的扩展库,使得redis除了应用于缓存以外,还能做队列等数据结构,直接使用的分布式锁,以及事务调度器等。

此项目更新比较频繁,生产较为推荐

官网:

https://github.com/redisson/redisson

tomcat 配置Redisson的文档链接

https://github.com/redisson/redisson/tree/master/redisson-tomcat

相关jar包下载链接

https://repository.sonatype.org/service/local/artifact/maven/redirect?r=central-
proxy&g=org.redisson&a=redisson-all&v=3.16.1&e=jar
https://repository.sonatype.org/service/local/artifact/maven/redirect?r=central-
proxy&g=org.redisson&a=redisson-tomcat-8&v=3.16.1&e=jar
https://repository.sonatype.org/service/local/artifact/maven/redirect?r=central-
proxy&g=org.redisson&a=redisson-tomcat-9&v=3.16.1&e=jar

范例: 使用redisson实现session共享

[root@centos8 ~]#vim /usr/local/tomcat/conf/context.xml
#倒数第一行前加下面内容
<Manager className="org.redisson.tomcat.RedissonSessionManager"
         configPath="${catalina.base}/conf/redisson.conf" 
         readMode="MEMORY"
         updateMode="DEFAULT"/>
</Context>

#或者使用官方配置
<Manager className="org.redisson.tomcat.RedissonSessionManager"
         configPath="${catalina.base}/conf/redisson.conf"
         readMode="REDIS"
         updateMode="DEFAULT"
         broadcastSessionEvents="false"
         keyPrefix=""/>
         
#创建下面文件内容
[root@centos8 ~]#vim /usr/local/tomcat/conf/redisson.conf         
{
    "singleServerConfig":{
        "idleConnectionTimeout":10000,
        "connectTimeout":10000,
        "timeout":3000,
        "retryAttempts":3,
        "retryInterval":1500,
        "password":null,
        "subscriptionsPerConnection":5,
        "clientName":null,
        "address": "redis://10.0.0.100:6379", #指向redis服务器地址
        "subscriptionConnectionMinimumIdleSize":1,
        "subscriptionConnectionPoolSize":50,
        "connectionMinimumIdleSize":32,
        "connectionPoolSize":64,
        "database":0,
        "dnsMonitoringInterval":5000
       },
       "threads":0,
        "nettyThreads":0,
        "codec":{
        	"class":"org.redisson.codec.JsonJacksonCodec"
		},
		"transportMode":"NIO"
}

#准备两个jar包到lib目录
#下载链接https://github.com/redisson/redisson/tree/master/redisson-tomcat
root@centos8 ~]#ls /usr/local/tomcat/lib/redisson-*
/usr/local/tomcat/lib/redisson-all-3.16.1.jar
/usr/local/tomcat/lib/redisson-tomcat-9-3.16.1.jar

#重启tomcat生效
systemctl restart tomcat

#准备测试页面
[root@centos8 ~]#cat /usr/local/tomcat/webapps/ROOT/test.jsp
<%@ page import="java.util.*" %>
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>tomcat test</title>
</head>
<body>
<h1> Tomcat Website </h1>
<div>On <%=request.getServerName() %></div>
<div><%=request.getLocalAddr() + ":" + request.getLocalPort() %></div>
<div>SessionID = <span style="color:blue"><%=session.getId() %></span></div>
<%=new Date()%>
</body>
</html>

#访问此页面
[root@centos8 ~]#curl 127.0.0.1:8080/test.jsp
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>tomcat test</title>
</head>
<body>
<h1> Tomcat Website </h1>
<div>On 127.0.0.1</div>
<div>127.0.0.1:8080</div>
<div>SessionID = <span
style="color:blue">F14D14DF86AD76D55789269190950393</span></div>
Fri Aug 06 14:44:18 CST 2021
</body>
</html>

#访问redis,查看生成数据
[root@ubuntu1804 ~]#redis-cli
127.0.0.1:6379> keys *
1) "redisson:tomcat_session:4B5FC68977FC980E3C32564C357A2785"
127.0.0.1:6379> type "redisson:tomcat_session:4B5FC68977FC980E3C32564C357A2785"
hash
127.0.0.1:6379> hgetall redisson:tomcat_session:4B5FC68977FC980E3C32564C357A2785
1) "session:thisAccessedTime"
2) "[\"java.lang.Long\",1628231049422]"
3) "session:isNew"
4) "false"
5) "session:lastAccessedTime"
6) "[\"java.lang.Long\",1628231049422]"
7) "session:maxInactiveInterval"
8) "1800"
9) "session:isValid"
10) "true"
11) "session:creationTime"
12) "[\"java.lang.Long\",1628231049358]"

利用 Tomcat Clustering Redis Session Manager 利用 Redis 实现session共享

Redis session manager 是一个插件。 它将会话存储到 Redis 中,以便在 Tomcat 服务器集群中轻松分发 HTTP 请求。

在这里,会话被实现为非粘性(意味着,每个请求都可以转到集群中的任何服务器,这与 Apache 提供的 Tomcat 集群设置不同。)

请求Sessions会立即存入Redis(Session属性必须是Serializable),供其他服务器使用。 当 tomcat 收到客户端的请求时,Sessions 直接从 Redis 加载。从而无需在负载均衡器中启用粘性会话(JSESSIONID)。

支持Redis默认、哨兵和集群模式,基于配置。

参考文档

https://github.com/ran-jit/tomcat-cluster-redis-session-manager

范例:

#下载相关文件并解压缩
wget https://github.com/ran-jit/tomcat-cluster-redis-session-manager/releases/download/3.0.1.1/tomcat-cluster-redis-session-manager.zip

unzip /opt/tomcat-cluster-redis-session-manager.zip -d /opt

#复制jar包到tomcat/lib目录中
cp /opt/tomcat-cluster-redis-session-manager/lib/* /usr/local/tomcat/lib/
chown -R tomcat.tomcat /usr/local/tomcat/lib

#复制redis配置文件到tomcat/conf目录中
cp /opt/tomcat-cluster-redis-session-manager/conf/redis-data-cache.properties  /usr/local/tomcat/conf/

#修改redis配置信息
vim /usr/local/tomcat/conf/redis-data-cache.properties
#修改下面两行
redis.hosts=10.0.0.100:6379 #指向redis服务器地址
redis.password=123456

#添加两行配置文件在 tomcat/conf/context.xml
vim /usr/local/tomcat/conf/context.xml
#在最后一行前加下两行
<Valve className="tomcat.request.session.redis.SessionHandlerValve" />
<Manager className="tomcat.request.session.redis.SessionManager" />
</Context> #此是最后一行

#修改session过期时间为60m,默认30m,此步可选
vim /usr/local/tomcat/conf/web.xml
<session-config>
<session-timeout>60</session-timeout>
</session-config>

#重启服务
systemctl restart tomcat

#nginx配置反向代理和均衡负载
vim /etc/nginx/conf.d/session.conf
upstream tomcat-server {
    server t1.wang.org:8080;
    server t2.wang.org:8080;
}
server {
    listen 80;
    server_name www.wang.org;
    location / {
        proxy_pass http://tomcat-server;
        proxy_set_header Host $http_host;
    }
}

#tomcat测试页面
cat /data/webapps/ROOT/test.jsp
<%@ page import="java.util.*" %>
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>tomcat test</title>
</head>
<body>
<h1> Tomcat1 Website </h1>
<div>On <%=request.getServerName() %></div>
<div><%=request.getLocalAddr() + ":" + request.getLocalPort() %></div>
<div>SessionID = <span style="color:blue"><%=session.getId() %></span></div>
<%=new Date()%>
</body>
</html>

评论