多语言动态 Web 应用服务器-Nginx Unit


Nginx Unit 以 Nginx 为基础、支持多语言的开源 Web 服务器,是用于各种轻型,动态的Web应用程序。它从头开始构建,可以一次运行多种语言版本的Web应用程序,也可以在运行时完全配置为零中断,从而可以对工程和操作进行实时粒度管理。可以在不中断服务的情况下完成部署配置更改,以多种语言运行代码。它运行多种语言的能力是基于内部路由器进程之间的隔离,路由器进程可终止传入的 HTTP 请求,以及应用程序进程的分组,路由器进程是持久的,不重新启动。

采用C语言开发并在ApacheV2.0协议下授权。
核心功能
使用 RESTful JSON API 可完整地动态重配置服务器
可同时运行多语言及多版本的应用
动态语言的进程管理功能,应用程序名称空间隔离
支持 TLS(OpenSSL 1.0.1 或更高)
广泛的请求路由功能和静态内容支持
适用于Node.js和Java的内置WebSocket服务器实现
可支持的应用程序语言:Perl、Python、PHP、Go、Ruby、JavaScript(Node.js)、Java
每个单独的应用,都可以在 Nginx Unit 的配置文件中,使用 JSON 语法来定义一个 applications。
里程碑
Nginx Unit 1.0是Nginx, Inc.公司在2018年4月12日正式发布的动态Web及应用服务器,Nginx Unit首先定位是应用服务器,也就是application server,对应竞品是unicorn、Tomcat、Passenger等一众动态语言的应用服务器。
下文转自《Nginx Unit发布,微服务利器》,感谢原作者。
多语言多版本支持
最令人兴奋的点是Nginx Unit直接支持多语言(Polyglot),并且支持同一语言的不同版本,目前微服务架构盛行,一大特征便是多语言支持,之前可能支持的方式便是不同语言运行在各自的应用服务器下,再通过Nginx进行反向代理,来实现多语言支持,现在可以通过Nginx Unit来直接做应用服务器,而不需要再引入原先的应用服务器,精简了部署架构,目前Nginx Unix支持的语言情况如下:

从上表可以看到,主流的动态语言已经支持了5种,另外计划中支持的Java和Node.js也是很让人期待的发布。
动态管理应用

上图是使用Nginx + Nginx Unit来部署PHP应用的一个典型架构,通过Nginx来做Web服务器(负责静态文件和反向代理服务等),Nginx Unit做应用服务器,这样我们能快速了解Nginx和Nginx Unit的定位区别,Nginx Unit更专注在应用服务器这里。
服务器动态管理能力也是Nginx Unit的亮点,通过Control REST API进行管理,例如对应用的增删改查(JSON格式),在进行管理时,Nginx Unit不需要重载配置,也不会中断服务,这个跟Nginx Unit的架构设计相关,它在设计之初就为动态能力为核心,本文后面会简单介绍Nginx Unit的架构,在此我们先看看Nginx Unit的应用配置管理。
Nginx Unit里面的应用需要配置application和listner两个字段才能提供应用服务,以下是一个最简单的应用服务配置:
{
"listeners": {
"*:8300": {
"application": "blogs"
}
},
"applications": {
"blogs": {
"type": "php",
"processes": 20,
"root": "/www/blogs/scripts",
"index": "index.php"
}
}
}
上面我们定义了一个名为blogs的应用,运行语言是PHP,另外定义了一个监听器,监听在8300端口来提供blogs应用服务,将该配置保存在json文件中,然后通过访问Control API进行应用服务添加,示例如下:
# curl -X PUT -d @/path/to/blogs.json --unix-socket /path/to/control.unit.sock http://localhost/config/
我们也可以通过如下命令来调用Control API来查看目前的配置:
# curl --unix-socket /path/to/control.unit.sock http://localhost/config/
# API返回示例如下
{
"listeners": {
"*:8300": {
"application": "blogs"
}
},
"applications": {
"blogs": {
"type": "php",
"user": "nobody",
"group": "nobody",
"root": "/www/blogs/scripts",
"index": "index.php"
}
}
}
这样使用JSON格式、通过Control REST API进行应用服务管理的方式,使得可以很方便地将基于Nginx Unit的应用服务发布管理融合到持续发布流程中,都不需要对Nginx Unit进行重载或中断服务。
Nginx Unit的架构

