欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

SpringBoot利用Undertow實(shí)現(xiàn)高可用的反向代理配置

 更新時(shí)間:2025年06月30日 08:26:24   作者:風(fēng)象南  
Undertow是一個(gè)采用Java開發(fā)的靈活的高性能Web服務(wù)器,本文將介紹如何利用?Undertow?服務(wù)器的反向代理能力,實(shí)現(xiàn)高可用的反向代理配置,感興趣的可以了解下

引言

在微服務(wù)架構(gòu)中,反向代理是一個(gè)不可或缺的組件,它負(fù)責(zé)請(qǐng)求轉(zhuǎn)發(fā)、負(fù)載均衡、安全過濾等關(guān)鍵功能。

通常我們會(huì)選擇 Nginx、HAProxy 等專業(yè)反向代理組件,但在某些場景下,使用 Spring Boot 內(nèi)置的反向代理功能可以簡化架構(gòu),減少運(yùn)維復(fù)雜度。

本文將介紹如何利用 Undertow 服務(wù)器的反向代理能力,實(shí)現(xiàn)高可用的反向代理配置。

Undertow 簡介

Undertow 是一個(gè)采用 Java 開發(fā)的靈活的高性能 Web 服務(wù)器,提供基于 NIO 的阻塞和非阻塞 API。

作為 Spring Boot 支持的內(nèi)嵌式服務(wù)器之一,它具有以下特點(diǎn):

  • 輕量級(jí):核心僅依賴于 JBoss Logging 和 xnio
  • 高性能:在多核系統(tǒng)上表現(xiàn)優(yōu)異
  • 內(nèi)置反向代理:支持 HTTP、HTTPS、HTTP/2 代理
  • 可擴(kuò)展:通過 Handler 鏈模式支持靈活擴(kuò)展

為什么選擇 Undertow 內(nèi)置反向代理

在某些場景下,使用 Undertow 內(nèi)置的反向代理功能比獨(dú)立部署 Nginx 等代理服務(wù)器更有優(yōu)勢:

1. 簡化架構(gòu):減少額外組件,降低部署復(fù)雜度

2. 統(tǒng)一技術(shù)棧:全 Java 技術(shù)棧,便于開發(fā)團(tuán)隊(duì)維護(hù)

3. 配置靈活:可通過代碼動(dòng)態(tài)調(diào)整代理規(guī)則

4. 節(jié)約資源:適合資源有限的環(huán)境,如邊緣計(jì)算場景

5. 集成監(jiān)控:與 Spring Boot 的監(jiān)控體系無縫集成

基礎(chǔ)配置

步驟 1:添加 Undertow 依賴

首先,確保 Spring Boot 項(xiàng)目使用 Undertow 作為嵌入式服務(wù)器:

<?xml version="1.0" encoding="UTF-8"?>
<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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>3.4.5</version>
        <relativePath/>
    </parent>
    <groupId>demo</groupId>
    <artifactId>springboot-undertow-proxy</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <dependencies>
        <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>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.32</version>
            <scope>provided</scope>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <source>21</source>
                    <target>21</target>
                    <encoding>utf-8</encoding>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <version>3.2.0</version>
                <executions>
                    <execution>
                        <goals>
                            <goal>repackage</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>

</project>

步驟 2:創(chuàng)建 Undertow 配置類

package com.example.config;

import io.undertow.Handlers;
import io.undertow.server.HttpHandler;
import io.undertow.server.handlers.PathHandler;
import io.undertow.server.handlers.RequestLimitingHandler;
import io.undertow.server.handlers.ResponseCodeHandler;
import io.undertow.server.handlers.proxy.LoadBalancingProxyClient;
import io.undertow.server.handlers.proxy.ProxyHandler;
import io.undertow.util.HeaderMap;
import io.undertow.util.HttpString;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.web.embedded.undertow.UndertowServletWebServerFactory;
import org.springframework.boot.web.server.WebServerFactoryCustomizer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.xnio.OptionMap;

import java.net.URI;

@Configuration
public class UndertowProxyConfig {

