jboss eap 6.3 集群(cluster)-Session 复制(Replication)
本文算是前一篇的后续,java web application中,难免会用到session,集群环境中apache会将http请求智能转发到其中某台jboss server。假设有二个jboss server:Server A,Server B,Session值在Server A上。用户在访问某一个依赖session的页面时,如果第一次访问到Server A,能正常取到Session值,刷新一下,如果这时转发到Server B,Session值取不到,问题就来了。
解决的办法简单到让人不敢相信,在app的web.xml中加一行 <distributable /> 即可(前提:jboss cluster是使用mod_cluster实现的),有了这个节点后,向某台server写入session时,session会自动复制到其它server node。
下面来具体验证一下:
网络环境:
如上图,有二台机器:172.21.129.181(Master Server & Apacha Server)、172.21.129.128(Slave Server)
User所在的计算机IP为: 172.21.129.57 (图中未标出)
Sample Application:
为了验证,我们建一个最简单的spring mvc web应用
Controller代码如下:
1 package com.cnblogs.yjmyzz;
2
3 import javax.servlet.http.HttpServletRequest;
4 import javax.servlet.http.HttpSession;
5
6 import org.apache.log4j.Logger;
7 import org.springframework.stereotype.Controller;
8 import org.springframework.ui.Model;
9 import org.springframework.web.bind.annotation.RequestMapping;
10 import org.springframework.web.bind.annotation.RequestMethod;
11 import org.springframework.web.servlet.ModelAndView;
12
13 @Controller
14 public class HomeController {
15
16 Logger log = Logger.getLogger(this.getClass());
17
18 private static final String sessionKey = "test";
19
20 /**
21 * 写入session
22 * @param request
23 * @return
24 */
25 @RequestMapping(value = "/session-write", method = RequestMethod.GET)
26 public String writeSession(HttpServletRequest request) {
27 HttpSession session = request.getSession();
28 session.setAttribute(sessionKey, "sample value");
29 return "session/write";
30 }
31
32 /**
33 * 读取session
34 * @param request
35 * @return
36 */
37 @RequestMapping(value = "/session-read", method = RequestMethod.GET)
38 public ModelAndView readSession(HttpServletRequest request) {
39 HttpSession session = request.getSession();
40 Object sessionValue = session.getAttribute(sessionKey);
41 ModelAndView model = new ModelAndView();
42 if (sessionValue != null) {
43 model.addObject(sessionKey, sessionValue);
44 }
45
46 try {
47 //显示几个IP到页面,用于辅助判断本次Http请求转发到了哪台server
48 String hostInfo = "InetAddress.getLocalHost() = "
49 + java.net.InetAddress.getLocalHost()
50 + "<br/>request.getRemoteAddr() = "
51 + request.getRemoteAddr() + ":" + request.getRemotePort()
52 + "<br/>x-forwarded-for = " + getUserReadIP(request)
53 + "<br/>request.getLocalAddr() = " + request.getLocalAddr()
54 + ":" + request.getLocalPort();
55 model.addObject("host", hostInfo);
56
57 } catch (Exception e) {
58
59 }
60 model.setViewName("session/read");
61 return model;
62 }
63
64 // 获取用户真实IP
65 private String getUserReadIP(HttpServletRequest request) {
66 if (request.getHeader("x-forwarded-for") == null) {
67 return request.getRemoteAddr();
68 }
69 return request.getHeader("x-forwarded-for");
70 }
71
72 }
write.jsp:(写入session)
1 <%@ page language="java" contentType="text/html; charset=UTF-8"
2 pageEncoding="UTF-8"%>
3 <html>
4 <head>
5 <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
6 <title>session write test</title>
7 </head>
8 <body>
9 <h1>Session写入成功!</h1>
10 </body>
11 </html>
read.jsp:(显示session)
1 <%@ page language="java" contentType="text/html; charset=UTF-8"
2 pageEncoding="UTF-8"%>
3 <html>
4 <head>
5 <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
6 <title>session read test</title>
7 </head>
8 <body>
9 <h1>Session("test"):${test}</h1>
10 <h1>${host}</h1>
11 </body>
12 </html>
准备就绪,依次以domain模式启动master server、slave server上的jboss,最后启动apache server。
然后访问:
http://172.21.129.181/ModClusterSample/session-write.do 写入session
继续访问:
http://172.21.129.181/ModClusterSample/session-read.do 读取session
从输出的几个IP看,本次请求apache转发到了 172.21.129.128上(即:slave Server),user客户端的IP为 172.21.129.57,而apache server的IP为172.21.129.181
另外第一行表明正确读取到了session值:sample value
这时进入master server的jboss控制台,将slave master上的jboss server给stop掉
再次刷新user机器上的http://172.21.129.181/ModClusterSample/session-read.do
可以看到,因为slave server上的jboss server已经被停掉了,所以本次http请求被转发到了172.21.129.181上(即master server),但是session值仍然能正常输出,说明session值在写入的同时,确实已经被复制到二台jboss server上了,session replication验证成功!
- 【Dev Club分享】微信读书iOS性能优化
- [svn: E155004]svn update报database is locked错误的解决办法
- WordPress高亮插件:Crayon Syntax Highlighter加载优化
- 深入理解 ButterKnife,让你的程序学会写代码
- JS+CSS让网站嗨起来,博客要被玩坏了!
- Linux系统zip压缩命令详细参数,附文件排除选项的正确用法
- 浅谈Android自定义锁屏页的发车姿势
- 移动App入侵与逆向破解技术-iOS篇
- 启用WP Super Cache纯代码版本之后的一些优化措施
- WP Super Cache静态缓存插件纯代码版(兼容多域名网站)
- 【Dev Club分享】React Native项目实战总结。
- HTML 5 视频直播一站式扫盲
- Golang之chan/goroutine
- 原创插件:WordPress博客友好对话框+文章随机推荐滚动条插件(附代码版)
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- 浏览器
- CSS样式规则及字体样式
- 引入CSS样式表(书写位置)
- CSS复合选择器
- 不是吧,Serverless 还能这么玩?
- 这一行代码,能让你的 Python 运行速度提高 100 倍!
- 【52期】记一道简单的Java面试题,但答错率很高!
- 面向隐私 AI 的 TensorFlow 深度定制化实践
- 别再问如何用Python提取PDF内容了!
- gff文件转换成gtf文件
- R的save,load函数和 .rda文件
- 10行Python代码自动清理电脑内重复文件,解放双手!
- 【一天一大 lee】二叉树的后序遍历 (难度:中等) - Day20200929
- 一日一技:在Golang下如何相对简单地开发爬虫?
- 原创 | 一文读懂正态分布与贝塔分布