apache+tomcat+memcached
最近闲的蛋疼,顺便研究下apache+tomcat+memcache,顺便记录一下。
准备工作
- apache http://httpd.apache.org/download.cgi(推荐大家选择2.2.2版本,否则还需要装apr,apr-util等)
- tomcat http://tomcat.apache.org/download-60.cgi
- mod_jk http://archive.apache.org/dist/jakarta/tomcat-connectors/jk/source/jk-1.2.15/jakarta-tomcat-connectors-1.2.15-src.tar.gz
- memcache http://memcached.org/
- xmemcache http://code.google.com/p/xmemcached/downloads/detail?name=xmemcached-1.3.8-bin-with-dependencies.tar.gz&can=2&q=
安装工作
1.apache
#tarxzvfhttpd-2.22.tar.gz
#cdhttpd-2.22
#./configure--prefix=/usr/local/apache--enable-so
#make
#makeinstall
2.mod_jk
#tarxzvfjakarta-tomcat-connectors-1.2.15-src.tar.gz
#cdjakarta-tomcat-connectors-1.2.15-src/jk/native
#./configure--with-apxs=/usr/test/apache/bin/apxs
#make
#cp./apache-2.0/mod_jk.so/usr/test/apache/modules/
3.memcache
这个有点多 详见http://yu-zhang430.iteye.com/admin/blogs/1601197配置工作
# cd /usr/test/apache/conf/ 在httpd.conf最后添加一句
Include conf/jk.conf
# touch jk.conf 在jk.conf写入以下配置
LoadModule jk_module modules/mod_jk.so
JkWorkersFIle conf/workers.properties
JkLogFile conf/jk.log
JkMount /*.jsp balancer//这里负责负载均衡
JkMount /jkstatus.jsp jkstatus//这里负责显示状态
#touch jk.log
#touch workers.properties 在workers.properties写入以下配置
worker.list=balancer,jkstatus
worker.tomcat1.host=localhost
worker.tomcat1.port=8009
worker.tomcat1.type=ajp13
worker.tomcat1.lbfactor=1//设置负载的比重
worker.tomcat2.host=localhost
worker.tomcat2.port=8029
worker.tomcat2.type=ajp13
worker.tomcat2.lbfactor=1//设置负载的比重
注:这里填的port不是tomcat的端口,曾经我填为8080和8081,测试一直不成功,这里的port是2个tomcat的AJP13的端口
worker.balancer.type=lb
worker.balancer.balance_workers=tomcat1,tomcat2
worker.balancer.sticky_session=0这里设置session是否粘帖 0为不粘帖
worker.jkstatus.type=status
到此位置负载均衡完毕。下来我们用Memcached来完成Session同步。
1.修改web.xml添加filter
<filter> <filter-name>session</filter-name> <filter-class>com.filter.SessionFilter</filter-class> </filter> <filter-mapping> <filter-name>session</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
2.添加filter
package com.filter; import java.io.IOException; import java.util.UUID; import javax.servlet.Filter; import javax.servlet.FilterChain; import javax.servlet.FilterConfig; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.http.Cookie; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; /** * Servlet Filter implementation class sessionFilter */ public class SessionFilter implements Filter { private int timout=36000000; @Override public void destroy() { } @Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { HttpServletRequest request=(HttpServletRequest)servletRequest; HttpServletResponse response=(HttpServletResponse)servletResponse; Cookie[] cookies=request.getCookies();//获取cookie String sessionId=""; if(cookies!=null&&cookies.length>0) { for(Cookie item:cookies) { if(item.getName().equals("sessionId")) { sessionId=item.getValue();//如果Cookie存在sessionId 重新计时 item.setMaxAge(timout); } } } if(cookies==null||sessionId.equals("")) { sessionId=UUID.randomUUID().toString(); Cookie cookie=new Cookie("sessionId", sessionId); cookie.setMaxAge(timout); response.addCookie(cookie);//如果Cookie不存在,创建cookie,生成sessionId添加到Cookie } //MyRequestWrapper装饰了httpservletrequest,我们重写一些request的方法 filterChain.doFilter(new MyRequestWrapper(sessionId,request), servletResponse); } @Override public void init(FilterConfig arg0) throws ServletException { } }
3.MyRequestWarpper.java
package com.filter; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequestWrapper; import javax.servlet.http.HttpSession; public class MyRequestWrapper extends HttpServletRequestWrapper { private String sessionId; public MyRequestWrapper(String sessionId,HttpServletRequest request) { super(request); this.sessionId=sessionId; } @Override public HttpSession getSession() { return new HttpSessionWrapper(sessionId, super.getSession());//重写getSession方法 } @Override public HttpSession getSession(boolean create) { return new HttpSessionWrapper(sessionId, super.getSession(create)); } }
3.HttpsessionWrapper.java
package com.filter; import java.util.Enumeration; import java.util.Map; import javax.servlet.ServletContext; import javax.servlet.http.HttpSession; import javax.servlet.http.HttpSessionContext; @SuppressWarnings({"deprecation","rawtypes","static-access"}) public class HttpSessionWrapper implements HttpSession { private String sid = "";//sessionId public static Map map = null;//session private int timeout=1800; private HttpSession session; public HttpSessionWrapper(String sid,HttpSession session) { this.session = session; this.sid = sid; this.map = MyMemcachedCinent.getInstance().getSession(sid,timeout); } public Object getAttribute(String arg0) { return this.map.get(arg0); } public Enumeration getAttributeNames() { return (new Enumerator(this.map.keySet(), true)); } public void invalidate() { this.map.clear(); MyMemcachedCinent.getInstance().removeSession(this.sid); } public void removeAttribute(String arg0) { this.map.remove(arg0); MyMemcachedCinent.getInstance().saveSession(this.sid,timeout, this.map); } @SuppressWarnings("unchecked") public void setAttribute(String arg0, Object arg1) { this.map.put(arg0, arg1); MyMemcachedCinent.getInstance().saveSession(this.sid,timeout, this.map); } public long getCreationTime() { return session.getCreationTime(); } public String getId() { return session.getId(); } public long getLastAccessedTime() { return session.getLastAccessedTime(); } public int getMaxInactiveInterval() { return session.getMaxInactiveInterval(); } public ServletContext getServletContext() { return session.getServletContext(); } public HttpSessionContext getSessionContext() { return session.getSessionContext(); } public Object getValue(String arg0) { return session.getValue(arg0); } public String[] getValueNames() { return session.getValueNames(); } public boolean isNew() { return session.isNew(); } public void putValue(String arg0, Object arg1) { session.putValue(arg0, arg1); } public void removeValue(String arg0) { session.removeValue(arg0); } public void setMaxInactiveInterval(int arg0) { session.setMaxInactiveInterval(arg0); } }
4.Enumerator.java
package com.filter; import java.util.Collection; import java.util.Enumeration; import java.util.Iterator; import java.util.List; import java.util.ArrayList; import java.util.Map; import java.util.NoSuchElementException; @SuppressWarnings({"rawtypes"}) public class Enumerator implements Enumeration { private Iterator iterator = null; public Enumerator(Collection collection) { this(collection.iterator()); } public Enumerator(Collection collection, boolean clone) { this(collection.iterator(), clone); } public Enumerator(Iterator iterator) { super(); this.iterator = iterator; } @SuppressWarnings("unchecked") public Enumerator(Iterator iterator, boolean clone) { super(); if (!clone) { this.iterator = iterator; } else { List list = new ArrayList(); while (iterator.hasNext()) { list.add(iterator.next()); } this.iterator = list.iterator(); } } public Enumerator(Map map) { this(map.values().iterator()); } public Enumerator(Map map, boolean clone) { this(map.values().iterator(), clone); } public boolean hasMoreElements() { return (iterator.hasNext()); } public Object nextElement() throws NoSuchElementException { return (iterator.next()); } }
5.MyMemcachedCinent
package com.filter; import java.io.IOException; import java.util.HashMap; import java.util.Map; import java.util.concurrent.TimeoutException; import net.rubyeye.xmemcached.MemcachedClient; import net.rubyeye.xmemcached.MemcachedClientBuilder; import net.rubyeye.xmemcached.XMemcachedClientBuilder; import net.rubyeye.xmemcached.exception.MemcachedException; import net.rubyeye.xmemcached.utils.AddrUtil; @SuppressWarnings({"rawtypes"}) public class MyMemcachedCinent { private static MyMemcachedCinent myMemcachedCinent; private MemcachedClient client; /** * 初始类的时候启动memcached */ private MyMemcachedCinent(){ MemcachedClientBuilder builder=new XMemcachedClientBuilder(AddrUtil.getAddresses("localhost:11211")); try { client=builder.build(); } catch (IOException e) { e.printStackTrace(); } } /** * MyMemcachedCinent单例 * @author zhangyu DateTime 2012-8-14 上午9:22:51 * @return */ public static synchronized MyMemcachedCinent getInstance() { if(myMemcachedCinent==null) { myMemcachedCinent= new MyMemcachedCinent(); } return myMemcachedCinent; } /** * 获取session * @author zhangyu DateTime 2012-8-14 上午9:18:19 * @param sid * @param timeout * @return */ public Map getSession(String sid,int timeout) { Map map=null; try { map = client.get(sid); if(map==null) { map=new HashMap(); client.set(sid, timeout, map); } } catch (TimeoutException e) { e.printStackTrace(); } catch (InterruptedException e) { e.printStackTrace(); } catch (MemcachedException e) { e.printStackTrace(); } return map; } /** * 添加Session或者更新Session * @author zhangyu DateTime 2012-8-14 上午9:18:32 * @param id * @param timeout * @param session */ public void saveSession(String id,int timeout, Map session) { try { client.set(id,timeout, session); } catch (TimeoutException e) { e.printStackTrace(); } catch (InterruptedException e) { e.printStackTrace(); } catch (MemcachedException e) { e.printStackTrace(); } } /** * 删除Session * @author zhangyu DateTime 2012-8-14 上午9:19:00 * @param id */ public void removeSession(String id) { try { client.delete(id); } catch (TimeoutException e) { e.printStackTrace(); } catch (InterruptedException e) { e.printStackTrace(); } catch (MemcachedException e) { e.printStackTrace(); } } }
大功告成,session是通过Cookie和memcache保存的,如果要更保险点,可以判断下用户的cookie有木有北禁用,吧sessionId拼接到url里