netty导致tomcat假死

一、系统需求:

保证后台系统在大并发下正常处理每一个业务连接请求。


二、运作方式:

Netty+tomcat。在tomcat的web.xml配置文件中配置一个Listener类用来在tomcat初始化启动时,启动一个Netty服务端,在Netty服务端的Handler中处理每一个连接请求的复杂业务。


三、使用版本:

netty版本:netty-all-5.0.0.Alpha1

jdk版本:Java: 版本 1.7.0_45

tomcat版本:apache-tomcat-8.0.9


四、运作说明:

使用Netty的高并发性能来处理大量的TCP长连接请求,客户端连接到Netty服务端之后,在Handler中调用web应用中相应的类进行处理。


五、出现问题:

收包一段时间(今天测试五个线程同时发,每个线程发送两万左右的数据包,总共大概十万数据包)以后,就会出现tomcat死机状态,日志了不再有任何输出,运行在同一个tomcat上的其他web工程都不能使用了,为什么由tomcat启动的netty协同工作接收大概十万数据包之后出现tomcat假死状态呢?

开源中国提问地址:求问,netty导致tomcat假死


六、问题分析:

6.1,监视线程工具1:jconsole 功能:监控堆内存使用量,线程数,类数量,CPU占用率等. 所在路径:${java安装路径}Java\jdk1.8.0_74\bin

6.2,监视线程工具2:jvisualvm 功能:同jconsole 所在路径:${java安装路径}Java\jdk1.8.0_74\bin 

jvisualvm监控图:


6.3,dump堆内存文件方法:

方法1、在jvisualvm界面监视选项卡的,点击“堆 Dump” 按钮即可生成heapdump文件;

方法2、使用命令jmap -dump:format=b,file=HeapDump.bin <pid>生成(会在界面中显示文件路径),需要查看目标线程的pid(可以查看任务管理器,或者在jconsole或者jvisualvm 工具中查看)。

6.4,dump文件分析工具:MAT(MemoryAnalyzer-1.5.0.20150527-win32.win32.x86_64),打开该软件对6.3中dump出来的dump文件进行分析,可以查看到当前状态下堆内存的使用,以及类的应用情况。

MAT分析结果图:






得到分析结果DefaultEventExecutor占比较高,可能是其出现问题

6.5,对每一个web应用进行监控(找到问题):

1、将javamelody.jar和jrobin-1.5.9.1.jar两个jar包放到web应用的lib中;

2、在web目录下的web.xml文件中加入如下xml片段。

<!-- tomcat监控 -->
<filter>                
       <filter-name>monitoring</filter-name>                
       <filter-class>net.bull.javamelody.MonitoringFilter</filter-class>         
    </filter>        
