实现目的:
在使用Nginx+Tomcat+zk项目实现负载均衡的时候,由于Nginx对不同的请求分发到某一个Tomcat,Tomcat在运行的时候分别是不同的容器里,因为会出现session不同步或者丢失的问题。
通过tomcat+redis+zk项目实现session共享
一、服务器环境配置
tomcat 版本7.0.62
redis 版本 3.0.1
jdk 版本 1.7.0_79
二、tomcat 下面配置 安装配置redis
将tomcat-redis-session-1.0-SNAPSHOT.jar、jedis-2.7.2.jar、commons-pool2-2.0.jar 三个jar包放在tomcat1实例下的lib目录下。
三、修改tomcat实例下conf/contex.xml文件
<?xml version='1.0' encoding='utf-8'?>
<Context>
<WatchedResource>WEB-INF/web.xml</WatchedResource>
<!-- tomcat-redis-session共享配置 -->
<Valve className="com.orangefunction.tomcat.redissessions.RedisSessionHandlerValve" />
<Manager className="com.orangefunction.tomcat.redissessions.RedisSessionManager"
host="192.168.0.159"
port="6379"
database="0"
maxInactiveInterval="60" />
</Context>
四、部署zk项目到tomcat zk项目源码下载
五、启动redis——启动tomcat ——访问登录界面
1.输入完用户名密码点击登录后发现 当前界面失效了。
![点击登录结果查询不到这个界面了](https://img-blog.csdnimg.cn/img_convert/448eaa5bde6e3d84b683e25bba9a0317.png
2.然后就查看zk的配置,发现每次请求会被DHtmlLayoutServlet拦截
web.xml
<servlet>
<description>ZK loader for ZUML pages</description>
<servlet-name>zkLoader</servlet-name>
<servlet-class>org.zkoss.zk.ui.http.DHtmlLayoutServlet</servlet-class>
<init-param>
<param-name>update-uri</param-name>
<param-value>/zkau</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>zkLoader</servlet-name>
<url-pattern>*.zul</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>zkLoader</servlet-name>
<url-pattern>*.zhtml</url-pattern>
</servlet-mapping>
3.打开 DHtmlLayoutServlet源码通过调试发现
初始化界面的时候回去判断当前页面是否有创建一个Desktop ,如果通过key在缓存中找不到这个Desktop 就会新增一个Desktop 。
protected boolean process(Session sess,
HttpServletRequest request, HttpServletResponse response, String path,
boolean bRichlet)
throws ServletException, IOException {
final WebApp wapp = sess.getWebApp();
final WebAppCtrl wappc = (WebAppCtrl)wapp;
final Configuration config = wapp.getConfiguration();
final boolean bInclude = Servlets.isIncluded(request);
final boolean compress = _compress && !bInclude;
final Writer out = compress ? (Writer)new StringWriter(): response.getWriter();
final DesktopRecycle dtrc = bInclude ? null: config.getDesktopRecycle();
final ServletContext ctx = getServletContext();
Desktop desktop = dtrc != null ?
DesktopRecycles.beforeService(dtrc, ctx, sess, request, response, path): null;
try {
if (desktop != null) { //recycle
final Page page = Utils.getMainPage(desktop);
if (page != null) {
final Execution exec = new ExecutionImpl(
ctx, request, response, desktop, page);
WebManager.setDesktop(request, desktop);
wappc.getUiEngine().recycleDesktop(exec, page, out);
} else
desktop = null; //something wrong (not possible; just in case)
}
if (desktop == null) {
//如果不存在desktop 就会新建一个 desktop
desktop = _webman.getDesktop(sess, request, response, path, true);
.......
}
创建的desktop 会被添加到SimpleDesktopCache._desktops 缓存当中去。
private final Cache _desktops;
//添加新的桌面到缓存 _desktops
public void addDesktop(Desktop desktop) {
final boolean added;
final Desktop old;
synchronized (_desktops) {
old = _desktops.put(desktop.getId(), desktop);
}
if (old != null) {
_desktops.put((old).getId(), old); //recover
log.warning(
desktop == old ? "Register a desktop twice: "+desktop:
"Replicated ID: "+desktop+"; already used by "+old);
}
//if (log.debugable()) log.debug("After added, desktops: "+_desktops);
}
当输入完用户名密码之后点击登录按钮又会被DHtmlLayoutServlet所拦截,这次请求会通过之前存储桌面的id去查找缓存中是否还存在当前的desktop。
SimpleDesktopCache.getDesktopIfAny(String desktopId)
这里去通过id 无法查找到对应的桌面,zk就会认为当前页面已经失效,登录请求被中断。
问题总结:(由于对zk理解能力不够,描述不够专业还请多多谅解。)
不知道为什么tomact下面配置了redis后,zk项目的Desktop 就没有存储到缓存当中去了。
由于没有找到合适的zk项目session共享的方案,希望大家有成功案例的朋友告诉下如果去配置。