`
wbj0110
  • 浏览: 1557132 次
  • 性别: Icon_minigender_1
  • 来自: 上海
文章分类
社区版块
存档分类
最新评论

高扩展Web应用HTTP Session共享方案

阅读更多

在构建能够灵活地进行水平扩展、高可用性的Java Web应用程序时候,对http session的处理策略很大程度决定了应用程序的扩展性、可用性。一般而言对http session有如下的处理方案: 

1、在服务器端不保存Session,完全无状态 

     对于不需要保持用户状态的Web应用,采用Stateless是最为恰当的,因此就不存在Session共享的问题。REST (Representational State Transfer) 算是最为典型的例子。 

2、基于浏览器Cookie的Session共享 

      此种方案把用户相关的Session信息存储到浏览器的Cookie中,也称为客户端Session。 

      采用Flash Cookie、URL重写的方式传递Session信息的方案也可以归为此类。 

      缺点:只能够存储字符串、数值等基本类型的数据;Cookie大小存在限制;安全性;带宽及数据解压缩、网络传输性能问题。 

3、基于数据库的Session共享,实现分布式应用间Session共享 

     此种方案把Session信息存储到数据库表,这样实现不同应用服务器间Session信息的共享。诸如Websphere Portal、Weblogic Portal都采用了类似的方案。 

     Tomcat Persistent Manager 的JDBC Based Store 提供了类似实现机制,表结构如下: 

        create table tomcat_sessions ( 
            session_id     varchar(100) not null primary key, 
            valid_session  char(1) not null, 
            max_inactive   int not null, 
            last_access    bigint not null, 
            app_name       varchar(255), 
            session_data   mediumblob, 
            KEY kapp_name(app_name) 
          ); 

        优点:实现简单 

        缺点:由于数据库服务器相对于应用服务器更难扩展且资源更为宝贵,在高并发的Web应用中,最大的性能瓶颈通常在于数据库服务器。因此如果将Session存储到数据库表,频繁的增加、删除、查询操作很容易造成数据库表争用及加锁,最终影响业务。 



4、基于应用服务器/Servlet容器的Clustering机制 

        一些常用的应用服务器及Servlet容器的Clustering机制可以实现Session Replication的功能,例如Tomcat Clustering/Session Replication、Jboss buddy replication。 

         缺点:基于Clustering的Session复制性能很差,扩展性也很不行。 

5、基于NFS的Session共享 

         通过NFS方式来实现各台服务器间的Session共享,各台服务器只需要mount共享服务器的存储Session的磁盘即可,实现较为简单。但NFS对高并发读写的性能并不高,在硬盘I/O性能和网络带宽上存在较大瓶颈,尤其是对于Session这样的小文件的频繁读写操作。 

        基于磁盘阵列/SAN/NAS等共享存储的方案道理也类似。 

6、基于Terracotta、Ehcache、JBossCache等Java Caching方案实现Session共享 

    如果系统架构是Java体系,可以考虑采用Terracotta、Ehcache、JbossCache、Oscache等Java Caching方案来实现Session 共享。 

    缺点:架构用于非java体系很不方便;对于是诸如静态页面之类的缓存,采用Memcached的方案比Java更为高效 

7、基于Memcached/Tokyo Tyrant 等Key-Value DB的Session共享 

    整体说来此种方案扩展性最好,推荐使用。 

    原理:Tomcat 服务器提供了org.apache.catalina.session.StandardManager 和org.apache.catalina.session.PersistentManager用于Session对象的管理,可以自定义PersistentManager的 

Store 类来实现自己Memcached、Tokyo Tyrant、Redis等Key-Value DB的客户端。 

    以Memcached的客户端为例(摘自Use MemCacheStore in Tomcat): 

Java代码   收藏代码
  1. package com.yeeach;  
  2. import com.danga.MemCached.MemCachedClient;   
  3. import com.danga.MemCached.SockIOPool;  
  4.   
  5. public class MemCacheStore extends StoreBase implements Store {  
  6.   
  7.     /** 
  8.      * The descriptive information about this implementation. 
  9.      */  
  10.     protected static String info = "MemCacheStore/1.0";  
  11.   
  12.     /** 
  13.      * The thread safe and thread local memcacheclient instance. 
  14.      */  
  15.     private static final ThreadLocal<MemCachedClient> memclient = new ThreadLocal<MemCachedClient>();  
  16.   
  17.     /** 
  18.      * The server list for memcache connections. 
  19.      */  
  20.     private List<String> servers = new ArrayList<String>();  
  21.   
  22.     /** 
  23.      * all keys for current request session. 
  24.      */  
  25.     private List<String> keys = Collections  
  26.             .synchronizedList(new ArrayList<String>());  
  27.   
  28.     /** 
  29.      * Return the info for this Store. 
  30.      */  
  31.     public String getInfo() {  
  32.         return (info);  
  33.     }  
  34.   
  35.     /** 
  36.      * Clear all sessions from the cache. 
  37.      */  
  38.     public void clear() throws IOException {  
  39.         getMemcacheClient().flushAll();  
  40.         keys.clear();  
  41.     }  
  42.   
  43.     /** 
  44.      * Return local keyList size. 
  45.      */  
  46.     public int getSize() throws IOException {  
  47.         return getKeyList().size();  
  48.     }  
  49.   
  50.     /** 
  51.      * Return all keys 
  52.      */  
  53.     public String[] keys() throws IOException {  
  54.         return getKeyList().toArray(new String[] {});  
  55.     }  
  56.   
  57.     /** 
  58.      * Load the Session from the cache with given sessionId. 
  59.      * 
  60.      */  
  61.     public Session load(String sessionId) throws ClassNotFoundException,  
  62.             IOException {  
  63.   
  64.         try {  
  65.   
  66.             byte[] bytes = (byte[]) getMemcacheClient().get(sessionId);  
  67.             if (bytes == null)  
  68.                 return null;  
  69.             ObjectInputStream ois = bytesToObjectStream(bytes);  
  70.   
  71.             StandardSession session = (StandardSession) manager  
  72.                     .createEmptySession();  
  73.             session.setManager(manager);  
  74.             session.readObjectData(ois);  
  75.             if (session.isValid() && !keys.contains(sessionId)) {  
  76.                 keys.add(sessionId);  
  77.             }  
  78.             return session;  
  79.   
  80.         } catch (Exception e) {  
  81.             return (null);  
  82.         }  
  83.     }  
  84.   
  85.     /** 
  86.      * transform a vaild Session from objectinputstream. 
  87.      * Check which classLoader is responsible for the current instance. 
  88.      * 
  89.      * @param bytes 
  90.      * @return ObjectInputStream with the Session object. 
  91.      * @throws IOException 
  92.      */  
  93.     private ObjectInputStream bytesToObjectStream(byte[] bytes)  
  94.             throws IOException {  
  95.         ByteArrayInputStream bais = new ByteArrayInputStream(bytes);  
  96.         ObjectInputStream ois = null;  
  97.         Loader loader = null;  
  98.         ClassLoader classLoader = null;  
  99.         Container container = manager.getContainer();  
  100.         if (container != null)  
  101.             loader = container.getLoader();  
  102.         if (loader != null)  
  103.             classLoader = loader.getClassLoader();  
  104.         if (classLoader != null)  
  105.             ois = new CustomObjectInputStream(bais, classLoader);  
  106.         else  
  107.             ois = new ObjectInputStream(bais);  
  108.         return ois;  
  109.     }  
  110.   
  111.     /** 
  112.      * remove the session with given sessionId 
  113.      */  
  114.     public void remove(String sessionId) throws IOException {  
  115.         getMemcacheClient().delete(sessionId);  
  116.         List<String> keyList = getKeyList();  
  117.         keyList.remove(sessionId);  
  118.     }  
  119.   
  120.     /** 
  121.      * Store a objectstream from the session into the cache. 
  122.      */  
  123.     public void save(Session session) throws IOException {  
  124.         ByteArrayOutputStream baos = new ByteArrayOutputStream();  
  125.         ObjectOutputStream oos = new ObjectOutputStream(baos);  
  126.         StandardSession standard = (StandardSession) session;  
  127.         standard.writeObjectData(oos);  
  128.         getMemcacheClient().add(session.getId(), baos.toByteArray());  
  129.         Object ob = getMemcacheClient().get(session.getId());  
  130.         List<String> keyList = getKeyList();  
  131.         keyList.add(session.getId());  
  132.     }  
  133.   
  134.     /** 
  135.      * 
  136.      * @return 
  137.      */  
  138.     private List<String> getKeyList() {  
  139.         return keys;  
  140.     }  
  141.   
  142.     /** 
  143.      * Simple instanc of the Memcache client and SockIOPool. 
  144.      * @return memchacheclient 
  145.      */  
  146.     private MemCachedClient getMemcacheClient() {  
  147.         if (memclient == null) {  
  148.   
  149.             Integer[] weights = { 1 };  
  150.             // grab an instance of our connection pool  
  151.             SockIOPool pool = SockIOPool.getInstance();  
  152.             if (!pool.isInitialized()) {  
  153.                 String[] serverlist = servers.toArray(new String[] {});  
  154.                 // set the servers and the weights  
  155.                 pool.setServers(serverlist);  
  156.                 pool.setWeights(weights);  
  157.   
  158.                 // set some basic pool settings  
  159.                 // 5 initial, 5 min, and 250 max conns  
  160.                 // and set the max idle time for a conn  
  161.                 // to 6 hours  
  162.                 pool.setInitConn(5);  
  163.                 pool.setMinConn(5);  
  164.                 pool.setMaxConn(250);  
  165.                 pool.setMaxIdle(1000 * 60 * 60 * 6);  
  166.   
  167.                 // set the sleep for the maint thread  
  168.                 // it will wake up every x seconds and  
  169.                 // maintain the pool size  
  170.                 pool.setMaintSleep(30);  
  171.   
  172.                 // set some TCP settings  
  173.                 // disable nagle  
  174.                 // set the read timeout to 3 secs  
  175.                 // and don't set a connect timeout  
  176.                 pool.setNagle(false);  
  177.                 pool.setSocketTO(3000);  
  178.                 pool.setSocketConnectTO(0);  
  179.   
  180.                 // initialize the connection pool  
  181.                 pool.initialize();  
  182.             }  
  183.   
  184.             // lets set some compression on for the client  
  185.             // compress anything larger than 64k  
  186.   
  187.             memclient.get().setCompressEnable(true);  
  188.             memclient.get().setCompressThreshold(64 * 1024);  
  189.         }  
  190.         return memclient.get();  
  191.     }  
  192.   
  193.     public List<String> getServers() {  
  194.         return servers;  
  195.     }  
  196.   
  197.     public void setServers(String serverList) {  
  198.         StringTokenizer st = new StringTokenizer(serverList, ", ");  
  199.         servers.clear();  
  200.         while (st.hasMoreTokens()) {  
  201.             servers.add(st.nextToken());  
  202.         }  
  203.     }  
  204.   
  205. }  


Tomcat 的配置文件: 

Xml代码   收藏代码
  1. <Context path="/test" docBase="test.war">  
  2.     <Manager className="org.apache.catalina.session.PersistentManager"  
  3.         distributable="true">  
  4.         <Store className="com.yeeach.MemcachedStore"  
  5.             servers="192.168.0.111:11211,192.168.0.112:11211" />  
  6.     </Manager>  
  7. </Context>  



    这里只是作为测试演示了在Tomcat中集成Memcached的实现方案。并没有考虑性能、高可用、Memcached 存储Session的持久化(可以使用Memcachedb实现)、Session管理等问题。 

    针对Tomcat与Memcached集成有一个开源项目memcached-session-manager  功能实现相对完善,尤其是其设计思想值得借鉴。 

    The memcached session manager installed in a tomcat holds all sessions locally in the own jvm, just like the StandardManager does it as well. 

    Additionally, after a request was finished, the session (only if existing) is additionally sent to a memcached node for backup. 

    When the next request for this session has to be served, the session is locally available and can be used, after this second request is finished the session is updated in the memcached node. 



    对于采用Tokyo Tyrant、Redis等当下流行的Key-Value DB实现机制类似。

 

 

大家可以加我个人微信号:scccdgf

 

 

或者关注soledede的微信公众号:soledede
  
分享到:
评论

相关推荐

    JAVA高并发高性能高可用高扩展架构视频教程

    session跨域共享 JAVANIO原理详解 高并发数据库(Mysql数据库性能优化) 软件质量管控 企业常用框架springMVC基于注解+xml配置方式实现链接 WEB服务器优化之Tomcat7性能调优 JVM概述 Java开发技术之(项目工程的日志...

    JWT-Json Web Token-目前最流行跨域身份验证解决方案

    这种模式的最大问题是没有分布式架构,不方便进行横向扩展,这种模式只适合于单体应用模式。如果需要进行服务集群则需要处理好共享session的问题。 如果一个庞大的系统需要按服务分解为多个独立的服务,使用分布式...

    基于REST的Web服务客户端v5.6.6

    【无需登录共享浏览器的Session】 本谷歌Chrome扩展程序可以帮助开发人员开发和测试REST风格的Web服务API与所有支持的方法,比如GET,POST,PUT,PATCH,DELETE 和 OPTIONS。 该扩展程序支持HTTP基本身份验证,支持...

    缓存还可以这么玩儿.pptx

    缓存包括Session 会话状态及应用横向扩展时的状态数据等,这类数据一般是难以恢复的,对可用性要求较高,多应用于高可用集群; 4) 并行处理.通常涉及大量中间计算结果需要共享; 5) 事件处理.分布式缓存提供了针对...

    jwt简单的介绍和了解

    cookie+session这种模式通常是保存在内存中,而且服务从单服务到多服务会面临的session共享问题,随着用户量的增多,开销就会越大。而JWT不是这样的,只需要服务端生成token,客户端保存这个token,每次请求携带这...

    Openresty_For_Windows_1.7.10.zip

    OpenResty 是一个通过扩展 nginx 的快速 Web 应用服务器。 Nginx Openresty For Windows (NOW) 是带有 Openresty 的 Windows 版本中的 Nginx。 它有一些特点: 高性能 并发两万多个连接 多进程 支持共享内存 支持...

    ASP.NET4高级程序设计(第4版) 3/3

    8.2.1 Web应用程序和DataSet 250 8.2.2 XML集成 251 8.3 DataSet类 251 8.4 DataAdapter类 252 8.4.1 填充DataSet 253 8.4.2 使用多个表和关系 254 8.4.3 查找特定行 257 8.4.4 在数据访问类里使用...

    ASP.NET4高级程序设计第4版 带目录PDF 分卷压缩包 part1

    8.2.1 Web应用程序和DataSet 8.2.2 XML集成 8.3 DataSet类 8.4 DataAdapter类 8.4.1 填充DataSet 8.4.2 使用多个表和关系 8.4.3 查找特定行 8.4.4 在数据访问类里使用DataSet 8.4.5 数据绑定 8.5...

    TP-LINK WR703N OpenWrt刷机教程及固件 4M ,稳定 支持3G和打印机共享外接卡簧

    因试过4M空间集成脱机、NAS等有难度,故不再出4M的脱机固件,请用extroot扩展后自行安装。 4. MentoHUST没有条件测试,如不能自动获取IP,请把Web界面的DHCP script的值由“udhcpc -i”改成“udhcpc -renew”试试...

    java-servlet-api.doc

    作为一个Servlet的开发者,你必须决定你的Web应用是否处理客户机不加入或不能加入Session。服务器会在Web服务器或Servlet规定的时间内维持一个Session对象。当Session终止时,服务器会释放Session对象以及所有绑定在...

    红顶网络办公系统3.0

    1、COOKIES、SESSION二种记录用户资料方式,使不支持COOKIESE的浏览器自动选择SESSION方式记录用户资料 2、免费、开源,非凡的访问速度和强大的负载能力。红顶网络办公系统一直坚持免费+开源的策略,依靠优质的服务...

    TP-LINK WR703N OpenWrt刷机教程及固件 4M ,稳定 支持3G和打印机共享外接网卡

    因试过4M空间集成脱机、NAS等有难度,故不再出4M的脱机固件,请用extroot扩展后自行安装。 4. MentoHUST没有条件测试,如不能自动获取IP,请把Web界面的DHCP script的值由“udhcpc -i”改成“udhcpc -renew”试试...

    net学习笔记及其他代码应用

    优点: 分工明确,条理清晰,易于调试,而且具有可扩展性。 缺点: 增加成本。 12.在下面的例子里 using System; class A { public A() { PrintFields(); } public virtual void PrintFields(){} } ...

    asp.net知识库

    ASP.NET 2.0构建动态导航的Web应用程序(TreeView和Menu ) 体验.net2.0的优雅(3) -- 为您的 SiteMap 添加 控制转发功能 GridView控件使用经验 ASP.NET 2.0:弃用 DataGrid 吧,有新的网格控件了! ASP.NET2.0控件...

    超级有影响力霸气的Java面试题大全文档

    多态性语言具有灵活、抽象、行为共享、代码共享的优势,很好的解决了应用程序函数同名问题。 5、String是最基本的数据类型吗?  基本数据类型包括byte、int、char、long、float、double、boolean和short。  java....

    22春“计算机科学与技术”专业《web技术》在线作业一答案参考6.docx

    Tomcat建立的web应用对文件的大小写是不敏感的。( ) A.正确 B.错误 参考答案:B 3. 若要以加粗宋体、6号字显示"hello"以下用法中,正确的是( ) 若要以加粗宋体、6号字显示"hello"以下用法中,正确的是( ) A、bfont ...

    万辰OA2·5正版企业美化版

    10、集成网络硬盘组件,提供便捷的局域网、广域网文件共享方案 11、集成商业管理组件,轻松的管理客户、供应商资料和产品销售记录 12、集成内部邮件、即时短信、文件柜、聊天室、论坛等模块,提供企业内部信息交流...

    万辰OA2.5正版企业美化版

    10、集成网络硬盘组件,提供便捷的局域网、广域网文件共享方案 11、集成商业管理组件,轻松的管理客户、供应商资料和产品销售记录 12、集成内部邮件、即时短信、文件柜、聊天室、论坛等模块,提供企业内部信息交流...

    Session Share-crx插件

    Web会话可以通过此插件传递给其他Internet用户。两个用户都必须安装该插件。1.在“上下文”菜单中“复制当前会话”。2.将复制到剪贴板复制到收件人的代码转发。3.收件人将代码复制到浏览器的地址栏,然后单击“接管...

Global site tag (gtag.js) - Google Analytics