简介 - aimingoo/ngx_4c GitHub Wiki

这个项目的源起

ngx_4c是一个编程框架,它是在一个分布式实时计算系统中的一部分。它不是独立存在的,它之所以被称为“4C”,是兼具“可控、可计算(Controllable, Computable)”和“通讯集群(Communication Cluster)”四个方面的特性。而其中,ngx_4c本身只是在nginx环境下提供前两者,至于通讯集群的能力是由ngx_cc这个项目来提供的。

ngx_cc项目远远早于ngx_4c,也更成熟。ngx_cc采用ngx.location.catpure()来实现在nginx集群中多方向通讯,是在nginx上的一个特定解决方案。而ngx_4c尽管也基于nginx,但实际上,是一个称为“4C”的整体架构标准下的、在nginx上的一个实现。

ngx_cc也好,ngx_4c也好,只是整个“4C架构”中的冰山一角。在nginx环境中,ngx_4c被称为“n4c programming architecture”,这是有着特定含义的:它是一个编程架构,解决“如何规范编程”的问题,而不是解决整个“4C架构”中的其它问题,例如集群稳定性问题、安全性问题、分布计算问题,或者是通讯问题等等。后面这些问题,是在“4C架构”中,在不同环境下采用不同的方案来实现的。

仅以nginx环境而言,ngx_4c是一个实现这些方案的基础:它定义基础的编程规范/模型。

对nginx环境的理解

nginx作为应用服务器是有缺陷的,例如对lua模块的依赖本身也是这些缺陷的一种——这意味着nginx并不原生地提供脚本编程能力,也不提供web application framework的支持。换言之,nginx原本就不是这些而设计的,直接拿它来跟一个传统的(成熟的、专门设计的)应用服务器作比较,多少显得不公平。

然而进一步地将nginx理解为应用服务器也是不足够的。lua的coroutine提供了在单进程环境中足够多的连接数,而nginx 1.9x在提供端口重用能力的同时进一步的刷新了这一上限。现在,nginx有足够的能力应付大规模并发的应用,无论从连接数、传输能力、服务的可配置性,以及CPU的利用率上,nginx作为分布式计算的结点的综合能力已经超过了大多数的既有方案。而另一方面,分布式环境下的可维护性问题,在nginx中几乎已经被抹平了(nginx的运维还会是问题么)。

只要稍加公平地考虑这些因素,nginx不仅仅是作为反向代理的时代就来临了。

ngx_4c可以是web application framework

ngx_4c的示例通常是一个webapp。这很容易理解,nginx不就是提供web服务的么。这样的示例在ngx_4c中简单而直白。

nginx.conf 配置

http {
	lua_package_path ...;

	init_by_lua_file 'init.lua';
	init_worker_by_lua 'n4c.startWorker();';
	rewrite_by_lua 'n4c.doRequestBegin();';

	server {
		listen 80;
	}
}

init.lua

n4c = {}

n4c.startWorker = function()
	-- NGX_4C launcher, with multicast events
	local events = require('lib.Events'):new()
	require('ngx_4c').apply(n4c, events)

	-- event handles
	events.on('RequestBegin', function(uri, method, params)
		if uri == '/hello' then
			ngx.say('hello, world.')
		end
	end)
end

现在,只要你正确配置nginx.conf中的lua_package_path,使得init_by_lua_file指令能找到init.lua这个文件,那么整个Webapp就可以运行了。——当然,你还要会把nginx运行起来,这想来就不算什么问题了。

但Webapp并非ngx_4c的全部

用的示例来说,它只使用了n4c的startWorker()和doRequestBegin()两个接口,分别由nginx的init_worker和rewrite两个pahses来驱动。如果进入ngx_4c.lua这个模块内部,事实上你会发现它什么也没有干,它就是把"RequestBegin"作为一个事件(event)转投给了events.RequestBegin而已。

这也就是ngx_4c的核心处:ngx_4c并不提供任何业务逻辑的实际实现,它只提供这些实现所需的编程模型、架构与机制。

在ngx_4c 0.9x中,我们公开了其中的四种机制:

  1. 多投事件驱动框架:Multi-cast event drive
  2. 异步编程模型:Promise in lua
  3. 反向代理结果预取:R-Proxy Response buffered
  4. 反向代理请求头定制:R-Proxy Request headers custom

机制1是面向Webapp的,它采用极轻量的Events实现(在这里:https://github.com/aimingoo/Events),因此既可作为Webapp的标准框架,也可以作为“4C架构”中的微任务(micro tasks)的驱动模型。

机制2是面向异步编程的,它同时也是“4C架构”中的分布式编程的基本模型,它采用的是基于ES6的Promise实现(在这里:https://github.com/aimingoo/Promise)。

后两种机制看起来仍然将nginx作为反向代理,但事实上,由于ngx_cc作为“通讯集群(Communication Cluster)”时,利用的就是nginx作为反向代理时的能力(pass_proxy)——也就是说,后两种机制其实是面向ngx_cc整合的,是对ngx_cc在集群通讯能力上的补充。

规范的事件循环

在nginx的编程中有很多种可能性。出于不同的目的你可以拿nginx + lua来做很多不同的事情,并采用种种不同的方案。但这带来的一个事实是:如何做一个Webapp或者一类确定的应用,却不存在一个可用的规范。

如下图所示,ngx_4c约定了一个事件循环: n4c event loop

如果你只需要实现Webapp,那么你只需要这其中的一个事件:

n4c.doBeginReuest()

并采用ngx_4c的标准方案将它launch起来就可以了——参见前面的示例,或者文档:README.me

如果你不需要使用ngx_cc,那么你并不总是需要装载其它的事件:

  • doBodyFilter
    • (privated) doResponseEnd
  • doSessionClose

而这些(装载/不装载)都是通过nginx.conf来控制的——包括对ngx_cc的集成。

对于ngx_4c来说,它本身只约定了“事件驱动”、“异步编程”等这样一些框架层面的技术与接口,我们可以在它的上面应用(apply)足够丰富的实现,而无碍于它在架构层面的简洁。