青岛大学医学院 抑郁症:多任务服务中并发策略的演变

来源:百度文库 编辑:偶看新闻 时间:2024/04/26 11:54:10

多任务服务中并发策略的演变

2011/04/09liuchangit抢沙发

在我们的web服务程序中,对每一个流入的用户请求,都需要执行N个不同任务才能完成整个处理过程。执行这些任务的多线程并发处理策略经历了几次演变。

在一开始的时候(约两年前),由于历史原因,对每一个任务,都是新开一个线程,如下:


帮助
1
Thread t = 
new Thread(task);2t.start();


所以对每个用户请求,在请求处理主线程中,都new了N个线程,每个线程的执行结果通过polling方式获取,即主线程在busy wait中轮循。这种方式非常不好:新创建的线程,执行一次任务,就被销毁,不能重用,线程创建/销毁的开销是很大的;而且不能限制资源消耗,只要有用户请求流入,就会不断地创建新线程,若流量太大,服务器很容易崩掉;且请求处理主线程存在busy wait,弊端多多,参见Future模式。

因此,对并发处理策略进行了改造(约一年前):通过线程池和Future模式,实现了在一个共享线程池中执行所有用户请求的所有任务。这样基本上避免了线程创建/销毁的开销(在服务启动时会一次性创建线程池中所有线程),可以通过设定线程池大小来限制服务器的资源占用进而提升稳定性,消除了busy wait。
随着时间的推移,共享线程池的弊端也慢慢浮现出来。由于N种不同任务的执行耗时是不一样的,线程池中总的线程数有限,因此耗时最长的一种任务就会较多地占用线程池中的线程,当流量低于服务器处理能力时,这不会有什么问题。而当流量超出服务器承载能力时,那些执行时间较短的任务就得不到可用的线程去执行,进而导致请求阻塞且不会超时,最终造成整个服务处理效率低下,响应非常缓慢。流量超出服务器处理能力越多,每种任务的执行耗时差别越大,后果越明显。

针对共享线程池的问题,再次进行了改造(约一月前):按照任务类型的不同,将共享线程池分割为多个线程池,同种任务由同一个线程池来处理,避免了不同任务之间竞争资源,造成某些任务得不到可用线程而饿死。这样虽然在流量过大时,同样会存在问题(这是不可避免的),但可以通过不同的线程池,为每种任务设定不同地资源上限,预留最少资源,来缓解共享线程池的问题。这种分割线程池的方式,是物理划分,也可以通过物理共享、逻辑划分的方式来实现,在淘宝数据平台博客上有一篇支持配额的共享线程池即是如此。综合来看,物理划分和逻辑划分两种方式是不相上下的,在我们当前的应用场景中,物理划分的方式基本上算是做到了尽头。