Netflix微调Tomcat的经验分享

15-07-30 banq
              

Netflix公司有许多高吞吐量,低延迟中间层服务。在这些服务中会发现:如果在很短的时间遭遇巨大的流量激增,服务器的CPU会变得反应迟钝。 这会导致不愉快的用户体验。

这里有一个读操作和连接超时的问题,如果读超时被设置得很高,运行时读操作超时情况反而很糟糕, 客户端将花很长时间等待服务器响应,而且在SOA情况下,这可能导致产生连锁反应,因为这些客户端的客户端也将因为读超时而等待,最后导致所有服务响应缓慢。

在正常情况下,这些机器有足够空闲的cpu,而且服务也不是CPU密集型的。 那么,为什么会出现这种情况? 为了理解这种情况,让我们先来看看这些服务的请求调用顺序:

----> Apache ----> Tomcat

在模拟访问量激增的测试环境中,发现造成CPU饥饿的原因是不正确的Apache和Tomcat配置导致。 当流量突然增加,多个apache worker变得忙碌,大量的tomcat的线程也忙了起来。 这时的CPU没有一个线程在做任何有意义的工作,它们的大部分时间花在了CPU上下文切换上。

首先看看tomcat的线程模型:

Tomcat有一个 acceptor线程来接受连接,有一个worker线程池来处理真正的工作,对于一个进来的请求:

1. TCP 在OS和客户端之间握手建立一个连接,取决于操作系统,这时会有一个队列或几个队列来hold住这个连接,在多个队列中,一个队列hold住tcp 握手还未完成的连接,一旦这个连接握手完成,连接会被迁移到一个已经完成连接的队列中,在这里等待应用程序调用使用,"acceptCount"参数是tomcat配置中用于配置这些队列大小的参数。

2.Tomcat的acceptor线程接受来自已经完成连接的队列的连接。

3.检查如果线程池中是否有worker线程可用,如果没有,创建一个worker线程,当然前提是当前活动的线程数量小于maxThread参数,否则等待一个worker线程变成空闲。

4.一旦一个空闲worker线程被发现,acceptor线程会将连接递交给它,然后回来再监听有没有新的已经完成连接的连接。

5.worker线程会实现从连接中读取输入等具体工作,然后处理请求,将响应发回给客户端,如果连接没有保持alive活动,它就要关闭这个连接,将自己返回空闲线程池,对于一个保持alive活跃 keep alive的连接,它会等待连接中更多数据进来,直至keepAlive Timeout参数设置的超时时间到了以后就不会再等待了,然后,关闭连接,将自己放回空闲的线程池。

如果tomcat的线程数量和acceptCount值被设置太高,对于突然增加的流量会填满OS队列,使得所有worker线程变得很忙,当

更多请求发送到服务器,队列中请求大量增加,导致大量增加很多忙线程,从而导致CPU饥饿。解决办法是避免OS和tomcat线程的请求队列数量设置过大,当系统容量达到最大值时,确保返回503这样的fail fast保护方案。

The Netflix Tech Blog: Tuning Tomcat For A High Th

              

2
lostalien
2015-08-10 14:55

确保返回503这样的fail fast保护方案

能详细讲讲这个么?我对fail fast的了解仅限于java里Iterator的那个快速失败

banq
2015-08-10 15:00

2015-08-10 14:55 "@lostalien"的内容
确保返回503这样的fail fast保护方案 ...

我个人理解,类似在Nginx这种代理中设置一下IP访问限制,也就是一个IP最多并发同时能发出多个请求,如果超过了这个最大请求数,返回Http编码 503,页面繁忙,请稍后请求。