启动Memcached支援

今天闲来没事,看了下宝塔的面板,发现宝塔有一个Memcached的功能,于是百度了下。

解释是这样的:
Memcached配合typecho的插件可以让您的博客支持更大的并发

em。。。。我的烂机子正好需要这个东西!

遂开始进行折腾。我们以宝塔面板为例子(方便):

找到你的php相应的版本,然后安装Memcached拓展。

未分类

稍等一阵子就好了,php.ini不用你手动设置哦,宝塔会自己帮你设置好的。
然后我们来安装typecho的支援插件!

cd
cd /www/wwwroot/你的域名/usr/plugins
git clone https://github.com/phpgao/TpCache.git

然后启用!并且配置相关信息!

未分类

然后就可以了。若有不懂的可以到作者这个项目下查看:https://github.com/phpgao/TpCache

CentOS7下安装memcached服务

首先下载memcached

wget http://www.memcached.org/files/memcached-1.5.9.tar.gz

安装前需要先安装libevent

yum -y install libevent libevent-devel
#解压
tar zxvf memcached-1.5.9.tar.gz
#进入目录
cd memcached-1.5.9
#配置
./configure --prefix=/usr/local/memcached --prefix=/usr/local/memcached/
#编译
make
#安装
make install
#启动memcached
/usr/local/memcached/bin/memcached -m 10 -u root &

注:-m 内存(单位为M) -u 用户 另外还可以有其他参数-l 主机IP -p 端口

如需设置开机自启动可以按如下方式编辑文件,然后加入启动命令

vi /etc/rc.d/rc.local

注:可能需要赋予rc.local文件可执行权限才可以开机执行

PHP 和 Python 基于 UDP 协议操作 memcached

