最近公司項目遇到一臺服務器崩潰導致項目無法運行,因項目採用單點的 Redis做session共享,權限處理,所以想到採用Redis主從方式這樣降低耦合性,爲方便以後查閱特記錄此處。
服務器系統爲centos 7 redis 4.0.6
兩臺主從Redis服務器: 192.168.0.35 6379 主
192.168.0.34 6379 從
一、Redis安裝
cd /opt
wget http://download.redis.io/releases/redis-4.0.6.tar.gz 若提示爲找到該命令,那麼需要安裝:yum install wget
tar xzf redis-4.0.6.tar.gz
cd redis-4.0.6
make
src/redis-server
客戶端訪問:
src/redis-cli
Redis設置開機自啓動:
1.修改配置文件參數daemonize爲yes
.vi /opt/redis-4.0.6/redis.conf
-
複製redis配置文件(啓動腳本需要用到配置文件內容,所以要複製)
#1.在/etc下新建redis文件夾
$ mkdir /etc/redis
#2.把安裝redis目錄裏面的redis.conf文件複製/etc/redis/6379.conf面,6379.conf是取的文件名稱,啓動腳本里面的變量會讀取這個名稱,所以要是redis的端口號改了,這裏也要修改
$ cp /opt/redis-4.0.6/redis.conf /etc/redis/6379.conf- 複製redis啓動腳本
find / -name redis_init_script- redis啓動腳本一般在redis根目錄的utils,如果不知道路徑,可以先查看路徑
find / -name redis_init_script
- 複製啓動腳本到/etc/init.d/redis文件中
cp /opt/redis-3.2.4//utils/redis_init_script /etc/init.d/redis - 修改啓動腳本參數
vi /etc/init.d/redis
- 複製redis啓動腳本
#在/etc/init.d/redis文件的頭部添加下面兩行註釋代碼,也就是在文件中#!/bin/sh的下方添加
#chkconfig: 2345 10 90
#description: Start and Stop redis
如圖
同時還要修改參數,指定redis的安裝路徑
由於項目需求,redis需要外界訪問所以採用密碼方式:
masterauth test(注意若設置密碼主從密碼最好一直,方便後面sentinel模式訪問)
打開redis命令:service redis start
關閉redis命令:service redis stop
設爲開機啓動:chkconfig redis on
至此35上的Redis安裝成功,34服務器上也按類似方法安裝,由於34是從所以在6379.conf中多一些配置
slaveof 192.168.0.35 6379
如圖
登陸34查看信息
至此Redis主從全部安裝完成,下面配置哨兵
二、sentinel 配置
#將sentinel配置文件拷貝到/etc/redis目錄後編輯
1.自動啓動
2.啓動
redis-sentinel sentinel.conf
當退出是 sentinel也退出 了,這時我們就採用redis-sentinel /etc/redis/sentinel.conf
查看進程sentinel進程一直都在。在35上也同樣配置到此Redis所有操作結束。
三、shior-Redis連接Redis
maven配置
此處切記shiro-redis架包使用比較新的,當時使用2.4.2.1-RELEASE時無法使用哨兵主從。
application配置
ShiroConfig 代碼
@Configuration
public class ShiroConfig {
@Value("${spring.redis.host}")
private String host;
@Value("${spring.redis.port}")
private int port;
@Value("${spring.redis.password}")
private String password;
@Value("${spring.redis.sentinel.nodes}")
private String redisNodes;
@Value("${spring.redis.sentinel.master}")
private String master;
@Value("${shiro.redisCacheExpire:1800}")
private int redisCacheExpire;
@Value("${shiro.filterChainDefinitions}")
private String filterChainDefinitions;
@Value("${shiro.sessionValidationInterval:300000}")
private long sessionValidationInterval;
@Autowired
private AuthorityService authorityService;
/**
* 配置shiro redisManager ----單點時使用
* 使用的是shiro-redis開源插件
*
* @return
*/
// public RedisManager redisManager() {
// RedisManager redisManager = new RedisManager();
// redisManager.setHost(host);
// redisManager.setPort(port);
// redisManager.setPassword(password);
// redisManager.setExpire(redisCacheExpire);
//// redisManager.setTimeout(2000);
// return redisManager;
// }
/**
* 配置shiro redisSentinelManager 哨兵模式
* 使用的是shiro-redis開源插件
* @return
*/
public RedisSentinelManager redisSentinelManager(){
RedisSentinelManager redisSentinelManager = new RedisSentinelManager();
redisSentinelManager.setMasterName(master);
redisSentinelManager.setHost(redisNodes);
redisSentinelManager.setPassword(password);
return redisSentinelManager;
}
/**
* cacheManager 緩存 redis實現
* 使用的是shiro-redis開源插件
*
* @return
*/
public RedisCacheManager cacheManager() {
RedisCacheManager redisCacheManager = new RedisCacheManager();
// redisCacheManager.setRedisManager(redisManager());
redisCacheManager.setRedisManager(redisSentinelManager());
return redisCacheManager;
}
/**
* RedisSessionDAO shiro sessionDao層的實現 通過redis
* 使用的是shiro-redis開源插件
*/
public RedisSessionDAO redisSessionDAO() {
RedisSessionDAO redisSessionDAO = new RedisSessionDAO();
redisSessionDAO.setRedisManager(redisSentinelManager());
return redisSessionDAO;
}
/**
* shiro session的管理
*/
public DefaultWebSessionManager sessionManager() {
DefaultWebSessionManager sessionManager = new DefaultWebSessionManager();
sessionManager.setSessionDAO(redisSessionDAO());
Cookie cookie = sessionManager.getSessionIdCookie();
cookie.setName("emp_sid");
sessionManager.setSessionIdCookie(cookie);
//shiro session過期監聽器
sessionManager.setSessionListeners(Arrays.asList(new ShiroSessionListener()));
sessionManager.setSessionValidationInterval(sessionValidationInterval);
return sessionManager;
}
/**
* 憑證匹配器
*
* @return
*/
public CredentialsMatcher credentialsMatcher() {
RetryLimitHashedCredentialsMatcher credentialsMatcher = new RetryLimitHashedCredentialsMatcher(cacheManager());
credentialsMatcher.setHashAlgorithmName("md5");//加密算法名稱
credentialsMatcher.setHashIterations(2);
credentialsMatcher.setStoredCredentialsHexEncoded(true);
return credentialsMatcher;
}
/**
* Realm實現
*
* @return
*/
@Bean
public AuthorizingRealm userRealm() {
EmployeeRealm employeeRealm = new EmployeeRealm();
employeeRealm.setCredentialsMatcher(credentialsMatcher());
//關閉登陸用戶信息緩存
employeeRealm.setAuthenticationCachingEnabled(false);
employeeRealm.setAuthorizationCachingEnabled(true);
return employeeRealm;
}
/**
* 安全管理器
*
* @return
*/
@Bean
public SecurityManager securityManager() {
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
securityManager.setRealm(userRealm());
securityManager.setSessionManager(sessionManager());
securityManager.setCacheManager(cacheManager());
ModularRealmAuthorizer authorizer = new ModularRealmAuthorizer();
authorizer.setRealms(securityManager.getRealms());
authorizer.setPermissionResolver(new EmployeePermissionResolver());
authorizer.setRolePermissionResolver(rolePermissionResolver());
securityManager.setAuthorizer(authorizer);
securityManager.setRememberMeManager(rememberMeManager());
return securityManager;
}
@Bean
public RolePermissionResolver rolePermissionResolver() {
return new MyRolePermissionResolver();
}
@Bean
public ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager) {
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
shiroFilterFactoryBean.setSecurityManager(securityManager);
Map<String, Filter> filters = shiroFilterFactoryBean.getFilters();
StaticUrlFilter staticUrlFilter = new StaticUrlFilter();
filters.put("staticUrl", staticUrlFilter);
TokenFilter tokenFilter=new TokenFilter();
filters.put("token",tokenFilter);
AuthorityFilter authorityFilter = new AuthorityFilter();
authorityFilter.setActionService(authorityService);
filters.put("auth", authorityFilter);
VersionFilter versionFilter = new VersionFilter();
filters.put("version", versionFilter);
shiroFilterFactoryBean.setFilters(filters);
//攔截器.
Map<String, String> filterChainDefinitionMap = new LinkedHashMap<String, String>();
// 配置不會被攔截的鏈接 順序判斷
//攔截器url配置格式爲:/**=user,等號前面爲路徑,後面爲名稱,多個攔截器用','分割,多個配置之間用';'分割
if (!StringUtils.isEmpty(filterChainDefinitions)) {
String[] array = StringUtils.delimitedListToStringArray(filterChainDefinitions, ";");
for (String str : array) {
if(StringUtils.isEmpty(str)){
continue;
}
String[] urlArray = str.split("=");
filterChainDefinitionMap.put(urlArray[0].trim(), urlArray[1].trim());
// String[] filterArray = urlArray[1].split(",");
// for (String s : filterArray) {
// filterChainDefinitionMap.put(urlArray[0].trim(), s.trim());
// }
}
}
shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
// shiroFilterFactoryBean.setFilterChainDefinitions(filterChainDefinitions);
// 如果不設置默認會自動尋找Web工程根目錄下的"/login.jsp"頁面
shiroFilterFactoryBean.setLoginUrl("/login");
// 登錄成功後要跳轉的鏈接
shiroFilterFactoryBean.setSuccessUrl("/");
shiroFilterFactoryBean.setUnauthorizedUrl("/401");
return shiroFilterFactoryBean;
}
public CookieRememberMeManager rememberMeManager() {
CookieRememberMeManager rememberMeManager = new CookieRememberMeManager();
rememberMeManager.getCookie().setMaxAge(2592000);//有效期30天
rememberMeManager.setCipherKey(Base64.decode("4AvVhmFLUs0KTA3Kprsdag=="));
return rememberMeManager;
}
}