搭建集群环境
拓扑图
nginx环境搭建
下载安装nginx,安装nginx(略)
nginx配置
nginx配置参考:ngix配置
#user nobody;
worker_processes 1;
#error_log logs/error.log;
#error_log logs/error.log notice;
#error_log logs/error.log info;
#pid logs/nginx.pid;
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
#定义日志格式
#log_format main '$remote_addr - $remote_user [$time_local] $request '
# '"$status" $body_bytes_sent "$http_referer" '
# '"$http_user_agent" "$http_x_forwarded_for"';
#access_log off;
access_log logs/access.log;
client_header_timeout 3m;
client_body_timeout 3m;
send_timeout 3m;
client_header_buffer_size 1k;
large_client_header_buffers 4 4k;
sendfile on;
tcp_nopush on;
tcp_nodelay on;
#fastcgi_intercept_errors on;
error_page 404 /404.html;
#keepalive_timeout 75 20;
gzip on;
gzip_min_length 1000;
gzip_types text/plain text/css application/x-javascript;
#配置被代理的服务器
upstream ds_web {
#ip_hash;
server 192.1.217.111:8080;
server 192.1.217.111:9091;
}
server {
#nginx监听80端口,请求该端口时转发到真实目标
listen 80;
#配置访问域名
server_name localhost;
location /ds {
#这里配置代理是指上面定义的两个被代理目标,ds_web名字必须一致
proxy_pass http://ds_web;
#proxy_redirect off;
#非80端口使用,目的是将代理服务器收到的用户的信息传到真实服务器上,我也不是很理解
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
client_max_body_size 10m;
client_body_buffer_size 128k;
proxy_connect_timeout 15; ##单位是s
proxy_send_timeout 15;
proxy_read_timeout 15;
proxy_buffer_size 4k;
proxy_buffers 4 32k;
proxy_busy_buffers_size 64k;
proxy_temp_file_write_size 64k;
add_header Access-Control-Allow-Origin *;
}
#此处定义500 502 503 504的错误页面
error_page 500 502 503 504 /50x.html;
#错误页面位置
location = /50x.html {
#root表示路径 html为nginx安装目录中的html文件夹
#位于/usr/local/nginx/html/下
root html;
}
}
}
启动nginx
##windows
start nginx.exe
##linux
./nginx
访问:localhost
服务节点
业务代码
@RestController
@RequestMapping("/user")
public class UserController {
@RequestMapping(value = "/index")
public String index(HttpServletRequest request ,HttpSession session) throws Exception{
//客户端信息
String clientInfo = IpAdrressUtil.getIpAdrress(request) + ":" +request.getRemotePort();
//服务器信息
String serverInfo = request.getLocalAddr()+ ":" +request.getLocalPort();
return "客户端信息:"+clientInfo+"<br/>"
+"服务器信息:"+serverInfo+"<br/>"
+"session信息:"+session.getId()+"<br/>";
}
}
节点1
节点2
Session共享
通过nginx的代理地址http://192.1.217.111/ds/user/index
访问,发现sessionId在不停变化。
解决session共享常见的有三种方法:
实现思路 | 优势 | 劣势 | |
---|---|---|---|
粘性Session | 开启nginxip_hash 策略,使得同一个用户的请求,转发给固定的一个节点处理。 | 简单,无侵入 | 当某一个节点重启、挂起,该节点上的session信息会丢失 |
Session复制 | web容器通过配置,将Session复制同步至其他容器节点上 | 代码无侵入,不会丢失session | 业内支持Session复制的web容器产品较少(tomat7.x) ,依赖web容器 |
Session共享 | 使用缓存管理Session,所有的节点都从缓冲中存取Session | 不会丢失session,不依赖web容器 | 实现复杂,配置较麻烦 |
粘性Session
开启nginx的ip_hash
即可。
upstream ds_web {
ip_hash;
server 192.1.217.111:8080;
server 192.1.217.111:9091;
}
- 开启
ip_hash
之后,浏览器不停刷新请求,请求全部转发至同一节点。 - 关闭该节点,请求会跳转至另一节点,session信息变更(丢失)。
Session复制
<Cluster className="org.apache.catalina.ha.tcp.SimpleTcpCluster"
channelSendOptions="8">
<Manager className="org.apache.catalina.ha.session.DeltaManager"
expireSessionsOnShutdown="false"
notifyListenersOnReplication="true"/>
<Channel className="org.apache.catalina.tribes.group.GroupChannel">
<Membership className="org.apache.catalina.tribes.membership.McastService"
address="228.0.0.4"
port="45564"
frequency="500"
dropTime="3000"/>
<Receiver className="org.apache.catalina.tribes.transport.nio.NioReceiver"
address="auto"
port="4000"
autoBind="100"
selectorTimeout="5000"
maxThreads="6"/>
<Sender className="org.apache.catalina.tribes.transport.ReplicationTransmitter">
<Transport className="org.apache.catalina.tribes.transport.nio.PooledParallelSender"/>
</Sender>
<Interceptor className="org.apache.catalina.tribes.group.interceptors.TcpFailureDetector"/>
<Interceptor className="org.apache.catalina.tribes.group.interceptors.MessageDispatch15Interceptor"/>
</Channel>
<Valve className="org.apache.catalina.ha.tcp.ReplicationValve"
filter=""/>
<Valve className="org.apache.catalina.ha.session.JvmRouteBinderValve"/>
<Deployer className="org.apache.catalina.ha.deploy.FarmWarDeployer"
tempDir="/tmp/war-temp/"
deployDir="/tmp/war-deploy/"
watchDir="/tmp/war-listen/"
watchEnabled="false"/>
<ClusterListener className="org.apache.catalina.ha.session.JvmRouteSessionIDBinderListener"/>
<ClusterListener className="org.apache.catalina.ha.session.ClusterSessionListener"/>
</Cluster>
Session共享
SpringMVC
- 增加maven依赖
<dependency>
<groupId>org.springframework.session</groupId>
<artifactId>spring-session-data-redis</artifactId>
<version>1.2.1.RELEASE</version>
</dependency>
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>2.8.1</version>
</dependency>
- 修改spring-mvc.xml配置
<!-- 里面配置了包含SpringSessionRepositoryFilter 在内的多个bean -->
<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_hostname}"/>
<property name="port" value="${redis_port}"/>
<property name="password" value="${redis_pwd}" />
<property name="timeout" value="3000"/>
<property name="usePool" value="true"/>
<property name="poolConfig" ref="jedisPoolConfig"/>
</bean>
- web.xml增加拦截器
<filter>
<!-- delegating 从spring容器中寻找springSessionRepositoryFilter bean-->
<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>
</filter-mapping>
SpringBoot 2.x
使用SpringBoot版本2.1.1.RELEASE
.
1.添加maven依赖
<dependency>
<groupId>org.springframework.session</groupId>
<artifactId>spring-session-data-redis</artifactId>
</dependency>
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
<version>2.4.2</version>
</dependency>
2.redis连接配置
spring:
redis:
host: s157
port: 6379
timeout: 10000
database: 0
lettuce:
pool:
max-active: 8
# 连接池最大阻塞等待时间(使用负值表示没有限制) 默认 -1
max-wait: -1
# 连接池中的最小空闲连接 默认 0
min-idle: 0
- 业务代码配置
//1.开启EnableRedisHttpSession
@EnableRedisHttpSession(maxInactiveIntervalInSeconds= 1800)
public class RedisSessionConfig {
}
结果