参照建立的

(1)supervisor_tomcat服务: https://blog.51cto.com/sf1314/2128372

(2)supervisor_nginx服务:  https://blog.51cto.com/sf1314/2131625   

下面建立supervisor_redis服务,实现tomcat+redis实现session共享缓存


不做redis共享缓存,刷新网页会话不会保持,导致原先登录的账户,因为刷新,显示不登录。

[3]supervisor管理:对异常中断子进程的自动重启(以redis高可用Sentinel哨兵)_第1张图片


[3]supervisor管理:对异常中断子进程的自动重启(以redis高可用Sentinel哨兵)_第2张图片


(1)Redis主从分离

       ①②③④⑤⑥⑦⑧⑨⑩

 ① redis介绍

  redis是一个key-value存储系统。和Memcached类似,它支持存储的value类型相对更多,包括string(字符串)、list(链表)、set(集合)、zset(sorted set --有序集合)和hash(哈希类型)。与memcached一样,为了保证效率,数据都是缓存在内存中。区别的是redis会周期性的把更新的数据写入磁盘或者把修改操作写入追加的记录文件,并且在此基础上实现master-slave(主从)同步。

  Redis是一个高性能的key-value数据库。redis的出现,很大程度补偿了memcached这类key/value存储的不足,在部分场合可以对关系数据库起到很好的补充作用。它提供了Java,C/C++,C#,PHP,JavaScript,Perl,Object-C,Python,Ruby等客户端,使用很方便。

  如果简单地比较Redis与Memcached的区别,基本上有以下3点:

1、Redis不仅仅支持简单的k/v类型的数据,同时还提供list,set,zset,hash等数据结构的存储。

2、Redis支持数据的备份,即master-slave模式的数据备份。

3、Redis支持数据的持久化,可以将内存中的数据保持在磁盘中,重启的时候可以再次加载进行使用。

  在Redis中,并不是所有的数据都一直存储在内存中的。这是和Memcached相比一个最大的区别。Redis只会缓存所有的key的信息,如果Redis发现内存的使用量超过了某一个阀值,将触发swap的操作,Redis根据“swappability =age*log(size_in_memory)”计算出哪些key对应的value需要swap到磁盘。然后再将这些key对应的value持久化到磁盘中,同时在内存中清除。这种特性使得Redis可以保持超过其机器本身内存大小的数据。当然,机器本身的内存必须要能够保持所有的key,因为这些数据是不会进行swap操作的。

  当从Redis中读取数据的时候,如果读取的key对应的value不在内存中,那么Redis就需要从swap文件中加载相应数据,然后再返回给请求方。

memcached和redis的比较

1、网络IO模型

  Memcached是多线程,非阻塞IO复用的网络模型,分为监听主线程和worker子线程,监听线程监听网络连接,接受请求后,将连接描述字pipe 传递给worker线程,进行读写IO, 网络层使用libevent封装的事件库,多线程模型可以发挥多核作用。

  Redis使用单线程的IO复用模型,自己封装了一个简单的AeEvent事件处理框架,主要实现了epoll、kqueue和select,对于单纯只有IO操作来说,单线程可以将速度优势发挥到最大,但是Redis也提供了一些简单的计算功能,比如排序、聚合等,对于这些操作,单线程模型实际会严重影响整体吞吐量,CPU计算过程中,整个IO调度都是被阻塞住的。

2、内存管理方面

  Memcached使用预分配的内存池的方式,使用slab和大小不同的chunk来管理内存,value根据大小选择合适的chunk存储。Redis使用现场申请内存的方式来存储数据。

3、存储方式及其它方面

  Memcached基本只支持简单的key-value存储,不支持持久化和复制等功能,Redis除key/value之外,还支持list,set,sortedset,hash等众多数据结构

 ② 如何保持session会话

  目前,为了使web能适应大规模的访问,需要实现应用的集群部署。集群最有效的方案就是负载均衡,而实现负载均衡用户每一个请求都有可能被分配到不固定的服务器上,这样我们首先要解决session的统一来保证无论用户的请求被转发到哪个服务器上都能保证用户的正常使用,即需要实现session的共享机制。

在集群系统下实现session统一的有如下几种方案:

1、请求精确定位:sessionsticky,例如基于访问ip的hash策略,即当前用户的请求都集中定位到一台服务器中,这样单台服务器保存了用户的session登录信息,如果宕机,则等同于单点部署,会丢失,会话不复制。

2、session复制共享:sessionreplication,如tomcat自带session共享,主要是指集群环境下,多台应用服务器之间同步session,使session保持一致,对外透明。 如果其中一台服务器发生故障,根据负载均衡的原理,调度器会遍历寻找可用节点,分发请求,由于session已同步,故能保证用户的session信息不会丢失,会话复制,。

此方案的不足之处:

必须在同一种中间件之间完成(如:tomcat-tomcat之间).

session复制带来的性能损失会快速增加.特别是当session中保存了较大的对象,而且对象变化较快时, 性能下降更加显著,会消耗系统性能。这种特性使得web应用的水平扩展受到了限制。

Session内容通过广播同步给成员,会造成网络流量瓶颈,即便是内网瓶颈。在大并发下表现并不好

3、基于cacheDB缓存的session共享

基于memcache/redis缓存的 session 共享

即使用cacheDB存取session信息,应用服务器接受新请求将session信息保存在cache DB中,当应用服务器发生故障时,调度器会遍历寻找可用节点,分发请求,当应用服务器发现session不在本机内存时,则去cache DB中查找,如果找到则复制到本机,这样实现session共享和高可用。


[3]supervisor管理:对异常中断子进程的自动重启(以redis高可用Sentinel哨兵)_第3张图片