在写完(https://mp.weixin.qq.com/s?__biz=MzAwOTU4NzM5Ng==&mid=2455770298&idx=1&sn=1a6232862a977c9bc85d99620a9e8499&scene=21#wechat_redirect)这篇文章后,我重新燃起了对 memcached 的兴趣,在新浪博客的时候,我们很早就使用了 memcached,但由于大部分服务使用了 squid 缓存,所以 memcached 没有大规模使用,十年过去了,我对 memcached 的认知也越来越肤浅了,乘着这次机会,我重新看了一遍 memcached 官方 wiki,打算写几篇文章回顾下,今天聊第一个话题,那就是如何基于 UDP 协议操作 memcached。

首先 memcached 支持 TCP 和 UDP 协议,至于两者的差别不是本文的重点,本文主要讲解如何在 PHP 和 Python 中以 UDP 协议的方式操作 memcached。

memcached 服务如何开启 UDP

由于出现过 memcached UDP 反射攻击,所以很多 linux 发行版默认启动的是关闭 UDP 端口的,如果你想开启,可以执行下列命令:

$ memcached -m 64 -p 11212 -U 11211 -u memcache -l 127.0.0.1

-U 参数表示指定 UDP 端口,如果 -U 参数的值为0 表示关闭 UDP 端口。

一旦执行上列命令,表示 memcached 服务器端同时监听 11211 的 UDP 和 TCP 端口,通过下列命令可看出:

$ netstat -an | grep 11211
tcp 0 0 127.0.0.1:11211 0.0.0.0:* LISTEN     
udp 0 0 127.0.0.1:11211 0.0.0.0:*

命令行 UDP 连接 memcached

在 Linux 中,telnet 只能运行于 TCP 模式,所以为了演示,只能采用 nc 命令行。UDP 操作 memcached,在操作数据的时候必须增加一个 frame 头,后续的数据格式和 TCP 操作 memcached 一样,查看官方手册:

 The frame header is 8 bytes long, as follows (all values are 16-bit integers

 in network byte order, high byte first):


 0-1 Request ID.

 2-3 Sequence number.

 4-5 Total number of datagrams in this message.

 6-7 Reserved for future use; must be 0.

为了说的简单点,可以执行下列命令,以 UDP 协议操作 memcached:

$ printf 'x00x00x00x00x00x01x00x00statsrn' | nc -u 127.0.0.1 11211 
$ printf 'x00x00x00x00x00x01x00x00set v 0 0 1rnxrn' | nc -u 127.0.0.1 11211 
$ printf 'x00x00x00x00x00x01x00x00get vrn' | nc -u 127.0.0.1 11211

PHP 以 UDP 协议操作 memcached

php-memcached 扩展也支持 UDP 协议操作 memcached,但并不鼓励,所以官方文档介绍 UDP 操作非常少,我也是查了官方的 Issues 才明白的。另外即使支持,UDP 操作也有限制,比如 set 命令支持 UDP 协议,但 get 命令就不支持,至于原因,大家可以思考下,后续我会简单说一说。

先看代码:

$m_udp = new Memcached();
# 使用 UDP 协议模式
$m_udp->setOption(Memcached::OPT_USE_UDP, true);
# 注意,支持文本模式的协议,而非二进制协议
$m_udp->setOption(Memcached::OPT_BINARY_PROTOCOL, false);

$m_udp->addServer('127.0.0.1', 11211, 1);

echo $m_udp->get('y');
var_dump($m_udp->getResultMessage());

输出 string(20) “ACTION NOT SUPPORTED”,可以看出 php-memcached 扩展做了限制,不允许 UDP 协议操作 get 命令。

$m_udp->set('y',"ok");
var_dump($m_udp->getResultMessage());
$m_tcp =new Memcached();
# 切换为默认的 TCP 连接方式
$m_tcp->addServer('127.0.0.1', 11211, 1);
echo $m_tcp->get("y");

执行完毕,成功输出 ok。

Python 以 UDP 协议操作 memcached

Python 有专门的包基于 UDP 协议操作 memcached,这就是 python-memcached-udp 包,安装后,演示一个例子:

client = memcached_udp.Client([('localhost', 11211)])
client.set('key1', 'value1')
r = client.get('key1')
print (r)

大家可以看看这个包的源代码,非常有意思,可以学到很多 memcached 命令知识。

Memcached的MemCachedClient设置过期时限

之前做的项目用到了Memcached,用来存储图片验证码.不过需要设置过期时限.代码参照下面.

testMemcache.java

public void testMemcache(){
MemcacheUtil.set("abc","abc", new Date(1*10*1000));
MemcacheUtil.set("bbb","bbb", new Date(System.currentTimeMillis()+8000));</code>

//大于2000为null
try {
Thread.sleep(1*8*1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}

System.out.println(MemcacheUtil.get("abc"));
System.out.println(MemcacheUtil.get("bbb"));
try {
Thread.sleep(1*1*1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(MemcacheUtil.get("abc"));
System.out.println(MemcacheUtil.get("bbb"));
try {
Thread.sleep(1*1*1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(MemcacheUtil.get("abc"));
System.out.println(MemcacheUtil.get("bbb"));
}

MemcacheUtil.java

import java.util.Date;</code>

import com.danga.MemCached.MemCachedClient;

public class MemcacheUtil {
public static MemCachedClient getMemCachedClient() {
return SpringContextUtils.getBean("memcachedClient", MemCachedClient.class);
}

public static boolean set(String key, Object value) {
String newKey = ResourceUtil.getPropertyValue("jdbc.username") + key;
return getMemCachedClient().set(newKey, value);
}

public static boolean set(String key, Object value,Date date) {
String newKey = ResourceUtil.getPropertyValue("jdbc.username") + key;
return getMemCachedClient().set(newKey, value, date);
}

public static Object get(String key) {
String newKey = ResourceUtil.getPropertyValue("jdbc.username") + key;
return getMemCachedClient().get(newKey);
}

public static boolean keyExists(String key) {
String newKey = ResourceUtil.getPropertyValue("jdbc.username") + key;
return getMemCachedClient().keyExists(newKey);
}

public static void clearCache(String...keys) {
for (String key : keys) {
String newKey = ResourceUtil.getPropertyValue("jdbc.username") + key;
getMemCachedClient().delete(newKey);
}
}

public static boolean clearCacheAll() {
return getMemCachedClient().flushAll();
}

/**
* 删除缓存中的数据
* @param key
*/
public static boolean deleteCache(String key){
String newKey = ResourceUtil.getPropertyValue("jdbc.username") + key;
return getMemCachedClient().delete(newKey);
}
}

输出结果:

abc
null
abc
null
null
null

如何调试Systemctl,以memcached为例。

背景:有时候我们使用systemctl命令,如简单点的systemctl start memcached来讲,出现错时,会有一些提示,但是提示的内容是变量,其并没有将参数给编译后的值放入,于是出现如下所示,但是要失败了怎么排查这些参数呢?此文就讲这个问题,如果不是为了linux开机启动提速而并行启动外,这个systemctl其本质是想接管很多东西,但也带来了很多麻烦,难怪linus对此有一定的意见,系统要保持简单,好用。像开机慢可以少开机或不关机嘛,学学人家苹果升级在半夜,你慢就慢,谁管你,从策略上就规避了,把技术搞复杂还是简单是一门哲学,而创始人的价值就在于坚守设计艺术,而不光是技术。

● memcached.service - Memcached
   Loaded: loaded (/usr/lib/systemd/system/memcached.service; enabled; vendor preset: disabled)
   Active: inactive (dead) since Fri 2018-07-20 18:48:50 CST; 19h ago
  Process: 15266 ExecStart=/usr/local/memcached/bin/memcached -u $USER -p $PORT -m $CACHESIZE -c $MAXCONN $OPTIONS (code=exited, status=0/SUCCESS)
Main PID: 15266 (code=exited, status=0/SUCCESS)

失败:

systemctl start memcached
Job for memcached.service failed because the control process exited with error code. See "systemctl status memcached.service" and "journalctl -xe" for details.
[Unit]
Description=Memcached
Before=httpd.service
After=network.target

[Service]
Type=simple
ExecStartPre=/bin/bash -l -c 'echo "/usr/local/memcached/bin/memcached" -u $USER -p $PORT -m $CACHESIZE -c $MAXC
ONN $OPTIONS > /tmp/systemctl.debug'
EnvironmentFile=-/etc/sysconfig/memcached
ExecStart=/usr/local/memcached/bin/memcached -u $USER -p $PORT -m $CACHESIZE -c $MAXCONN $OPTIONS

[Install]
WantedBy=multi-user.target

/etc/sysconfig/memcached

PORT="11211"
USER="memcached"
MAXCONN="1024"
CACHESIZE="64"
OPTIONS=" -vv >> /data/logs/memcached/11211/memcached.log 2>&1"
systemctl daemon-reload
systemctl start memcached
systemctl status memcached.service
  Active: failed (Result: exit-code) since Sat 2018-07-21 14:35:22 CST; 5s ago
  Process: 11417 ExecStart=/usr/local/memcached/bin/memcached -u $USER -p $PORT -m $CACHESIZE -c $MAXCONN $OPTIONS (code=exited, status=71)
  Process: 11399 ExecStartPre=/bin/bash -l -c echo "/usr/local/memcached/bin/memcached" -u $USER -p $PORT -m $CACHESIZE -c $MAXCONN $OPTIONS > /tmp/systemctl.debug (code=exited, status=0/SUCCESS)
Main PID: 11417 (code=exited, status=71)

如果有错,需要挑食的参数查看 /tmp/systemctl.debug:

cat /tmp/systemctl.debug
/usr/local/memcached/bin/memcached -u root -p 11211 -m 64 -c 1024 -vv >> /data/logs/memcached/11211/memcached.log 2>&1

Memcached群集

实验环境

未分类

实验过程

1、配置memcached主缓存节点和从缓存节点

两台缓存节点配置相同;

yum install gcc gcc-c++ make #安装环境包
tar xf memcached-1.5.6.tar.gz -C /opt/
tar xf libevent-2.1.8-stable.tar.gz -C /opt/
cd /opt/libevent-2.1.8-stable #安装lib插件
./configure --prefix=/usr/
make && make install #编译安装
cd ../memcached-1.5.6 #安装memcached
./configure --with-libevent=/usr
make && make install #编译安装
mkdir /opt/magent
tar xf magent-0.5.tar.gz -C /opt/magent
cd /opt/magent/
vi ketama.h
#ifndef SSIZE_MAX               #在内容开头添加
#define SSIZE_MAX 32767
#endif
vi Makefile
LIBS = -levent -lm
make #编译
cp magent /usr/bin/ #把生成的mgent程序让系统识别
scp magent [email protected]:/usr/bin/ #把产生的magent命令执行文件直接复制到从服务器,从服务器无需再次进行配置了。

2、配置keepalived

两台服务器都需配置,配置不同之处将会标出;

yum install keepalived -y
vi /etc/keepalived/keepalived.conf
router_id test01                #两台服务器不同,从为test02

vrrp_script magent {            
        script "/opt/shell/magent.sh"       #脚本目录,需要创建
        interval 2              #检测脚本时间间隔
}

vrrp_instance VI_1 {
    state MASTER                #从服务器为BACKUP
    interface ens33
    virtual_router_id 51        #两台服务器不同,从服务器为52
    priority 100                #从服务器小,从服务器为90
    advert_int 1
    authentication {
        auth_type PASS
        auth_pass 1111
    }

    track_script {      #调用脚本
        magent
    }
    virtual_ipaddress {     #虚拟IP
        192.168.27.111
    }
}

3、设置magent管理脚本

两台服务器的magent管理脚本不同

1)、主服务器上设置magent管理脚本;

cd /opt
cd /opt
mkdir shell
cd shell
vi magent.sh
#!/bin/bash
K=`ps -ef | grep keepalived | grep -v grep | wc -l`
if [ $K -gt 0 ]; then
        magent -u root -n 51200 -l 192.168.27.111 -p 12000 -s 192.168.27.160:11211 -b 192.168.27.163:11211
else
pkill -9 magent
fi

#-n 51200 //定义用户最大连接数
#-l 192.168.175.188 //指定虚拟IP
#-p 12000  //指定端口号
#-s //指定主缓存服务器
#-b //指定从缓存服务器
chmod +x magent.sh #赋予执行权限
systemctl start keepalived.service #开启服务

2)、从服务器上设置magent管理脚本;

cd /opt
mkdir shell
cd shell
vi magent.sh
#!/bin/bash
K=`ip addr | grep 192.168.27.111 | grep -v grep | wc -l`
if [ $K -gt 0 ]; then
        magent -u root -n 51200 -l 192.168.27.11 -p 12000 -s 192.168.27.160:11211 -b 192.168.27.163:11211
else
pkill -9 magent
fi  
chmod +x magent.sh #赋予执行权限
systemctl start keepalived.service #开启服务

4、启动memcached服务

memcached -m 512k -u root -d -l 192.168.27.160 -p 11211 #启动主
memcached -m 512k -u root -d -l 192.168.27.163 -p 11211 #启动从

5、验证

1)、在客户机上登录并插入内容,在两台主从服务器上都可查看到内容;

未分类

未分类

未分类

2)、将主服务器关掉,在客服机上插入新的内容,从服务器上仍能查看到内容;

未分类

未分类

在CentOS7上部署Memcached主主复制+Keepalived高可用架构

原理:

Memcached主主复制是指在任意一台Memcached服务器修改数据都会被同步到另外一台,但是Memcached API客户端是无法判断连接到哪一台Memcached服务器的,所以需要设置VIP地址,提供给Memcached API客户端进行连接。可以使用Keepalived产生的VIP地址连接主Memcached服务器,并且提供高可用架构。

使用两台Memcached服务器,一台客户机来完成,实验环境表如下:

未分类

1.配置memcached主缓存节点和从缓存节点—–两台配置相同

 [root@localhost ~]# tar zxvf libevent-2.1.8-stable.tar.gz -C /opt/   //解包//
 [root@localhost ~]# tar zxvf memcached-1.5.6.tar.gz -C /opt/
 [root@localhost ~]# mkdir /opt/magent
 [root@localhost ~]# tar zxvf magent-0.5.tar.gz -C /opt/magent/ 
 [root@localhost opt]#cd libevent-2.1.8-stable/
 [root@localhost libevent-2.1.8-stable]# yum install gcc gcc-c++ make -y
 [root@localhost libevent-2.1.8-stable]# ./configure --prefix=/usr
 [root@localhost libevent-2.1.8-stable]# make && make install
 [root@localhost libevent-2.1.8-stable]# cd ../memcached-1.5.6/
 [root@localhost memcached-1.5.6]# ./configure --with-libevent=/usr

 [root@localhost memcached-1.5.6]# ln -s /usr/lib/libevent-2.1.so.6 /usr/lib64/libevent-2.1.so.6    //软链接//

2.关闭防火墙并开启memcached服务

[root@localhost memcached-1.5.6]# systemctl stop firewalld.service 
[root@localhost memcached-1.5.6]# setenforce 0
[root@localhost memcached-1.5.6]# memcached -d -m 32m -p 11211 -u root
[root@localhost memcached-1.5.6]# netstat -ntap | grep 11211
tcp        0      0 0.0.0.0:11211           0.0.0.0:*               LISTEN      11224/memcached     
tcp6       0      0 :::11211                :::*                    LISTEN      11224/memcached

3.在主服务器上安装magent

[root@localhost memcached-1.5.6]# cd /opt/magent/
[root@localhost magent]# ls
ketama.c  ketama.h  magent.c  Makefile
[root@localhost magent]# vim ketama.h

#ifndef SSIZE_MAX
#define SSIZE_MAX 32767
#endif
[root@localhost magent]# vim Makefile 
LIBS = -levent -lm //第一行末尾加-lm (不是数字1
LIBS = -levent -lm
CFLAGS = -Wall -O2 -g

[root@localhost magent]# make
gcc -Wall -O2 -g  -c -o magent.o magent.c
gcc -Wall -O2 -g  -c -o ketama.o ketama.c
gcc -Wall -O2 -g -o magent magent.o ketama.o -levent -lm

4.把生成的mgent程序让系统识别

ls一下可看到magent可执行程序
[root@localhost magent]# ls
ketama.c  ketama.h  ketama.o  magent  magent.c  magent.o  Makefile
[root@localhost magent]# cp magent /usr/bin/

5.把产生的magent文件直接复制到从服务器。

[root@localhost bin]# yum install openssh-clients -y
[root@localhost bin]# scp magent [email protected]:/usr/bin/ 

6.安装keepalived,修改默认配置文件。

[root@localhost bin]# yum install keepalived -y
[root@localhost bin]# vim /etc/keepalived/keepalived.conf 
! Configuration File for keepalived
vrrp_script magent {
        script "/opt/shell/magent.sh"
        interval 2
}

global_defs {
   notification_email {
     [email protected]
     [email protected]
     [email protected]
   }
   notification_email_from [email protected]
   smtp_server 192.168.200.1
   smtp_connect_timeout 30
   router_id MAGENT_HA    //主服务器名称//
}

vrrp_instance VI_1 {
    state MASTER
    interface ens33     //网卡名称//
    virtual_router_id 51
    priority 100    //优先级//
    advert_int 1
    authentication {
        auth_type PASS
        auth_pass 1111   
    }
    virtual_ipaddress {
        192.168.126.188     //虚拟IP//
    }
track_script {
        magent     //函数//
}
}

7.从服务器上安装keepalived,配置文件进行修改。

[root@localhost bin]# vim /etc/keepalived/keepalived.conf 
! Configuration File for keepalived
vi keepalived.conf
vrrp_script magent {
        script "/opt/shell/magent.sh"
        interval 2
}

global_defs {
   notification_email {
     [email protected]
     [email protected]
     [email protected]
   }
   notification_email_from [email protected]
   smtp_server 192.168.200.1
   smtp_connect_timeout 30
   router_id MAGENT_HB      //从服务器的名称//
}

vrrp_instance VI_1 {
    state BACKUP            //从服务器的热备状态要修改成BACKUP//
    interface ens33  //网卡名称//
    virtual_router_id 52    //不能与主服务器相同//
    priority 90       //从调度器的优先级要小于主的//
    advert_int 1
    authentication {
        auth_type PASS
        auth_pass 1111
    }
    virtual_ipaddress {
        192.168.126.188     //虚拟IP//
    }
track_script {        //函数//
        magent  
}
}

8.在主服务器上设置magent管理脚本

[root@localhost bin]# mkdir /opt/shell
[root@localhost bin]# vim /opt/shell/magent.sh

#!/bin/bash
K=`ps -ef | grep keepalived | grep -v grep | wc -l`
if [ $K -gt 0 ]; then
        magent -u root -n 51200 -l 192.168.126.188 -p 12000 -s 192.168.126.138:11211 -b 192.168.126.166:11211
else
pkill -9 magent
fi

参数注解:
-n 51200 //定义用户最大连接数
-l 192.168.126.188 //指定虚拟IP
-p 12000  //指定端口号
-s //指定主缓存服务器
-b //指定从缓存服务器

[root@localhost shell]# chmod +x magent.sh   // 增加执行权限//

9.在从服务器上操作

[root@localhost bin]# mkdir /opt/shell
[root@localhost bin]# cd /opt/shell/
[root@localhost shell]# vim magent.sh
[root@localhost shell]# vim magent.sh
脚本内容如下,与主服务器脚本有区别!
#!/bin/bash
K=`ip addr | grep 192.168.126.188 | grep -v grep | wc -l`
if [ $K -gt 0 ]; then
        magent -u root -n 51200 -l 192.168.126.188 -p 12000 -s 192.168.126.138:11211 -b 192.168.126.166:11211
else
pkill -9 magent
fi  
[root@localhost shell]# chmod +x magent.sh 

10.开始验证

1)启动主服务器

[root@localhost shell]# systemctl start keepalived.service 
[root@localhost shell]# netstat -ntap | grep 12000  //确认magent运行//
tcp        0      0 192.168.126.188:12000   0.0.0.0:*               LISTEN      12422/magent 

2)启动从服务器

[root@localhost shell]# systemctl start keepalived.service 
[root@localhost shell]# netstat -ntap | grep 12000
tcp        0      0 192.168.126.188:12000   0.0.0.0:*               LISTEN      11716/magent  

3)在主服务器上使用telnet进行简单验证复制功能

[root@localhost shell]# telnet 192.168.126.188 12000  //用漂移地址登陆服务//
Trying 192.168.126.188...
Connected to 192.168.126.188.
Escape character is '^]'.
add username 0 0 7      //添加一条键值数据//
1234567
STORED

在从服务器上查看
[root@localhost shell]# telnet 192.168.126.188 12000 
Trying 192.168.126.188...
Connected to 192.168.126.188.
Escape character is '^]'.
get username    //查看键值数据
VALUE username 0 7
1234567         //内容存在,写入成功//
END

11.在客户端用漂移地址登陆服务

[root@localhost ~]# yum install telnet -y
[root@localhost ~]# telnet 192.168.126.188 12000 
Trying 192.168.126.188...
Connected to 192.168.126.188.
Escape character is '^]'.
add username 0 0 8    //添加一条键值数据//
12345678
STORED

1)在主服务器和从服务器上查看是否写入成功。

主服务器
get username
VALUE username 0 8
12345678
END

从服务器
get username
VALUE username 0 8
12345678
END