    @Bean
    @ConditionalOnProperty(name = "user.enabled", havingValue = "false", matchIfMissing = true)
    public WebServerFactoryCustomizer<UndertowServletWebServerFactory> undertowProxyCustomizer() {
        return factory -> factory.addDeploymentInfoCustomizers(deploymentInfo -> {
            deploymentInfo.addInitialHandlerChainWrapper(handler -> {
                PathHandler pathHandler = Handlers.path(handler);

                // 配置代理路由
                HttpHandler handler1 = createProxyClient("http://127.0.0.1:8081/user");
                HttpHandler handler2 = createProxyClient("http://127.0.0.2:8081/user/users2");

                handler1 = secureProxyHandler(handler1);
                handler1 = createRateLimitingHandler(handler1);

                // 添加路由規(guī)則
                pathHandler.addPrefixPath("/user", handler1);
                pathHandler.addPrefixPath("/user/users2", handler2);

                return pathHandler;
            });
        });
    }
    
    private HttpHandler createProxyClient(String targetUrl) {
        try {
            URI uri = new URI(targetUrl);
            LoadBalancingProxyClient proxyClient = new LoadBalancingProxyClient();
            proxyClient.addHost(uri);
            proxyClient
                    .setConnectionsPerThread(20)
                    .setMaxQueueSize(10)
                    .setSoftMaxConnectionsPerThread(20)
                    .setProblemServerRetry(5)
                    .setTtl(30000);

            return ProxyHandler.builder()
                    .setProxyClient(proxyClient)
                    .setMaxRequestTime(30000)
                    .setRewriteHostHeader(false)
                    .setReuseXForwarded(true)
                    .build();

        } catch (Exception e) {
            throw new RuntimeException("創(chuàng)建代理客戶端失敗", e);
        }
    }

    private HttpHandler secureProxyHandler(HttpHandler proxyHandler) {
        return exchange -> {
            // 移除敏感頭部
            HeaderMap headers = exchange.getRequestHeaders();
            headers.remove("X-Forwarded-Server");

            // 添加安全頭部
            exchange.getResponseHeaders().add(new HttpString("X-XSS-Protection"), "1; mode=block");
            exchange.getResponseHeaders().add(new HttpString("X-Content-Type-Options"), "nosniff");
            exchange.getResponseHeaders().add(new HttpString("X-Frame-Options"), "DENY");

            // 添加代理信息
            headers.add(new HttpString("X-Forwarded-For"), exchange.getSourceAddress().getAddress().getHostAddress());
            headers.add(new HttpString("X-Forwarded-Proto"), exchange.getRequestScheme());
            headers.add(new HttpString("X-Forwarded-Host"), exchange.getHostName());

            proxyHandler.handleRequest(exchange);
        };
    }

    private HttpHandler createRateLimitingHandler(HttpHandler next) {
        // 根據(jù)實(shí)際情況調(diào)整
        return new RequestLimitingHandler(1,1,next);
    }

}

高可用配置

要實(shí)現(xiàn)真正的高可用反向代理,需要考慮以下幾個(gè)關(guān)鍵方面:

1. 負(fù)載均衡策略

Undertow 提供多種負(fù)載均衡策略,可以根據(jù)需求選擇:

@Bean
public LoadBalancingProxyClient loadBalancingProxyClient() {
    LoadBalancingProxyClient loadBalancer = new LoadBalancingProxyClient();
    
    // 配置負(fù)載均衡策略
    loadBalancer.setRouteParsingStrategy(RouteParsingStrategy.RANKED);
    loadBalancer.setConnectionsPerThread(20);

    // 添加后端服務(wù)器
    loadBalancer.addHost(new URI("http://backend1:8080"));
    loadBalancer.addHost(new URI("http://backend2:8080"));
    loadBalancer.addHost(new URI("http://backend3:8080"));
    
    // 設(shè)置會(huì)話親和性(可選)
    loadBalancer.addSessionCookieName("JSESSIONID");
    
    return loadBalancer;
}

2. 健康檢查與自動(dòng)故障轉(zhuǎn)移

實(shí)現(xiàn)定期健康檢查,自動(dòng)剔除不健康節(jié)點(diǎn):

package com.example.config;

import io.undertow.server.handlers.proxy.LoadBalancingProxyClient;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.http.ResponseEntity;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestTemplate;

import java.net.URI;
import java.net.URISyntaxException;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

