# 分阶段事件驱动架构(SEDA)

SEDA(staged event-driven architecture)结合了线程和事件驱动程序模型去管理并发、IO、定时和资源管理。

# 传统线程模型

最普遍使用的server架构就是每一个线程一个请求的模型。如图所示,每一个进入系统的request请求被分配一个线程,线程处理请求之后将结果发回客户端。

这种模型易于实现,但瓶颈也显而易见:当线程数过多时,性能会严重下降。另一个问题在于线程和进程一般都是由操作系统进行硬件资源的分配和调度,一般不会给应用程序太多的控制权限,因此一般来说基于线程进行分配的优化能力是比较有限的。

如下图所示,随着线程数增多,吞吐量急剧下降。

# 有界线程池

为了避免线程的过度使用,一些程序会引入有界线程池。通过限制并发线程数,server可以避免传统线程的线程过多的问题。

但线程池的问题也很明显,当请求数过多时,可能会导致所有的线程都在阻塞或占用,使得同一时间的请求并不会被“公平”地执行。例如一些请求消耗的资源很少(缓存静态页面),但因为同一时间有很多请求在执行,因此那些耗费资源的请求会占用有限的线程,成为系统的瓶颈。同时应用层是无法控制线程的调度的,

# 事件驱动并发

这种模型,首先应用层包含了一小部分线程(一般一个CPU核一个),线程一直循环,来执行处理不同队列中的事件。如下图,每一个FSM代表了单个请求,由于所有的任务均由Scheduler进行调度,因此应用可以自己控制所有任务的执行状态,而不需要依赖线程上下文。当然这种模型给程序开发者提出了比较高的挑战,需要设计一个高效的事件调度器,用于平衡请求优先级、资源消耗、处理顺序等。

事件驱动的优点在于,随着任务数量增多,吞吐量可以维持在CPU(驱动)可以支撑的上限。

事件驱动的限制在于,每一个事件的处理必须是非阻塞的。

# SEDA模型

SEDA模型的目标在于:

  • 支持大规模并发
  • 简化优质服务的建设
  • 允许程序自我分析
  • 支持资源的准确管理

SEDA模型的基本单元成为stage,stage由一个事件管理器,一个输入事件队列和一个线程池组成。stage的操作被controller管理,controller动态控制资源分配和调度。如下图所示。

这样设计的好处在于:

  • 每个stage由一小部分线程限制,每个stage按照需求来分配线程资源。
  • 多个stage的运行是并行的。

这样的架构使得应用只需要关注事件处理器本身(具体业务逻辑),然后通过队列将stage组成一个应用。每个stage可以独立开发,每个stage也可以动态添加和卸载。

# 参考

  • SEDA: An Architecture for Well-Conditioned, Scalable Internet Services, Matt Welsh, David Culler, and Eric Brewer. In Proceedings of the Eighteenth Symposium on Operating Systems Principles (SOSP-18), Banff, Canada, October, 2001.