使用 Undertow 替代 Tomcat

使用 Undertow 替代 Tomcat 的优势与配置

为什么要用 Undertow 替代 Tomcat

1. 性能优势

  • 更低的资源占用:Undertow 内存占用比 Tomcat 少 30-50%

  • 更高的并发处理能力:基于 XNIO 的非阻塞 I/O 模型

  • 更好的响应时间:轻量级架构减少处理延迟

2. 架构优势

  • 模块化设计:只加载需要的组件

  • 嵌入式部署:更适合微服务架构

  • 灵活配置:支持编程式配置

详细优势对比

性能指标对比

指标 Tomcat Undertow 优势
内存占用 较高 减少30-50%
启动时间 较慢 减少40-60%
并发连接 10k+ 50k+ 5倍提升
CPU使用率 中等 更高效

技术特性对比

java 复制代码
// Undertow 基于 XNIO 的优势:
// 1. 非阻塞I/O
// 2. 零拷贝技术
// 3. 直接内存访问
// 4. 更精细的线程控制

Spring Boot 中配置 Undertow

1. 添加依赖

XML 复制代码
<!-- 移除 Tomcat -->
<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>

<!-- 添加 Undertow -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-undertow</artifactId>
</dependency>

2. 基础配置

java 复制代码
# application.yml
server:
  port: 8080
  undertow:
    # 线程池配置
    threads:
      io: 16
      worker: 256
    # 缓冲区配置
    buffer-size: 1024
    direct-buffers: true
    # HTTP配置
    max-http-post-size: 0
    # 连接配置
    max-connections: 10000

3. 高级配置示例

java 复制代码
@Configuration
public class UndertowConfig {
    
    @Bean
    public UndertowServletWebServerFactory undertowServletWebServerFactory() {
        UndertowServletWebServerFactory factory = new UndertowServletWebServerFactory();
        
        // 自定义构建器
        factory.addBuilderCustomizers(new UndertowBuilderCustomizer() {
            @Override
            public void customize(Builder builder) {
                // 服务器配置
                builder.setServerOption(UndertowOptions.ENABLE_HTTP2, true)
                       .setServerOption(UndertowOptions.HTTP2_SETTINGS_ENABLE_PUSH, true)
                       .setServerOption(UndertowOptions.ALWAYS_SET_KEEP_ALIVE, false)
                       .setServerOption(UndertowOptions.ALWAYS_SET_DATE, true);
                
                // 缓冲区配置
                builder.setBufferSize(1024 * 16)
                       .setIoThreads(Runtime.getRuntime().availableProcessors() * 2)
                       .setWorkerThreads(200);
            }
        });
        
        // 监听器配置
        factory.addDeploymentInfoCustomizers(deploymentInfo -> {
            deploymentInfo.setDefaultEncoding("UTF-8");
            deploymentInfo.setUrlCharset(StandardCharsets.UTF_8.name());
        });
        
        return factory;
    }
}

4. 完整的配置类

java 复制代码
@Configuration
@EnableConfigurationProperties(UndertowProperties.class)
public class AdvancedUndertowConfig {
    
    @Autowired
    private UndertowProperties undertowProperties;
    
    @Bean
    @Primary
    public ServletWebServerFactory servletContainer() {
        UndertowServletWebServerFactory factory = 
            new UndertowServletWebServerFactory();
        
        // 基础配置
        factory.setPort(undertowProperties.getPort());
        factory.setContextPath(undertowProperties.getContextPath());
        
        // 高级自定义配置
        factory.addBuilderCustomizers(this::customizeBuilder);
        factory.addDeploymentInfoCustomizers(this::customizeDeployment);
        
        return factory;
    }
    
    private void customizeBuilder(Builder builder) {
        // XNIO 工作线程配置
        builder.setWorkerThreads(undertowProperties.getWorkerThreads());
        builder.setIoThreads(undertowProperties.getIoThreads());
        
        // 缓冲区配置
        builder.setBufferSize(undertowProperties.getBufferSize());
        builder.setDirectBuffers(undertowProperties.isDirectBuffers());
        
        // 连接配置
        builder.setServerOption(UndertowOptions.MAX_CONNECTIONS, 
                              undertowProperties.getMaxConnections());
        builder.setServerOption(UndertowOptions.MAX_ENTITY_SIZE, 
                              undertowProperties.getMaxEntitySize());
        
        // HTTP/2 配置
        builder.setServerOption(UndertowOptions.ENABLE_HTTP2, true);
        builder.setServerOption(UndertowOptions.HTTP2_SETTINGS_HEADER_TABLE_SIZE, 4096);
        builder.setServerOption(UndertowOptions.HTTP2_SETTINGS_INITIAL_WINDOW_SIZE, 65535);
        
        // 安全配置
        builder.setServerOption(UndertowOptions.RECORD_REQUEST_START_TIME, false);
        builder.setServerOption(UndertowOptions.ALLOW_UNESCAPED_CHARACTERS_IN_URL, true);
    }
    
