`
xhfei
  • 浏览: 115428 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

httpsession的原理及负载均衡

阅读更多
前阵子去面试正好被问到httpsession和cookie,今天正巧有个分享会讲到了session及负载均衡方面的东东,拿出来分享一下,以前也曾研究过负载均衡,在session共享的时候遇到了问题,这里面正好有解答,目前最好的办法是memcached。

1、Servlet  Session基础

包括servlet session、http cookie原理讲解。

2、Session管理的原理

可以参考一下这篇http://blog.sina.com.cn/s/blog_4a157f470100a81z.html

有几个问题大家思考一下:

         1)、怎样相对准确获取同时在线用户数,怎样实现类似于聊天室的管理员把用户踢出聊天室的功能,怎样实现类似在线聊天室的功能?
      可以借鉴一下clickstream(http://www.opensymphony.com/clickstream/)的实现机制。
         2)、怎样实现同一账号同一时间点只能有一个账号在线

         3)、在多标签的浏览器中(例如ie8、firefox、chrome),用户开几个标签使用同一个web应用,是一个session还是多个session

         4)、struts2中避免用户重复提交同一页面的机制?

         5)、怎样实现类似于gmail、sina等大型网站的用户自动登录功能

         6)、怎样实现类似于在线投票防止同一用户重复投票的功能。具体可以参考以前发过的《基于浏览器的客户跟踪技术概述》

还有其他类似的问题实际上也与Session有关。

3、多台服务器负载均衡情况下的Session管理
前段时间发过一篇写的《多台服务器负载均衡情况下的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):
package com.yeeach; import com.danga.MemCached.MemCachedClient; 
import com.danga.MemCached.SockIOPool;  
 public class MemCacheStore extends StoreBase implements Store {           /**          
* The descriptive information about this implementation. 
 */        
 protected static String info = "MemCacheStore/1.0";       
 /**          
* The thread safe and thread local memcacheclient instance.          
*/        
 private static final ThreadLocal<MemCachedClient> memclient = new ThreadLocal<MemCachedClient>();          

 /**          
* The server list for memcache connections.          
*/        
 private List<String> servers = new ArrayList<String>();           
/**          
* all keys for current request session.          
*/         
private List<String> keys = Collections.synchronizedList(newArrayList<String>());           
/**         
 * Return the info for this Store.          
*/         
public String getInfo() {               
 return (info);       
  }          
 /**         
 * Clear all sessions from the cache.          
*/         
public void clear() throws IOException {                getMemcacheClient().flushAll();               
 keys.clear();         
}           
/**         
 * Return local keyList size.          
*/         

public int getSize() throws IOException {                
return getKeyList().size();         }           
/**          
* Return all keys          
*/         
public String[] keys() throws IOException {               
 return getKeyList().toArray(new String[] {});         }           
/**         
 * Load the Session from the cache with given sessionId.          *          */    
     
public Session load(String sessionId) throws ClassNotFoundException,IOException {                  

try {                         
 byte[] bytes = (byte[]) getMemcacheClient().get(sessionId);                        
if (bytes == null)                                
     return null;                       
 ObjectInputStream ois = bytesToObjectStream(bytes);                          StandardSession session = (StandardSession) manager.createEmptySession();                        session.setManager(manager);                        session.readObjectData(ois);                        
if (session.isValid() && !keys.contains(sessionId)) {                               
 keys.add(sessionId);                       
 }                        
return session;                  
} catch (Exception e) {                       
 return (null);               
 }         
}           
/**          
* transform a vaild Session from objectinputstream.         
 * Check which classLoader is responsible for the current instance.          *          
* @param bytes          
* @return ObjectInputStream with the Session object.          
* @throws IOException          */        

 private ObjectInputStream bytesToObjectStream(byte[]bytes) throws IOException {               
     ByteArrayInputStream bais = new ByteArrayInputStream(bytes);                ObjectInputStream ois = null;                
Loader loader = null;                
ClassLoader classLoader = null;                
Container container = manager.getContainer();                
if (container != null)                        
loader = container.getLoader();                 
if (loader != null)                        
classLoader = loader.getClassLoader();                
if (classLoader != null)                        
ois = new CustomObjectInputStream(bais, classLoader);                else                        
ois = new ObjectInputStream(bais);                
return ois;         
}           
/**          
* remove the session with given sessionId         
 */         
public void remove(String sessionId) throws IOException {   
             getMemcacheClient().delete(sessionId);                
              List<String> keyList = getKeyList(); 
               keyList.remove(sessionId);        
 }          

 /**          
* Store a objectstream from the session into the cache.          
*/  


public void save(Session session) throws IOException {   
       ByteArrayOutputStream baos = new ByteArrayOutputStream();                ObjectOutputStream oos = new ObjectOutputStream(baos);                StandardSession standard = (StandardSession) session;    
            standard.writeObjectData(oos);                getMemcacheClient().add(session.getId(), baos.toByteArray());                Object ob = getMemcacheClient().get(session.getId());                List<String> keyList = getKeyList();                keyList.add(session.getId());        
 }          
 /**          
*          
* @return          
*/         
private List<String> getKeyList() {                
return keys;         
}           
/**          
* Simple instanc of the Memcache client and SockIOPool.          
* @return memchacheclient          
*/        
 private MemCachedClient getMemcacheClient() {               
 if (memclient == null) {                          
Integer[] weights = { 1 };                        
// grab an instance of our connection pool                        
SockIOPool pool = SockIOPool.getInstance();                        
if (!pool.isInitialized()) {                               
 String[] serverlist = servers.toArray(new String[] {});                                
// set the servers and the weights                                pool.setServers(serverlist);                                pool.setWeights(weights);                                  
// set some basic pool settings                               
 // 5 initial, 5 min, and 250 max conns                              
  // and set the max idle time for a conn                                
// to 6 hours                                pool.setInitConn(5);                                pool.setMinConn(5);                                pool.setMaxConn(250);                               
 pool.setMaxIdle(1000 * 60 * 60 * 6);                                
 // set the sleep for the maint thread                              
  // it will wake up every x seconds and                              
  // maintain the pool size                                pool.setMaintSleep(30);                                 
 // set some TCP settings                               
 // disable nagle                               
 // set the read timeout to 3 secs                                
// and don't set a connect timeout                                pool.setNagle(false);                                pool.setSocketTO(3000);                                pool.setSocketConnectTO(0);                                 
 // initialize the connection pool                                pool.initialize();                        }                          
// lets set some compression on for the client                        
// compress anything larger than 64k                          memclient.get().setCompressEnable(true);                        memclient.get().setCompressThreshold(64 * 1024);               
 }               
 return memclient.get();         
}       

    public List<String> getServers() {               
            return servers;    
     }          
 public void setServers(String serverList) {               
 StringTokenizer st = new StringTokenizer(serverList, ", ");                servers.clear();               
 while (st.hasMoreTokens()) {                        servers.add(st.nextToken());              
  }      
 }   
} 
Tomcat 的配置文件: 
<Context path="/test" docBase="test.war">        
 <Manager className="org.apache.catalina.session.PersistentManager"                distributable="true">              
  <Store className="com.yeeach.MemcachedStore"                        servers="192.168.0.111:11211,192.168.0.112:11211" />        
 </Manager>   
</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实现机制类似。
分享到:
评论

相关推荐

    主要讲J2EE集群原理 ,很不错。

    Web层的集群主要涉及Web负载均衡和HTTPSession失败接管。Web负载均衡器可以是专门的硬件设备,如F5 Load Balancer,也可以是带有负载均衡插件的服务器,甚至是一些嵌入式Linux设备。HTTPSession失败接管则需要服务器...

    关于session.doc

    3. **负载均衡**:对于使用集群架构的应用程序,Session可以通过集中式存储来解决负载均衡带来的问题。 #### 五、理解javax.servlet.http.HttpSession 在Java Web开发中,`javax.servlet.http.HttpSession`接口是...

    J2EE_Clustering 王昱.pdf

    它通过负载均衡和容错恢复机制,确保即使在部分节点故障的情况下,服务依然可以持续提供,从而增强系统的容错性能和用户体验。 ### 基本术语解析 - **可扩展性(Scalability)**:指系统在不降低性能的前提下,能够...

    跨服务器session应用详解

    - 使用负载均衡器共享session数据。 - 数据库存储session:将session信息存储在数据库中,所有服务器都能访问。 - Session复制:服务器间实时同步session数据。 - 使用共享缓存服务,如Memcached或Redis。 八、总结...

    Session详细解答

    3. **负载均衡器**:配置负载均衡器以便在不同服务器之间共享Session数据。 #### 八、总结 Session机制是现代Web应用中不可或缺的一部分,它解决了HTTP协议无状态性的限制,使得复杂的交互式应用成为可能。通过对...

    Springboot实现多服务器session共享

    如果开发者需要对项目进行横向拓展搭建集群,那么可以用一些硬件和软件工具来做负载均衡,此时,来自同一用户的HTTP请求有可能会被发送到不同的实例上去,如何保证各个实例之间的Session同步就成为了一个必须解决的...

    java web在线聊天系统

    3. 负载均衡:当用户量增大时,可部署多台服务器,通过负载均衡器分发请求,提高系统整体性能。 总结,Java Web在线聊天系统通过Servlet技术实现了基于HTTP的通信,结合WebSockets或其他实时通信机制,为用户提供...

    redis 集群共享Session

    - **负载均衡器配置**:在负载均衡器如Nginx上,可以配置不依赖SessionID的分发策略,如IP Hash,确保同一用户请求始终被分发到同一台服务器,保证Session的一致性。 5. **安全性考虑** 尽管Redis提供了安全性,...

    (转)讲解各种session

    - Sticky Sessions:负载均衡器会记住用户请求的特定服务器,将后续请求转发给同一服务器,避免Session冲突。 - Session集中存储:使用共享的Session存储(如数据库或缓存),所有服务器都从同一位置读写Session。 ...

    基于JSP+JavaBean+Servlet做的简单的学生选课系统.zip

    【性能优化】可能包括缓存技术(如使用HttpSession缓存用户信息)、负载均衡(多台服务器共享用户负载)、数据库查询优化(避免全表扫描,使用索引)等。 总的来说,这个学生选课系统展示了如何使用JSP、Servlet和...

    译How Tomcat Works(第四章)

    会话管理包括创建、更新、移除会话,以及在集群环境下的会话复制和负载均衡。 7. **安全性**: Tomcat提供了多种安全特性,如角色基础的访问控制(RBAC)、SSL/TLS加密,以及通过`Realm`组件实现的身份验证。 8. ...

    java基于用户会话的开发程序

    而会话粘滞则是通过负载均衡器将特定用户的请求始终定向到同一台服务器,避免会话信息在多台服务器之间同步的复杂性。 在实际开发中,还可以利用第三方库如Spring Session来简化会话管理。Spring Session支持将会话...

    在线聊天室.

    可能的优化策略包括缓存策略、数据库优化、负载均衡等。 在提供的"Test1"文件中,可能包含了实现这些功能的相关代码和资源,例如Servlet类、HTML模板、CSS样式表、JavaScript脚本等。为了深入了解这个在线聊天室的...

    SpringSession+Redis实现Session共享案例

    这样,Session数据可以在多台服务器之间共享,解决了负载均衡下的Session粘滞问题。 - `SpringSession` 提供了对原生Servlet API的透明支持,以及与Spring MVC的集成,使得开发者无需修改大量代码就能启用Session...

    JAVAWEB校园订餐系统项目源码.rar

    10. **部署与运维**:项目部署可能涉及到Tomcat、Apache等Web服务器,还需要了解服务器配置、负载均衡、安全策略等相关知识。 通过学习和分析这个JAVAWEB校园订餐系统项目源码,开发者不仅可以提升JavaWeb开发技能...

    JAVA JSP的聊天室

    8. **性能优化**:对于高并发的聊天室应用,可能需要考虑负载均衡、缓存策略、数据库优化等方法来提高性能。 通过分析和学习这个"jspchat"项目,我们可以深入理解JSP开发、数据库操作、网络通信以及Web应用的安全性...

    servlet小程序-选课

    7. **性能优化**:对于大型选课系统,可能需要使用缓存来减少对数据库的访问,或者通过负载均衡来分散服务器压力。 这个"初学者可用"的项目很可能是简化版的选课系统,旨在帮助学习者理解Servlet如何与Web服务器和...

    网页聊天室

    可以考虑使用线程池来高效地管理并发,或者使用负载均衡技术分散服务器压力。 7. **持久化存储**:为了保留聊天记录,我们可以将数据存储在数据库中,如MySQL或MongoDB。这样即使服务器重启,聊天记录也不会丢失。 ...

    Session登录在线人

    这需要实现Session复制或黏性负载均衡策略。 7. **监控与管理**:在生产环境中,对Session的监控也很重要,包括统计在线人数、查看Session使用情况、检测异常Session等,这有助于优化系统性能和及时发现潜在问题。 ...

Global site tag (gtag.js) - Google Analytics