注意这几点,轻轻松松配置 Nginx + Tomcat 的集群和负载均衡

Tomcat 集群是当单台服务器达到性能瓶颈,经过横向扩展的方式提升总体系统性能的有效手段。Nginx 是一个高性能的 HTTP 和反向代理 web 服务器,能够经过简单的配置实现 Tomcat 集群的负载均衡。css

本文使用的 Tomcat 是 8.5.35 版本,Nginx 是 1.14.2 版本。接下来看下配置的过程以及可能会遇到的问题,首发于微信公众号「顿悟源码」。html

1. 概述

对于 Web 应用来讲,集群最大的问题就是 Session 信息的共享,通常有如下解决方法:nginx

  • 使用粘性会话,好比,使用 IP Hash 的负载均衡策略,将当前用户的请求都集中到一台服务器上;缺点是单点故障,会话丢失
  • 使用 Session 复制,使用 Tomcat 自带的 Session 复制策略,将会话信息同步到集群的各个节点;缺点是消耗更多内存和带宽,适用于小型集群
  • 使用第三方缓存中间件缓存整个集群会话信息,好比 Redis 缓存,可由应用程序控制与 Session 的关联,也能够适配 Tomcat
  • 固然了,也能够把会话信息存到共享文件系统或者数据库

在配置 Nginx 的过程当中,可能会遇到如下问题:web

  • 配置 upstream 名称时不能使用下划线,好比 tomcat_ha,不然 Tomcat 会抛出 The character [_] is never valid in a domain name 的异常
  • 在 windows 上杀掉全部的 nginx.exe 进程,taskkill /fi "imagename eq nginx.exe" /f
  • 在 windows 上有个 pid 为 4 的系统进程会占用 80 端口,因此这里将 nginx 改成了 8000

在配置 Tomcat 集群的过程当中,须要注意的问题:数据库

  • 确保 web.xml 配置了 <distributable/> 元素
  • 确保 Context 的 Manager 别被替换成了标准会话管理器
  • Receiver.address 不要配置成 auto,由于默承认能会绑定 127.0.0.1;Receiver.port 可改也可不改,Tomcat 会自行检测 4000-4100 范围内的可用端口,自动处理冲突
  • 若是在不一样服务器上,须要关闭防火墙或开端口,还有时间同步

2. Nginx 核心配置

Nginx 使用的是默认配置,添加和修改的核心配置以下:apache

http {
  ...
  #gzip  on;
  
  #设置负载均衡的服务器列表和权重
  upstream tomcat-ha {
      #ip_hash; 
      server 172.31.1.41:8080 weight=1;
      server 172.31.1.42:8080 weight=1;
  }
  
  server {
      listen       8000;
      server_name  localhost;

      #charset koi8-r;
      #access_log  logs/host.access.log  main;

      location / {
          root   html;
          index  index.html index.htm;
          #转发请求
          proxy_pass http://tomcat-ha;
          proxy_set_header Host $http_host;
          proxy_set_header X-Real-IP $remote_addr;
          proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
          proxy_set_header X-Forwarded-Proto $scheme;
      }
      ...
  }
}

3. Tomcat 集群配置

启用集群配置,在 <Engine> 元素中添加如下配置:windows

<!-- channelSendOptions=6 同步复制 -->
<Cluster className="org.apache.catalina.ha.tcp.SimpleTcpCluster" channelSendOptions="6">
  <!-- 集群 Session 管理器 -->
  <Manager className="org.apache.catalina.ha.session.BackupManager"
             expireSessionsOnShutdown="false"
             notifyListenersOnReplication="true"
             mapSendOptions="6"/>
  <!--
  <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"/>
    <Receiver className="org.apache.catalina.tribes.transport.nio.NioReceiver"
              address="192.168.10.2"
              port="5000"
              selectorTimeout="100"
              maxThreads="6"/>
    <Sender className="org.apache.catalina.tribes.transport.ReplicationTransmitter">
      <Transport className="org.apache.catalina.tribes.transport.nio.PooledParallelSender"/>
    </Sender>
    <Interceptor className="org.apache.catalina.tribes.group.interceptors.TcpFailureDetector"/>
    <Interceptor className="org.apache.catalina.tribes.group.interceptors.MessageDispatchInterceptor"/>
    <Interceptor className="org.apache.catalina.tribes.group.interceptors.ThroughputInterceptor"/>
  </Channel>
  <!-- 此 vavle 拦截请求,并将 Session 信息发给内部节点 -->
  <Valve className="org.apache.catalina.ha.tcp.ReplicationValve"
         filter=".*\.gif|.*\.js|.*\.jpeg|.*\.jpg|.*\.png|.*\.htm|.*\.html|.*\.css|.*\.txt"/>
  <ClusterListener className="org.apache.catalina.ha.session.ClusterSessionListener"/>
</Cluster>

简单描述下工做原理:浏览器

  1. nginx 将请求转发给 Tomcat1,请求登陆认证,建立会话,生成 Cookie,在响应返回以前,将 Session 信息复制到 Tomcat2
  2. 再次请求时,nginx 将带着会话 Cookie 的请求转发给了 Tomcat2,Tomcat2 发现内部 Session 池中有关联的已认证成功的 Session 对象,再也不认证返回请求资源

4. 验证负载均衡和 Session 复制

4.1 测试环境

  1. 使用两台 PC 部署 Tomcat,对应关系是:172.31.1.41-Tomcat1,172.31.1.42-Tomcat2
  2. 部署基于使用 Tomcat 自带的 SessionExample 程序,编写了一个 tomcat-benchmark 的 web 应用
  3. 结合 Tomcat 自带的 Manager 应用,查看已部署应用内部 Session 池

4.2 负载均衡

修改 tomcat-benchmark 部署描述符文件中的 context-param 为 "I'm Tomcat 1/2" 用于区分两个 Tomcat,启动 Nginx 和 Tomcat,在浏览器访问 172.31.1.42:8080 能够看到请求在两个服务器间切换:缓存

req-balance

4.3 Session 复制

为了方便理解,这里先把 Nginx 的负载均衡策略设置成 ip_hash:tomcat

  1. 假设 Nginx 始终将请求定位到 Tomcat1 上,而后在 Tomcat1 上建立会话,往会话中添加一些属性
  2. 关闭 Tomcat1 模拟故障,此时 Nginx 会带着以前的会话 Cookie 将请求转发到 Tomcat2,上
  3. 查看 Tomcat2 上是否存在与 Cookie(JSESSIONID) 关联的 Session 信息,如有表示复制成功

整个过程以下:

session-copy

动图正好与上述描述的相反,能够看到 Session 信息从 Tomcat2 复制到了 Tomcat1 中。

5. 小结

搜索微信号「顿悟源码」,回复「Tomcat」后,可获取本文测试使用的工程以及 Nginx 和 Tomcat 的配置文件。

相关文章
相关标签/搜索