引言
最近对公司的项目进行改造实施负载均衡,以便可以方便的进行横向扩展,提升性能,于是在项目中引入了SpringSession,来实现不同服务器上同一个项目的Session共享。
改造过程
由于项目较老,SpringMVC所使用的版本是
3.1.4.RELEASE
负载均衡
- 在pom.xml中引入SpringSession
<!-- Jedis -->
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>2.9.0</version>
</dependency>
<!-- Spring Data Redis -->
<dependency>
<groupId>org.springframework.session</groupId>
<artifactId>spring-session-data-redis</artifactId>
<version>1.2.1.RELEASE</version>
</dependency>
<!-- Spring Session -->
<dependency>
<groupId>org.springframework.session</groupId>
<artifactId>spring-session</artifactId>
<version>1.2.1.RELEASE</version>
</dependency>
- application.xml中增加redis的配置
<bean id="redisHttpSessionConfiguration" class="org.springframework.session.data.redis.config.annotation.web.http.RedisHttpSessionConfiguration">
<property name="maxInactiveIntervalInSeconds" value="600" />
</bean>
<bean id="jedisPoolConfig" class="redis.clients.jedis.JedisPoolConfig">
<property name="maxTotal" value="100" />
<property name="maxIdle" value="10" />
</bean>
<bean id="jedisConnectionFactory"
class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory"
destroy-method="destroy">
<property name="hostName" value="${redis.host}" />
<property name="password" value="${redis.pwd}" />
<property name="port" value="${redis.port}" />
<property name="database" value="${redis.database}" />
<property name="usePool" value="true" />
<property name="poolConfig" ref="jedisPoolConfig" />
</bean>
- 修改web.xml新增过滤器
<filter>
<filter-name>springSessionRepositoryFilter</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
<filter-name>springSessionRepositoryFilter</filter-name>
<url-pattern>/*</url-pattern>
<dispatcher>REQUEST</dispatcher>
<dispatcher>ERROR</dispatcher>
</filter-mapping>
- Nginx配置改造
upstream demo-site {
server 192.168.0.1:86; #服务器A
server 192.168.0.2:86; #服务器B
}
server {
listen 80;
server_name host;
location / {
proxy_pass http://demo-site;
}
}
改造完毕后,通过域名访问项目,会轮询访问这两台服务器上的应用,Session也会在这两个应用上进行共享。
文件共享
两台服务器通过NFS协议挂载了同一个NAS云盘,路径统一为/nas
,文件上传路径都配置这个路径就可以了。
坑
- 前端的post请求 后端Controller中使用
request.getInputStream()
获取到流为空
- 原因:SpringSession中获取SessionId的操作使用了
request.getParameter()
方法具体代码位置在CookieHttpSessionStrategy
类中
public String getRequestedSessionId(HttpServletRequest request) {
Map<String, String> sessionIds = getSessionIds(request);
String sessionAlias = getCurrentSessionAlias(request);
return sessionIds.get(sessionAlias);
}
public String getCurrentSessionAlias(HttpServletRequest request) {
if (this.sessionParam == null) {
return DEFAULT_ALIAS;
}
String u = request.getParameter(this.sessionParam);
if (u == null) {
return DEFAULT_ALIAS;
}
if (!ALIAS_PATTERN.matcher(u).matches()) {
return DEFAULT_ALIAS;
}
return u;
}
20160803175011173.jpg
request.getParameter()
操作会读取流信息,从而导致流被掏空,以致请求到达Controller时没数据可以读取。
- 解决办法
调用方使用接口时contentType 指定为'application/json;charset=UTF-8'
或其它,只要不是application/x-www-form-urlencoded
就可以
- Log日志写入混乱。
- 应用使用Log4J记录日志,因为做了文件共享,所以考虑到日志查看方便,所以也都写到同一个文件,运行了几天才发现日志有丢失问题,估计是多个log4j进程同时写文件有冲突。
- 解决方法
日志配置中增加变量log4j.appender.E.File=/folder/path/info.${log4j.logtype}.log
服务器A Tomcat配置bin/catalina.sh
中增加参数JAVA_OPTS='-Xms512m -Xmx2048m -Dlog4j.logtype=1'
服务器B Tomcat配置bin/catalina.sh
中增加参数JAVA_OPTS='-Xms512m -Xmx2048m -Dlog4j.logtype=2'
建议
项目中尽量不要使用Application/Session存取数据。
网友评论