@Component
@ConditionalOnProperty(name = "user.enabled", havingValue = "false", matchIfMissing = true)
@Slf4j
public class BackendHealthMonitor {
    
    private final LoadBalancingProxyClient loadBalancer;
    private final List<URI> backendServers;
    private final RestTemplate restTemplate;
    
    public BackendHealthMonitor(@Value("#{'${user.backends}'.split(',')}") String[] backends,
            LoadBalancingProxyClient loadBalancer) throws URISyntaxException {
        this.loadBalancer = loadBalancer;
        this.restTemplate = new RestTemplate();
        this.backendServers = Arrays.stream(backends)
                .map(url -> {
                    try {
                        return new URI(url);
                    } catch (URISyntaxException e) {
                        throw new RuntimeException(e);
                    }
                })
                .collect(Collectors.toList());
    }
    
    @Scheduled(fixedDelay = 10000) // 每10秒檢查一次
    public void checkBackendHealth() {
        for (URI server : backendServers) {
            try {
                String healthUrl = server.getScheme() + "://" + server.getHost() + ":" + server.getPort() + "/health";
                ResponseEntity<String> response = restTemplate.getForEntity(healthUrl, String.class);
                
                if (response.getStatusCode().is2xxSuccessful()) {
                    loadBalancer.addHost(server);
                    log.info("后端服務(wù) {} 狀態(tài)正常,已添加到負(fù)載均衡", server);
                } else {
                    // 服務(wù)不健康,從負(fù)載均衡器中移除
                    loadBalancer.removeHost(server);
                    log.warn("后端服務(wù) {} 狀態(tài)異常,已從負(fù)載均衡中移除", server);
                }
            } catch (Exception e) {
                // 連接異常,從負(fù)載均衡器中移除
                loadBalancer.removeHost(server);
                log.error("后端服務(wù) {} 連接異常: {}", server, e.getMessage());
            }
        }
    }
}

3. 集群高可用

為確保被代理服務(wù)的高可用,可配置多個(gè)代理實(shí)例:

user:
  backends: "http://127.0.0.1:8081,http://127.0.0.2:8081"

性能優(yōu)化

要獲得最佳性能,需要調(diào)整 Undertow 的相關(guān)參數(shù)(需要根據(jù)項(xiàng)目實(shí)際情況進(jìn)行測試調(diào)整):

server:
  undertow:
    threads: 
      io: 8                      # IO線程數(shù),建議設(shè)置為CPU核心數(shù)
      worker: 64                 # 工作線程數(shù),IO線程數(shù)的8倍
    buffer-size: 16384           # 緩沖區(qū)大小
    direct-buffers: true         # 使用直接緩沖區(qū)
    max-http-post-size: 10485760 # 最大POST大小
    max-parameters: 2000         # 最大參數(shù)數(shù)量
    max-headers: 200             # 最大請(qǐng)求頭數(shù)量
    max-cookies: 200             # 最大Cookie數(shù)量

連接池優(yōu)化

@Bean
public UndertowServletWebServerFactory undertowFactory() {
    UndertowServletWebServerFactory factory = new UndertowServletWebServerFactory();
    factory.addBuilderCustomizers(builder -> {
        builder.setSocketOption(Options.KEEP_ALIVE, true)
               .setSocketOption(Options.TCP_NODELAY, true)
               .setSocketOption(Options.REUSE_ADDRESSES, true)
               .setSocketOption(Options.BACKLOG, 10000)
               .setServerOption(UndertowOptions.MAX_ENTITY_SIZE, 16 * 1024 * 1024L)
               .setServerOption(UndertowOptions.IDLE_TIMEOUT, 60 * 1000)
               .setServerOption(UndertowOptions.REQUEST_PARSE_TIMEOUT, 30 * 1000)
               .setServerOption(UndertowOptions.NO_REQUEST_TIMEOUT, 60 * 1000)
               .setServerOption(UndertowOptions.MAX_CONCURRENT_REQUESTS_PER_CONNECTION, 200);
    });
    return factory;
}

安全強(qiáng)化

反向代理需要考慮安全性,可以添加以下配置:

1. 請(qǐng)求頭過濾與重寫