2)把主服务器停了业务不影响

[root@localhost shell]# systemctl stop keepalived.service
[root@localhost shell]# ip addr
inet 192.168.126.138/24 brd 192.168.126.255 scope global dynamic ens33

3)在从服务器上查看

[root@localhost shell]# ip addr
inet 192.168.126.166/24 brd 192.168.126.255 scope global dynamic ens33
       valid_lft 1146sec preferred_lft 1146sec
    inet 192.168.126.188/32 scope global ens33
可以看到漂移地址已经转移到从服务器上了,说明从已接受工作。

4)再把主服务器开启

[root@localhost shell]# systemctl start keepalived.service 
[root@localhost shell]# ip addr
inet 192.168.126.138/24 brd 192.168.126.255 scope global dynamic ens33
       valid_lft 1145sec preferred_lft 1145sec
    inet 192.168.126.188/32 scope global ens33
       valid_lft forever preferred_lft forever
漂移地址再次转移到主服务器上,接手地址,服务依然不受影响。

实验成功

Nginx+Tomcat+memcached高可用会话保持

一、概述

之前文章已经描述了企业高可用负载相关的架构及实现,其中常用的nginx或haproxy,LVS结合keepalived做前端高可用调度器;但之前没有提到会话高可用保持;
本文通过 Tomcat Session Replication Cluster(tomcat自带)和tomcat结合memcat及第三方组件实现Tomcat Memcache Session Server高可用会话缓存服务;
实现的效果:
同一客户端访问业务网站,经过调度器负载调度到达后端,不管选择的是那个后端,session ID都不变,都保存在两台或多台的memcached缓存中(负载冗余);以保持持会话;

架构图:

未分类

说明:客户端请求时nginx通过负载调度算法将请求调度至某一后端服务器;tomcat 把会话通过组播的方式复制到集群各节点;所有节点共享会话;

未分类

说明:客户端请求时nginx通过负载调度算法将请求调度至某一后端服务器;并把session存储到两台memcached中;客户端刷新(不换浏览器)时,请求换成另一个后端服务器响应时session ID保持不变;

测试环境:

nginx: CentOS7 epel 安装nginx WAN:172.16.3.152 LAN:192.168.10.254
tomcat A: CentOS7 node1.san.com epel 安装 tomcat 7 openjdk-1.8.0 memcached(现实环境中单独服务器)
tomcat B: CentOS7 nodde2.san.com epel 安装 tomcat 7 openjdk-1.8.0 memcached 现实环境中单独服务器)
测试客户端ubuntu 16.04

cat /etc/hosts
172.16.3.152       www.san.com

二、安装配置集群

nginx安装

[root@nginx ~]# yum install epel-release -y
[root@nginx ~]# yum install nginx -y

nginx配置

在/etc/nginx/nginx.conf http段添加如下行

    upstream tcsrvs {
        server 192.168.10.11:8080;
        server 192.168.10.12:8080;
        }

cat /etc/nginx/conf.d/san.com.conf

