Java Tomcat 6集群配置是否有useDirtyFlag选项?

Java Tomcat 6集群配置是否有useDirtyFlag选项?,java,session,replication,tomcat6,cluster-computing,Java,Session,Replication,Tomcat6,Cluster Computing,在Tomcat 5.0.x中,您可以设置useDirtyFlag=“false”以在每次请求后强制复制会话,而不是检查set/removeAttribute调用 <Cluster className="org.apache.catalina.cluster.tcp.SimpleTcpCluster" managerClassName="org.apache.catalina.cluster.session.SimpleTcpReplicationManag

在Tomcat 5.0.x中,您可以设置useDirtyFlag=“false”以在每次请求后强制复制会话,而不是检查set/removeAttribute调用

<Cluster className="org.apache.catalina.cluster.tcp.SimpleTcpCluster"
                 managerClassName="org.apache.catalina.cluster.session.SimpleTcpReplicationManager"
                 expireSessionsOnShutdown="false"
                 **useDirtyFlag="false"**
                 doClusterLog="true"
                 clusterLogName="clusterLog"> ...
。。。
server.xml中的注释说明这可用于执行以下操作:

<%
    HashMap map = (HashMap)session.getAttribute("map");
    map.put("key","value");
%>

i、 e.更改已放入会话中的对象的状态,您可以确保该对象仍被复制到集群中的其他节点

根据Tomcat6文档,您只有两个“管理器”选项-DeltaManager和BackupManager。。。这两者似乎都不允许这种选择或类似的选择。在我的测试中,默认设置为:

  <Cluster className="org.apache.catalina.ha.tcp.SimpleTcpCluster"/>

默认情况下,当您获得DeltaManager时,它的行为肯定是useDirtyFlag=“true”(正如我所期望的)

所以我的问题是——Tomcat6中是否有一个等价物


查看源代码,我可以看到一个管理器实现“org.apache.catalina.ha.session.simpletcreplicationmanager”,它确实有useDirtyFlag,但javadoc注释在这种状态下是“Tomcat 4.0的Tomcat会话复制”。。。我不知道这是否可以使用-我猜不会,因为主集群配置文档中没有提到它