说明:在这个图中,nginx做为反向代理,实现静动分离,将客户动态请求根据权重随机分配给两台tomcat服务器,

redis做为两台tomcat的共享session数据服务器,mysql做为两台tomcat的后端数据库。


 ③ 安装redis主从

在讲解Sentinel 哨兵集群之前,我们先来搭建一个简单的主从分离(读写分离)。

 1:下载

wget http://download.redis.io/releases/redis-3.2.8.tar.gz

下载指定版本,可以登录https://redis.io/download查看

 2:安装

tar zxvf redis-3.2.8.tar.gz
cd redis-3.2.8
make
make install

这时Redis 的可执行文件被放到了/usr/local/bin

 3:配置

将redis.conf拷贝多份,并且创建多个目录,用于区分多个redis 服务:

# cd /usr/local/
# mkdir redis_6380
# mkdir redis_6381
# mkdir redis_6382
# find / -name redis.conf
/home/redis-3.2.8/redis.conf
#6380作为redis_master,6381、6382作为redis_slave。
# cp /home/redis-3.2.8/redis.conf /usr/local/redis_6380/
# cp /home/redis-3.2.8/redis.conf /usr/local/redis_6381/
# cp /home/redis-3.2.8/redis.conf /usr/local/redis_6382/

 1)配置Master

  1、修改端口

     redis 的默认端口是6379,这里我们把主服务器的端口设置为6380

# sed -i "s#port 6379#port 6380#g" /usr/local/redis_6380/redis.conf

  2、修改pidfile

# sed -i "s#redis_6379.pid#redis_6380.pid#g" /usr/local/redis_6380/redis.conf

  pidfile 是我们启动redis 的时候,linux 为我们分配的一个pid 进程号,如果这里不作修改,会影响后面redis服务的启动

 # /usr/local/bin/redis-server /usr/local/redis_6380/redis.conf &

[root@docker1 ~]# ps -ef |grep redis
root      43128  43126  0 08:36 ?        00:00:05 /usr/local/bin/redis-server 127.0.0.1:6380
root      43815  43740  0 09:52 pts/0    00:00:00 grep --color=auto redis

  启动redis,我们可以看到,redis已经占领了6380 端口

  进入客户端

# redis-cli -p 6380

前面redis没有设置密码:

需要永久配置密码的话就去redis.conf的配置文件中找到requirepass这个参数,如下配置:

修改redis.conf配置文件  

# requirepass foobared

requirepass sheng@123        #指定密码sheng@123

echo "requirepass sheng@123" >> redis.conf   #然后重启redis-cli -p 6380 shutdown

我们可以看到,redis 现在的角色是一个master 启动的服务。

 # kill -9 PID   #PID为redisd_6380的进程号

 # /usr/local/bin/redis-server /usr/local/redis_6380/redis.conf &

# redis-cli -p 6380 
127.0.0.1:6380> keys *
(error) NOAUTH Authentication required.
127.0.0.1:6380> config get requirepass
(error) NOAUTH Authentication required.
127.0.0.1:6380> auth sheng@123
OK
127.0.0.1:6380> info
# Server
redis_version:3.2.8
redis_git_sha1:00000000
redis_git_dirty:0
redis_build_id:6a9207c0ce8cb723
redis_mode:standalone
os:Linux 3.10.0-693.5.2.el7.x86_64 x86_64
arch_bits:64
multiplexing_api:epoll
gcc_version:4.8.5
process_id:43919
run_id:ee713d37a438fab4125f08d8c5ab17e52638e554
tcp_port:6380
uptime_in_seconds:174
uptime_in_days:0
hz:10
lru_clock:4552019
executable:/usr/local/bin/redis-server
config_file:/usr/local/redis_6380/redis.conf

# Clients
connected_clients:1
client_longest_output_list:0
client_biggest_input_buf:0
blocked_clients:0

# Memory
used_memory:822520
used_memory_human:803.24K
used_memory_rss:8114176
used_memory_rss_human:7.74M
used_memory_peak:822520
used_memory_peak_human:803.24K
total_system_memory:1911832576
total_system_memory_human:1.78G
used_memory_lua:37888
used_memory_lua_human:37.00K
maxmemory:0
maxmemory_human:0B
maxmemory_policy:noeviction
mem_fragmentation_ratio:9.87
mem_allocator:jemalloc-4.0.3

# Persistence
loading:0
rdb_changes_since_last_save:0
rdb_bgsave_in_progress:0
rdb_last_save_time:1531278501
rdb_last_bgsave_status:ok
rdb_last_bgsave_time_sec:-1
rdb_current_bgsave_time_sec:-1
aof_enabled:0
aof_rewrite_in_progress:0
aof_rewrite_scheduled:0
aof_last_rewrite_time_sec:-1
aof_current_rewrite_time_sec:-1
aof_last_bgrewrite_status:ok
aof_last_write_status:ok

# Stats
total_connections_received:1
total_commands_processed:1
instantaneous_ops_per_sec:0
total_net_input_bytes:81
total_net_output_bytes:73
instantaneous_input_kbps:0.00
instantaneous_output_kbps:0.00
rejected_connections:0
sync_full:0
sync_partial_ok:0
sync_partial_err:0
expired_keys:0
evicted_keys:0
keyspace_hits:0
keyspace_misses:0
pubsub_channels:0
pubsub_patterns:0
latest_fork_usec:0
migrate_cached_sockets:0

# Replication
role:master
connected_slaves:0
master_repl_offset:0
repl_backlog_active:0
repl_backlog_size:1048576
repl_backlog_first_byte_offset:0
repl_backlog_histlen:0

