nginx一般直接在配置文件里配置upstream即可实现负载均衡,但有些特定的环境下此种方式就显得有些局限性。比如后端服务器无法依据端口占用检查存活的时候;后台动态调整节点的时候;调整节点后不想修改配置文件重启nginx的时候等等。
此文的思路是将配置文件从nginx本地迁移到其他第三方服务上如etcd、consul上,然后时候拉取配置到本地。理论上说任何第三方配置中心都可以实现该功能,但需要对应的nginx模块。本文采用nginx-upsync-module,主要支持consul、etcd,本文以consul为例。
迁移配置文件还无法满足需求,还需要解决服务检测机制。这里不再以端口占用为准,而是实际访问某一个接口,查看是否返回数据,并以此为存活依据,最后通过调用consul的rest接口管理配置。
nginx安装参照前文《Linux下Nginx1.8安装》
需要注意的是,在安装nginx的时候需要安装nginx-upsync-module模块。
打开https://github.com/weibocom/nginx-upsync-module,如果遇到github打不开,可以参照如下链接解决:https://www.php.cn/faq/445082.html
下载完成后,解压到linux目录备用。
consul的安装比较简单,这里不再赘述,可参照如下链接:https://blog.csdn.net/junaozun/article/details/90699384
本文的基础目录为:
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;
# }
#}
}
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 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中运行。
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)中的文件名为[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启动时将发生以下部署顺序:
在正在运行的Tomcat服务器上部署
可以将Web应用程序部署到正在运行的Tomcat服务器。
如果 Host的 autoDeploy属性为“true”,主机将尝试根据需要动态部署和更新Web应用程序,例如,如果将新的.WAR放入appBase。为此,主机需要启用后台处理,这是默认配置。
autoDeploy设置为“true”,运行Tomcat允许:
请注意,也可以在加载程序中配置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脚本,具有以下目标:
为了配置部署,请创建一个名为的文件deployer.properties在TCD安装目录root中。在此文件中,每行添加以下name = value对:
此外,您需要确保已为目标Tomcat Manager(TCD使用)设置了用户,否则TCD将不会使用Tomcat Manager进行身份验证,部署将失败。要执行此操作,请参阅Tomcat Manager页面。
较早之前,部署 Java web 服务只是单纯使用 Tomcat 做 Web 服务器,前后端代码融合在一个工程之中。Tomcat 启动后对外提供一个端口接收和相应 http请求。随着 Nginx 得越来越流行,同时加上其优秀的反向代理和负载均衡功能,我们在线上的 Java web 通常会结合二者,即使用 Nginx + Tomcat 的方式来部署 Java web 服务。最近两年,随着微服务化和前后端工程分离思想的流行,使用 Spring Boot 和 Vue 框架进行 Java web 开发的人的人越来越多。由于前后端分离后需要解决请求跨域的问题,往往会使用 Nginx 做一层反向代理,这样可以减少一些代码风险。所以,目前主流的 Java web开发模式是:
前端框架如 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 服务发送请求
...
}
}
...
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 指令。
总结 Nginx 部署 java 服务,主要是使用 proxy_pass 指令进行端口转发,因为都是 http 请求的转发,所以配置会比较简单。但是如果服务较多时, Nginx 需要编写多个 server 指令块或者多个 location 块去匹配不同的 URL并转发到对应的上游服务。往往大型网站使用的服务较多时,会使用 include 指令对 Nginx 的配置进行拆分,不同的配置处理不同服务的转发,这样会更简洁明了,方便网站运维人员管理和修改 Nginx 配置。
*请认真填写需求信息,我们会在24小时内与您取得联系。