我在tomcat用户邮件列表上发布了基本相同的问题,对此的回复以及tomcat bugzilla([43866])中的一些信息使我得出了以下结论:

  • 没有与useDirtyFlag等效的方法,如果要在会话中放置可变(即更改)对象,则需要自定义编码的解决方案
  • Tomcat ClusterValve似乎是此解决方案的一个有效位置—插入集群机制,操纵属性,使DeltaManager觉得会话中的所有属性都已更改。这将强制复制整个会话 步骤1:编写
    ForceReplicationValve
    (扩展
    ValveBase
    实现
    ClusterValve

    我将不包括整个类,而是逻辑的关键部分(除去日志记录和检查实例):

    现在将在每次请求之后将会话复制到所有群集节点

    旁白:注意
    channelSendOptions
    设置。这将替换Tomcat 5.0.x中的
    replicationMode=asynchronous/synchronous/pooled
    。有关可能的int值,请参阅

    附录:要求的完整阀源

    package org.apache.catalina.ha.tcp;
    
    import java.io.IOException;
    import java.util.Enumeration;
    import java.util.LinkedList;
    import java.util.List;
    
    import javax.servlet.ServletException;
    import javax.servlet.http.HttpSession;
    
    import org.apache.catalina.Lifecycle;
    import org.apache.catalina.LifecycleException;
    import org.apache.catalina.LifecycleListener;
    import org.apache.catalina.Session;
    import org.apache.catalina.connector.Request;
    import org.apache.catalina.connector.Response;
    import org.apache.catalina.ha.CatalinaCluster;
    import org.apache.catalina.ha.ClusterValve;
    import org.apache.catalina.ha.session.ReplicatedSession;
    import org.apache.catalina.ha.session.SimpleTcpReplicationManager;
    import org.apache.catalina.util.LifecycleSupport;
    //import org.apache.catalina.util.StringManager;
    import org.apache.catalina.valves.ValveBase;
    
    /**
     * <p>With the {@link SimpleTcpReplicationManager} effectively deprecated, this allows
     * mutable objects to be replicated in the cluster by forcing the "dirty" status on 
     * every request.</p> 
     * 
     * @author Jon Brisbin (via post on tomcat-users http://markmail.org/thread/rdo3drcir75dzzrq)
     * @author Kevin Jansz
     */
    public class ForceReplicationValve extends ValveBase implements Lifecycle, ClusterValve {
        private static org.apache.juli.logging.Log log =
            org.apache.juli.logging.LogFactory.getLog( ForceReplicationValve.class );
    
        @SuppressWarnings("hiding")
        protected static final String info = "org.apache.catalina.ha.tcp.ForceReplicationValve/1.0";
    
    // this could be used if ForceReplicationValve messages were setup 
    // in org/apache/catalina/ha/tcp/LocalStrings.properties
    //    
    //    /**
    //     * The StringManager for this package.
    //     */
    //    @SuppressWarnings("hiding")
    //    protected static StringManager sm =
    //        StringManager.getManager(Constants.Package);
    
        /** 
         * Not actually required but this must implement {@link ClusterValve} to 
         * be allowed to be added to the Cluster.
         */
        private CatalinaCluster cluster = null ;
    
        /**
         * Also not really required, implementing {@link Lifecycle} to allow 
         * initialisation and shutdown to be logged. 
         */
        protected LifecycleSupport lifecycle = new LifecycleSupport(this);    
    
    
        /**
         * Default constructor
         */
        public ForceReplicationValve() {
            super();
            if (log.isInfoEnabled()) {
                log.info(getInfo() + ": created");
            }
        }
    
        @Override
        public String getInfo() {
            return info;
        }
    
        @Override
        public void invoke(Request request, Response response) throws IOException,
                ServletException {
    
            getNext().invoke(request, response);
    
            Session session = null;
            try {
                session = request.getSessionInternal();
            } catch (Throwable e) {
                log.error(getInfo() + ": Unable to perform replication request.", e);
            }
    
            String context = request.getContext().getName();
            String task = request.getPathInfo();
            if(task == null) {
                task = request.getRequestURI();
            }
            if (session != null) {
                if (log.isDebugEnabled()) {
                    log.debug(getInfo() + ": [session=" + session.getId() + ", instanceof=" + session.getClass().getName() + ", context=" + context + ", request=" + task + "]");
                }
                if (session instanceof ReplicatedSession) {
                    // it's a SimpleTcpReplicationManager - can just set to dirty
                    ((ReplicatedSession) session).setIsDirty(true);
                    if (log.isDebugEnabled()) {
                        log.debug(getInfo() + ": [session=" + session.getId() + ", context=" + context + ", request=" + task + "] maked DIRTY");
                    }
                } else {
                    // for everything else - cycle all attributes
                    List cycledNames = new LinkedList();
    
                    // in a cluster where the app is <distributable/> this should be
                    // org.apache.catalina.ha.session.DeltaSession - implements HttpSession
                    HttpSession deltaSession = (HttpSession) session;
                    for (Enumeration<String> names = deltaSession.getAttributeNames(); names.hasMoreElements(); ) {
                        String name = names.nextElement();
                        deltaSession.setAttribute(name, deltaSession.getAttribute(name));
    
                        cycledNames.add(name);                    
                    }
    
                    if (log.isDebugEnabled()) {
                        log.debug(getInfo() + ": [session=" + session.getId() + ", context=" + context + ", request=" + task + "] cycled atrributes=" + cycledNames + "");
                    }
                }
            } else {
                String id = request.getRequestedSessionId();
                log.warn(getInfo()  + ": [session=" + id + ", context=" + context + ", request=" + task + "] Session not available, unable to send session over cluster.");
            }
        }
    
    
        /* 
         * ClusterValve methods - implemented to ensure this valve is not ignored by Cluster  
         */
    
        public CatalinaCluster getCluster() {
            return cluster;
        }
    
        public void setCluster(CatalinaCluster cluster) {
            this.cluster = cluster;
        }
    
    
        /* 
         * Lifecycle methods - currently implemented just for logging startup 
         */
    
        /**
         * Add a lifecycle event listener to this component.
         *
         * @param listener The listener to add
         */
        public void addLifecycleListener(LifecycleListener listener) {
            lifecycle.addLifecycleListener(listener);
        }
    
        /**
         * Get the lifecycle listeners associated with this lifecycle. If this 
         * Lifecycle has no listeners registered, a zero-length array is returned.
         */
        public LifecycleListener[] findLifecycleListeners() {
            return lifecycle.findLifecycleListeners();
        }
    
        /**
         * Remove a lifecycle event listener from this component.
         *
         * @param listener The listener to remove
         */
        public void removeLifecycleListener(LifecycleListener listener) {
            lifecycle.removeLifecycleListener(listener);
        }
    
        public void start() throws LifecycleException {
            lifecycle.fireLifecycleEvent(START_EVENT, null);
            if (log.isInfoEnabled()) {
                log.info(getInfo() + ": started");
            }
        }
    
        public void stop() throws LifecycleException {
            lifecycle.fireLifecycleEvent(STOP_EVENT, null);
            if (log.isInfoEnabled()) {
                log.info(getInfo() + ": stopped");
            }
        }
    
    }
    
    package org.apache.catalina.ha.tcp;
    导入java.io.IOException;
    导入java.util.Enumeration;
    导入java.util.LinkedList;
    导入java.util.List;
    导入javax.servlet.ServletException;
    导入javax.servlet.http.HttpSession;
    导入org.apache.catalina.Lifecycle;
    导入org.apache.catalina.LifecycleException;
    导入org.apache.catalina.LifecycleListener;
    导入org.apache.catalina.Session;
    导入org.apache.catalina.connector.Request;
    导入org.apache.catalina.connector.Response;
    导入org.apache.catalina.ha.CatalinaCluster;
    导入org.apache.catalina.ha.ClusterValve;
    导入org.apache.catalina.ha.session.ReplicatedSession;
    导入org.apache.catalina.ha.session.simpletcreplicationmanager;
    导入org.apache.catalina.util.LifecyclesSupport;
    //导入org.apache.catalina.util.StringManager;
    导入org.apache.catalina.valves.ValveBase;
    /**
    *由于{@link simpletcreplicationmanager}实际上已被弃用,这允许
    *通过强制“脏”状态在集群中复制的可变对象
    *每个请求。

    * *@author Jon Brisbin(通过tomcat用户发帖)http://markmail.org/thread/rdo3drcir75dzzrq) *@作者Kevin Jansz */ 公共类ForceReplicationValve扩展ValveBase实现生命周期,ClusterValve{ 私有静态org.apache.juli.logging.Log= org.apache.juli.logging.LogFactory.getLog(ForceReplicationValve.class); @抑制警告(“隐藏”) 受保护的静态最终字符串info=“org.apache.catalina.ha.tcp.ForceReplicationValve/1.0”; //如果设置了ForceReplicationValve消息,则可以使用此选项 //在org/apache/catalina/ha/tcp/LocalStrings.properties中 // // /** //*此程序包的StringManager。 // */ //@SuppressWarnings(“隐藏”) //受保护的静态StringManager sm= //StringManager.getManager(Constants.Package); /** *实际上不需要,但必须实现{@link ClusterValve}到 *被允许添加到群集。 */ 私有CatalInCluster集群=null; /** *也不是真的需要,实现{@link Lifecycle}以允许 *要记录初始化和关机。 */ 受保护生命周期支持生命周期=新生命周期支持(此); /** *默认构造函数 */ 公共力复制阀(){ 超级(); if(log.isInfoEnabled()){ log.info(getInfo()+“:created”); } } @凌驾 公共字符串getInfo(){ 退货信息; } @凌驾 public void invoke(请求、响应)抛出IOException, ServletException{ getNext().invoke(请求、响应); 会话=空; 试一试{ session=request.getSessionInternal(); }捕获(可丢弃的e){ log.error(getInfo()+“:无法执行复制请求。”,e); } String context=request.getContext().getName(); String task=request.getPathInfo(); 如果(任务==null){ task=request.getRequestURI(); } if(会话!=null){ if(log.isDebugEnabled()){ log.debug(getInfo()+”:[session=“+session.getId()+”,instanceof=“+session.getClass().getName()+”,context=“+context+”,request=“+task+””; } if(复制会话的会话实例){
    <Cluster className="org.apache.catalina.ha.tcp.SimpleTcpCluster"
                channelSendOptions="8">        
        <Valve className="org.apache.catalina.ha.tcp.ForceReplicationValve"/>
        <Valve className="org.apache.catalina.ha.tcp.ReplicationValve"
              filter=".*\.gif;.*\.jpg;.*\.png;.*\.js;.*\.htm;.*\.html;.*\.txt;.*\.css;"/>
        <Valve className="org.apache.catalina.ha.session.JvmRouteBinderValve"/>
    
        <ClusterListener className="org.apache.catalina.ha.session.JvmRouteSessionIDBinderListener"/>
        <ClusterListener className="org.apache.catalina.ha.session.ClusterSessionListener"/>
    </Cluster>
    
    package org.apache.catalina.ha.tcp;
    
    import java.io.IOException;
    import java.util.Enumeration;
    import java.util.LinkedList;
    import java.util.List;
    
    import javax.servlet.ServletException;
    import javax.servlet.http.HttpSession;
    
    import org.apache.catalina.Lifecycle;
    import org.apache.catalina.LifecycleException;
    import org.apache.catalina.LifecycleListener;
    import org.apache.catalina.Session;
    import org.apache.catalina.connector.Request;
    import org.apache.catalina.connector.Response;
    import org.apache.catalina.ha.CatalinaCluster;
    import org.apache.catalina.ha.ClusterValve;
    import org.apache.catalina.ha.session.ReplicatedSession;
    import org.apache.catalina.ha.session.SimpleTcpReplicationManager;
    import org.apache.catalina.util.LifecycleSupport;
    //import org.apache.catalina.util.StringManager;
    import org.apache.catalina.valves.ValveBase;
    
    /**
     * <p>With the {@link SimpleTcpReplicationManager} effectively deprecated, this allows
     * mutable objects to be replicated in the cluster by forcing the "dirty" status on 
     * every request.</p> 
     * 
     * @author Jon Brisbin (via post on tomcat-users http://markmail.org/thread/rdo3drcir75dzzrq)
     * @author Kevin Jansz
     */
    public class ForceReplicationValve extends ValveBase implements Lifecycle, ClusterValve {
        private static org.apache.juli.logging.Log log =
            org.apache.juli.logging.LogFactory.getLog( ForceReplicationValve.class );
    
        @SuppressWarnings("hiding")
        protected static final String info = "org.apache.catalina.ha.tcp.ForceReplicationValve/1.0";
    
    // this could be used if ForceReplicationValve messages were setup 
    // in org/apache/catalina/ha/tcp/LocalStrings.properties
    //    
    //    /**
    //     * The StringManager for this package.
    //     */
    //    @SuppressWarnings("hiding")
    //    protected static StringManager sm =
    //        StringManager.getManager(Constants.Package);
    
        /** 
         * Not actually required but this must implement {@link ClusterValve} to 
         * be allowed to be added to the Cluster.
         */
        private CatalinaCluster cluster = null ;
    
        /**
         * Also not really required, implementing {@link Lifecycle} to allow 
         * initialisation and shutdown to be logged. 
         */
        protected LifecycleSupport lifecycle = new LifecycleSupport(this);    
    
    
        /**
         * Default constructor
         */
        public ForceReplicationValve() {
            super();
            if (log.isInfoEnabled()) {
                log.info(getInfo() + ": created");
            }
        }
    
        @Override
        public String getInfo() {
            return info;
        }
    
        @Override
        public void invoke(Request request, Response response) throws IOException,
                ServletException {
    
            getNext().invoke(request, response);
    
            Session session = null;
            try {
                session = request.getSessionInternal();
            } catch (Throwable e) {
                log.error(getInfo() + ": Unable to perform replication request.", e);
            }
    
            String context = request.getContext().getName();
            String task = request.getPathInfo();
            if(task == null) {
                task = request.getRequestURI();
            }
            if (session != null) {
                if (log.isDebugEnabled()) {
                    log.debug(getInfo() + ": [session=" + session.getId() + ", instanceof=" + session.getClass().getName() + ", context=" + context + ", request=" + task + "]");
                }
                if (session instanceof ReplicatedSession) {
                    // it's a SimpleTcpReplicationManager - can just set to dirty
                    ((ReplicatedSession) session).setIsDirty(true);
                    if (log.isDebugEnabled()) {
                        log.debug(getInfo() + ": [session=" + session.getId() + ", context=" + context + ", request=" + task + "] maked DIRTY");
                    }
                } else {
                    // for everything else - cycle all attributes
                    List cycledNames = new LinkedList();
    
                    // in a cluster where the app is <distributable/> this should be
                    // org.apache.catalina.ha.session.DeltaSession - implements HttpSession
                    HttpSession deltaSession = (HttpSession) session;
                    for (Enumeration<String> names = deltaSession.getAttributeNames(); names.hasMoreElements(); ) {
                        String name = names.nextElement();
                        deltaSession.setAttribute(name, deltaSession.getAttribute(name));
    
                        cycledNames.add(name);                    
                    }
    
                    if (log.isDebugEnabled()) {
                        log.debug(getInfo() + ": [session=" + session.getId() + ", context=" + context + ", request=" + task + "] cycled atrributes=" + cycledNames + "");
                    }
                }
            } else {
                String id = request.getRequestedSessionId();
                log.warn(getInfo()  + ": [session=" + id + ", context=" + context + ", request=" + task + "] Session not available, unable to send session over cluster.");
            }
        }
    
    
        /* 
         * ClusterValve methods - implemented to ensure this valve is not ignored by Cluster  
         */
    
        public CatalinaCluster getCluster() {
            return cluster;
        }
    
        public void setCluster(CatalinaCluster cluster) {
            this.cluster = cluster;
        }
    
    
        /* 
         * Lifecycle methods - currently implemented just for logging startup 
         */
    
        /**
         * Add a lifecycle event listener to this component.
         *
         * @param listener The listener to add
         */
        public void addLifecycleListener(LifecycleListener listener) {
            lifecycle.addLifecycleListener(listener);
        }
    
        /**
         * Get the lifecycle listeners associated with this lifecycle. If this 
         * Lifecycle has no listeners registered, a zero-length array is returned.
         */
        public LifecycleListener[] findLifecycleListeners() {
            return lifecycle.findLifecycleListeners();
        }
    
        /**
         * Remove a lifecycle event listener from this component.
         *
         * @param listener The listener to remove
         */
        public void removeLifecycleListener(LifecycleListener listener) {
            lifecycle.removeLifecycleListener(listener);
        }
    
        public void start() throws LifecycleException {
            lifecycle.fireLifecycleEvent(START_EVENT, null);
            if (log.isInfoEnabled()) {
                log.info(getInfo() + ": started");
            }
        }
    
        public void stop() throws LifecycleException {
            lifecycle.fireLifecycleEvent(STOP_EVENT, null);
            if (log.isInfoEnabled()) {
                log.info(getInfo() + ": stopped");
            }
        }
    
    }
    
    package org.apache.catalina.ha.tcp;
    
    import java.io.IOException;
    import java.util.Enumeration;
    import java.util.LinkedList;
    import java.util.List;
    
    import javax.servlet.ServletException;
    import javax.servlet.http.HttpSession;
    
    import org.apache.catalina.Lifecycle;
    import org.apache.catalina.LifecycleException;
    import org.apache.catalina.LifecycleListener;
    import org.apache.catalina.Session;
    import org.apache.catalina.connector.Request;
    import org.apache.catalina.connector.Response;
    import org.apache.catalina.ha.CatalinaCluster;
    import org.apache.catalina.ha.ClusterValve;
    import org.apache.catalina.util.LifecycleSupport;
    import org.apache.catalina.valves.ValveBase;
    import org.apache.catalina.LifecycleState;
    // import org.apache.tomcat.util.res.StringManager;
    
    /**
     * <p>With the {@link SimpleTcpReplicationManager} effectively deprecated, this allows
     * mutable objects to be replicated in the cluster by forcing the "dirty" status on 
     * every request.</p> 
     * 
     * @author Jon Brisbin (via post on tomcat-users http://markmail.org/thread/rdo3drcir75dzzrq)
     * @author Kevin Jansz
     */
    public class ForceReplicationValve extends ValveBase implements Lifecycle, ClusterValve {
        private static org.apache.juli.logging.Log log =
            org.apache.juli.logging.LogFactory.getLog( ForceReplicationValve.class );
    
        @SuppressWarnings("hiding")
        protected static final String info = "org.apache.catalina.ha.tcp.ForceReplicationValve/1.0";
    
    // this could be used if ForceReplicationValve messages were setup 
    // in org/apache/catalina/ha/tcp/LocalStrings.properties
    //    
    //    /**
    //     * The StringManager for this package.
    //     */
    //    @SuppressWarnings("hiding")
    //    protected static StringManager sm =
    //        StringManager.getManager(Constants.Package);
    
        /** 
         * Not actually required but this must implement {@link ClusterValve} to 
         * be allowed to be added to the Cluster.
         */
        private CatalinaCluster cluster = null;
    
        /**
         * Also not really required, implementing {@link Lifecycle} to allow 
         * initialisation and shutdown to be logged. 
         */
        protected LifecycleSupport lifecycle = new LifecycleSupport(this);    
    
    
        /**
         * Default constructor
         */
        public ForceReplicationValve() {
            super();
            if (log.isInfoEnabled()) {
                log.info(getInfo() + ": created");
            }
        }
    
        @Override
        public String getInfo() {
            return info;
        }
    
        @Override
        public void invoke(Request request, Response response) throws IOException,
                ServletException {
    
            getNext().invoke(request, response);
    
            Session session = null;
            try {
                session = request.getSessionInternal();
            } catch (Throwable e) {
                log.error(getInfo() + ": Unable to perform replication request.", e);
            }
    
            String context = request.getContext().getName();
            String task = request.getPathInfo();
            if(task == null) {
                task = request.getRequestURI();
            }
            if (session != null) {
                if (log.isDebugEnabled()) {
                    log.debug(getInfo() + ": [session=" + session.getId() + ", instanceof=" + session.getClass().getName() + ", context=" + context + ", request=" + task + "]");
                }
                //cycle all attributes
                List<String> cycledNames = new LinkedList<String>();
    
                // in a cluster where the app is <distributable/> this should be
                // org.apache.catalina.ha.session.DeltaSession - implements HttpSession
                HttpSession deltaSession = (HttpSession) session;
                for (Enumeration<String> names = deltaSession.getAttributeNames(); names.hasMoreElements(); ) {
                    String name = names.nextElement();
                    deltaSession.setAttribute(name, deltaSession.getAttribute(name));
    
                    cycledNames.add(name);                    
                }
    
                if (log.isDebugEnabled()) {
                    log.debug(getInfo() + ": [session=" + session.getId() + ", context=" + context + ", request=" + task + "] cycled atrributes=" + cycledNames + "");
                }
            } else {
                String id = request.getRequestedSessionId();
                log.warn(getInfo()  + ": [session=" + id + ", context=" + context + ", request=" + task + "] Session not available, unable to send session over cluster.");
            }
        }
    
    
        /* 
         * ClusterValve methods - implemented to ensure this valve is not ignored by Cluster  
         */
    
        public CatalinaCluster getCluster() {
            return cluster;
        }
    
        public void setCluster(CatalinaCluster cluster) {
            this.cluster = cluster;
        }
    
    
        /* 
         * Lifecycle methods - currently implemented just for logging startup 
         */
    
        /**
         * Add a lifecycle event listener to this component.
         *
         * @param listener The listener to add
         */
        public void addLifecycleListener(LifecycleListener listener) {
            lifecycle.addLifecycleListener(listener);
        }
    
        /**
         * Get the lifecycle listeners associated with this lifecycle. If this 
         * Lifecycle has no listeners registered, a zero-length array is returned.
         */
        public LifecycleListener[] findLifecycleListeners() {
            return lifecycle.findLifecycleListeners();
        }
    
        /**
         * Remove a lifecycle event listener from this component.
         *
         * @param listener The listener to remove
         */
        public void removeLifecycleListener(LifecycleListener listener) {
            lifecycle.removeLifecycleListener(listener);
        }
    
        protected synchronized void startInternal() throws LifecycleException {
            setState(LifecycleState.STARTING);
            if (log.isInfoEnabled()) {
                log.info(getInfo() + ": started");
            }
        }
    
        protected synchronized void stopInternal() throws LifecycleException {
            setState(LifecycleState.STOPPING);
            if (log.isInfoEnabled()) {
                log.info(getInfo() + ": stopped");
            }
        }
    
    }