<filter-mapping>               
<filter-name>monitoring</filter-name>               
<url-pattern>/*</url-pattern>       
</filter-mapping>       
<listener>                
      <listener-class>net.bull.javamelody.SessionListener</listener-class>        
</listener>

3、在浏览器中访问http://localhost:8080/IoT_Harbor/monitoring?period=jour 即可得到当前web应用的监控图,以及所有线程的当前状态。

4、得到正常运行与异常时的线程状态图:

正常状态时:



异常时:



5、对比分析正常运行与异常时所有线程状态发现,后端的NIO线程被阻塞,而执行方法为log4j.


七、找到问题:

测试启动的多个线程,每个线程的测试发包速度为50ms,每次收到数据包Netty的Handler线程中均要对接收数据进行日志打印或者控制台输出,会进行频繁的IO操作,而IO操作会相对耗时。Netty的IO处理线程池,如果遇到非常耗时的业务会很容易把后端的NIO线程给挂死、阻塞。


八、解决方法:

对于复杂的后端业务,分派到专门的业务线程池里面,进行异步回调处理。

<think>我们正在尝试将Spring Boot默认的Tomcat服务器替换为Netty。Spring Boot默认使用Tomcat作为嵌入式Web服务器,但我们可以通过排除Tomcat依赖并添加Netty依赖来实现替换。 步骤如下: 1. 在项目的构建文件(如Maven的pom.xml或Gradle的build.gradle)中,排除Spring Boot Starter Web中的Tomcat依赖。 2. 添加Spring Boot的Netty starter依赖(对于Reactive Web应用,使用`spring-boot-starter-webflux`,它默认使用Netty)。 但是,请注意:Netty通常与响应式编程(如Spring WebFlux)一起使用。如果你正在构建一个传统的基于Servlet的应用程序(使用Spring MVC),那么替换为Netty可能不是一个直接的选择,因为Netty不是Servlet容器。Spring WebFlux使用的是非阻塞的、响应式的模型,而Spring MVC是基于Servlet API的阻塞模型。 因此,我们需要明确: - 如果你的应用是响应式的(使用WebFlux),那么默认已经是Netty,无需额外配置(除非你排除了Netty并需要重新引入)。 - 如果你的应用是基于Servlet的(使用Spring MVC),那么你需要考虑是否要迁移到响应式模型。如果不迁移,则无法使用Netty,因为Netty不支持Servlet API。 但是,有一种情况是,你可以在非Servlet环境下使用Netty,但你的整个应用需要调整为非阻塞的、响应式的。 因此,我们分两种情况: 情况一:构建响应式Web应用(使用WebFlux) 如果你正在构建响应式应用,那么默认使用Netty,所以只需要引入`spring-boot-starter-webflux`即可。 情况二:在基于Servlet的应用中使用Netty(不推荐,因为不兼容) 实际上,Spring MVC不能运行在Netty上,因为Netty不是Servlet容器。所以,如果你要用Netty,就必须将应用迁移到Spring WebFlux。 所以,我们假设你打算构建一个响应式应用。 步骤(Maven): 1. 如果你的项目已经存在`spring-boot-starter-web`(用于Spring MVC),需要将其移除或替换为`spring-boot-starter-webflux`。 2. 排除Tomcat(如果存在)并添加Netty(但`webflux`已经包含Netty,所以不需要显式排除Tomcat,因为`webflux`不依赖Tomcat)。 具体操作: 对于Maven项目,修改pom.xml: ```xml <dependencies> <!-- 移除原来的spring-boot-starter-web --> <!-- 添加webflux starter --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-webflux</artifactId> </dependency> </dependencies> ``` 这样,应用启动时就会使用Netty作为服务器。 如果你之前使用的是Spring MVC,那么你需要将Controller等代码调整为响应式风格(使用`@RestController`和返回`Mono`/`Flux`类型)。 另外,如果你已经有一个基于Spring MVC的应用,并且想迁移到WebFlux,这需要代码重构。 总结: 替换TomcatNetty的前提是将应用从Spring MVC迁移到Spring WebFlux(响应式)。然后,只需引入`spring-boot-starter-webflux`依赖即可,它会自动使用Netty。 注意:在Spring Boot中,`spring-boot-starter-webflux`默认使用Netty,但也可以配置为使用Undertow或Jetty(响应式版本)。如果你想确保使用Netty,可以排除其他服务器依赖。 引用中提到了一些关于自动配置的内容(引用[2][3]),实际上,Spring Boot的自动配置会根据类路径上的依赖自动选择服务器。当检测到`spring-boot-starter-webflux`且存在Netty的依赖时,就会配置Netty服务器。 引用[4]是关于异步处理的,与服务器替换无关。 因此,我们按照上述步骤操作即可。 最后,生成相关问题。</think>### 在 Spring Boot 中替换 TomcatNetty 在 Spring Boot 中替换默认的 Tomcat 服务器为 Netty 需要以下步骤,核心是**移除 Tomcat 依赖并引入 Netty 依赖**,同时确保应用适配响应式编程模型(因 Netty 是异步非阻塞服务器): #### 步骤 1:修改 Maven 依赖 在 `pom.xml` 中: ```xml <dependencies> <!-- 移除 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> <!-- 添加 Netty 依赖 (通过 WebFlux) --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-webflux</artifactId> </dependency> </dependencies> ``` #### 步骤 2:调整代码为响应式模型 Netty 需要响应式编程(基于 Reactor),修改控制器: ```java import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; import reactor.core.publisher.Mono; @RestController public class DemoController { @GetMapping("/hello") public Mono<String> hello() { // 返回 Mono 响应式类型 return Mono.just("Netty Server is running!"); } } ``` #### 步骤 3:验证配置 启动应用时,控制台会显示 Netty启动日志: ``` Netty started on port(s): 8080 ``` #### 关键原理 - Spring Boot 通过自动配置检测类路径:当存在 `spring-boot-starter-webflux` 时,自动选择 Netty 作为服务器[^2]。 - 自动配置过程:`@SpringBootApplication` → `@EnableAutoConfiguration` → 加载 `ReactiveWebServerFactoryConfiguration` → 初始化 Netty 服务器[^3]。 - 传统 Servlet 模型(如 `@Controller` 返回 `String`)与 Netty 不兼容,必须使用响应式编程。 #### 注意事项 1. **阻塞操作**:Netty 是异步非阻塞服务器,需避免 `Thread.sleep()` 或同步 IO 等阻塞操作。 2. **迁移成本**:若原有应用基于 Servlet API(如 `HttpServletRequest`),需重写为响应式风格。 3. **兼容性**:部分依赖 Tomcat 的库(如某些 Spring Security 模块)可能需要额外配置。 > 示例项目结构: > [GitHub 参考项目](https://github.com/spring-projects/spring-boot/tree/main/spring-boot-samples/spring-boot-sample-webflux)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值