【问题标题】:Tomcat session replication in docker swarmdocker swarm 中的 Tomcat 会话复制
【发布时间】:2020-05-19 07:15:50
【问题描述】:

我看到很多帖子使用 traefik 在 docker swarm 中实现 Tomcat 会话复制。但我只是不想添加另一个组件。我使用 httpd 作为 tomcat 的前端。 Tomcat 将部署为具有 4 个副本的服务,并在需要时进行扩展。 httpd 作为 docker 服务运行,并且两者都在同一个网络中。我的问题是,在这种情况下,有什么方法可以在 docker swarm 中实现 Tomcat 会话复制。 TIA。

【问题讨论】:

    标签: apache docker-swarm tomcat9


    【解决方案1】:

    只要所有 Tomcat Docker 容器都可以访问,您就可以通过下面的集群设置来实现这一点。

    以下设置适用于 tomcat 7,但对于其他版本也应该以相同的方式工作。

    如果是 Apache Tomcat 7,请取消注释 <Cluster className=”org.apache.catalina.ha.tcp.SimpleTcpCluster”/> 标记并更新集群详细信息,如下所示。

    <Cluster className="org.apache.catalina.ha.tcp.SimpleTcpCluster">
        <Manager className="org.apache.catalina.ha.session.DeltaManager"
            expireSessionsOnShutdown="false"        
            notifyListenersOnReplication="true"/>
        
        <Channel className="org.apache.catalina.tribes.group.GroupChannel">
        
            <Membership className="org.apache.catalina.tribes.membership.McastService"
            address="228.0.0.4"
            port="45564" frequency="500"
            dropTime="3000"/>           
    
            <Sender className="org.apache.catalina.tribes.transport.ReplicationTransmitter">                
                <Transport className="org.apache.catalina.tribes.transport.nio.PooledParallelSender"/>              
            </Sender>           
            
            <Receiver className="org.apache.catalina.tribes.transport.nio.NioReceiver" 
            address="auto" port="4000" autoBind="100"
            selectorTimeout="5000" maxThreads="6"/>                     
            
            <Interceptor className="org.apache.catalina.tribes.group.interceptors.TcpFailureDetector"/>         
            <Interceptor className="org.apache.catalina.tribes.group.interceptors.MessageDispatch15Interceptor"/>   
            <Interceptor className="org.apache.catalina.tribes.group.interceptors.ThroughputInterceptor"/>                      
        
        </Channel>
        
        <Valve className="org.apache.catalina.ha.tcp.ReplicationValve" />       
        <ClusterListener className="org.apache.catalina.ha.session.ClusterSessionListener" />       
        
    </Cluster>
    

    另外,我们需要在apache/conf/ 路径中添加workers.properties

    请注意此文件必须放置在将在集群中运行的所有 Tomcat 服务器中。

    您可以阅读更多详细信息here

    【讨论】:

    • 这不起作用,因为多播在覆盖网络中不起作用
    【解决方案2】:

    您可以在没有前端的情况下执行此操作,但是您会遇到问题,因为如果入口路由到不同的节点,则该节点必须从另一个节点请求会话。

    普通的 tomcat 映像不足以进行集群,它需要对集群配置进行一些自定义 /usr/local/tomcat/conf/server.xml 才能使用 DNSMembershipProvider

    <Cluster className="org.apache.catalina.ha.tcp.SimpleTcpCluster">
      <Channel className="org.apache.catalina.tribes.group.GroupChannel">
        <Membership
          className="org.apache.catalina.tribes.membership.cloud.CloudMembershipService"
          membershipProviderClassName="org.apache.catalina.tribes.membership.cloud.DNSMembershipProvider"
        />
      </Channel>
    </Cluster>
    

    DNSMembershipProvider 使用环境变量DNS_MEMBERSHIP_SERVICE_NAME 来查找服务器,因此它应该与服务名称匹配。

    下面的docker-compose.yml 展示了如何在没有任何其他组件的情况下部署它。

    version: "3.8"
    services:
      tomcat:
        build: ./tomcat
        image: sample-tomcat
        environment:
          - DNS_MEMBERSHIP_SERVICE_NAME=tomcat
        ports:
          - 50000:80
        deploy:
          replicas: 6
          update_config:
            order: start-first
    

    正确方法

    正如我之前所说,使用上述方法将满足 OP 不添加额外组件的要求,但会出现严重的性能问题。相反,您需要一个可以路由到具有以下功能的服务器的代理:

    1. 会话粘性
    2. Docker Swarm 服务标签发现
    3. 通过提前检测服务器停机来减少潜在用户影响的运行状况检查。

    Traefik 可以很好地处理所有要求,即使它本身不支持集群 due to their ACME storage not allowing concurrent access 而无需转到其 EE 版本。

    docker-compose.yml 如下所示。

    version: "3.8"
    services:
      proxy:
        image: traefik:2.6
        command:
          - "--providers.docker.swarmMode=true"
          - "--providers.docker.exposedbydefault=false"
          - "--entrypoints.app.address=:80"
        volumes:
          - /var/run/docker.sock:/var/run/docker.sock:ro
        ports:
          - 50000:80
      tomcat:
        build: ./tomcat
        image: sample-tomcat
        environment:
          - DNS_MEMBERSHIP_SERVICE_NAME=tomcat
        deploy:
          replicas: 6
          labels:
            - "traefik.enable=true"
            - "traefik.http.routers.app.entrypoints=app"
            - "traefik.http.routers.app.rule=Host(`localhost`)"
            - "traefik.http.services.app-service.loadBalancer.sticky.cookie=true"
            - "traefik.http.services.app-service.loadBalancer.sticky.cookie.httponly=true"
            - "traefik.http.services.app-service.loadbalancer.server.port=8080"
            - "traefik.http.services.app-service.loadbalancer.healthcheck.path=/"
          update_config:
            order: start-first
          endpoint_mode: dnsrr
    

    需要注意的一个属性是endpoint_mode: dnsrr 在早期公开端口时不可用。这样可以更好地复制 Tomcat 集群中的会话数据,因为每个节点都有单独的 ID。

    我的 github repo https://github.com/trajano/tomcat-docker-swarm 中有一个示例实现

    【讨论】:

      猜你喜欢
      • 2019-06-21
      • 2011-02-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多