分享 Puma 源代码分析 - 概述

ylt · 2015年02月27日 · 最后由 lanzhiheng 回复于 2018年06月05日 · 8127 次阅读
本帖已被设为精华帖!

2015年春节期间,通读了Puma的源代码。阅读Puma的源码是一个愉快的技术探索过程,这里把阅读所得分享出来。

Puma总体架构

什么是Puma?

Puma是一个面向ruby语言的并发的Web服务器(a modern, concurrent web server for ruby)。它的官方网站是puma.io.

什么是Web服务器?

一个标准的Web服务器遵循HTTP协议,接受HTTP Request请求,返回HTTP Response的响应结果。请求和响应都是字符串流的格式。如图1所示:

使用curl命令可以很方便的测试和学习HTTP协议。比如执行下面的curl命令,可以看到http的请求和响应。

curl  -v http://z.cn

Http的请求由curl发出,curl此时就是Web Client。

GET / HTTP/1.1
User-Agent: curl/7.37.1
Host: z.cn
Accept: */*

然后z.cn的web服务器收到HTTP Request请求,并返回HTTP Response的响应结果,如下:

HTTP/1.1 301 Moved Permanently
Date: Thu, 26 Feb 2015 07:25:05 GMT
Location: http://www.amazon.cn/ref=z_cn?tag=zcn0e-23
Content-Length: 250
Content-Type: text/html; charset=iso-8859-1

<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html><head>
<title>301 Moved Permanently</title>
</head><body>
<h1>Moved Permanently</h1>
<p>The document has moved <a href="http://www.amazon.cn/ref=z_cn?tag=zcn0e-23">here</a>.</p>
</body></html>

Web服务器根据Http请求的路径和其他头部信息来决定如何输出Http的响应结果。Web服务器有三种方式处理Http请求:

  1. 代理到下一级的Web服务器;
  2. 对静态文件请求,直接读取本地文件内容并输出;
  3. 对动态请求,则通过接口调用动态程序。

对于第三种的动态请求,又有很多接口规范,比如cgi/fastcgi, servlet, rack等。其中cgi/fastcgi是语言无关的,servlet是特定于java语言的,而rack是特定于ruby语言的。

Ruby/Rack Web服务器

Rack的官方网站是rack.github.io。支持Rack的Web服务器的架构如图2所示:

Rack应用的输入是一个表示环境的hash,输出是一个数组包括三个元素:

  1. HTTP响应码
  2. HTTP响应头的Hash
  3. HTTP响应体, 该响应体必须支持each方法调用

Rack服务器和Rack应用之间通过ruby对象交互,Rack服务器直接调用Rack应用;而Web服务器和Web客户端之间则是通过字符串流交互。

Puma是一个支持Ruby/Rack applications的Web服务器。其它支持Rack规范的Web服务器还有Unicorn/Thin/Passenger等。

Puma的源代码结构

Puma是一个典型的Rack服务器。其总体目录结构与关键源代码文件如下:

├── bin   可执行脚本
│   ├── puma      启动脚本
│   ├── puma-wild
│   └── pumactl   控制脚本
├── docs 文档
├── examples  一些例子文件
├── ext   ruby的原生扩展,实现快速解析HTTP的头部
│   └── puma_http11  
├── lib
│   ├── puma
│   │   ├── app
│   │   │   └── status.rb     响应pumactl的控制请求
│   │   ├── binder.rb         启动并绑定Tcp/Unix端口
│   │   ├── cli.rb            Puma的命令行接口,解析命令行参数
│   │   ├── client.rb         代表Http请求的客户端
│   │   ├── cluster.rb            Puma的集群模式
│   │   ├── configuration.rb  Puma的配置参数
│   │   ├── control_cli.rb     命令行控制脚本的实现代码
│   │   ├── daemon_ext.rb      实现puma进程的daemon化
│   │   ├── events.rb          服务器的事件支持
│   │   ├── null_io.rb            当request没有body时rack.input的值
│   │   ├── rack_default.rb   指定缺省的rack handler
│   │   ├── rack_patch.rb     Patch CommonLogger to use after_reply
│   │   ├── reactor.rb        所有需要监听新数据的client链接,放到reactor的@sockets队列中
│   │   ├── runner.rb     启动Puma Server的基类,Single/Cluster继承它
│   │   ├── server.rb     The HTTP Server itself. Serves out a single Rack app.
│   │   ├── single.rb     Puma的单进程模式
│   │   ├── thread_pool.rb 线程池,其中是所有可执行的worker
│   ├── puma.rb
│   └── rack
│       └── handler
│           └── puma.rb       缺省的puma rack handler实现
├── test  测试代码
└── tools 进程监控脚本:init.d/upstart
    ├── jungle
    │   ├── init.d
    │   └── upstart

本系列后续部分将详细分析Puma如何启动、如何监听tcp连接,如何解析http header,如何执行rack app,如何响应控制命令,如何处理文件上传,如何实现集群模式,如何使用reactor模型处理io等。

Puma中关于Jruby和SSL支持的部分本文档不会涉及。因为笔者自己都是在MRI ruby上跑puma的,没有用过jruby跑puma,而且SSL都是交给web接入层比如nginx处理的,所以puma中这两个功能点的代码就不关心了。

Puma 源代码分析 - 启动流程 Puma 源代码分析 - 单进程模式 Puma 源代码分析 - 集群模式 Puma 源代码分析 - IO处理 Puma 源代码分析 - http协议解析 Puma 源代码分析 - 完结篇

共收到 25 条回复

#1楼 @iBachue 写文档比读源码费时间,实际读代码也就三天时间,全部写出来可能要一个星期以上了。

👍 强烈支持

delicious

:plus1:

#2楼 @ylt LZ,分享一下你是如何来读Puma 源代码的呗。

:plus1:

:plus1:

11楼 已删除
12楼 已删除

#7楼 @ruby_sky ruby是动态语言,其源代码的读法和静态语言不一样。我的方法就是按代码执行流程来读,碰到不懂的打断点,然后在断点处调试,调试其实就是在断点处写代码(这是和静态语言的调试很不一样的地方)。碰到函数/变量不知道含义,直接grep搜索名称,看整个代码库里函数在哪些地方调用了,变量什么时候赋值、什么时候读取,一般就能知道其用途了。

非常赞, 期待下文.

脸脸的用户 只能说这是个很好的 app 只是没有线上推广 貌似

#15楼 @riskgod 是啊,脸脸还没有线上推广 ,资金到位后会推的。

ruby有puma/unicorn等多种竞争品,为何php没看到类似现象呢? fastcgi, rack是互相竞争的么?还是不相关的呢?

#17楼 @chenge fastcgi是语言无关的一个接口,使用fastcgi时web server和script是两个进程;而rack是一个进程内同语言的方法调用。至于fastcgi和php的关系我也不是太清楚,至少spawn-fcgi与PHP-FPM就是支持PHP的两个FastCGI进程管理器。

#18楼 @ylt 是否可以这样理解,puma是类似php-fpm这样的,而php没有太多别的选择。 php也是用的fastcgi吧。还有比fastcgi更先进的么?

赞 :plus1:

#13楼 @ylt 非常牛!

感谢分享

感谢分享 🍎

http://puma.io/居然被土番了

#24楼 @mogodb 没有啊,我这里深圳电信,不使用代理也可以

26楼 已删除
27楼 已删除
29楼 已删除
需要 登录 后方可回复, 如果你还没有账号请点击这里 注册