# CPU
used_cpu_sys:0.21
used_cpu_user:0.13
used_cpu_sys_children:0.00
used_cpu_user_children:0.00

# Cluster
cluster_enabled:0

# Keyspace
127.0.0.1:6380> 
127.0.0.1:6380> exit


二、配置Slave

  和上面配置 master一样,我们需要修改端口号和pid 文件,

# sed -i "s#port 6379#port 6381#g" /usr/local/redis_6381/redis.conf
# sed -i "s#redis_6380.pid#redis_6381.pid#g" /usr/local/redis_6381/redis.conf

# sed -i "s#port 6379#port 6382#g" /usr/local/redis_6382/redis.conf
# sed -i "s#redis_6380.pid#redis_6382.pid#g" /usr/local/redis_6382/redis.conf

加密redisd_6381服务:

# pwd
/usr/local/redis_6381
# echo "requirepass sheng@123" >> redis.conf

加密redisd_6382服务:

# pwd
/usr/local/redis_6382
# echo "requirepass sheng@123" >> redis.conf

在修改完之后,我们有两种方法配置从服务

  1、在配置文件中配置从服务

# vi redis.conf 
################################# REPLICATION #################################
# Master-Slave replication. Use slaveof to make a Redis instance a copy of
# another Redis server. A few things to understand ASAP about Redis replication.
#
# 1) Redis replication is asynchronous, but you can configure a master to
#    stop accepting writes if it appears to be not connected with at least
#    a given number of slaves.
# 2) Redis slaves are able to perform a partial resynchronization with the
#    master if the replication link is lost for a relatively small amount of
#    time. You may want to configure the replication backlog size (see the next
#    sections of this file) with a sensible value depending on your needs.
# 3) Replication is automatic and does not need user intervention. After a
#    network partition slaves automatically try to reconnect to masters
#    and resynchronize with them.
#
# slaveof  

# echo "slaveof 127.0.0.1 6380" >> /usr/local/redis_6381/redis.conf 


 我们可以在配置文件中直接修改 slaveof 属性,我们直接配置主服务器的ip 地址,和端口号,如果这里主服务器有配置密码

  可以通过配置masterauth 来设置链接密码

# If the master is password protected (using the "requirepass" configuration
# directive below) it is possible to tell the slave to authenticate before
# starting the replication synchronization process, otherwise the master will
# refuse the slave request.
#
# masterauth 

# echo "masterauth sheng@123" >> /usr/local/redis_6381/redis.conf

启动6381的

# /usr/local/bin/redis-server /usr/local/redis_6381/redis.conf &
# redis-cli  -p 6381
127.0.0.1:6381> info
NOAUTH Authentication required.
127.0.0.1:6381> auth sheng@123
OK
127.0.0.1:6381> info
......
# Replication
role:slave
master_host:127.0.0.1     #我们可以看到,现在的redis 是一个从服务的角色,连接着6380的服务。
master_port:6380     
master_link_status:up
master_last_io_seconds_ago:7
master_sync_in_progress:0
slave_repl_offset:491
slave_priority:100
slave_read_only:1
connected_slaves:0
master_repl_offset:0
repl_backlog_active:0
repl_backlog_size:1048576
repl_backlog_first_byte_offset:0
repl_backlog_histlen:0
......

同理:redis_6382的也需要这样操作

最好需要在redis_master查看连接状态:

# redis-cli -p 6380
127.0.0.1:6380> auth sheng@123
OK
127.0.0.1:6380> info
......
# Replication
role:master
connected_slaves:2
slave0:ip=127.0.0.1,port=6381,state=online,offset=3809,lag=0
slave1:ip=127.0.0.1,port=6382,state=online,offset=3809,lag=1
master_repl_offset:3809
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:2
repl_backlog_histlen:3808
......

 我们可以可以看到,两个从服务已经在连着主服务器,上面两种配置的区别在于,当salve 断线重连之后,

 如果我们是修改类配置文件,重连之后会自己链接上去master,并且同步master 上面的数据,

 如果我们是手动连接上去的主服务器,重连之后,从服务器会读取自己本地的 rdb 回复数据,而不会去自动链接主服务

 

 我们如果需要设置读写分离,只需要在主服务器中设置:

# Note: read only slaves are not designed to be exposed to untrusted clients
# on the internet. It's just a protection layer against misuse of the instance.
# Still a read only slave exports by default all the administrative commands
# such as CONFIG, DEBUG, and so forth. To a limited extent you can improve
# security of read only slaves using 'rename-command' to shadow all the
# administrative / dangerous commands.
slave-read-only yes


 4:用redis启动脚本设置开机自启动

  启动脚本 redis_init_script 位于位于Redis的 /utils/ 目录下,

# find / -name redis_init_script

/home/redis-3.2.8/utils/redis_init_script

redis_init_script脚本代码如下:

#!/bin/sh
#
# Simple Redis init.d script conceived to work on Linux systems
# as it does use of the /proc filesystem.
 
#redis服务器监听的端口
REDISPORT=6380            #这里端口有6380,6381,6382,写三个启动脚本
 
#服务端所处位置
EXEC=/usr/local/bin/redis-server
 
#客户端位置
CLIEXEC=/usr/local/bin/redis-cli
 
#redis的PID文件位置,需要修改
PIDFILE=/var/run/redis_${REDISPORT}.pid
 
#redis的配置文件位置,需将${REDISPORT}修改为文件名
#CONF="/etc/redis/${REDISPORT}.conf"   根据实际需求进行修改
CONF="/usr/local/redis_${REDISPORT}/redis.conf"
 
