springboot+shiro+redis實現高可用集羣,shiro連接哨兵redis集羣,springboot配置方法,接上篇文章

在上篇文章中,我記錄了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<String, String> 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宕機,可以切換到從機,但是管理員無感知,所以我需要研究一下有沒有官方方法,比如發郵件提示,實在沒有的話我會寫一個運維腳本,監測主從切換後自動發送郵件到我的郵箱!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章