[root@nginx ~]# cat /etc/nginx/conf.d/san.com.conf 
server {
            listen 80;
            server_name www.san.com;
            location / {
                proxy_pass http://tcsrvs;
                }
        }

Tomcat配置:
两台均需要安装

#yum install epel-release -y
#yum install java-1.8.0 java-1.8.0-openjdk-devel tomcat tomcat-webapps tomcat-admin-webapps tomcat-docs-webapp  -y

说明:也可以通过oracle官方下载jdk 下载tomcat 解压到指定目录并添加环境变量;一般企业推荐此种方式;为了快捷,我们用epel仓库中的稳定版本;

添加测试页

yum 安装的tomcat工作目录在/var/lib/tomcat/webapps 分别在node1与node2上,此目录下创建测试项目,title 分别叫Tomcat A与Tomcat B 颜色分别为green与red;以示区别;生产环境node1 与node2内容一致;这里为了测试区别node1与node2内容;

#mkdir -pv /var/lib/tomcat/webapps/test/{WEB-INF,META-INF,classes,lib}
#cat /var/lib/tomcat/webapps/test/index.jsp
<%@ page language="java" %>
 <html>
      <head><title>Tomcat A</title></head>
          <body>
             <h1><font color="red">TomcatA.san.com</font></h1>
           <table align="centre" border="1">
            <tr>
                <td>Session ID</td>
            <% session.setAttribute("san.com","san.com"); %>
            <td><%= session.getId() %></td>
            </tr>
            <tr>
            <td>Created on</td>
           <td><%= session.getCreationTime() %></td>
           </tr>
      </table>
    </body>
</html>

配置管理页密码

tomcat与管理程序安装好后配置访问密码
修改注释/etc/tomcat/tomcat-users.xml文件

<role rolename="admin-gui"/>
<role rolename="manager-gui"/>
<user username="tomcat" password="tomcat" roles="manager-gui,admin-gui"/>

备份默认/etc/tomcat/server.xml文件

cd /etc/tomcat
cp server.xml server.xml_def

测试页访问

http://www.san.com/test 如图:出现Tomcat A

未分类

Ctrl+F5强制刷新 又出现Tomcat B

未分类

引发问题:如果是两台内容一样的配置,客户端访问刷新一下就换到另一个后端处理;类似通过session保留信息的服务(购买物车)如何保留?换句话说,如何保持会话不中断,无论请求被分配到那一个后端?

解决方案

1)会话sticky(粘性):分为source_ip 基于源ip和cookie

source_ip在不同的调度器上有不同的实现方式:
lvs:sh算法;
nginx:ip_hash或hash $request_uri consistent(一致性哈希算法)
haproxy: source

cookie:
nginx:hash 或 hash $cookie_name consistent;
haproxy:cookie

2)会话集群(session cluster):delta session manager

3)session server: redis(store),memcached(cache)

以下基于tomcat自带会话集群与memcached实现会话保持 功能;

三、Tomcat Session Replication Cluster配置

Tomcat Session Replication Cluster中文又叫 tomcat 会话复制集群,即会话通过组播方式复制到每一个后端tomcat节点;
可参考自带帮助文档:http://www.san.com/docs/cluster-howto.html
两台node1 node2节点/etc/hosts中添加如下:

#cat /etc/hosts
192.168.10.11 node1.san.com node1
192.168.10.12 node2.san.com node2

两台tomcat 节点sever.xml的Host字段中添加如下内容:

