整合營銷服務商

          電腦端+手機端+微信端=數據同步管理

          免費咨詢熱線:

          nginx+nginx-upsync-module實現動態負載及自定義驗證

          、說明

          nginx一般直接在配置文件里配置upstream即可實現負載均衡,但有些特定的環境下此種方式就顯得有些局限性。比如后端服務器無法依據端口占用檢查存活的時候;后臺動態調整節點的時候;調整節點后不想修改配置文件重啟nginx的時候等等。

          此文的思路是將配置文件從nginx本地遷移到其他第三方服務上如etcd、consul上,然后時候拉取配置到本地。理論上說任何第三方配置中心都可以實現該功能,但需要對應的nginx模塊。本文采用nginx-upsync-module,主要支持consul、etcd,本文以consul為例。

          遷移配置文件還無法滿足需求,還需要解決服務檢測機制。這里不再以端口占用為準,而是實際訪問某一個接口,查看是否返回數據,并以此為存活依據,最后通過調用consul的rest接口管理配置。

          二、安裝

          2.1安裝nginx

          nginx安裝參照前文《Linux下Nginx1.8安裝》

          需要注意的是,在安裝nginx的時候需要安裝nginx-upsync-module模塊。

          2.2安裝nginx-upsync-module

          打開https://github.com/weibocom/nginx-upsync-module,如果遇到github打不開,可以參照如下鏈接解決:https://www.php.cn/faq/445082.html

          下載完成后,解壓到linux目錄備用。

          2.3安裝consul

          consul的安裝比較簡單,這里不再贅述,可參照如下鏈接:https://blog.csdn.net/junaozun/article/details/90699384

          三、搭建&測試

          3.1搭建

          本文的基礎目錄為:

          1、nginx源碼目錄:/opt/server/software/nginx-1.19.1

          2、nginx安裝目錄:/home/nginx/nginx

          3、nginx-upsync-module目錄:/opt/server/software/nginx-upsync-module/

          確定consul正常運行后,配置nginx:

          consul.conf

          #user  nobody;
          worker_processes  1;
          
          
          #error_log  logs/error.log;
          #error_log  logs/error.log  notice;
          #error_log  logs/error.log  info;
          
          
          #pid        logs/nginx.pid;
          
          
          
          
          events {
              worker_connections  1024;
          }
          
          
          
          
          http {
              include       mime.types;
              default_type  application/octet-stream;
          
          
              #log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
              #                  '$status $body_bytes_sent "$http_referer" '
              #                  '"$http_user_agent" "$http_x_forwarded_for"';
          
          
              #access_log  logs/access.log  main;
          
          
              sendfile        on;
              #tcp_nopush     on;
          
          
              #keepalive_timeout  0;
              keepalive_timeout  65;
          
          
              #gzip  on;
          
          
              upstream testconsul {
                  #這個配置無用了,但刪除后啟動會報錯,如果consul里沒有配置則會調用此地址,故此設置應該設置為一個默認的可用的地址,一旦從consul拉取到數據這個配置就無用了
                  server 127.0.0.1:11111;
                  #### 連接consul server,獲取動態upstreams,配置負載均衡信息,間隔0.5s獲取配置信息,upsync_timeout配置從consul拉取上游服務器配置的超時時間;upsync_interval配置從consul拉取上游服務器配置的間隔時間;upsync_type指定使用consul配置服務器;strong_dependency配置nginx在啟動時是否強制依賴配置服務器,如果配置為on,則拉取配置失敗時nginx啟動同樣失敗
                  upsync 192.168.1.97:8500/v1/kv/upstreams/testconsul/  upsync_timeout=6m upsync_interval=500ms upsync_type=consul strong_dependency=off;
                  ### 動態獲取consul server相關負載均衡配置信息持久化在硬盤,這樣即使consul服務器出問題了,本地還有一個備份。
                  upsync_dump_path /home/nginx/nginx/conf/servers/testconsul.conf;
                  }
          
          
                  server {
                          listen       80 ;
                          server_name  testconsul;
                          charset utf8;
                          location /{
                                  proxy_set_header Host $host;
                                  proxy_set_header X-Real-IP $remote_addr;
                                  proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
                                  proxy_pass http://testconsul/HelloWord;
          
          
                         }        
          
          
                          access_log /home/nginx/nginx/logs/access-upsync.log;
                          location /stub-status {
                                  stub_status on;
                          }       
                          location = /upstream_show {
                              upstream_show;
                          }   
          
          
                    }     
          
          
          
          
          
          
              # another virtual host using mix of IP-, name-, and port-based configuration
              #
              #server {
              #    listen       8000;
              #    listen       somename:8080;
              #    server_name  somename  alias  another.alias;
          
          
              #    location / {
              #        root   html;
              #        index  index.html index.htm;
              #    }
              #}
          
          
          
          
              # HTTPS server
              #
              #server {
              #    listen       443 ssl;
              #    server_name  localhost;
          
          
              #    ssl_certificate      cert.pem;
              #    ssl_certificate_key  cert.key;
          
          
              #    ssl_session_cache    shared:SSL:1m;
              #    ssl_session_timeout  5m;
          
          
              #    ssl_ciphers  HIGH:!aNULL:!MD5;
              #    ssl_prefer_server_ciphers  on;
          
          
              #    location / {
              #        root   html;
              #        index  index.html index.htm;
              #    }
              #}
          
          
          }

          3.2測試

          URL目錄

          1、負載狀態:http://nginxhost:port/stub-status

          2、當前負載節點列表:http://nginxhost:port/upstream_show

          3、測試URL:http://nginxhost:port/HelloWord

          4、consul增加節點(也可直接在UI上添加):http://consulhost:port/v1/kv/upstreams/consultest/192.168.1.22:8080

          四、自定義檢測機制

          核心功能是根據配置檢測服務是否可用,然后根據結果更新到consul上。代碼比較簡單,主要代碼如下:

          pom.xml

          <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
            xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
            <modelVersion>4.0.0</modelVersion>
          
          
            <groupId>com.cmgplex.aotucheck4consul</groupId>
            <artifactId>aotucheck4consul</artifactId>
            <version>1.0.1-SNAPSHOT</version>
            <packaging>jar</packaging>
          
          
            <name>aotucheck4consul</name>
            <url>http://www.cmgplex.com</url>
          
          
            <parent>
              <groupId>com.cmgplex.hr.parent</groupId>
              <artifactId>hr-parent</artifactId>
              <version>0.0.1-SNAPSHOT</version>
              <relativePath></relativePath>
            </parent>
            <properties>
              <snippetsDirectory>${project.build.directory}/generated-snippets</snippetsDirectory>
              <asciidoctor.input.directory>${project.basedir}/docs/asciidoc</asciidoctor.input.directory>
              <generated.asciidoc.directory>${project.build.directory}/asciidoc</generated.asciidoc.directory>
              <asciidoctor.html.output.directory>${project.build.directory}/asciidoc/html</asciidoctor.html.output.directory>
              <asciidoctor.pdf.output.directory>${project.build.directory}/asciidoc/pdf</asciidoctor.pdf.output.directory>
            </properties>
          
          
            <dependencies>
              <!--base dependency for all start -->
              <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter</artifactId>
                <exclusions>
                  <exclusion>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-starter-logging</artifactId>
                  </exclusion>
                </exclusions>
              </dependency>
              <dependency>
                <groupId>net.logstash.log4j</groupId>
                <artifactId>jsonevent-layout</artifactId>
                <version>1.0</version>
              </dependency>
              <dependency>
                <groupId>org.slf4j</groupId>
                <artifactId>slf4j-log4j12</artifactId>
              </dependency>
              <dependency>
                <groupId>org.slf4j</groupId>
                <artifactId>slf4j-api</artifactId>
              </dependency>
              <dependency>
                <groupId>com.google.guava</groupId>
                <artifactId>guava</artifactId>
              </dependency>
              <dependency>
                <groupId>commons-lang</groupId>
                <artifactId>commons-lang</artifactId>
              </dependency>
              <!--base dependency for all end -->
          
          
              <!--jetty begin -->
              <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
                <exclusions>
                  <exclusion>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-starter-tomcat</artifactId>
                  </exclusion>
                </exclusions>
              </dependency>
              <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-undertow</artifactId>
              </dependency>
              <!--jetty end -->
          
          
              <!--consul begin -->
              <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-consul-all</artifactId>
              </dependency>
              <!--consul end -->
          
          
              <!--stream rabbit begin -->
              <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-stream-rabbit</artifactId>
              </dependency>
              <!--stream rabbit end -->
              <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
              </dependency>
              <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-netflix-hystrix-dashboard</artifactId>
              </dependency>
              <!--feign begin -->
              <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-openfeign</artifactId>
              </dependency>
              <!--feign end -->
          
          
              <!--actuator begin -->
              <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-actuator</artifactId>
              </dependency>
              <!--actuator end -->
          
          
          
          
              <dependency>
                <groupId>com.alibaba</groupId>
                <artifactId>fastjson</artifactId>
                <version>1.2.46</version>
              </dependency>
              <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-configuration-processor</artifactId>
                <optional>true</optional>
              </dependency>
              <dependency>
                <groupId>javax.mail</groupId>
                <artifactId>mail</artifactId>
                <version>1.4.7</version>
              </dependency>
              <dependency>
                <groupId>com.sun.mail</groupId>
                <artifactId>javax.mail</artifactId>
              </dependency>
              <!-- consul api begin -->
              <dependency>
                <groupId>com.ecwid.consul</groupId>
                <artifactId>consul-api</artifactId>
                <version>1.4.5</version>
              </dependency>
              <!-- consul api end -->
            </dependencies>
            <build>
              <finalName>aotucheck4consul</finalName>
              <plugins>
                <plugin>
                  <groupId>org.apache.maven.plugins</groupId>
                  <artifactId>maven-compiler-plugin</artifactId>
                  <configuration>
                    <source>${java.version}</source>
                    <target>${java.version}</target>
                    <encoding>UTF-8</encoding>
                  </configuration>
                </plugin>
                <plugin>
                  <groupId>org.springframework.boot</groupId>
                  <artifactId>spring-boot-maven-plugin</artifactId>
                </plugin>
              </plugins>
              <resources>
                <resource>
                  <directory>src/main/java</directory>
                  <includes>
                    <include>**/*.xml</include>
                  </includes>
                </resource>
                <resource>
                  <directory>src/main/resources</directory>
                  <includes>
                    <include>**/*.*</include>
                  </includes>
                </resource>
                <resource>
                  <directory>src/main/webapp</directory>
                  <targetPath>META-INF/resources</targetPath>
                  <includes>
                    <include>**/*.*</include>
                  </includes>
                </resource>
              </resources>
            </build>
            <!-- 這里是為了方便未配置maven的情況下,找到依賴 -->
            <repositories>
              <repository>
                <id>lumi-snapshots</id>
                <name>lumi-snapshots</name>
                <url>http://repo.lumiai.top/repository/maven-snapshots/</url>
                <layout>default</layout>
                <snapshots>
                  <enabled>true</enabled>
                </snapshots>
              </repository>
            </repositories>
          </project>

          application.properties

          spring.main.allow-bean-definition-overriding=true
          
          
          #the following is for cloud
          
          
          spring.datasource.hikari.idle-timeout = 600000
          spring.datasource.hikari.connection-timeout = 30000
          spring.datasource.hikari.max-lifetime = 1800000
          spring.datasource.hikari.maximum-pool-size = 20
          spring.datasource.type = com.zaxxer.hikari.HikariDataSource
          
          
          #這個是關于mq的配置
          spring.rabbitmq.addresses=amqp://192.168.1.2:5672
          spring.rabbitmq.password=guest
          spring.rabbitmq.username=guest
          spring.cloud.stream.default-binder=rabbit
          #定時檢查,每隔1分鐘
          job.cleanConsulDeadService.cron=1 * * * * ? 
          #consul配置key默認前綴
          consul.default.key.prefix=upstreams/
          #服務檢查配置
          #----------------api服務
          #要檢查服務的url,不包含地址
          server.check.apps.api.url=/api/b
          #要檢查服務的host,只能是IP,包含端口,即使是80也不能少,不然nginx那邊讀取不到配置會報錯而導致配置不可用
          server.check.apps.api.hosts=http://192.168.1.1:80,http://192.168.1.2:81
          #要檢查服務的method
          server.check.apps.api.method=get
          #暫不支持json參數
          server.check.apps.api.param=get
          #鏈接超時時間,單位毫秒
          server.check.apps.api.timeout=3000
          #斷定服務正常的response返回code
          server.check.apps.api.successcode=200,302
          #----------------baidu服務
          #要檢查服務的url,不包含地址
          server.check.apps.consultest.url=/s
          #要檢查服務的host,只能是IP,包含端口,即使是80也不能少,不然nginx那邊讀取不到配置會報錯而導致配置不可用
          server.check.apps.consultest.hosts=http://182.61.200.6:80
          #要檢查服務的method
          server.check.apps.consultest.method=get
          #暫不支持json參數
          server.check.apps.consultest.param=wd=javahttp&tn=98012088_5_dg&ch=11
          #鏈接超時時間,單位毫秒
          server.check.apps.consultest.timeout=3000
          #斷定服務正常的response返回code
          server.check.apps.consultest.successcode=200,302
          
          
          
          
          #********************************************
          #本地服務監聽端口
          server.port = 17000
          #cpu的核數
          server.undertow.io-threads=4
          #預估的最佳線程數
          server.undertow.worker-threads=400
          spring.application.name=aotucheck4consul
          spring.profiles.active=dev
          #********************************************
          #consul的配置
          spring.cloud.consul.enabled=true
          spring.cloud.consul.host=192.168.1.2
          spring.cloud.consul.port=8500
          
          
          #********************************************
          #注冊中心的配置
          spring.cloud.consul.discovery.enabled=false
          spring.cloud.consul.discovery.prefer-ip-address=true
          spring.cloud.consul.discovery.health-check-path=/actuator/health
          spring.cloud.consul.discovery.health-check-interval=10s
          spring.cloud.consul.discovery.health-check-timeout=1s
          spring.cloud.consul.discovery.instance-id=${spring.application.name}:${spring.cloud.client.ip-address}:${server.port}
          
          
          
          
          #是否把自己向注冊中心注冊,可以做純consumer不注冊自己
          spring.cloud.consul.discovery.register=true
          
          
          #********************************************
          #配置服務的配置
          spring.cloud.consul.config.enabled=true
          spring.cloud.consul.config.prefix=config
          spring.cloud.consul.config.profile-separator=,
          spring.cloud.consul.config.default-context=application
          spring.cloud.consul.config.watch.enabled=true
          spring.cloud.consul.config.watch.delay=1000
          spring.cloud.consul.config.watch.wait-time=3
          spring.cloud.consul.config.format=properties
          spring.cloud.consul.config.data-key=configuration
          #禁用熔斷器首次調用時強制1秒超時
          hystrix.command.default.execution.timeout.enabled=false

          CheckServiceScheduler.java

          @Component
          @EnableScheduling
          public class CheckServiceScheduler {
            private static final Logger LOGGER = LoggerFactory.getLogger(CheckServiceScheduler.class);
            @Autowired
            private ICheckService checkService;
          
          
            
            @Scheduled(cron = "${job.cleanConsulDeadService.cron}")
            public void checkServer() {
              LOGGER.info("-----------------------------start checkServer Scheduler-----------------------------");
              this.checkService.check();
              LOGGER.info("-----------------------------end checkServer Scheduler-----------------------------");
            }
          }
          
          
          
          
          CheckServiceImpl.java
          @Service
          public class CheckServiceImpl implements ICheckService {
            private static final Logger LOGGER = LoggerFactory.getLogger(CheckServiceImpl.class);
            @Resource
            private ServerPropertiesConfig serverPropertiesConfig;
            @Resource
            private IConsulService consulService;
            @Value("${consul.default.key.prefix}")
            private String consulKeyPrefix;
          
          
            /*
             * (非 Javadoc) <p>Title: check</p> <p>Description: </p>
             * 
             * @return
             * 
             * @see com.cmgplex.aotucheck4consul.jobsystem.service.ICheckService#check()
             */
            @Override
            public void check() {
              LOGGER.debug("serverPropertiesConfig={}", this.serverPropertiesConfig);
              Map<String, ServerInfoVo> apps = this.serverPropertiesConfig.getApps();
              for (Entry<String, ServerInfoVo> app : apps.entrySet()) {
                String appName = app.getKey();
                LOGGER.info("appName={}", appName);
                ServerInfoVo config = app.getValue();
                LOGGER.info("config={}", config);
                List<Integer> expectCodeList = ListUtils.str2list(config.getSuccesscode(), ",");
                List<String> hostsList = ListUtils.str2list4String(config.getHosts(), ",");
                String method = config.getMethod();
                HttpMethod httpMethod = HttpMethod.valueOf(method.toUpperCase());
                String param = config.getParam();
                Integer timeout = config.getTimeout();
                hostsList.parallelStream().forEach(host -> {
                  try {
                    LOGGER.info("host={}", host);
                    String httpurl = host + config.getUrl();
                    LOGGER.info("httpurl={}", httpurl);
                    boolean isSuccess = HttpTools.compareCode(expectCodeList, httpMethod, httpurl, param, timeout);
                    LOGGER.info("isSuccess={}", isSuccess);
                    String key = this.consulKeyPrefix + appName + "/"
                        + host.replace("http://", "").replace("https://", "");
                    LOGGER.info("key={}", key);
                    // 如果服務可用
                    if (isSuccess) {
                      // 檢查consul上配置是否正常
                      if (!this.consulService.isKeyExist(key)) {
                        // 如果不正常,則更新正常
                        this.consulService.addKeyValue(key, new NginxServerConfig(2, 1, 10));
                        LOGGER.info("server success,consul faild,now update consul,key={}", key);
                      }
                    } else {
                      // 如果服務不可用
                      // 檢查consul上配置是否正常
                      if (this.consulService.isKeyExist(key)) {
                        // 如果正常,則更新為不正常
                        this.consulService.deleteKey(key);
                        LOGGER.info("server faild,consul success,now update consul,key={}", key);
                      }
                    }
                  } catch (Exception e) {
                    LOGGER.error(e.getMessage(), e);
                  }
                });
              }
            }
          
          
          }

          ConsulServiceImpl.java

          ntroduction

          部署是指將Web應用程序(第三方WAR或您自己的自定義Web應用程序)安裝到Tomcat服務器的過程。

          Web應用程序部署可以在Tomcat服務器中以多種方式完成。

          • 靜態;在Tomcat啟動之前設置Web應用程序
          • 動態;通過直接操作已部署的Web應用程序(依賴于auto-deployment功能)或使用Tomcat Manager Web應用程序遠程訪問

          Tomcat Manager是一個Web應用程序,可以通過HTML GUI交互使用,或以編程方式(通過基于URL的API)來部署和管理Web應用程序。

          有許多方法可以執行依賴Manager Web應用程序的部署。 Apache Tomcat為Apache Ant構建工具提供任務。Apache Tomcat Maven Plugin project提供與Apache Maven的集成。還有一個名為Client Deployer的工具,可以從命令行使用它,并提供其他功能,例如編譯和驗證Web應用程序以及將Web應用程序打包到Web應用程序資源(WAR)文件中。

          Installation

          靜態部署Web應用程序不需要安裝,因為Tomcat提供了開箱即用的功能。使用Tomcat Manager的部署功能也不需要任何安裝,盡管需要進行一些配置,詳細說明在下一節。但是,如果您希望使用Tomcat客戶端部署程序(TCD),則需要安裝。

          TCD未與Tomcat核心發行版一起打包,因此必須從“下載”區域單獨下載。下載通常是標記的apache-tomcat-9.0.x-deployer.


          TCD需要先安裝Apache Ant 1.6.2+和Java。您需要設置指向Ant安裝根目錄的ANT_HOME環境值,以及指向Java安裝根目錄的JAVA_HOME值。此外,您應該確保Ant的ant命令,以及Java javac編譯器命令可以在shell中運行。

          1. 下載TCD發行版
          2. 不需要將TCD包提取到任何現有的Tomcat安裝中,它可以被提取到任何位置。
          3. Read Using the Tomcat Client Deployer

          A word on Contexts

          在談論Web應用程序的部署時,Context這個概念需要被理解。 Context在Tomcat中被稱為Web應用程序。

          為了在Tomcat中配置一個Context ,一個Context Descriptor(Context描述)是必須的。Context Descriptor只是一個XML文件,它包含上下文的Tomcat相關配置,例如命名資源或會話管理器配置。在早期版本的Tomcat中,Context Descriptor配置的內容通常存儲在Tomcat的主配置文件中server.xml。但現在不鼓勵這種做法(盡管目前仍然有效)。


          Context Descriptor不僅幫助Tomcat知道如何配置上下文,而且其他工具(如Tomcat Manager和TCD)通常使用這些上下文描述符來正確執行其角色。

          Context Descriptor的位置是:

          1. $CATALINA_BASE/conf/[enginename]/[hostname]/[webappname].xml
          2. $CATALINA_BASE/webapps/[webappname]/META-INF/context.xml

          (1)中的文件名為[webappname] .xml,但(2)中的文件名為context.xml。如果沒有為Context提供Context Descriptor,Tomcat將使用默認值配置Context。

          在Tomcat啟動時部署

          如果您對使用Tomcat Manager或TCD不感興趣,那么您需要將Web應用程序靜態部署到Tomcat,然后啟動Tomcat,此類部署的位置稱為appBase,它對于每個主機是指定的。你要么復制一個所謂的exploded web application到此位置,或壓縮的Web應用程序資源.WAR文件。

          還有當Host的deployOnStartup屬性為“true”時,在Tomcat啟動時應用才會部署到appBase指定的位置。

          在這種情況下,Tomcat啟動時將發生以下部署順序:

          1. 將首先部署任何上下文描述符。
          2. 然后將部署未被任何上下文描述符引用的exploded web application。如果他們在appBase中有一個關聯的.WAR文件,并且它比exploded web application更新,則會刪除exploded web application,并從.WAR重新部署webapp。
          3. 將部署.WAR文件

          在正在運行的Tomcat服務器上部署

          可以將Web應用程序部署到正在運行的Tomcat服務器。

          如果 Host的 autoDeploy屬性為“true”,主機將嘗試根據需要動態部署和更新Web應用程序,例如,如果將新的.WAR放入appBase。為此,主機需要啟用后臺處理,這是默認配置。

          autoDeploy設置為“true”,運行Tomcat允許:

          • 部署.WAR文件復制到主機中appBase.
          • 部署已復制到主機中的exploded web application.
          • 重新部署已在提供新.WAR時從.WAR部署的Web應用程序。在這種情況下,將刪除exploded web application,并再次展開.WAR。請注意,如果配置主機以便.WAR不會使用展開,unpackWARs屬性設置為“false”,在這種情況下,Web應用程序將簡單地重新部署為壓縮存檔。
          • 如果更新了/WEB-INF/web.xml文件(或定義為WatchedResource的任何其他資源),則重新加載Web應用程序。
          • 如果更新了部署Web應用程序的Context Descriptor文件,則重新部署Web應用程序。
          • 如果更新Web應用程序使用的全局或每主機上下文描述符文件,則重新部署從屬Web應用程序。
          • 如果將上下文描述符文件(具有與先前部署的Web應用程序的上下文路徑對應的文件名)添加到Web應用程序,則重新部署Web應用程序$CATALINA_BASE/conf/[enginename]/[hostname]/ directory.
          • 如果刪除了其文檔庫(docBase),則取消部署Web應用程序。請注意,在Windows上,這假定啟用了反鎖定功能(請參閱上下文配置),否則無法刪除正在運行的Web應用程序的資源。

          請注意,也可以在加載程序中配置Web應用程序重新加載,在這種情況下,將跟蹤已加載的類以進行更改。

          使用客戶端部署程序包進行部署

          最后,可以使用Tomcat Client Deployer實現Web應用程序的部署。這是一個包,可用于驗證,編譯,壓縮到.WAR,以及將Web應用程序部署到生產或開發Tomcat服務器。應該注意,此功能使用Tomcat Manager,因此目標Tomcat服務器應該運行。

          假設用戶熟悉Apache Ant以使用TCD。 Apache Ant是一個腳本化的構建工具。 TCD預先打包了要使用的構建腳本。只需要對Apache Ant有一定的了解(本頁前面列出的安裝,熟悉使用操作系統命令shell和配置環境變量)。

          TCD包括Ant任務,部署前用于JSP編譯的Jasper頁面編譯器,以及驗證Web應用程序上下文描述符的任務。驗證器任務(類org.apache.catalina.ant.ValidatorTask)僅允許一個參數:解壓的Web應用程序的基本路徑。

          TCD使用解壓的Web應用程序作為輸入(請參閱下面使用的屬性列表)。以部署程序編程部署的Web應用程序可以包括上下文描述符/META-INF/context.xml.

          TCD包含一個即用型Ant腳本,具有以下目標:

          • compile(默認):編譯并驗證Web應用程序。這可以單獨使用,也不需要運行Tomcat服務器。已編譯的應用程序僅在關聯的應用程序上運行Tomcat X.Y.Z服務器版本,并不保證在另一個Tomcat版本上工作,因為Jasper生成的代碼取決于其運行時組件。還應該注意的是,該目標還將自動編譯位于其中的任何Java源文件/WEB-INF/classesWeb應用程序的文件夾。
          • deploy:將Web應用程序(已編譯或未編譯)部署到Tomcat服務器。
          • undeploy:取消部署Web應用程序
          • start:啟動Web應用程序
          • reload:重新加載Web應用程序
          • stop:停止Web應用程序

          為了配置部署,請創建一個名為的文件deployer.properties在TCD安裝目錄root中。在此文件中,每行添加以下name = value對:

          此外,您需要確保已為目標Tomcat Manager(TCD使用)設置了用戶,否則TCD將不會使用Tomcat Manager進行身份驗證,部署將失敗。要執行此操作,請參閱Tomcat Manager頁面。

          • build:默認情況下,使用的構建文件夾將是${build}/webapp/${path} (${build},默認情況下,指向${basedir}/build)。執行結束后compile目標,Web應用程序.WAR將位于${build}/webapp/${path}.war.
          • webapp:包含將被編譯和驗證的解壓的Web應用程序的目錄。默認情況下,該文件夾是myapp.
          • path:默認情況下,部署Web應用程序的上下文路徑/myapp.
          • url:正在運行的Tomcat服務器的Tomcat Manager Web應用程序的絕對URL,將用于部署和取消部署Web應用程序。默認情況下,部署者將嘗試訪問在localhost上運行的Tomcat實例http://localhost:8080/manager/text.
          • username:Tomcat Manager用戶名(用戶應該具有manager-script的角色)
          • password:Tomcat Manager密碼。

          較早之前,部署 Java web 服務只是單純使用 Tomcat 做 Web 服務器,前后端代碼融合在一個工程之中。Tomcat 啟動后對外提供一個端口接收和相應 http請求。隨著 Nginx 得越來越流行,同時加上其優秀的反向代理和負載均衡功能,我們在線上的 Java web 通常會結合二者,即使用 Nginx + Tomcat 的方式來部署 Java web 服務。最近兩年,隨著微服務化和前后端工程分離思想的流行,使用 Spring Boot 和 Vue 框架進行 Java web 開發的人的人越來越多。由于前后端分離后需要解決請求跨域的問題,往往會使用 Nginx 做一層反向代理,這樣可以減少一些代碼風險。所以,目前主流的 Java web開發模式是:

          • 基于 Vue 等優秀的前端框架完成頁面開發;
          • 使用 Spring Boot 等 java web 框完成后端服務開發;
          • 前端工程打包后是一堆靜態文件,可以直接由 Nginx 進行代理訪問;后端服務啟動后會占用端口等待請求,Nginx 將使用反向代理功能將前端發起的 http 請求轉到對應的后臺服務去處理。如果在多臺機器上部署了相同的服務,還可以使用 Nginx 中的負載均衡功能,將請求均勻分發到上游的服務,實現系統的高可用性。

          1. 部署前端

          前端框架如 Vue 打包出來往往是靜態的文件 index.html 加上一個 static 目錄。static 目錄下有 fonts、css、js、img等靜態資源目錄。前端的訪問是從 index.html 開始的。假設服務器上打包出的前端代碼放到/root/test-web目錄下,對應部署前端的配置如下:

          ...
          
          http{
              server {
                 # 監聽8080端口
                 listen 8080;     
                 # 指定域名,不指定也可以
                 server_name www.xxx.com;
                 
                 # 瀏覽器交互調參,打開gzip壓縮、緩存等等
                 gzip on;
                 ...
                 
                 location / {
                     root  /root/test-web;
                     # 也可以簡單使用 index index.html
                     try_files $uri $uri/ /index.html;
                 }
                 
                 # vue 頁面中向后臺 java 服務發送請求
                 ...
              }
          }
          ...
          
          

          2. 部署java后臺服務

          Nginx 部署 Java Web 服務時,主要用到是 Nginx 的代理轉發功能,對于不同類型的接口而言,可能會有不同的轉發邏輯。如果是使用 spring cloud 這樣的微服務框架,每個服務可能會部署多個或者分開部署在不同機器,在 Nginx 同樣只需要使用 proxy_pass 指令將 http 請求轉發到對應的上游服務上即可,同時負載均衡模塊也在 java web 后臺服務中用到的比較多。最后是在java web 的開發中,也常常會涉及到 websocket 協議,因此 Nginx 在部署 java web 服務時也會用到 websocket 代理轉發。所以 Nginx 在部署 Java Web 服務時的基本配置大概如下:

          ...
          
          http{
          
              server {
                 # 監聽8080端口
                 listen 8080;     
                 # 指定域名,不指定也可以
                 server_name www.xxx.com;
                 
                 # 參數調優
                 client_max_body_size 20m; 
                 client_body_buffer_size 128k
                 ...
                 
                 # 如果使用多個后臺服務,可以配置負載均衡
                 ...
                 
                 # 訪前端的 vue 頁面
                 location / {
                     ...
                 }
                 # vue 頁面中向后臺 java 服務發送請求
                 location /xxxx { 
                      proxy_pass http://xxxx:xx/xxx;
                 }
                 
                 # 配置多種方向代理,不同類型接口有不同的轉發方式
                 ...
                 
                 # 如果有,則配置websocket代理
                 location /xxxy {
                     proxy_http_version 1.1;
                     proxy_set_header Upgrade $http_upgrade;
                     proxy_set_header Connection "upgrade";
                     proxy_pass http://xxxxx:xx/yyy;
                 }
              }   
          }
          ...
          

          如果涉及的服務較多, Nginx 的配置往往會拆成多個文件進行編寫,這樣就用到了前面提到的 include 指令。

          3. 小結

          總結 Nginx 部署 java 服務,主要是使用 proxy_pass 指令進行端口轉發,因為都是 http 請求的轉發,所以配置會比較簡單。但是如果服務較多時, Nginx 需要編寫多個 server 指令塊或者多個 location 塊去匹配不同的 URL并轉發到對應的上游服務。往往大型網站使用的服務較多時,會使用 include 指令對 Nginx 的配置進行拆分,不同的配置處理不同服務的轉發,這樣會更簡潔明了,方便網站運維人員管理和修改 Nginx 配置。


          主站蜘蛛池模板: 亚洲国产av一区二区三区丶| 国产一区二区三区在线观看精品 | 性色AV一区二区三区无码| 日本韩国一区二区三区| 少妇无码一区二区二三区| 波多野结衣的AV一区二区三区| 色噜噜狠狠一区二区| 无码人妻视频一区二区三区| 国产另类TS人妖一区二区| 亚洲一区二区高清| 日韩精品一区二区午夜成人版 | 国模私拍福利一区二区| 无码人妻精品一区二区三| 国产色精品vr一区区三区| 动漫精品专区一区二区三区不卡| 无码一区二区三区中文字幕| 在线免费观看一区二区三区| 亚洲国产高清在线精品一区| 日韩精品一区二区亚洲AV观看| 在线观看午夜亚洲一区| 国产在线一区二区在线视频| 亚洲无线码在线一区观看 | 国产精品视频无圣光一区| 濑亚美莉在线视频一区| 精品国产一区二区二三区在线观看| 无码中文字幕乱码一区| 精品国产天堂综合一区在线| 亚洲国产欧美一区二区三区| 精品无人乱码一区二区三区| 精品国产免费观看一区| 国产一区二区福利久久| chinese国产一区二区| 国产在线aaa片一区二区99| 午夜影视日本亚洲欧洲精品一区 | 亚洲码欧美码一区二区三区| 久久久无码精品人妻一区| 国产精品日韩欧美一区二区三区| 国产精品一区电影| 国产高清在线精品一区二区三区| 手机看片一区二区| 激情内射亚洲一区二区三区|