case "$1" in
    start)
        if [ -f $PIDFILE ]
        then
                echo "$PIDFILE exists, process is already running or crashed"
        else
                echo "Starting Redis server..."
                #需要在$EXEC $CONF加上&
                $EXEC $CONF &
        fi
        ;;
    stop)
        if [ ! -f $PIDFILE ]
        then
                echo "$PIDFILE does not exist, process is not running"
        else
                PID=$(cat $PIDFILE)
                echo "Stopping ..."
                $CLIEXEC -p $REDISPORT shutdown
                while [ -x /proc/${PID} ]
                do
                    echo "Waiting for Redis to shutdown ..."
                    sleep 1
                done
                echo "Redis stopped"
        fi
        ;;
    *)
        echo "Please use start or stop as first argument"
        ;;
esac

 根据启动脚本,将修改好的配置文件复制到指定目录下,用root用户进行操作:


# cp /home/redis-3.2.8/utils/redis_init_script /etc/init.d/redisd_6380
# cp /home/redis-3.2.8/utils/redis_init_script /etc/init.d/redisd_6381
# cp /home/redis-3.2.8/utils/redis_init_script /etc/init.d/redisd_6382
然后根据实际情况redisd_6380、redisd_6381、redisd_6382的REDISPORT端口为对应的6380、6381、6382。


设置为开机自启动,直接配置开启自启动 chkconfig redisd on 发现错误: service redisd does not support chkconfig

解决办法,在启动脚本开头添加如下注释来修改运行级别:

#!/bin/sh

# chkconfig:   2345 90 10

 再设置即可


#设置为开机自启动服务器

chkconfig redisd on

#打开服务

service redisd start

#关闭服务

service redisd stop

5:运行和关闭

cd /etc/init.d
启动端口为6380的redis,其他同理
# ./redisd_6380 start
或者
# service redisd_6380 start
启动端口为6381的redis,其他同理
# ./redisd_6380 stop
或者
# service redisd_6380 stop
也可以通过redis客户端关闭
# redis-cli -p 6380 shutdown

5:使用supervisor监控进程