<Cluster className="org.apache.catalina.ha.tcp.SimpleTcpCluster"
                 channelSendOptions="8">

          <Manager className="org.apache.catalina.ha.session.DeltaManager"
                   expireSessionsOnShutdown="false"
                   notifyListenersOnReplication="true"/>

          <Channel className="org.apache.catalina.tribes.group.GroupChannel">
            <Membership className="org.apache.catalina.tribes.membership.McastService"
                        address="228.10.0.4"
                        port="45564"
                        frequency="500"
                        dropTime="3000"/>
            <Receiver className="org.apache.catalina.tribes.transport.nio.NioReceiver"
                      address="auto"           <!--   如果没有/etc/hosts解析则需要本机ip   -->
                      port="4000"
                      autoBind="100"
                      selectorTimeout="5000"
                      maxThreads="6"/>

            <Sender className="org.apache.catalina.tribes.transport.ReplicationTransmitter">
              <Transport className="org.apache.catalina.tribes.transport.nio.PooledParallelSender"/>
            </Sender>
            <Interceptor className="org.apache.catalina.tribes.group.interceptors.TcpFailureDetector"/>
            <Interceptor className="org.apache.catalina.tribes.group.interceptors.MessageDispatch15Interceptor"/>
          </Channel>

          <Valve className="org.apache.catalina.ha.tcp.ReplicationValve"
                 filter=""/>
          <Valve className="org.apache.catalina.ha.session.JvmRouteBinderValve"/>

          <Deployer className="org.apache.catalina.ha.deploy.FarmWarDeployer"
                    tempDir="/tmp/war-temp/"
                    deployDir="/tmp/war-deploy/"
                    watchDir="/tmp/war-listen/"
                    watchEnabled="false"/>

          <ClusterListener className="org.apache.catalina.ha.session.JvmRouteSessionIDBinderListener"/>
          <ClusterListener className="org.apache.catalina.ha.session.ClusterSessionListener"/>
        </Cluster>

复制 /etc/tomcat/web.xml /var/lib/tomcat/webapps/test/WEB-INF/ 下并在web.xml的”“字段下添加 ““;
重启tomcat 并再次访问http://www.san.com/test 如图:

未分类

Ctrl + F5强制刷新如图:

未分类

可以可出会话得到保持,只要是从同一个客户端中请求,刷新或关闭重新打开(基于同一个浏览器) 只要会话没有过期,会话(session id) 无论来自那个后端,均是一样;

缺点:

tomcat自带支持会话集群(能过多播方式发送各节点);但有一个缺点;后端tomcat节点过多时效率低下,不适用大规模;

四、Tomcat Memcache Session Server高可用配置

原理说明:
客户端请求到达前端nginx调度器并分配到后端某tomcat节点时,tomcat会优先使用本机内存保存session,当一个请求结束后,tomcat会通过第三方组件(kryo,javolution,xstream,flexjson)把session序列化并发送到memcached节点上存放作备份,第二次请求时,如果本地有session就直接返回,第二次请求结束,把session修改后的信息更新到后端的memcached服务器,以这样的方式来保持本地的session与memcached上的session同步。当这个tomcat节点宕机时,那么用户的下一次请求就会被前端的负载均衡器路由到另一个tomcat节点上,而这个节点上并没有这个用户的session信息,这个节点就从memcached服务器上去读取session,并把session保存到本地的内存,当请求结束,session又被修改,再送回到memcached进行存放备份
当后端配置了多台memcached时,tomcat在更新session信息时会同时向多个memcached节点更新session,当一个memcached节点故障时,tomcat可以从选择一个正常工作的memcached节点读取session信息来发送给用户的浏览器,让其重置session信息,这样,memcached也达到了高可用的目的;
以下操作均在两台node上操作

还原默认配置文件

#cd /etc/tomcat/
#cp server.xml server.xml_cluster
#cp server.xml_def server.xml
#systemctl stop tomcat

安装memcached服务

#yum install memcached -y
#systemctl start memcached

memcache配置(默认即可,生产环境时需要加大内存与并发连接数)

# cat /etc/sysconfig/memcached 
PORT="11211"
USER="memcached"
MAXCONN="1024"
CACHESIZE="64"
OPTIONS=""

两台/etc/tomcat/server.xml Host段中添加如下内容:

<Context path="/test" docBase="test" reloadable="true">
        <Manager className="de.javakaffee.web.msm.MemcachedBackupSessionManager"
                memcachedNodes="m1:192.168.10.11:11211,m2:192.168.10.12:11211"
                failoverNodes="m1"
                requestUriIgnorePattern=".*.(ico|png|gif|jpg|css|js)$"
                transcoderFactoryClass="de.javakaffee.web.msm.serializer.javolution.JavolutionTranscoderFactory"/>
        </Context>

说明:

添加两个冗余备份memcached节点分别叫m1,m2 failoverNodes=”m1″ 表示m1作为备份;当m2失败时连接;即使用m2;

安装对应版本组件

下载以下JAR包到tomcat库目录;
cd /usr/share/tomcat/lib 
wget http://www.java2s.com/Code/JarDownload/javolution/javolution-5.5.1.jar.zip  
#需要解压 unzip javolution-5.5.1.jar.zip
wget http://repo1.maven.org/maven2/net/spy/spymemcached/2.12.1/spymemcached-2.12.1.jar
wget http://repo1.maven.org/maven2/de/javakaffee/msm/msm-javolution-serializer/2.1.1/msm-javolution-serializer-2.1.1.jar
wget http://repo1.maven.org/maven2/de/javakaffee/msm/memcached-session-manager-tc7/2.1.1/memcached-session-manager-tc7-2.1.1.jar
wget http://repo1.maven.org/maven2/de/javakaffee/msm/memcached-session-manager/2.1.1/memcached-session-manager-2.1.1.jar