private HttpHandler secureProxyHandler(HttpHandler proxyHandler) {
    return exchange -> {
        // 移除敏感頭部
        HeaderMap headers = exchange.getRequestHeaders();
        headers.remove("X-Forwarded-Server");
        
        // 添加安全頭部
        exchange.getResponseHeaders().add(new HttpString("X-XSS-Protection"), "1; mode=block");
        exchange.getResponseHeaders().add(new HttpString("X-Content-Type-Options"), "nosniff");
        exchange.getResponseHeaders().add(new HttpString("X-Frame-Options"), "DENY");
        
        // 添加代理信息
        headers.add(new HttpString("X-Forwarded-For"), exchange.getSourceAddress().getAddress().getHostAddress());
        headers.add(new HttpString("X-Forwarded-Proto"), exchange.getRequestScheme());
        headers.add(new HttpString("X-Forwarded-Host"), exchange.getHostName());
        
        proxyHandler.handleRequest(exchange);
    };
}

2. 請(qǐng)求限流

private HttpHandler createRateLimitingHandler(HttpHandler next) {
    return new RequestLimitingHandler(100,next);
}

實(shí)際案例:某系統(tǒng) API 網(wǎng)關(guān)

以一個(gè)電商系統(tǒng)為例,展示 Undertow 反向代理的實(shí)際應(yīng)用:

package com.example.config;

import io.undertow.Handlers;
import io.undertow.server.HttpHandler;
import io.undertow.server.handlers.PathHandler;
import io.undertow.server.handlers.proxy.LoadBalancingProxyClient;
import io.undertow.server.handlers.proxy.ProxyHandler;
import org.springframework.boot.web.embedded.undertow.UndertowServletWebServerFactory;
import org.springframework.boot.web.server.WebServerFactoryCustomizer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.net.URI;

@Configuration
public class EcommerceProxyConfig {

    @Bean
    public WebServerFactoryCustomizer<UndertowServletWebServerFactory> ecommerceProxyCustomizer() {
        return factory -> factory.addDeploymentInfoCustomizers(deploymentInfo -> {
            deploymentInfo.addInitialHandlerChainWrapper(handler -> {
                PathHandler pathHandler = Handlers.path(handler);
                try {
                    // 用戶服務(wù)代理
                    LoadBalancingProxyClient userServiceClient = new LoadBalancingProxyClient();
                    userServiceClient.addHost(new URI("http://user-service-1:8080/api/users"));
                    userServiceClient.addHost(new URI("http://user-service-2:8080/api/users"));

                    // 商品服務(wù)代理
                    LoadBalancingProxyClient productServiceClient = new LoadBalancingProxyClient();
                    productServiceClient.addHost(new URI("http://product-service-1:8080/api/products"));
                    productServiceClient.addHost(new URI("http://product-service-2:8080/api/products"));

                    // 訂單服務(wù)代理
                    LoadBalancingProxyClient orderServiceClient = new LoadBalancingProxyClient();
                    orderServiceClient.addHost(new URI("http://order-service-1:8080/api/orders"));
                    orderServiceClient.addHost(new URI("http://order-service-2:8080/api/orders"));

                    // 路由規(guī)則
                    pathHandler.addPrefixPath("/api/users", createProxyHandler(userServiceClient));
                    pathHandler.addPrefixPath("/api/products", createProxyHandler(productServiceClient));
                    pathHandler.addPrefixPath("/api/orders", createProxyHandler(orderServiceClient));

                    return pathHandler;
                }catch (Exception e){
                    throw new RuntimeException(e);
                }
            });
        });
    }
    
    private HttpHandler createProxyHandler(LoadBalancingProxyClient client) {
        return ProxyHandler.builder()
                .setProxyClient(client)
                .setMaxRequestTime(30000)
                .setRewriteHostHeader(true)
                .build();
    }
}

總結(jié)

Spring Boot 內(nèi)置的 Undertow 反向代理功能為微服務(wù)架構(gòu)提供了一種輕量級(jí)的代理解決方案。

雖然功能上可能不如專業(yè)的反向代理服務(wù)器(如 Nginx)那么豐富,但在特定場景下,尤其是希望簡化架構(gòu)、統(tǒng)一技術(shù)棧的情況下,可以作為一種備選方案。