    private void customizeDeployment(DeploymentInfo deploymentInfo) {
        deploymentInfo.setDefaultEncoding("UTF-8");
        deploymentInfo.setEagerFilterInit(true);
        deploymentInfo.setIgnoreFlush(false);
        
        // Session 配置
        deploymentInfo.setDefaultSessionTimeout(1800);
    }
}

// 配置属性类
@ConfigurationProperties(prefix = "server.undertow")
@Data
public class UndertowProperties {
    private int port = 8080;
    private String contextPath = "";
    private int workerThreads = 256;
    private int ioThreads = Runtime.getRuntime().availableProcessors() * 2;
    private int bufferSize = 1024;
    private boolean directBuffers = true;
    private int maxConnections = 10000;
    private long maxEntitySize = 10485760L; // 10MB
}

5. 性能优化配置

java 复制代码
# application-prod.yml
server:
  undertow:
    threads:
      worker: 500
      io: 32
    buffer-size: 2048
    direct-buffers: true
    max-http-post-size: 104857600  # 100MB
    max-connections: 10000
    no-request-timeout: 60000
    idle-timeout: 30000
    
spring:
  servlet:
    multipart:
      max-file-size: 100MB
      max-request-size: 100MB

6. 监控和健康检查

java 复制代码
@RestController
public class ServerStatusController {
    
    @Autowired
    private XnioWorker xnioWorker;
    
    @GetMapping("/server/status")
    public Map<String, Object> getServerStatus() {
        Map<String, Object> status = new HashMap<>();
        
        // 线程池状态
        status.put("ioThreadCount", xnioWorker.getIoThreadCount());
        status.put("workerThreadCount", xnioWorker.getWorkerThreadCount());
        status.put("busyWorkerThreads", xnioWorker.getBusyWorkerThreadCount());
        
        // 内存状态
        Runtime runtime = Runtime.getRuntime();
        status.put("maxMemory", runtime.maxMemory());
        status.put("totalMemory", runtime.totalMemory());
        status.put("freeMemory", runtime.freeMemory());
        status.put("usedMemory", runtime.totalMemory() - runtime.freeMemory());
        
        return status;
    }
}

迁移注意事项

1. 会话管理

java 复制代码
@Configuration
public class SessionConfig {
    
    @Bean
    public UndertowSessionCustomizer undertowSessionCustomizer() {
        return deploymentInfo -> {
            deploymentInfo.setSessionPersistenceManager(new FileSessionPersistence(
                new File(System.getProperty("java.io.tmpdir"))
            ));
        };
    }
}

2. SSL 配置

java 复制代码
server:
  ssl:
    key-store: classpath:keystore.p12
    key-store-password: changeit
    key-store-type: PKCS12
    key-alias: tomcat
  undertow:
    ssl-contexts:
      default:
        enabled-protocols:
          - TLSv1.2
          - TLSv1.3

总结

使用 Undertow 替代 Tomcat 的主要好处:

  1. 性能提升:更低的延迟,更高的吞吐量

  2. 资源优化:减少内存占用,提高资源利用率

  3. 架构适配:更适合云原生和微服务架构

  4. 配置灵活:支持更细粒度的性能调优

在需要高性能、低延迟的应用场景中,Undertow 是比 Tomcat 更好的选择,特别是在微服务架构和云原生环境中。

相关推荐
Mintopia4 小时前
🇨🇳 Next.js 在国内场景下的使用分析与实践指南
前端·后端·全栈
冬夜戏雪4 小时前
[学习日记]看书笔记
java·学习
初级程序员Kyle4 小时前
开始改变第一天 JVM的原理到调优(2)
java·面试
程序员三明治5 小时前
Spring AOP:注解配置与XML配置双实战
java·后端·spring·代理模式·aop·1024程序员节
绝无仅有5 小时前
京东面试题解析:同步方法、线程池、Spring、Dubbo、消息队列、Redis等
后端·面试·github
非凡ghost5 小时前
Tenorshare 4DDiG(数据恢复软件) 最新版
前端·javascript·后端
来一杯龙舌兰5 小时前
【Sentinel】Springboot整合Sentinel、Socket进行熔断限流(生产级熔断限流)
spring boot·后端·sentinel·熔断限流
DKPT5 小时前
JVM直接内存和堆内存比例如何设置?
java·jvm·笔记·学习·spring