Session 是客户端与服务器通讯会话技术, 比如浏览器登陆、记录整个浏览会话信息。
实现原理:客户对向服务器端发送请求后,Session 创建在服务器端,返回Sessionid给客户端浏览器保存在本地,当下次发送请求的时候,在请求头中传递sessionId获取对应的从服务器上获取对应的Session。Session 存放在服务器上,关闭浏览器是不会影响到session的。
如果服务器产生了集群后,因为session是存放在服务器上,客户端会使用同一个Sessionid在多个不同的服务器上获取对应的Session,从而会导致Session不一致问题
3.1 nginx或者haproxy实现IP绑定(不推荐 弊端很大,相当于负载均衡用处不大)
用Nginx 做的负载均衡可以添加ip_hash这个配置,
用haproxy做的负载均衡可以用 balance source这个配置。
从而使同一个ip的请求发到同一台服务器。
3.2 利用数据库同步session (不推荐 效率不高)
3.3 tomcat内置支持session同步(不推荐)同步可能会产生延迟
3.4 使用缓存框架缓存session,将Session集群存放Redis
使用spring-session框架,底层实现原理是重写httpsession
3.5 可以使用token 替代 session功能
现在说下 spring-session框架用法实现:
1、在pom.xml中添加依赖信息
org.springframework.boot
spring-boot-starter-parent
2.0.0.RELEASE
2.8.0
1.8
1.8
UTF-8
UTF-8
zh_CN
org.projectlombok
lombok
org.springframework.boot
spring-boot-starter-web
com.alibaba
fastjson
1.2.47
org.springframework.boot
spring-boot-starter-test
test
org.springframework.boot
spring-boot-starter-data-redis
org.springframework.session
spring-session-data-redis
org.apache.commons
commons-pool2
redis.clients
jedis
org.apache.maven.plugins
maven-compiler-plugin
1.8
org.springframework.boot
spring-boot-maven-plugin
com.meiteedu.WxMpApplication
repackage
2、yml文件中配置redis信息
server:
port: 8081
spring:
redis:
database: 0
host: 192.168.212.151
port: 6379
password: 123456
jedis:
pool:
max-active: 8
max-wait: -1
max-idle: 8
min-idle: 0
timeout: 10000
redis:
hostname: 192.168.212.151
port: 6379
password: 123456
3、写redis服务器的连接配置类
//这个类用配置redis服务器的连接
//maxInactiveIntervalInSeconds为SpringSession的过期时间(单位:秒)
@EnableRedisHttpSession(maxInactiveIntervalInSeconds = 1800)
public class SessionConfig {
// 冒号后的值为没有配置文件时,制动装载的默认值
@Value("${redis.hostname:localhost}")
String HostName;
@Value("${redis.port:6379}")
int Port;
@Value("${redis.password}")
String password;
@Bean
public JedisConnectionFactory connectionFactory() {
JedisConnectionFactory connection = new JedisConnectionFactory();
connection.setPort(Port);
connection.setHostName(HostName);
connection.setPassword(password);
return connection;
}
}
4、初始化Session配置
//初始化Session配置
public class SessionInitializer extends AbstractHttpSessionApplicationInitializer {
public SessionInitializer() {
super(SessionConfig.class);
}
}
开启多个springboot启动tomcat, 使用nginx配置反向代理,集群tomcat, 然后进行测试,即可。访问不同的端口的tomcat,获取到的 session值 是否都是一样,是否都能获取到正确的session。 可以查看redis上面,是否存放在了 redis上面。
@Service
public class TokenService {
@Autowired
private RedisService redisService;
// 新增 返回token
public String put(Object object) {
if(object== null) {
return null;
}
String token = getToken();
redisService.setString(token, object);
return token;
}
// 获取信息
public String get(String token) {
String reuslt = redisService.getString(token);
return reuslt;
}
public String getToken() {
return UUID.randomUUID().toString();
}
}
@RestController
public class TokenController {
@Autowired
private TokenService tokenService;
@Value("${server.port}")
private String serverPort;
@RequestMapping("/put")
public String put(String nameValue) {
String token = tokenService.put(nameValue);
return token + "-" + serverPort;
}
@RequestMapping("/get")
public String get(String token) {
String value = tokenService.get(token);
return value + "-" + serverPort;
}
}
@Component
public class RedisService {
@Autowired
private StringRedisTemplate stringRedisTemplate;
// public void set(String key, Object object, Long time) {
// stringRedisTemplate.opsForValue();
// // 存放String 类型
// if (object instanceof String) {
// setString(key, object);
// }
// // 存放 set类型
// if (object instanceof Set) {
// setSet(key, object);
// }
// // 设置有效期 以秒为单位
// stringRedisTemplate.expire(key, time, TimeUnit.SECONDS);
// }
//
public void setString(String key, Object object) {
// 开启事务权限
// stringRedisTemplate.setEnableTransactionSupport(true);
try {
// 开启事务 begin
// stringRedisTemplate.multi();
String value = (String) object;
stringRedisTemplate.opsForValue().set(key, value);
System.out.println("存入完毕,马上开始提交redis事务");
// 提交事务
// stringRedisTemplate.exec();
} catch (Exception e) {
// 需要回滚事务
// stringRedisTemplate.discard();
}
}
public void setSet(String key, Object object) {
Set value = (Set) object;
for (String oj : value) {
stringRedisTemplate.opsForSet().add(key, oj);
}
}
public String getString(String key) {
return stringRedisTemplate.opsForValue().get(key);
}
}