如上图所示,Nginx Unit的进程如下:
主进程:唯一进程,负责创建路由、应用进程;
路由进程:唯一进程,负责所有出入网络请求的处理,可以快速实施配置变更而不中断服务。另外这个进程是持久的,不会重启;
控制器进程:唯一进程,负责接收处理通过管理API过来的配置请求,并且将配置下发给主进程和路由进程;
应用进程:每个进程部署在各自沙盒环境中,保证安全隔离,应用进程数量是动态变化的。
Nginx Unit支持按需扩展进程,每个进程都运行在自己的沙箱环境中,这样应用进程才能够在同一个Nginx Unit里面支持多语言多版本的应用了。
Nginx Unit的未来
从官方介绍中可以得知,接下来Nginx Unit会支持Java和Node.js,这样Nginx Unit就将目前主流Web编程语言都支持了;另外计划支持HTTPS和HTTP/2协议,以及通过URI和主机名进行路由等特性。不难看出这里Nginx, Inc公司的野心,想将Nginx Unit打造成为多语言多版本支持、简易管理及可靠度高的应用服务器,来更好支持微服务、Service Mesh架构。

目前Nginx Unit刚发布1.0版本,各个语言的支持情况还不会特别完善,例如一些框架在Nginx Unit下运行可能会有问题,抑或是性能表现还需要观察,但总体而言,Nginx Unit还是值得尝试的新应用服务器,从Nginx的生态版本可以看到它的定位还是很清晰的,就是来取代之前各语言的应用服务器。
最新版本:1.2x
1.21.0 的更新内容除了常规的 bugfix 外,还增加了部分新特性,例如支持条件匹配的 PCRE 和多线程请求处理等。
因此,开发者现在可以调整每个应用程序进程中用于请求处理的线程数,这样能改善伸缩能力并优化内存使用率。另外,应用程序可以将多个进程和每个进程的多个线程结合使用,以实现真正的动态扩展。此功能可直接用于任何 Java、Python、Perl 或 Ruby 应用程序, 而无需更新其代码。部分更新内容:
当使用"rootfs"隔离时,所有语言的 procfs 都会被默认挂载
现在支持在 HTTP header 名字中使用任何符合 RFC 7230 标准的有效字符
包含下划线 ("_") 的 HTTP header 字段现在会被默认从请求中丢弃
为 Java、Python、Perl 和 Ruby 应用程序提供可选的多线程请求处理
路由匹配模式中新增正则表达式支持
兼容 Python 3.9,Python 模块支持 ASGI 2.0 遗留应用,Python 应用中的"protocol"选项有助于在 ASGI 和 WSGI 之间进行选择
PHP 函数 fastcgi_finish_request() 可以在不保持客户端连接的情况下完成请求处理并继续执行代码
HTTP 选项"discard_unsafe_fields"可以丢弃字段名中含有不规则字符(但仍然有效)的请求头字段
"procfs" 和 "tmpfs" 自动挂载隔离选项,可以禁用同名文件系统的自动挂载
在高负载下运行 Go 应用时,路由器进程可能会崩溃;该 bug 曾在 1.19.0 中出现
使用"rootfs"隔离后,一些语言依赖可能会保持挂载
Java 应用中的多项兼容性问题
使用 musl C 库构建的 Java 模块无法运行使用"rootfs"隔离的应用程序
在2021年3月未发布的1.23.版本中更新内容包括改进对 TLS 的支持、简化 TLS 配置以及修复错误等。
1.28.0 已正式于2022年9月中旬发布,新版本在可观测性方面进入了一个里程碑:
新版本支持获取有关连接、请求和其他每个应用程序指标的基本信息
上述数据可通过 Nginx Unit 的 RESTful API 获取
除此之外,Nginx Unit 1.28.0 还引入了新变量,支持使用它们来定制访问日志的格式。除了期待已久的统计和日志记录用例,新版本还提供:
通过新的配置语法和 X-Forwarded-Proto 支持,增强对 forward header 的处理
在类 Linux 系统上的侦听器中支持抽象的 UNIX 域套接字 (domain socket)
修复多个社区报告的错误
官方主页:http://nginx.org/

采用C语言开发并在ApacheV2.0协议下授权。
核心功能
使用 RESTful JSON API 可完整地动态重配置服务器
可同时运行多语言及多版本的应用
动态语言的进程管理功能,应用程序名称空间隔离
支持 TLS(OpenSSL 1.0.1 或更高)
广泛的请求路由功能和静态内容支持
适用于Node.js和Java的内置WebSocket服务器实现
可支持的应用程序语言:Perl、Python、PHP、Go、Ruby、JavaScript(Node.js)、Java
每个单独的应用,都可以在 Nginx Unit 的配置文件中,使用 JSON 语法来定义一个 applications。
里程碑
Nginx Unit 1.0是Nginx, Inc.公司在2018年4月12日正式发布的动态Web及应用服务器,Nginx Unit首先定位是应用服务器,也就是application server,对应竞品是unicorn、Tomcat、Passenger等一众动态语言的应用服务器。
下文转自《Nginx Unit发布,微服务利器》,感谢原作者。
多语言多版本支持
最令人兴奋的点是Nginx Unit直接支持多语言(Polyglot),并且支持同一语言的不同版本,目前微服务架构盛行,一大特征便是多语言支持,之前可能支持的方式便是不同语言运行在各自的应用服务器下,再通过Nginx进行反向代理,来实现多语言支持,现在可以通过Nginx Unit来直接做应用服务器,而不需要再引入原先的应用服务器,精简了部署架构,目前Nginx Unix支持的语言情况如下:

语言 | 支持版本 |
---|---|
PHP | PHP 5, 7 |
Python | Python 2.6, 2.7, 3 |
Golang | Go 1.6 及更新版本 |
Perl | Perl 5.12 及更新版本 |
Ruby | Ruby 2.0 及更新版本 |
Java | 计划支持 |
JavaScript/Node.js | 计划支持 |
从上表可以看到,主流的动态语言已经支持了5种,另外计划中支持的Java和Node.js也是很让人期待的发布。
动态管理应用

上图是使用Nginx + Nginx Unit来部署PHP应用的一个典型架构,通过Nginx来做Web服务器(负责静态文件和反向代理服务等),Nginx Unit做应用服务器,这样我们能快速了解Nginx和Nginx Unit的定位区别,Nginx Unit更专注在应用服务器这里。
服务器动态管理能力也是Nginx Unit的亮点,通过Control REST API进行管理,例如对应用的增删改查(JSON格式),在进行管理时,Nginx Unit不需要重载配置,也不会中断服务,这个跟Nginx Unit的架构设计相关,它在设计之初就为动态能力为核心,本文后面会简单介绍Nginx Unit的架构,在此我们先看看Nginx Unit的应用配置管理。
Nginx Unit里面的应用需要配置application和listner两个字段才能提供应用服务,以下是一个最简单的应用服务配置:
{
"listeners": {
"*:8300": {
"application": "blogs"
}
},
"applications": {
"blogs": {
"type": "php",
"processes": 20,
"root": "/www/blogs/scripts",
"index": "index.php"
}
}
}
上面我们定义了一个名为blogs的应用,运行语言是PHP,另外定义了一个监听器,监听在8300端口来提供blogs应用服务,将该配置保存在json文件中,然后通过访问Control API进行应用服务添加,示例如下:
# curl -X PUT -d @/path/to/blogs.json --unix-socket /path/to/control.unit.sock http://localhost/config/
我们也可以通过如下命令来调用Control API来查看目前的配置:
# curl --unix-socket /path/to/control.unit.sock http://localhost/config/
# API返回示例如下
{
"listeners": {
"*:8300": {
"application": "blogs"
}
},
"applications": {
"blogs": {
"type": "php",
"user": "nobody",
"group": "nobody",
"root": "/www/blogs/scripts",
"index": "index.php"
}
}
}
这样使用JSON格式、通过Control REST API进行应用服务管理的方式,使得可以很方便地将基于Nginx Unit的应用服务发布管理融合到持续发布流程中,都不需要对Nginx Unit进行重载或中断服务。
Nginx Unit的架构