前提:supervisor配置文件中需要下面两行
# cat /etc/supervisor/supervisord.conf
......
;包含其他配置文件
[include]
files = /etc/supervisor/config.d/*.ini   ;可以指定一个或多个以.ini结束的配置文件
......

# cd /etc/supervisor/config.d/
# vi redisd_6380.ini      #后续同理,把6380改为6381,6382即可
[program:redisd_6380]
command=/usr/local/bin/redis-server /usr/local/redis_6380/redis.conf
autostart=true
startsecs=10
autorestart=true
startretries=3
user=root
priority=999
;redirect_stderr=true      ;把stferr重定向到stdout,默认为false,为true的话,stderr的log会并入stdout的log
stdout_logfile=/var/log/redisd_6380/redisd6380_stdout.log
stdout_logfile_maxbytes=10MB
stdout_logfile_backups=20
stderr_logfile=/var/log/redisd_6380/redisd6380_stderr.log
stderr_logfile_maxbytes=10MB
stderr_logfile_backups=20

# ls
nginx.ini  redisd_6380.ini  redisd_6381.ini  redisd_6382.ini  tomcat.ini

#  mkdir /var/log/redisd_6380 /var/log/redisd_6381 /var/log/redisd_6382


6:更新supervisor配置

# supervisorctl update
或者
# supervisord -c /etc/supervisor/supervisord.conf

现在redis服务已经在后台运行

# supervisorctl -c /etc/supervisor/supervisord.conf 
nginx                      RUNNING   pid 43127, uptime 0:06:04
redisd_6380                   RUNNING   pid 43128, uptime 0:06:04
redisd_6381                   RUNNING   pid 43129, uptime 0:06:04
redisd_6382                   RUNNING   pid 43130, uptime 0:06:04
supervisor_tomcat1                 RUNNING   pid 43131, uptime 0:06:04
supervisor_tomcat2                 RUNNING   pid 43144, uptime 0:06:04
supervisor> exit

[3]supervisor管理:对异常中断子进程的自动重启(以redis高可用Sentinel哨兵)_第4张图片

7:关闭redis

在supervisord.conf文件中,[program:redisd]标志意味着在管理redis服务时,使用redisd(在redis后面加了一个字母d)去操作。 
所以,关闭redis服务的方法有以下几种

[root@docker1 config.d]# supervisorctl -c /etc/supervisor/supervisord.conf 
nginx                            RUNNING   pid 43127, uptime 0:09:21
redisd_6380                      RUNNING   pid 43128, uptime 0:09:21
redisd_6381                      RUNNING   pid 43129, uptime 0:09:21
redisd_6382                      RUNNING   pid 43130, uptime 0:09:21
supervisor_tomcat1               RUNNING   pid 43131, uptime 0:09:21
supervisor_tomcat2               RUNNING   pid 43144, uptime 0:09:21
supervisor> stop redisd_6382 
redisd_6382: stopped
supervisor> exit
[root@docker1 config.d]# supervisorctl -c /etc/supervisor/supervisord.conf 
nginx                     RUNNING   pid 43127, uptime 0:09:32
redisd_6380                  RUNNING   pid 43128, uptime 0:09:32
redisd_6381                  RUNNING   pid 43129, uptime 0:09:32
redisd_6382                  STOPPED   Jul 10 09:15 PM
supervisor_tomcat1              RUNNING   pid 43131, uptime 0:09:32
supervisor_tomcat2              RUNNING   pid 43144, uptime 0:09:32
supervisor> exit
#或者通过redis客户端的方式关闭
redis-cli -p 6380 shutdown

8:再次重新启动

supervisor> start redisd_6382
redisd_6382: started
supervisor> exit
# supervisorctl -c /etc/supervisor/supervisord.conf 
nginx                      RUNNING   pid 43127, uptime 0:11:53
redisd_6380                   RUNNING   pid 43128, uptime 0:11:53
redisd_6381                   RUNNING   pid 43129, uptime 0:11:53
redisd_6382                   RUNNING   pid 43199, uptime 0:01:22
supervisor_tomcat1                RUNNING   pid 43131, uptime 0:11:53
supervisor_tomcat2                RUNNING   pid 43144, uptime 0:11:53
supervisor> exit

更多supervisor操作,请查看: 
linux进程管理工具supervisor http://blog.csdn.net/win_turn/article/details/60466562


9.配置tomcat基于缓存的Session共享

tomcat连接redis的阀包 基于缓存的Session共享 http://down.51cto.com/data/2449143 

基于缓存的Session共享所提供的安装包如下:    (发现只支持tomcat7

 tomcat-redis-session-manager-2.0.0.jar、    

 jedis-2.9.0.jar、     

commons-pool2-2.2.jar, 

下载地址:https://share.weiyun.com/5huRwCi 

然后把jar放到/usr/local/apache-tomcat-8.0.27/lib,/usr/local/apache-tomcat-8.0.28/lib下


下载后自己编译成jar包就行了,不过这个开源项目最高支持Tomcat7.X,8.X并不支持,想要支持8.X需要稍微改动些源码就可以支持了(不建议采用此种做法,后续使用其他jar包)

修改源码:RedisSessionManager.java



--------------------------------------------------------------------

推荐做法:

tomcat8基于缓存的Session共享所提供的安装包如下:

commons-pool2-2.3.jar

jedis-2.7.2.jar

tomcat-embed-logging-juli-8.0.23.jar

tomcat-redis-session-manager-master-0.0.1-SNAPSHOT.jar

下载地址:https://share.weiyun.com/5VUJJmr 

然后把jar放到/usr/local/apache-tomcat-8.0.27/lib,/usr/local/apache-tomcat-8.0.28/lib下

# pwd

/usr/local/apache-tomcat-8.0.27/lib


配置 context.xml 文件:session共享 (apache-tomcat-8.0.28也要做相同配置,连接IP,端口,密码也要和apache-tomcat-8.0.27设置一致)

# pwd
/usr/local/apache-tomcat-8.0.27/conf
# cat context.xml





    
    
    WEB-INF/web.xml
    ${catalina.base}/conf/web.xml
    
    
    
    
    
    
    
      
        
    
         
    


基于supervisor自动启动进程,杀死对应的tomcat进程,tomcat就会自动重启,lib包和context.xml即可生效。


10.测试tomcat基于缓存的Session共享

访问10.0.0.10发现session id=38DF852F4F7C1A11CFADB37BF4C0B6D8都是一致的,tomcat却不一致,则实现了redis的共享session_id的功能。

[3]supervisor管理:对异常中断子进程的自动重启(以redis高可用Sentinel哨兵)_第5张图片



(2)Sentinel哨兵模式集群搭建

  1.Sentinel概念,作用,工作方式

   ① Sentinel概念

   Sentinel(哨兵)是Redis 的高可用性解决方案:由一个或多个Sentinel 实例 组成的Sentinel 系统可以监视任意多个主服务器,以及这些主服务器属下的所有从服务器,并在被监视的主服务器进入下线状态时,自动将下线主服务器属下的某个从服务器升级为新的主服务器。

例如:

[3]supervisor管理:对异常中断子进程的自动重启(以redis高可用Sentinel哨兵)_第6张图片

在Server1 掉线后:

[3]supervisor管理:对异常中断子进程的自动重启(以redis高可用Sentinel哨兵)_第7张图片


升级Server2 为新的主服务器:

[3]supervisor管理:对异常中断子进程的自动重启(以redis高可用Sentinel哨兵)_第8张图片

  ② Sentinel的作用:

A、Master 状态监测

B、如果Master 异常,则会进行Master-slave 转换,将其中一个Slave作为Master,将之前的Master作为Slave 

C、Master-Slave切换后,master_redis.conf、slave_redis.conf和sentinel.conf的内容都会发生改变,即master_redis.conf中会多一行slaveof的配置,sentinel.conf的监控目标会随之调换 

  ③ Sentinel的工作方式:

1):每个Sentinel以每秒钟一次的频率向它所知的Master,Slave以及其他 Sentinel 实例发送一个 PING 命令 
2):如果一个实例(instance)距离最后一次有效回复 PING 命令的时间超过 down-after-milliseconds 选项所指定的值, 则这个实例会被 Sentinel 标记为主观下线。 
3):如果一个Master被标记为主观下线,则正在监视这个Master的所有 Sentinel 要以每秒一次的频率确认Master的确进入了主观下线状态。 
4):当有足够数量的 Sentinel(大于等于配置文件指定的值)在指定的时间范围内确认Master的确进入了主观下线状态, 则Master会被标记为客观下线 
5):在一般情况下, 每个 Sentinel 会以每 10 秒一次的频率向它已知的所有Master,Slave发送 INFO 命令 
6):当Master被 Sentinel 标记为客观下线时,Sentinel 向下线的 Master 的所有 Slave 发送 INFO 命令的频率会从 10 秒一次改为每秒一次 
7):若没有足够数量的 Sentinel 同意 Master 已经下线, Master 的客观下线状态就会被移除。 
若 Master 重新向 Sentinel 的 PING 命令返回有效回复, Master 的主观下线状态就会被移除。

 2.Sentinel配置端口

  在sentinel.conf 配置文件中, 我们可以找到port 属性,这里是用来设置sentinel 的端口,一般情况下,至少会需要三个哨兵对redis 进行监控,我们可以通过修改端口启动多个sentinel 服务。 

# find / -name sentinel.conf
/home/redis-3.2.8/sentinel.conf
# pwd
/usr/local
# mkdir sentinel
# cp /home/redis-3.2.8/sentinel.conf /usr/local/sentinel/sentinel26380.conf
# cp /home/redis-3.2.8/sentinel.conf /usr/local/sentinel/sentinel26381.conf
# cp /home/redis-3.2.8/sentinel.conf /usr/local/sentinel/sentinel26382.conf
# vi sentinel.conf
......
# port 
# The port that this sentinel instance will run on
port 26379          
#sentinel26380.conf端口改为26380,sentinel26381.conf端口改为26381,sentinel26382.conf端口改为26382
......

创建3个sentinel.conf配置文件:sentinel26380.conf、sentinel26381.conf、sentinel26382.conf并修改端口号分别为:263803638146382,并启动服务:

[root@docker1 sentinel]# cat sentinel26380.conf 
# Example sentinel.conf
# port 
port 26380

# 守护进程模式
daemonize yes

# 指明日志文件名
logfile "./sentinel1.log"

# 工作路径,sentinel一般指定/tmp比较简单
dir "/usr/local/sentinel"

# 哨兵监控这个master,在至少quorum个哨兵实例都认为master down后把master标记为odown
# (objective down客观down;相对应的存在sdown,subjective down,主观down)状态。
# slaves是自动发现,所以你没必要明确指定slaves。
sentinel myid f1fc87e38bc8f5e17941d3e965954c514d6f07f9

# master或slave多长时间(默认30秒)不能使用后标记为s_down状态,6380为redis_master的端口。
sentinel monitor TestMaster 127.0.0.1 6380 1

# 若sentinel在该配置值内未能完成failover操作(即故障时master/slave自动切换),则认为本次failover失败。
sentinel down-after-milliseconds TestMaster 1500

# 设置master和slaves验证密码
sentinel failover-timeout TestMaster 10000
#sentinel auth-pass TestMaster 0234kz9*l
sentinel auth-pass TestMaster sheng@123
sentinel config-epoch TestMaster 15

# #除了当前哨兵, 还有哪些在监控这个master的哨兵
sentinel leader-epoch TestMaster 8972
sentinel known-slave TestMaster 127.0.0.1 6381
sentinel known-slave TestMaster 127.0.0.1 6382

# Generated by CONFIG REWRITE
sentinel known-sentinel TestMaster 127.0.0.1 26382 8c36c5d67a5fcd7c86e67c3f51624d10d28ce134
sentinel known-sentinel TestMaster 127.0.0.1 0 0aca3a57038e2907c8a07be2b3c0d15171e44da5
sentinel known-sentinel TestMaster 127.0.0.1 26381 4ccf57b52f07f49921c709e83d68358f2202bce8
sentinel known-sentinel TestMaster 127.0.0.1 0 ac1ef015411583d4b9f3d81cee830060b2f29862
sentinel current-epoch 8972


[root@docker1 sentinel]# cat sentinel26381.conf 
# Example sentinel.conf
# port 
port 26381

# 守护进程模式
daemonize yes

# 指明日志文件名
logfile "./sentinel2.log"

# 工作路径,sentinel一般指定/tmp比较简单
dir "/usr/local/sentinel"

# 哨兵监控这个master,在至少quorum个哨兵实例都认为master down后把master标记为odown
# (objective down客观down;相对应的存在sdown,subjective down,主观down)状态。
# slaves是自动发现,所以你没必要明确指定slaves。
sentinel myid 4ccf57b52f07f49921c709e83d68358f2202bce8

# master或slave多长时间(默认30秒)不能使用后标记为s_down状态。
sentinel monitor TestMaster 127.0.0.1 6380 1

# 若sentinel在该配置值内未能完成failover操作(即故障时master/slave自动切换),则认为本次failover失败。
sentinel down-after-milliseconds TestMaster 1500

# 设置master和slaves验证密码
sentinel failover-timeout TestMaster 10000
#sentinel auth-pass TestMaster 0234kz9*l
sentinel auth-pass TestMaster sheng@123
sentinel config-epoch TestMaster 15

# #除了当前哨兵, 还有哪些在监控这个master的哨兵
sentinel leader-epoch TestMaster 8972
sentinel known-slave TestMaster 127.0.0.1 6382
sentinel known-slave TestMaster 127.0.0.1 6381
# Generated by CONFIG REWRITE
sentinel known-sentinel TestMaster 127.0.0.1 0 0aca3a57038e2907c8a07be2b3c0d15171e44da5
sentinel known-sentinel TestMaster 127.0.0.1 26382 8c36c5d67a5fcd7c86e67c3f51624d10d28ce134
sentinel known-sentinel TestMaster 127.0.0.1 0 ac1ef015411583d4b9f3d81cee830060b2f29862
sentinel known-sentinel TestMaster 127.0.0.1 26380 f1fc87e38bc8f5e17941d3e965954c514d6f07f9
sentinel current-epoch 8972


[root@docker1 sentinel]# cat sentinel26382.conf 
# Example sentinel.conf
# port 
port 26382

# 守护进程模式
daemonize yes

# 指明日志文件名
logfile "./sentinel3.log"

# 工作路径,sentinel一般指定/tmp比较简单
dir "/usr/local/sentinel"

# 哨兵监控这个master,在至少quorum个哨兵实例都认为master down后把master标记为odown
# (objective down客观down;相对应的存在sdown,subjective down,主观down)状态。
# slaves是自动发现,所以你没必要明确指定slaves。
sentinel myid 8c36c5d67a5fcd7c86e67c3f51624d10d28ce134

# master或slave多长时间(默认30秒)不能使用后标记为s_down状态。
sentinel monitor TestMaster 127.0.0.1 6380 1

# 若sentinel在该配置值内未能完成failover操作(即故障时master/slave自动切换),则认为本次failover失败。
sentinel down-after-milliseconds TestMaster 1500

# 设置master和slaves验证密码
sentinel failover-timeout TestMaster 10000
#sentinel auth-pass TestMaster 0234kz9*l
sentinel auth-pass TestMaster sheng@123
sentinel config-epoch TestMaster 15

# #除了当前哨兵, 还有哪些在监控这个master的哨兵
sentinel leader-epoch TestMaster 8972
sentinel known-slave TestMaster 127.0.0.1 6381
sentinel known-slave TestMaster 127.0.0.1 6382
# Generated by CONFIG REWRITE
sentinel known-sentinel TestMaster 127.0.0.1 26381 4ccf57b52f07f49921c709e83d68358f2202bce8
sentinel known-sentinel TestMaster 127.0.0.1 0 0aca3a57038e2907c8a07be2b3c0d15171e44da5
sentinel known-sentinel TestMaster 127.0.0.1 0 ac1ef015411583d4b9f3d81cee830060b2f29862
sentinel known-sentinel TestMaster 127.0.0.1 26380 f1fc87e38bc8f5e17941d3e965954c514d6f07f9
sentinel current-epoch 8972

启动sentinel进程

 /usr/local/bin/redis-sentinel sentinel26380.conf 
 /usr/local/bin/redis-sentinel sentinel26381.conf 
 /usr/local/bin/redis-sentinel sentinel26382.conf


追踪错误日志:连接问题sentinel monitor TestMaster 127.0.0.1 6380 1

[root@docker1 sentinel]# tail -f sentinel1.log 
19410:X 07 Aug 15:01:23.312 # +new-epoch 8911
19410:X 07 Aug 15:01:23.315 # +vote-for-leader 8c36c5d67a5fcd7c86e67c3f51624d10d28ce134 8911
19410:X 07 Aug 15:01:23.331 # Next failover delay: I will not start a failover before Tue Aug  7 15:01:43 2018
19410:X 07 Aug 15:01:43.773 # +new-epoch 8912
19410:X 07 Aug 15:01:43.773 # +try-failover master TestMaster 127.0.0.1 7003
19410:X 07 Aug 15:01:43.778 # +vote-for-leader f1fc87e38bc8f5e17941d3e965954c514d6f07f9 8912
19410:X 07 Aug 15:01:43.782 # 4ccf57b52f07f49921c709e83d68358f2202bce8 voted for 4ccf57b52f07f49921c709e83d68358f2202bce8 8912
19410:X 07 Aug 15:01:43.783 # 8c36c5d67a5fcd7c86e67c3f51624d10d28ce134 voted for 4ccf57b52f07f49921c709e83d68358f2202bce8 8912
19410:X 07 Aug 15:01:54.513 # -failover-abort-not-elected master TestMaster 127.0.0.1 7003
19410:X 07 Aug 15:01:54.576 # Next failover delay: I will not start a failover before Tue Aug  7 15:02:04 2018
19410:X 07 Aug 15:02:04.065 # +new-epoch 8913
19410:X 07 Aug 15:02:04.067 # +vote-for-leader 4ccf57b52f07f49921c709e83d68358f2202bce8 8913
19410:X 07 Aug 15:02:04.067 # Next failover delay: I will not start a failover before Tue Aug  7 15:02:24 2018

正确的连接日志:

[root@docker1 sentinel]# tail -f sentinel1.log 
20107:X 07 Aug 15:30:19.250 # Sentinel ID is f1fc87e38bc8f5e17941d3e965954c514d6f07f9
20107:X 07 Aug 15:30:19.250 # +monitor master TestMaster 127.0.0.1 6380 quorum 1
20107:X 07 Aug 15:30:19.250 * +slave slave 127.0.0.1:6382 127.0.0.1 6382 @ TestMaster 127.0.0.1 6380
20107:X 07 Aug 15:30:19.259 * +slave slave 127.0.0.1:6381 127.0.0.1 6381 @ TestMaster 127.0.0.1 6380
20107:X 07 Aug 15:30:20.757 # +sdown sentinel 8c36c5d67a5fcd7c86e67c3f51624d10d28ce134 127.0.0.1 26382 @ TestMaster 127.0.0.1 6380
20107:X 07 Aug 15:30:20.758 # +sdown sentinel 0aca3a57038e2907c8a07be2b3c0d15171e44da5 127.0.0.1 0 @ TestMaster 127.0.0.1 6380
20107:X 07 Aug 15:30:20.758 # +sdown sentinel 4ccf57b52f07f49921c709e83d68358f2202bce8 127.0.0.1 26381 @ TestMaster 127.0.0.1 6380
20107:X 07 Aug 15:30:20.758 # +sdown sentinel ac1ef015411583d4b9f3d81cee830060b2f29862 127.0.0.1 0 @ TestMaster 127.0.0.1 6380
20107:X 07 Aug 15:30:24.489 # -sdown sentinel 4ccf57b52f07f49921c709e83d68358f2202bce8 127.0.0.1 26381 @ TestMaster 127.0.0.1 6380
20107:X 07 Aug 15:30:27.604 # -sdown sentinel 8c36c5d67a5fcd7c86e67c3f51624d10d28ce134 127.0.0.1 26382 @ TestMaster 127.0.0.1 6380


redis主挂了之后:

[root@docker1 ~]# /usr/local/bin/redis-cli -p 6380 -a sheng@123 info Replication
# Replication
role:slave
master_host:127.0.0.1
master_port:6382
master_link_status:down
master_last_io_seconds_ago:-1
master_sync_in_progress:0
slave_repl_offset:1
master_link_down_since_seconds:1534321361
slave_priority:100
slave_read_only:1
connected_slaves:0
master_repl_offset:0
repl_backlog_active:0
repl_backlog_size:1048576
repl_backlog_first_byte_offset:0
repl_backlog_histlen:0

[root@docker1 ~]# /usr/local/bin/redis-cli -p 6381 -a sheng@123 info Replication
# Replication
role:slave
master_host:127.0.0.1
master_port:6382
master_link_status:up
master_last_io_seconds_ago:2
master_sync_in_progress:0
slave_repl_offset:323009
slave_priority:100
slave_read_only:1
connected_slaves:0
master_repl_offset:0
repl_backlog_active:0
repl_backlog_size:1048576
repl_backlog_first_byte_offset:0
repl_backlog_histlen:0


[root@docker1 ~]# /usr/local/bin/redis-cli -p 6382 -a sheng@123 info Replication
# Replication
role:master
connected_slaves:1
slave0:ip=127.0.0.1,port=6381,state=online,offset=323023,lag=1
master_repl_offset:323023
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:2
repl_backlog_histlen:323022





3.Sentinel配置主服务器的ip和端口

我们把监听的端口修改成6380,并且加上权值为2,这里的权值,是用来计算我们需要将哪一台服务器升级升主服务器

mymaster 后跟的是master的ip和端口,最后一个’2’代表我要启动只要有2个sentinel认为master下线,就认为该master客观下线,启动failover并选举产生新的master。通常最后一个参数不能多于启动的sentinel实例数。

# vi sentinel26380.conf
......
# sentinel monitor    
#
# Tells Sentinel to monitor this master, and to consider it in O_DOWN
# (Objectively Down) state only if at least  sentinels agree.
#
# Note that whatever is the ODOWN quorum, a Sentinel will require to
# be elected by the majority of the known Sentinels in order to
# start a failover, so no failover can be performed in minority.
#
# Slaves are auto-discovered, so you don't need to specify slaves in
# any way. Sentinel itself will rewrite this configuration file adding
# the slaves using additional configuration options.
# Also note that the configuration file is rewritten when a
# slave is promoted to master.
#
# Note: master name should not include special characters or spaces.
# The valid charset is A-z 0-9 and the three characters ".-_".
sentinel monitor mymaster 127.0.0.1 6380 2
......




-----------------------------------------------------------------------------------------------

问题:redis其中一台宕机,sentinel导致redis主从切换,

[root@docker1 ~]# /usr/local/bin/redis-cli -p 6380
127.0.0.1:6380> auth sheng@123
OK
127.0.0.1:6380> info
# Server
redis_version:3.2.8
redis_git_sha1:00000000
redis_git_dirty:0
redis_build_id:6a9207c0ce8cb723
redis_mode:standalone
os:Linux 3.10.0-693.5.2.el7.x86_64 x86_64
arch_bits:64
multiplexing_api:epoll
gcc_version:4.8.5
process_id:1539
run_id:27525f478b7916332202fc10b9ad391602369f2c
tcp_port:6380
uptime_in_seconds:64430
uptime_in_days:0
hz:10
lru_clock:7096893
executable:/usr/local/bin/redis-server
config_ 

# Clients
connected_clients:1
client_longest_output_list:0
client_biggest_input_buf:0
blocked_clients:0

# Memory
used_memory:821512
used_memory_human:802.26K
used_memory_rss:8114176
used_memory_rss_human:7.74M
used_memory_peak:882288
used_memory_peak_human:861.61K
total_system_memory:1911832576
total_system_memory_human:1.78G
used_memory_lua:37888
used_memory_lua_human:37.00K
maxmemory:0
maxmemory_human:0B
maxmemory_policy:noeviction
mem_fragmentation_ratio:9.88
mem_allocator:jemalloc-4.0.3

# Persistence
loading:0
rdb_changes_since_last_save:0
rdb_bgsave_in_progress:0
rdb_last_save_time:1533759119
rdb_last_bgsave_status:ok
rdb_last_bgsave_time_sec:-1
rdb_current_bgsave_time_sec:-1
aof_enabled:0
aof_rewrite_in_progress:0
aof_rewrite_scheduled:0
aof_last_rewrite_time_sec:-1
aof_current_rewrite_time_sec:-1
aof_last_bgrewrite_status:ok
aof_last_write_status:ok

# Stats
total_connections_received:93
total_commands_processed:397
instantaneous_ops_per_sec:0
total_net_input_bytes:24954
total_net_output_bytes:11977
instantaneous_input_kbps:0.00
instantaneous_output_kbps:0.00
rejected_connections:0
sync_full:0
sync_partial_ok:0
sync_partial_err:0
expired_keys:0
evicted_keys:0
keyspace_hits:0
keyspace_misses:294
pubsub_channels:0
pubsub_patterns:0
latest_fork_usec:0
migrate_cached_sockets:0

# Replication
role:slave
master_host:127.0.0.1
master_port:6382
master_link_status:down
master_last_io_seconds_ago:-1
master_sync_in_progress:0
slave_repl_offset:1
master_link_down_since_seconds:1533823549
slave_priority:100
slave_read_only:1
connected_slaves:0
master_repl_offset:0
repl_backlog_active:0
repl_backlog_size:1048576
repl_backlog_first_byte_offset:0
repl_backlog_histlen:0

# CPU
used_cpu_sys:116.31
used_cpu_user:36.86
used_cpu_sys_children:0.00
used_cpu_user_children:0.00

# Cluster
cluster_enabled:0

# Keyspace