Rails 请教 Rails 的是怎样运行起来的?

uestc_bird · 2016年04月15日 · 最后由 uestc_bird 回复于 2016年04月15日 · 3465 次阅读

目前典型的 rails 服务器的构成都是这样一种模型: Nginx(web server) ----> Passenger/unicorn/puma 等 (app server) -----> rails(App)

  1. Nginx 服务器一般是用来作为反向代理以及负载均衡来使用的,它是一个单独的进程(相对于 os 来说),能够监听在某个端口上,提供 http 的 request/response 服务,当 nginx 服务器接收到一个 http 请求的时候,会立马转发给下一层的服务器,例如 passenger,将这个请求原封不动的转给 passenger, 他们之间的通信一般用的是 socket;
  2. Passenger 服务器,独立运行在操作系统的环境下,启动之后,在 OS 里面可以查看到其 Pid, 典型的服务器模型(被启动之后,初始设置完成后,监听在某个端口,进入 while true 死循环来处理请求,当一个 http 请求到来的时候,passenger 服务器会将这个请求转发给一个 worker 进程来处理这个请求,passenger 这个服务器是由很多个进程组成的,这些进程共同实现了服务器的基本功能 ----- 转发请求,等待回应,将 rsponse 转发给上层的 nginx 服务器;
  3. 当 worker 将请求转发给 rails 处理的时候......就不明白了。。。。。。。

问题:

  1. rails 是怎样运行起来的?是个单独的进程吗?是个服务器模型的进程吗?如果是个单独的进程,那么它是怎么样运行起来的?里面有个 while true 之类的死循环来检测事件的到来以便处理吗?
  2. rails 直接面对的是 passenger 之类的中间层服务器,他们是怎样进行数据通信的?passenger 是怎么样把自己的请求转发给 rails 的?rack?
  3. rack?rack 是个常住进程吗?为什么 rack 这个接口规范却可以传递数据?怎样做到的?
  4. passenger 在启动 worker 进程的时候,会把 rails 加载到 worker 的进程空间里面,怎么做到的?

补充: 我们其实完全不用这么麻烦,用那么多的中间件一起来构成一个 Web server。也可以完全使用纯的 ruby 来实现一个 web server:自己启动之后,监听在一个端口上面,等待 http 请求的到来,解析 http,自己处理,然后回复。这样的话,这个用纯 ruby 写成的 web server 在操作系统的眼里就是一个普通的进程而已。那么 rails 这个框架,从操作系统的角度看,它是什么呢?

passenger/thin/unicorn 这类 app server 实现了 rack 的 handler 方法后,自己常驻内存,拿到请求后,交给 rails/sinatra/padrino 这类所有实现了 rack app call 方法的框架/中间件. app server 初始化的时候,就带动 rack 和相关的框架/中间件一起初始化了.

#1 楼 @ch3n

  1. “自己常驻内存”,“自己 “指的是 passenger/thin/unicorn 这类 app server 吗?
  2. 我看过一些资料,像 passenger 这种用 C++ 写的中间件服务器,在自己启动的时候,就会把 rails 的 code 加载到自己的进程空间,如果是这样的话,那就不难理解了:passenger 和 rails 的代码是在一个进程空间中(passenger 的进程空间),那么 passenger 拿到请求之后,可以在自己的进程空间里面就像是调用函数/方法一样来调用 rack 的 handle 了,那么接下来的数据流也就很明白了。不知道是不是这样的?还有如果是这样的话,passenger 只怎么做到把 rails 的代码加载到自己的进程空间的,还能够执行其代码?感觉很神秘的样子。那么,是否就可以认为:rails 并不是一个可以单独存在的进程,它只是被其他的进程来调用?这很像是在执行 shell 脚本一样,动态运行,需要执行哪个脚本的时候,调用一下:sh XXX.sh 就行了,是这样的吗?

同学习

可以换种方式理解。

passenger、rack、rails 这些都可以称之为独立的应用,但本质上都是在执行代码。一个进程可以先执行 passenger 的代码,再执行 rack 的代码,最后执行 rails 的代码,render 以后再反着来一遍完成一次 request 响应。

当 rack 根据 rack 规范调用 rack 应用 (比如 rails) 的时候,其实并没有切换进程,运行在内存里的进程始终都是 ruby 的执行进程,它只负责解释和执行 ruby 代码。

也就是说,进程和 ruby 应用并不在同一个抽象层面上。

#4 楼 @adamshen 那么是否可以理解为 passenger 在调用 rack 的方法,继而接着将数据流传入 rails,实质上就是在执行 ruby xxxx.rb 的过程,就像是在调用 shell 脚本那样? 那为啥在 passenger 的官网上,解释 rails 的时候,用的是 load code of rails 这种说法?

#5 楼 @uestc_bird ruby 是动态语言,只要把 rails 代码从硬盘载到内存运行,就是 load code of rails 了吧。Rails 本身没有进程,只是一段等待被 rack 调用的代码。

建议你直接看 unicorn 的 http_server.rb 文件,简单易懂. 1: unicorn 初始化 rails(load code of rails),也就是加载 gem 和初始化 rails 的 app.call 2: 监听端口 3: 拿到请求交给 rails 的 app.call

passenger 就是相当于给 unicorn 套了个 nginx 反向代理.

https://github.com/defunkt/unicorn/blob/master/lib/unicorn/http_server.rb

#7 楼 @ch3n 恩 好的 我好好研究一下,谢谢

需要 登录 后方可回复, 如果你还没有账号请 注册新账号