随着 Rails4.0 的发布,Ruby 的 Web 开发社区开始进入多线程的时代了:
多线程服务器的模型,相比传统多进程服务器模型,可以非常有效的提高 IO 并发的吞吐量。我现在开发 Web 应用,已经全部改用多线程了,我写过一个相关的文档介绍:Web 并发模型粗浅探讨,有哪些 Ruby 的应用服务器可以良好的支持多线程呢?
rainbows和unicorn是同一个作者 Eric Wong 开发的,rainbows 和 unicorn 非常像,他们之间的主要区别就是:unicorn 是多进程服务器,rainbows 是多线程服务器,此外基本用法,配置都一样的,本身 rainbows 就是基于 unicorn 开发的。
unicorn 现在被广泛的使用在很多负载非常高的生产环境中,rainbows 也和 unicorn 同样非常稳定。由于 Ruby1.9 的 GIL,多线程并发只能有效使用 1 颗 CPU 内核,因此在多核服务器上,需要运行多个 rainbows 进程。一般来说,服务器有多少 CPU 内核,就启动多少个 rainbows worker 进程。每个 rainbows 进程里面再启动多个线程,因此理想情况下,能够同时处理的 IO 并发请求数量等于“进程数” × “线程数”,看一个例子:
rainbows.rb,注意以下 3 项配置:
use :ThreadPool # 使用线程池模式,进程启动的时候创建好线程数 worker_processes 4 # 创建多少个进程 worker_connections 64 # 每个进程创建多少个线程
以上面的配置为例,如果你在一台 4 核服务器上面部署应用,希望尽量使用服务器资源,那么可以创建 4 个进程,每个进程创建 64 个线程,因此整个服务器 IO 并发处理能力是 256 个执行线程,这比传统的多进程模式要高得多。
控制 rainbows 服务器的 shell 脚本很容易写:rainbows.sh,rainbows 和 unicorn 一样,都是通过给进程发送信号来控制服务器的。
以上的配置启动以后,会有 5 个 rainbows 进程:1 个 master 控制进程,4 个 worker 工作进程。master 进程负责加载应用程序代码,创建和销毁 worker 进程,分发请求;worker 进程负责处理请求。这个 master-workers 的工作模式和 nginx 是一样的。你还可以通过给 master 进程发送信号,让 master 进程创建更多 worker 进程,或者减少 worker 进程,还可以实现“平滑的重启”,即在不中断 web 请求服务的同时,重新启动进程,加载新的应用代码,这一点通过: rainbowsctl reload
就可以实现。
此外如果你使用的是 Ruby2.0,还可以在rainbows.rb
里面打开 copy on write 特性,如下:
preload_app true GC.respond_to?(:copy_on_write_friendly=) and GC.copy_on_write_friendly = true
可以让多个进程共享加载应用程序框架和库的内存空间,节省很多物理内存。
总之对于大型多线程 Ruby Web 应用,推荐使用 rainbows,我使用下来感觉也很不错。
我在相当长一段时间都不怎么关注 puma,因为 puma 是个单进程多线程服务器,没有 cluster 模式,不太适合真实有负载的环境,对于多核服务器,启动多进程跑 cluster 是必须的。但是最近 Puma 升级到 2.0 版本以后,也支持了多进程 cluster 模式,而且也是 master-workers 的方式,类似 nginx 和 rainbows,请看配置文件:puma.rb
workers 0 # 指定创建多少个 worker 进程,如果 0 则不打开 cluster 模式 threads 0, 16 # 最少线程和最多线程,可根据请求量在这个范围自动伸缩
通过 workers 设置进程数,通过 threads 设置线程数,最大 IO 并发请求量等于进程数乘以最大线程数。Puma 比较有意思的地方在于:
此外 puma 也支持“平滑的重启”,也提供了很多有趣的状态控制方式,请看puma.sh Puma 启动的时候可以设置一个状态文件,它会把进程的运行状态写进去,方便你控制进程的运行。
我对 Rainbows 和 Puma 做了一些简单的性能压力测试,测试结果表明两者之间的性能差异非常小,Rainbows 稍稍胜出。使用哪个,更多取决于个人偏好。我觉得大型应用使用 Rainbows 更好一些,希望节省服务器资源的小型应用更适合用 Puma。这是因为:
zbatery也是 unicorn 和 rainbows 的作者 Eric Wong 开发的,配置文件可以直接用 rainbows 的,它是 rainbows 的简化版本,只支持单进程多线程,没有 master 进程,信号支持的也不完整,而且很久没有升级过了。比较正规的生产环境可能就不太适合了。但 zbatery 的好处是特别节省内存,比单进程的 puma 还要节省很多内存,如果你想在一个 VPS 上跑很多 web 应用,每个 web 应用流量都很小,那用 zbatery 到非常合适。