注意:epel安装的tomcat 和openjdk版本如下:
openjdk: “1.8.0_161”
tomcat : “7.0.76”
以上第三方插件须和对应的版本是兼容的;如发现tomcat启动有问题;无法访问或如下类似错误

#tail -fn 100 /var/log/tomcat/catalina.xxxx.log
三月 23, 2018 4:12:52 下午 org.apache.catalina.core.StandardContext startInternal
严重: The session manager failed to start
org.apache.catalina.LifecycleException: Failed to start component [de.javakaffee.web.msm.MemcachedBackupSessionManager[/test]]
    at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:162)
    at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5643)
    at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:145)

则表示第三方组件与tomcat不兼容!请重新下载版本;

测试:
浏览器访问http://www.san.com/test 如图:

未分类

Ctrl+F5强刷新 如图:

未分类

从测试上可以看出目前已经通过memcache存储session等缓存信息;并同步到两台memcache上;当前只使用m2节点;

总结

通过nginx快速实现负载tomcat应用;引用session不可保持问题;通过自带的Tomcat Session Replication Cluster和结合memcached及第三方组件实现高可用会话缓存服务来保持会话;前者不适合大规模应用;

memcached数据库简单配置介绍

一、memcached数据库

(基于内存的储存方式;默认端口11211)

1、装包yum -y install memcached telnet (telnet是一款远程访问工具,mem软件无客户端,所以需安装telnet连接服务器)

2、启服务:systemctl restart memcached.server
查看端口是否启用:netstat -antpu | grep mem

3、查看配置文件(默认不需要修改):vim /etc/sysconfig/memcached

4、连接数据库验证是否可用:telnet 127.0.0.1 11211 (测试环境使用的工具)

set name 0 180 3 添加一个数据
get name 查看添加的数据
  • 0代表数据不压缩
  • 180数据在内存里只存180秒
  • 3代表存3个字符的数据

5、安装php和数据库关联的软件

正常情况下,数据库要和php脚本关联起来,php软件包并不具备关联功能,需要手动安装;

软件包可以通过搜索查看:yum list | grep memcached

yum -y install php-pecl-memcache (安装可以关联mem数据库的软件)

开启次服务systemctl restart php-fpm

6、之前做过nginx的动静分离,现在可以直接放一个php的页面到html下面直接访问;

二、基于java的web集群指定共用数据库

1、这个环境需要在两个web服务器上配置,先cp软件
需要先安装一个jave关联memcached的软件,这个软件只需要在lnmp中cp相应文件即可实现;

cd lnmp_soft/session
cp *jar /usr/local/tomcat/lib (关联软件的相关包)
cp context.xml /usr/local/tomcat/conf/ (配置文件)

2、修改配置文件vim /usr/local/tomcat/conf/context.xml
只需要修改36行的配置,写入我们web集群共用的memcached数据库的ip地址

3、重启web服务;启动数据库

php7.0编译memcached扩展

场景

系统自带的memcache.so扩展只适用于系统自带的php5.3,由于生产环境的php7.0是自己编译的,所以各种扩展也要重新编译生成

php的memcache客户端扩展有两种

1. memcache扩展

列表地址:http://pecl.php.net/package/memcache

源码包包直接下载地址:http://pecl.php.net/get/memcache

这个最新的版本也是2013年的了,下载编译了一下,报了一个 not found php_smart_str_public.h文件的错误,查看了一下 php安装目录下的 include/php/ext/standard 目录,发现这个头文件在php7.0中已经被改名为php_smart_string_public.h。由此可见这个memcache的客户端版本已太旧,不支持php7.0了

2. memcached扩展

列表地址:http://pecl.php.net/package/memcached

源码包直接下载地址:http://pecl.php.net/get/memcached

此外还有一个git维护地址 https://github.com/php-memcached-dev/php-memcached

这个包最新版本是2017年11月份更新的,是支持php7.0的。

下载流程

git clone https://github.com/php-memcached-dev/php-memcached

wget http://pecl.php.net/get/memcached

解压后将源码放入 /root 下或者 /home/用户目录下

编译流程

进入源码目录

#cd ~/php-memcached

调用phpize(根据实际phpize路径)

#/usr/local/php7.0/bin/phpize

configure目录

#./configure --with-php-config=/usr/local/php7.0/bin/php-config --with-zlib-dir

编译 & 安装

#make && make install

tips

因为memcached版本的扩展基于libmemcached,如果服务器上未安装,编译的时候会提示错误

解决方案就是yum安装即可

yum install libmemcached

yum install libmemcached-devel

成功

打开 php安装目录/lib/php/extensions/no-debug-zts-*/即可看到memcached.so扩展

然后再php.ini配置文件加载即可