如上图所示,Nginx Unit的进程如下:
主进程:唯一进程,负责创建路由、应用进程;
路由进程:唯一进程,负责所有出入网络请求的处理,可以快速实施配置变更而不中断服务。另外这个进程是持久的,不会重启;
控制器进程:唯一进程,负责接收处理通过管理API过来的配置请求,并且将配置下发给主进程和路由进程;
应用进程:每个进程部署在各自沙盒环境中,保证安全隔离,应用进程数量是动态变化的。
Nginx Unit支持按需扩展进程,每个进程都运行在自己的沙箱环境中,这样应用进程才能够在同一个Nginx Unit里面支持多语言多版本的应用了。
Nginx Unit的未来
从官方介绍中可以得知,接下来Nginx Unit会支持Java和Node.js,这样Nginx Unit就将目前主流Web编程语言都支持了;另外计划支持HTTPS和HTTP/2协议,以及通过URI和主机名进行路由等特性。不难看出这里Nginx, Inc公司的野心,想将Nginx Unit打造成为多语言多版本支持、简易管理及可靠度高的应用服务器,来更好支持微服务、Service Mesh架构。

目前Nginx Unit刚发布1.0版本,各个语言的支持情况还不会特别完善,例如一些框架在Nginx Unit下运行可能会有问题,抑或是性能表现还需要观察,但总体而言,Nginx Unit还是值得尝试的新应用服务器,从Nginx的生态版本可以看到它的定位还是很清晰的,就是来取代之前各语言的应用服务器。
最新版本:1.2x
1.21.0 的更新内容除了常规的 bugfix 外,还增加了部分新特性,例如支持条件匹配的 PCRE 和多线程请求处理等。
因此,开发者现在可以调整每个应用程序进程中用于请求处理的线程数,这样能改善伸缩能力并优化内存使用率。另外,应用程序可以将多个进程和每个进程的多个线程结合使用,以实现真正的动态扩展。此功能可直接用于任何 Java、Python、Perl 或 Ruby 应用程序, 而无需更新其代码。部分更新内容:
当使用"rootfs"隔离时,所有语言的 procfs 都会被默认挂载
现在支持在 HTTP header 名字中使用任何符合 RFC 7230 标准的有效字符
包含下划线 ("_") 的 HTTP header 字段现在会被默认从请求中丢弃
为 Java、Python、Perl 和 Ruby 应用程序提供可选的多线程请求处理
路由匹配模式中新增正则表达式支持
兼容 Python 3.9,Python 模块支持 ASGI 2.0 遗留应用,Python 应用中的"protocol"选项有助于在 ASGI 和 WSGI 之间进行选择
PHP 函数 fastcgi_finish_request() 可以在不保持客户端连接的情况下完成请求处理并继续执行代码
HTTP 选项"discard_unsafe_fields"可以丢弃字段名中含有不规则字符(但仍然有效)的请求头字段
"procfs" 和 "tmpfs" 自动挂载隔离选项,可以禁用同名文件系统的自动挂载
在高负载下运行 Go 应用时,路由器进程可能会崩溃;该 bug 曾在 1.19.0 中出现
使用"rootfs"隔离后,一些语言依赖可能会保持挂载
Java 应用中的多项兼容性问题
使用 musl C 库构建的 Java 模块无法运行使用"rootfs"隔离的应用程序
在2021年3月未发布的1.23.版本中更新内容包括改进对 TLS 的支持、简化 TLS 配置以及修复错误等。
1.28.0 已正式于2022年9月中旬发布,新版本在可观测性方面进入了一个里程碑:
新版本支持获取有关连接、请求和其他每个应用程序指标的基本信息
上述数据可通过 Nginx Unit 的 RESTful API 获取
除此之外,Nginx Unit 1.28.0 还引入了新变量,支持使用它们来定制访问日志的格式。除了期待已久的统计和日志记录用例,新版本还提供:
通过新的配置语法和 X-Forwarded-Proto 支持,增强对 forward header 的处理
在类 Linux 系统上的侦听器中支持抽象的 UNIX 域套接字 (domain socket)
修复多个社区报告的错误
官方主页:http://nginx.org/