SEDA(Staged Event-Driven Architecture)并不是很新的技术,但它总会在我阅读的资料里出现些许影子,所以就拿出一些时间看了一下与它相关的论文资料。SEDA的目标很远大,它要构建支持大并发的互联网系统,并克服多线程及事件驱动的服务器端模型的缺点。但SEDA来源于学术界,并且这个东西还是有些复杂了,所以至今工业级的应用不是很多。它的官网是http://www.eecs.harvard.edu/~mdw/proj/seda/,上面的一些论文还是很不错的,值得拜读。


对于服务端端处理模型,目前广泛使用的有两种:

1、多线程处理模型。这种模型由一个主线程和多个work线程构成,主线程负责接收请求,并将接收到的请求分发给合适的work线程处理,work线程处理完请求后直接将响应返回给客户端。这种模型很简单,也有着广泛的应用,尤其是通常的后端模块,处理逻辑在work线程里是阻塞进行的。这个模型的缺点也很明显,如果大量的work线程因为某种原因被堵住(比如连接的DB响应太慢、从磁盘获取文件数据等),将使得后续的请求得不到处理,而最经典的例子莫不过apache了。

2、事件驱动(Event-Driven)处理模型。这种模型克服了多线程模型的并发量缺点,对请求采用事件驱动方式处理,这里的事件通常是IO事件,其底层的实现依赖于非阻塞IO和IO多路复用。事件驱动模型很适合于IO密集型的应用,这种应用对CPU消耗代价甚至要小于线程间的切换代价,比如各种proxy。而现在的proxy,基本都标配Epoll,使得能支持的并发请求数在万级别。像lightty、nginx,是事件驱动模型的经典应用,请求的处理流程是由状态机驱动的,每次状态的切换经由一次事件触发,这样单线程就够用了(当然,如果需要支持更高的处理能力,可以采用多进程的事件驱动模型)。事件驱动的缺点在于:1)单个处理阶段不能阻塞太长,如果有这方面的问题,一般可采用专门的线程处理,处理完了再触发事件让主线程接着处理。2)整个事件驱动流程通常是固定的,在一个线程内由调度器完成,这使得它很难做的通用,使应用可以自定义流程。

基于上面提到的两种模型的优缺点,SEDA被提出来,它的核心思路是:一个请求被分成多个stage进行处理,每个stage彼此间独立,一个请求的多个stage可以串行化也可以并行化。stage内部使用Event-Driven,新到的请求放到event queue中,系统从thread pool中的选择一个线程经由Event Handler处理,Event Handler处理完后将请求派发到下一个stage。下面的是假想的一个Web server的SEDA的处理流程:

wKiom1N9nk_DQiBcAAHLlTz_AXE396.jpg


对于SEDA中的每个stage,它由下面的三部分组成:

1)输入的event queue。SEDA中的event queue的大小是有限制的。所以,如果event queue 达到阈值,新到的event可能会被拒绝或者转发到特定的stage(比如错误处理stage)。

2)thread pool:这个线程池对应用是透明的,并且每个stage的线程池是彼此独立的。针对请求量及特点,线程池可以动态的调整大小,不至于某个stage的线程池耗尽所有的资源。

3)event handler,event handler接收系统给予的event,做具体的逻辑处理后将event分发到其他stage。event handler通常需要应用开发者编写。

wKioL1N9nm6Q0UJgAADh4qAYscU129.jpg

SEDA stage内部结构图

针对各个stage运行时的状态,SEDA引入resource controller来调整stage的资源分配和调度参数等。核心的两个Controller是thread pool controller和batching controller。thread pool controller用来控制thread pool的运行时大小,比如当event queue很大时,就多分配些线程,反之则减少线程数。batching controller用来控制event handler同时处理的event的并发量(batching factor),当batching factor增大时,增加了吞吐量但event平均响应时间会变长,当batching factor变小时,情况相反。batching controller的控制效果使得batching factor的上下波动来控制吞吐量和响应时间。

wKiom1N9ntCSbo3oAAEKLxH1QKk535.jpg

SEDA controller结构图

SEDA的一个实现框架是Sandstorm,开发者可以基于它开发应用。限于精力,没有对它做实战,但使用上来说,它还是很简单的。可以想象的是,Sandstorm提供了一些编程接口做事件处理,并通过XML文件(Java的固有风格)来配置stage策略等。对于使用这样分阶段事件驱动框架来说,编程中需要注意stage间不要共享数据,并合理的划分stage策略。

就应用来说,SEDA的多stage处理模型,能够将应用组件化、模块化,解耦了处理的不同阶段,这可能很适合于如工作流等企业业务流程场景。但像通常简单的后端模块,对一个请求可能很难划分出多个职责明确的stage,并且这种分stage策略也增加了处理流程的复杂度,性能上也会受到损失。所以,针对不同的应用特点,SEDA的实用性仍值得商榷。


本文转载自:http://www.kafka0102.com/2010/02/34.html