同事聊起这个话题,当请求建立时是否tomcat就为每个连接分配线程了? 是否只要发起足够多的连接不必发送任何数据就可以DDoS了?对于DDoS这个话题不展开,这里仅仅说一下连接过来时,服务器端是否就一定分配了线程。这取决于tomcat配置的connector模式,只讨论一下bio和nio的情况。
以bio模式启动tomcat,然后建立3个连接(不发送任何数据):
$ nc localhost 8080 &
$ nc localhost 8080 &
$ nc localhost 8080 &
这时我们来看tomcat的bio执行线程是与连接数一对一的:
$ ./appctrl.sh jstack | grep http-bio-8080-exec
"http-bio-8080-exec-3" #24 daemon prio=5 os_prio=31 tid=0x00007fdd7a840800 nid=0x6607 runnable [0x000000011d78b000]
"http-bio-8080-exec-2" #23 daemon prio=5 os_prio=31 tid=0x00007fdd7a83f800 nid=0x6507 runnable [0x000000011d618000]
"http-bio-8080-exec-1" #22 daemon prio=5 os_prio=31 tid=0x00007fdd7a800000 nid=0x4107 runnable [0x000000011addd000]
而在nio模式下,请求建立时,并不会有执行线程,只有接收到数据发时,才会有线程分配:
$ nc localhost 8080
POST /test/post?name=foo HTTP/1.1
Host: localhost:8080
Context-Length: 10000
上面在nc建立连接后,发送了一段http header(还未发送body,请求保持中),这时才会对这些请求数据分配线程阻塞执行:
$ ./appctrl.sh jstack | grep http-nio-8080-exec
"http-nio-8080-exec-3" #26 daemon prio=5 os_prio=31 tid=0x00007ffefb001800 nid=0x6007 waiting on condition [0x0000000123af7000]
"http-nio-8080-exec-2" #25 daemon prio=5 os_prio=31 tid=0x00007ffefa029000 nid=0x5d07 waiting on condition [0x000000012351c000]
"http-nio-8080-exec-1" #24 daemon prio=5 os_prio=31 tid=0x00007ffef900a000 nid=0x680b waiting on condition [0x000000012328f000]
上面的测试是在tomcat7下测试的,nio在处理http request的时候是非阻塞的,但读取数据的时候是模拟阻塞的,因为servlet3.1之前对input的处理就是一种阻塞模式,参考以前的一张截图: