1. 程式人生 > >使用redis來解決nginx--tomcat負載均衡部署session不一致

使用redis來解決nginx--tomcat負載均衡部署session不一致

從上圖中我們可以看出,session是不同步的

  • 解決方案
    • 使用IP來限定每次訪問的伺服器
      • ip_hash
      • 只需要在配置nginx的時候加上上述配置即可
      • 缺點
        • 萬一使用者正在訪問的伺服器突然宕機了,就不好了
    • 使用redis來實現session共享
    • 使用統一認證

我們來講講怎麼是用redis來實現tomcat的session共享的?

  • 開啟redis服務
  • 裝置    


  • Tomcat7
    • 把上述的連結中的三個jar包copy到tomcat到lib/目錄中
    • 修改conf/context.xml檔案,新增
      • <Valve className="com.orangefunction.tomcat.redissessions.RedisSessionHandlerValve" />
      • <Manager className="com.orangefunction.tomcat.redissessions.RedisSessionManager"
      • host="192.168.56.103"
      • port="6379"
      • database="0"
      • maxInactiveInterval="60" />
    • 重啟tomcat
    • 第二個tomcat重複第一個tomcat的步驟

  • Tomcat8.5
    • 把上述連結三個jar包copy到tomcat的lib/目錄下
    • 修改conf/context.xml檔案,新增
      • <Valve className="com.s.tomcat.redissessions.RedisSessionHandlerValve"/>
      • <Manager className="com.s.tomcat.redissessions.RedisSessionManager"
      • host="192.168.56.103"
      • port="6379"
      • database="0"
      • maxInactiveInterval="60" />
    • 重啟tomcat
    • 第二個tomcat亦如此

  • Tomcat8.5的開源專案還提供了tomcat8.0redis session共享的解決

  • 開啟nginx,發現如下

  • Spring boot 專案使用redis實現共享會話
    • 新增maven依賴
      • <!--redis-->
      • <dependency>
      • <groupId>
        org.springframework.boot</groupId>
      • <artifactId>spring-boot-starter-data-redis</artifactId>
      • <version>1.5.4.RELEASE</version>
      • </dependency>
      • <!-- redis session -->
      • <dependency>
      • <groupId>org.springframework.session</groupId>
      • <artifactId>spring-session-data-redis</artifactId>
      • <version>1.3.1.RELEASE</version>
      • </dependency>
    • 新建三個相關類
      • import org.springframework.data.redis.cache.RedisCachePrefix;
      • import org.springframework.data.redis.serializer.RedisSerializer;
      • import org.springframework.data.redis.serializer.StringRedisSerializer;
      • public class RedisPrefix implements RedisCachePrefix {
      • private final RedisSerializer serializer;
      • private final String delimiter;
      • public RedisPrefix(String delimiter) {
      • this.serializer = new StringRedisSerializer();
      • this.delimiter = delimiter;
      • }
      • @Override
      • public byte[] prefix(String cacheName) {
      • return this.serializer.serialize(this.delimiter != null ? this.delimiter.concat(":").concat(cacheName).concat(":") : cacheName.concat(":"));
      • }
      • }
      • package com.wpg.test.config;
      • import org.slf4j.Logger;
      • import org.slf4j.LoggerFactory;
      • import org.springframework.beans.factory.annotation.Value;
      • import org.springframework.cache.CacheManager;
      • import org.springframework.cache.annotation.CachingConfigurerSupport;
      • import org.springframework.cache.annotation.EnableCaching;
      • import org.springframework.context.annotation.Bean;
      • import org.springframework.context.annotation.Configuration;
      • import org.springframework.data.redis.cache.RedisCacheManager;
      • import org.springframework.data.redis.connection.RedisConnectionFactory;
      • import org.springframework.data.redis.core.RedisTemplate;
      • import redis.clients.jedis.JedisPool;
      • import redis.clients.jedis.JedisPoolConfig;
      • import java.util.Map;
      • import java.util.concurrent.ConcurrentHashMap;
      • @Configuration
      • @EnableCaching
      • public class RedisCacheConfigextends CachingConfigurerSupport {
      • Logger logger = LoggerFactory.getLogger(RedisCacheConfig.class);
      • @Value("${spring.redis.host}")
      • private String host;
      • @Value("${spring.redis.port}")
      • private int port;
      • @Value("${spring.redis.timeout}")
      • private int timeout;
      • @Value("${spring.redis.pool.max-idle}")
      • private int maxIdle;
      • @Value("${spring.redis.pool.max-wait}")
      • private long maxWaitMillis;
      • @Value("${spring.redis.password}")
      • private String password;
      • @Bean
      • public JedisPool redisPoolFactory() {
      • logger.info("JedisPool注入成功!!");
      • JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
      • jedisPoolConfig.setMaxIdle(maxIdle);
      • jedisPoolConfig.setMaxWaitMillis(maxWaitMillis);
      • JedisPool jedisPool = new JedisPool(jedisPoolConfig, host, port, timeout, password);
      • return jedisPool;
      • }
      • @Bean
      • public RedisTemplate<String, String> redisTemplate(RedisConnectionFactory cf) {
      • RedisTemplate<String, String> redisTemplate = new RedisTemplate<String, String>();
      • redisTemplate.setConnectionFactory(cf);
      • return redisTemplate;
      • }
      • @Bean
      • public CacheManager cacheManager(RedisTemplate redisTemplate) {
      • //todo 設定快取過期時間
      • RedisCacheManager manager = new RedisCacheManager(redisTemplate);
      • manager.setUsePrefix(true);
      • RedisCachePrefix cachePrefix = new RedisPrefix("com.wpg.mybatis");
      • manager.setCachePrefix(cachePrefix);
      • // 整體快取過期時間
      • manager.setDefaultExpiration(100L);
      • // 設定快取過期時間。key和快取過期時間,單位秒
      • Map<String, Long> expiresMap = new HashMap<>();
      • expiresMap.put("com.wpg.mybatis", 100L);
      • manager.setExpires(expiresMap);
      • return manager;
      • }
      • }
      • package com.wpg.test.config;
      • import org.springframework.context.annotation.Configuration;
      • import org.springframework.session.data.redis.config.annotation.web.http.EnableRedisHttpSession;
      • @Configuration
      • //maxInactiveIntervalInSeconds session超時時間,單位秒
      • @EnableRedisHttpSession(maxInactiveIntervalInSeconds =600)
      • public class RedisSessionConfig {
      • }
    • 測試
      • @RestController
      • @RequestMapping("/session")
      • public class IndexController {
      • @GetMapping("/set")
      • public Object setSession(@RequestParam(value = "name",defaultValue = "聞品高") String name, HttpServletRequest request){
      • request.getSession().setAttribute("name",name);
      • return "ok";
      • }
      • @GetMapping("/get")
      • public Object getSession(HttpServletRequest request){
      • Object name = request.getSession().getAttribute("name");
      • return name;
      • }
      • }

  • guns專案部署到兩個tomcat上
    • 不行,guns專案不是使http session來記錄使用者狀態的
    • 由於guns使用了shiro,Session都跑shiro去了
    • 終於找到方法了
      • 把guns-admin pom檔案中被註釋對的依賴開啟

      • 在主類上添加註解
        • @EnableRedisHttpSession
      • 取消SpringSessionConfig類上的註釋
      • 修改配置值