在上篇文章中,我记录了keeplived+nginx+tomcat实现高可用nginx集群,并且主备切换可以发送邮件提示管理员,链接:
centos7+keepalived+nginx+tomcat+springboot实现nginx+tomcat高可用以及故障邮件通知
shiro分布式session共享(链接单机redis)
nginx+springboot+shiro+redis实现分布式session共享,同一项目部署多份实现负载均衡
本文章要实现的需求是做到redis高可用,我要做的就是实现基本的高可用就是两个服务器,两个redis做高可用,redis做集群的话可以用哨兵模式,也可以用cluster模式,cluster模式解决数据量大,提高性能,我要实现单项目,小数据量的高可用,数据量小的话省事来吧,搭建redis哨兵模式,项目业务可以连接redis集群,shiro的Session也是要放入redis集群,本文主要介绍我搭建shiro连接哨兵模式集群redis的过程
两台centos7虚拟机安装redis,编译安装,或者是吧编译好的redis文件直接复制过来就可以,我之前的的文章有介绍怎么在oracle vm虚拟机安装centos7虚拟机。以及redis等的安装,有兴趣的伙伴可以访问下我的主页哦!
redis配置文件相较于单机redis主要做如下修改,首先为了使主从之间可以相互切换意思是:主机宕机,切换到从机,这时原来的从机是主机,原来的主机宕机,管理严修复启动原来宕机的主机后,原来的主机变为从机,这时主从互换了身份,然后现在主机再次宕机后,从机又升级为主机,有点晕了。。,重要的就是都相互配置上对方的远程连接密码,方法如下
【masterauth:要连接的密码】,注意是对方的密码,其次,从机比主机多一项【slaveof:192.168.1.6】,此ip地址是主机的ip地址
这样分别启动主机,从机,进入命令行使用info命令就可以查看主从状态了,如下
主机info信息
从机info信息
这样主从建立了连接,可以信息同步,但需要主机,从机可读,不可写,从机升级为主机后才可读可写
接下来要开启哨兵监控
创建sentinel.conf文件和redis-sentinel命令放在同级目录就可以,如下:
主机sentinel.conf配置文件:
port 26379
# 守护进程模式
daemonize yes
# # 指明日志文件名
logfile "./sentinel.log"
#
dir "/opt/redis/redis-property/bin"
sentinel myid 40c7dd9ddad12a4c4dcf652dcb7b45a8dc5d8b0d
sentinel deny-scripts-reconfig yes
sentinel monitor mymaster 192.168.1.21 6666 1
sentinel down-after-milliseconds mymaster 5000
# Generated by CONFIG REWRITE
protected-mode no
sentinel failover-timeout mymaster 18000
sentinel auth-pass mymaster property
sentinel config-epoch mymaster 8
sentinel leader-epoch mymaster 9
sentinel known-replica mymaster 192.168.1.22 6666
sentinel known-sentinel mymaster 192.168.1.21 26379 8894c1030073e2062ea8369261528e1338919005
sentinel current-epoch 9
从机sentinel.conf配置文件:
port 26379
# 守护进程模式
daemonize yes
# # 指明日志文件名
logfile "./sentinel.log"
#
dir "/opt/redis/redis-property/bin"
sentinel myid 8894c1030073e2062ea8369261528e1338919005
sentinel deny-scripts-reconfig yes
sentinel monitor mymaster 192.168.1.21 6666 1
sentinel down-after-milliseconds mymaster 5000
# Generated by CONFIG REWRITE
protected-mode no
sentinel failover-timeout mymaster 18000
sentinel auth-pass mymaster property
sentinel config-epoch mymaster 8
sentinel leader-epoch mymaster 8
sentinel known-replica mymaster 192.168.1.22 6666
sentinel known-sentinel mymaster 192.168.1.22 26379 40c7dd9ddad12a4c4dcf652dcb7b45a8dc5d8b0d
sentinel current-epoch 9
启动命令如下,我都配置到了/etc/rc.d/rc.local中,方便开机自动启动:
/opt/redis/redis-property/bin/redis-server /opt/redis/redis-property/bin/redis.conf
/opt/redis/redis-property/bin/redis-sentinel /opt/redis/redis-property/bin/sentinel.conf
这样redis和哨兵分别启动,在spring boot中配置Shrio连接到集群这样配置原来的RedisManager修改为RedisSentineManager
shiro配置如下
package com.huohua.common.config;
import com.huohua.modules.sys.shiro.UserRealm;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.session.mgt.SessionManager;
import org.apache.shiro.spring.LifecycleBeanPostProcessor;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;
import org.apache.shiro.web.session.mgt.ServletContainerSessionManager;
import org.crazycake.shiro.RedisSentinelManager;
import org.crazycake.shiro.RedisSessionDAO;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.LinkedHashMap;
import java.util.Map;
@Configuration
public class ShiroConfig {
@Bean
public DefaultWebSessionManager sessionManager(@Value("${globalSessionTimeout:3600}") long globalSessionTimeout){
DefaultWebSessionManager sessionManager = new DefaultWebSessionManager();
sessionManager.setSessionValidationSchedulerEnabled(true);
sessionManager.setSessionIdUrlRewritingEnabled(false);
sessionManager.setSessionValidationInterval(globalSessionTimeout * 1000);
sessionManager.setGlobalSessionTimeout(globalSessionTimeout * 1000);
sessionManager.setSessionDAO(redisSessionDAO(new Long(globalSessionTimeout).intValue()));
return sessionManager;
}
@ConfigurationProperties("spring.redis.sentinel")
@Bean
public RedisSentinelManager redisSentinelManager() {
return new RedisSentinelManager();
}
@Bean
public RedisSessionDAO redisSessionDAO(@Value("${globalSessionTimeout:3600}") int globalSessionTimeout) {
RedisSessionDAO redisSessionDAO = new RedisSessionDAO();
redisSessionDAO.setExpire(globalSessionTimeout);
redisSessionDAO.setRedisManager(redisSentinelManager());
return redisSessionDAO;
}
@Bean("securityManager")
public SecurityManager securityManager(UserRealm userRealm, SessionManager sessionManager) {
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
securityManager.setRealm(userRealm);
securityManager.setSessionManager(sessionManager);
securityManager.setRememberMeManager(null);
return securityManager;
}
@Bean("shiroFilter")
public ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager) {
ShiroFilterFactoryBean shiroFilter = new ShiroFilterFactoryBean();
shiroFilter.setSecurityManager(securityManager);
shiroFilter.setLoginUrl("/login.html");
shiroFilter.setUnauthorizedUrl("/");
Map filterMap = new LinkedHashMap<>();
filterMap.put("/swagger/**", "anon");
filterMap.put("/v2/api-docs", "anon");
filterMap.put("/swagger-ui.html", "anon");
filterMap.put("/webjars/**", "anon");
filterMap.put("/swagger-resources/**", "anon");
filterMap.put("/statics/**", "anon");
filterMap.put("/login.html", "anon");
filterMap.put("/sys/login", "anon");
filterMap.put("/favicon.ico", "anon");
filterMap.put("/captcha.jpg", "anon");
filterMap.put("/**", "authc");
shiroFilter.setFilterChainDefinitionMap(filterMap);
return shiroFilter;
}
@Bean("lifecycleBeanPostProcessor")
public LifecycleBeanPostProcessor lifecycleBeanPostProcessor() {
return new LifecycleBeanPostProcessor();
}
@Bean
public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) {
AuthorizationAttributeSourceAdvisor advisor = new AuthorizationAttributeSourceAdvisor();
advisor.setSecurityManager(securityManager);
return advisor;
}
}
主要配置还是吧shiro的Session交给redis管理,只不过这篇文章相对于上篇,单机redis变成了哨兵集群
注意这里
我在application.yml这样配置:
这块有点纠结,host和nodes都是需要的,因为spring boot初始化redisTemplate需要用到nodes这个字段,初始化RedisSentineManager需要用到host这个字段,先这样实现吧,有更好办法的大佬欢迎赐教
这样配置完成后,启动可以吧spring boot项目打包部署多份,并且可以测试关掉主服务器就可以切换到从服务器了。
但是做到这里还不算完善,主机redis宕机,可以切换到从机,但是管理员无感知,所以我需要研究一下有没有官方方法,比如发邮件提示,实在没有的话我会写一个运维脚本,监测主从切换后自动发送邮件到我的邮箱!