以上就是SpringBoot利用Undertow實(shí)現(xiàn)高可用的反向代理配置的詳細(xì)內(nèi)容,更多關(guān)于SpringBoot Undertow反向代理的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • SpringBoot WebSocket連接報(bào)no mapping for GET問題

    SpringBoot WebSocket連接報(bào)no mapping for GE

    文章描述了一個(gè)在調(diào)試WebSocket連接時(shí)遇到的`nomappingforGET`異常問題,并提供了問題解決的方法,包括檢查WebSocket注解和補(bǔ)充相關(guān)配置,此外,還特別提到了在使用Nginx轉(zhuǎn)發(fā)WebSocket時(shí)所需的配置
    2025-02-02
  • Java MeteoInfo解析與繪圖代碼教程詳解

    Java MeteoInfo解析與繪圖代碼教程詳解

    這篇文章主要介紹了Java MeteoInfo解析與繪圖代碼教程,對(duì)于后端導(dǎo)出圖片的話,就需要添加色階了,這一文很簡單,就涉及色階,名稱,網(wǎng)格刻度線,感興趣的朋友一起看看吧
    2021-10-10
  • SpringBoot結(jié)合mockito測試實(shí)戰(zhàn)

    SpringBoot結(jié)合mockito測試實(shí)戰(zhàn)

    與集成測試將系統(tǒng)作為一個(gè)整體測試不同,單元測試更應(yīng)該專注于某個(gè)類。所以當(dāng)被測試類與外部類有依賴的時(shí)候,尤其是與數(shù)據(jù)庫相關(guān)的這種費(fèi)時(shí)且有狀態(tài)的類,很難做單元測試。但好在可以通過“Mockito”這種仿真框架來模擬這些比較費(fèi)時(shí)的類,從而專注于測試某個(gè)類內(nèi)部的邏輯
    2022-11-11
  • Springboot接收文件與發(fā)送文件實(shí)例教程

    Springboot接收文件與發(fā)送文件實(shí)例教程

    最近工作中遇到個(gè)需求,springboot簡單的上傳文檔或者圖片,并且進(jìn)行操作,操作完后進(jìn)行保存指定路徑,下面這篇文章主要給大家介紹了關(guān)于Springboot接收文件與發(fā)送文件的相關(guān)資料,需要的朋友可以參考下
    2023-05-05
  • 關(guān)于Spring?Data?Jpa?自定義方法實(shí)現(xiàn)問題

    關(guān)于Spring?Data?Jpa?自定義方法實(shí)現(xiàn)問題

    這篇文章主要介紹了關(guān)于Spring?Data?Jpa?自定義方法實(shí)現(xiàn)問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-12-12
  • JavaFX Metro UI 和 開發(fā)庫使用簡介

    JavaFX Metro UI 和 開發(fā)庫使用簡介

    這篇文章主要介紹了JavaFX Metro UI 和 開發(fā)庫解析,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2019-08-08
  • 一文搞懂JAVA 修飾符

    一文搞懂JAVA 修飾符

    這篇文章主要介紹了JAVA 修飾符的的相關(guān)資料,文中代碼非常詳細(xì),幫助大家更好的理解和學(xué)習(xí),感興趣的朋友可以了解下
    2020-06-06
  • Java countDownLatch如何實(shí)現(xiàn)多線程任務(wù)阻塞等待

    Java countDownLatch如何實(shí)現(xiàn)多線程任務(wù)阻塞等待

    這篇文章主要介紹了Java countDownLatch如何實(shí)現(xiàn)多線程任務(wù)阻塞等待,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-10-10
  • idea提交文件時(shí)如何忽略某些文件的提交

    idea提交文件時(shí)如何忽略某些文件的提交

    這篇文章主要介紹了idea提交文件時(shí)如何忽略某些文件的提交問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-02-02
  • java實(shí)現(xiàn)微信公眾平臺(tái)自定義菜單的創(chuàng)建示例

    java實(shí)現(xiàn)微信公眾平臺(tái)自定義菜單的創(chuàng)建示例

    這篇文章主要介紹了java實(shí)現(xiàn)微信公眾平臺(tái)自定義菜單的創(chuàng)建示例,需要的朋友可以參考下
    2014-04-04

最新評(píng)論