php-fpm cgi php-cgi fastcgi 之间的关系

cgi

CGI是为了保证web server传递过来的数据是标准格式的,方便CGI程序的编写者。

web server(比如说nginx)只是内容的分发者。比如,如果请求/index.html,那么web server会去文件系统中找到这个文件,发送给浏览器,这里分发的是静态数据。好了,如果现在请求的是/index.php,根据配置文件,nginx知道这个不是静态文件,需要去找PHP解析器来处理,那么他会把这个请求简单处理后交给PHP解析器。Nginx会传哪些数据给PHP解析器呢?url要有吧,查询字符串也得有吧,POST数据也要有,HTTP header不能少吧,好的,CGI就是规定要传哪些数据、以什么样的格式传递给后方处理这个请求的协议。仔细想想,你在PHP代码中使用的用户从哪里来的。

当web server收到/index.php这个请求后,会启动对应的CGI程序,这里就是PHP的解析器。接下来PHP解析器会解析php.ini文件,初始化执行环境,然后处理请求,再以规定CGI规定的格式返回处理后的结果,退出进程。web server再把结果返回给浏览器。

CGI是个协议,跟进程什么的没关系。

php-cgi

php-cgi是解释PHP脚本的程序

php-cgi 是一个实现了CGI协议的程序

fastcgi

维基上的解释:
快速通用网关接口(Fast Common Gateway Interface/FastCGI)是一种让交互程序与Web服务器通信的协议。FastCGI是早期通用网关接口(CGI)的增强版本。
FastCGI致力于减少网页服务器与CGI程序之间互动的开销,从而使服务器可以同时处理更多的网页请求。

Fastcgi是用来提高CGI解释器程序性能的一种协议,属于cgi协议的一种

提高性能,那么CGI解释器程序的性能问题在哪呢?”PHP解析器会解析php.ini文件,初始化执行环境”,就是这里了。标准的CGI解释器程序对每个请求都会执行这些步骤(不闲累啊!启动进程很累的说!),所以处理每个时间的时间会比较长。这明显不合理嘛!那么Fastcgi是怎么做的呢?首先,Fastcgi会先启一个master,解析配置文件,初始化执行环境,然后再启动多个CGI解释器进程。当请求过来时,master会传递给一个CGI解释器进程,然后立即可以接受下一个请求。这样就避免了重复的劳动,效率自然是高。而且当worker不够用时,master可以根据配置预先启动几个CGI解释器进程等着;当然空闲CGI解释器进程太多时,也会停掉一些,这样就提高了性能,也节约了资源。这就是fastcgi的对进程的管理。

php-fpm

大家都知道,PHP的解释器是php-cgi。php-cgi只是个CGI程序,他自己本身只能解析请求,返回结果,不会进程管理(皇上,臣妾真的做不到啊!)所以就出现了一些能够调度php-cgi进程的程序,比如说由lighthttpd分离出来的spawn-fcgi。好了PHP-FPM也是这么个东东,在长时间的发展后,逐渐得到了大家的认可(要知道,前几年大家可是抱怨PHP-FPM稳定性太差的),也越来越流行。

php-fpm是一个实现了Fastcgi的程序。用来管理 php-cgi 程序的

FastCGI程序的工作原理

  

  • Web Server启动时载入FastCGI进程管理器(IIS ISAPI或Apache Module)

  

  • FastCGI进程管理器自身初始化,启动多个CGI解释器进程(可见多个php-cgi)并等待来自Web Server的连接。

   

  • 当客户端请求到达Web Server时,FastCGI进程管理器选择并连接到一个CGI解释器。Web server将CGI环境变量和标准输入发送到FastCGI子进程php-cgi。

  

  • FastCGI子进程完成处理后将标准输出和错误信息从同一连接返回Web Server。当FastCGI子进程关闭连接时,请求便告处理完成。FastCGI子进程接着等待并处理来自FastCGI进程管理器(运行在Web Server中)的下一个连接。 在CGI模式中,php-cgi在此便退出了。

  
在上述情况中,你可以想象CGI通常有多慢。每一个Web请求PHP都必须重新解析php.ini,重新载入全部扩展并重初始化全部数据结构。使用FastCGI,所有这些都只在进程启动时发生一次。一个额外的好处是,持续数据库连接(Persistent database connection)可以工作。

zf2 启动简介:二,服务的获取

zf2框架在启动的过程中会创建一个service manager对象 (仅仅会实例化一次)

而zf2框架中各种服务的调用都是通过 service manager 对象来实现的

最常用的如 get 方法,用来获取某一个服务

1
2
3
4
5
6
7
8
9
10
11
12
//Zend\Mvc\Application::init(require 'config/application.config.php')
public static function init($configuration = array())
{
$smConfig = isset($configuration['service_manager']) ? $configuration['service_manager'] : array();
$listeners = isset($configuration['listeners']) ? $configuration['listeners'] : array();
$serviceManager = new ServiceManager(new Service\ServiceManagerConfig($smConfig));
$serviceManager->setService('ApplicationConfig', $configuration);
$serviceManager->get('ModuleManager')->loadModules();
return $serviceManager->get('Application')->bootstrap($listeners);
}

在zf2启动过程中一开始便通过 Zend/Mvc/Service/ServiceManagerConfig.php 来初始化的创建一个服务管理器
提供的默认配置如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
protected $invokables = array(
'SharedEventManager' => 'Zend\EventManager\SharedEventManager',
);
/**
* Service factories
*
* @var array
*/
protected $factories = array(
'EventManager' => 'Zend\Mvc\Service\EventManagerFactory',
'ModuleManager' => 'Zend\Mvc\Service\ModuleManagerFactory',
);
/**
* Abstract factories
*
* @var array
*/
protected $abstractFactories = array();
/**
* Aliases
*
* @var array
*/
protected $aliases = array(
'Zend\EventManager\EventManagerInterface' => 'EventManager',
);
/**
* Shared services
*
* Services are shared by default; this is primarily to indicate services
* that should NOT be shared
*
* @var array
*/
protected $shared = array(
'EventManager' => false,
);

这些默认初始化配置会合并到 service manager 对象中,在启动过程中除了这些默认配置以外,其实在启动的其他位置也提供了许多 service manager 对象默认的服务配置
Zend/Mvc/Service/ServiceListenerFactory.php 中提供的默认配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
protected $defaultServiceConfig = array(
'invokables' => array(
'DispatchListener' => 'Zend\Mvc\DispatchListener',
'RouteListener' => 'Zend\Mvc\RouteListener',
'SendResponseListener' => 'Zend\Mvc\SendResponseListener'
),
'factories' => array(
'Application' => 'Zend\Mvc\Service\ApplicationFactory',
'Config' => 'Zend\Mvc\Service\ConfigFactory',
'ControllerLoader' => 'Zend\Mvc\Service\ControllerLoaderFactory',
'ControllerPluginManager' => 'Zend\Mvc\Service\ControllerPluginManagerFactory',
'ConsoleAdapter' => 'Zend\Mvc\Service\ConsoleAdapterFactory',
'ConsoleRouter' => 'Zend\Mvc\Service\RouterFactory',
'ConsoleViewManager' => 'Zend\Mvc\Service\ConsoleViewManagerFactory',
'DependencyInjector' => 'Zend\Mvc\Service\DiFactory',
'DiAbstractServiceFactory' => 'Zend\Mvc\Service\DiAbstractServiceFactoryFactory',
'DiServiceInitializer' => 'Zend\Mvc\Service\DiServiceInitializerFactory',
'DiStrictAbstractServiceFactory' => 'Zend\Mvc\Service\DiStrictAbstractServiceFactoryFactory',
'FilterManager' => 'Zend\Mvc\Service\FilterManagerFactory',
'FormElementManager' => 'Zend\Mvc\Service\FormElementManagerFactory',
'HttpRouter' => 'Zend\Mvc\Service\RouterFactory',
'HttpViewManager' => 'Zend\Mvc\Service\HttpViewManagerFactory',
'HydratorManager' => 'Zend\Mvc\Service\HydratorManagerFactory',
'InputFilterManager' => 'Zend\Mvc\Service\InputFilterManagerFactory',
'MvcTranslator' => 'Zend\Mvc\Service\TranslatorServiceFactory',
'PaginatorPluginManager' => 'Zend\Mvc\Service\PaginatorPluginManagerFactory',
'Request' => 'Zend\Mvc\Service\RequestFactory',
'Response' => 'Zend\Mvc\Service\ResponseFactory',
'Router' => 'Zend\Mvc\Service\RouterFactory',
'RoutePluginManager' => 'Zend\Mvc\Service\RoutePluginManagerFactory',
'SerializerAdapterManager' => 'Zend\Mvc\Service\SerializerAdapterPluginManagerFactory',
'ValidatorManager' => 'Zend\Mvc\Service\ValidatorManagerFactory',
'ViewHelperManager' => 'Zend\Mvc\Service\ViewHelperManagerFactory',
'ViewFeedRenderer' => 'Zend\Mvc\Service\ViewFeedRendererFactory',
'ViewFeedStrategy' => 'Zend\Mvc\Service\ViewFeedStrategyFactory',
'ViewJsonRenderer' => 'Zend\Mvc\Service\ViewJsonRendererFactory',
'ViewJsonStrategy' => 'Zend\Mvc\Service\ViewJsonStrategyFactory',
'ViewManager' => 'Zend\Mvc\Service\ViewManagerFactory',
'ViewResolver' => 'Zend\Mvc\Service\ViewResolverFactory',
'ViewTemplateMapResolver' => 'Zend\Mvc\Service\ViewTemplateMapResolverFactory',
'ViewTemplatePathStack' => 'Zend\Mvc\Service\ViewTemplatePathStackFactory',
),
'aliases' => array(
'Configuration' => 'Config',
'Console' => 'ConsoleAdapter',
'Di' => 'DependencyInjector',
'Zend\Di\LocatorInterface' => 'DependencyInjector',
'Zend\Mvc\Controller\PluginManager' => 'ControllerPluginManager',
'Zend\View\Resolver\TemplateMapResolver' => 'ViewTemplateMapResolver',
'Zend\View\Resolver\TemplatePathStack' => 'ViewTemplatePathStack',
'Zend\View\Resolver\AggregateResolver' => 'ViewResolver',
'Zend\View\Resolver\ResolverInterface' => 'ViewResolver',
),
'abstract_factories' => array(
'Zend\Form\FormAbstractServiceFactory',
)

而对于框架的使用者来说我们可以在模块配置文件中自定义服务配置,或者在控制器或者方法中动态注册服务(不太推荐,相对于在配置中注册多走了一道流程)

如下是用户自定义配置实例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
<?php
// a module configuration, "module/SomeModule/config/module.config.php"
return array(
'service_manager' => array(
'abstract_factories' => array(
// Valid values include names of classes implementing
// AbstractFactoryInterface, instances of classes implementing
// AbstractFactoryInterface, or any PHP callbacks
'SomeModule\Service\FallbackFactory',
),
'aliases' => array(
// Aliasing a FQCN to a service name
'SomeModule\Model\User' => 'User',
// Aliasing a name to a known service name
'AdminUser' => 'User',
// Aliasing to an alias
'SuperUser' => 'AdminUser',
),
'factories' => array(
// Keys are the service names.
// Valid values include names of classes implementing
// FactoryInterface, instances of classes implementing
// FactoryInterface, or any PHP callbacks
'User' => 'SomeModule\Service\UserFactory',
'UserForm' => function ($serviceManager) {
$form = new SomeModule\Form\User();
// Retrieve a dependency from the service manager and inject it!
$form->setInputFilter($serviceManager->get('UserInputFilter'));
return $form;
},
),
'invokables' => array(
// Keys are the service names
// Values are valid class names to instantiate.
'UserInputFiler' => 'SomeModule\InputFilter\User',
),
'services' => array(
// Keys are the service names
// Values are objects
'Auth' => new SomeModule\Authentication\AuthenticationService(),
),
'shared' => array(
// Usually, you'll only indicate services that should _NOT_ be
// shared -- i.e., ones where you want a different instance
// every time.
'UserForm' => false,
),
),
);

zf2 启动简介:一,类的加载

AutoloaderFactory

自动加载工厂类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Zend\Loader\AutoloaderFactory::factory(array(
'Zend\Loader\StandardAutoloader' => array(
'autoregister_zf' => true,
'namespaces'=>array(
'Etah'=>__DIR__ . '/etah'
),
// 'prefixes' => array(
// 'Scapi' => __DIR__ . '/../library/Scapi',
// ),
'fallback_autoloader' => true
),
'Zend\Loader\ClassMapAutoloader' => array(
$zf2Path . '/autoload_classmap.php'
)
));

后面会介绍这段代码的意思

既然AutoloaderFactory是工厂类,那么它封装的自动加载类有那些呢

  • ClassMapAutoloader

    类地图自动加载器—类地图映射的方式加载类(zf2类库)

  • ModuleAutoloader

    模块自动加载器—同ClassMapAutoloader(模块类)

  • StandardAutoloader

    标准自动加载器—通过注册命名空间加载类 (默认加载方式)

Zend\Loader\AutoloaderFactory::factory()

factory方法参数数组的第一个配置元素必须为 Zend\Loader\StandardAutoloader

或者在 Zend\Loader\AutoloaderFactory::factory 调用之前手动载入 Zend\Loader\ClassMapAutoloader

  • StandardAutoloader

    • autoregister_zf == 是否自动注册Zend命名空间,若为false,下面需要手动注册

    • namespaces == 注册命名空间

    • prefixes 命名空间出现之前的和命名空间作用相似的东西,以_分割(一般用不上)

    • fallback_autoloader == 拼装实际类路径时可能会用到(一般情况下用不到,默认配成true)

  • ClassMapAutoloader

    • 类地图映射php文件

  • ModuleAutoloader

    • 从各种来源定位和按需加载的模块类(后续介绍)

这三个类都是通过 spl_autoload_register 函数注册自动加载函数

所以建议的Zend\Loader\AutoloaderFactory::factory()参数顺序

先配置 StandardAutoloader

然后再配置 ClassMapAutoloader

原因是:在载入类的时候会先调用 ClassMapAutoloader 中的加载类方法,若未找到则会调用 StandardAutoloader 中的类加载方法

ClassMapAutoloader 加载类的方式比 StandardAutoloader中更加的高效
前者只是在一个大的数组映射表中寻值,而后者则需要拼装截取才能获得最终的路径

以下为测试数据:(请求开始时间-请求结束时间)//i7 四核条件下(性能低的机器上会更加明显)

通过 StandardAutoloader 方式

start-time = 1394976543.9461

end-time = 1394976544.2273

耗时 0.2812 秒

通过 ClassMapAutoloader 方式

start-time = 1394976731.8825

end-time = 1394976732.2164

耗时0.3339 秒

速度提升16%

以下是以数组的方式打印自动装载器数组

1
2
3
4
5
6
$loader = \Zend\Loader\AutoloaderFactory::getRegisteredAutoloaders();
echo "<pre>";
print_r($loader);

输出

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
Array
(
[Zend\Loader\StandardAutoloader] => Zend\Loader\StandardAutoloader Object
(
[namespaces:protected] => Array
(
[Zend\] => /Applications/XAMPP/xamppfiles/htdocs/zend/vendor/ZF2/library/Zend/
[Etah\] => /Applications/XAMPP/xamppfiles/htdocs/zend/etah/
[Application\] => /Applications/XAMPP/xamppfiles/htdocs/zend/module/Application/src/Application/
)
[prefixes:protected] => Array
(
)
[fallbackAutoloaderFlag:protected] => 1
)
[Zend\Loader\ClassMapAutoloader] => Zend\Loader\ClassMapAutoloader Object
(
[mapsLoaded:protected] => Array
(
[0] => vendor/ZF2/library/autoload_classmap.php
)
[map:protected] => Array
(
[Zend\Authentication\Adapter\AbstractAdapter] => /Applications/XAMPP/xamppfiles/htdocs/zend/vendor/ZF2/library/Zend/Authentication/Adapter/AbstractAdapter.php
[Zend\Authentication\Adapter\AdapterInterface] => /Applications/XAMPP/xamppfiles/htdocs/zend/vendor/ZF2/library/Zend/Authentication/Adapter/AdapterInterface.php
[Zend\Authentication\Adapter\DbTable\AbstractAdapter] => /Applications/XAMPP/xamppfiles/htdocs/zend/vendor/ZF2/library/Zend/Authentication/Adapter/DbTable/AbstractAdapter.php
[Zend\Authentication\Adapter\DbTable\CallbackCheckAdapter] => /Applications/XAMPP/xamppfiles/htdocs/zend/vendor/ZF2/library/Zend/Authentication/Adapter/DbTable/CallbackCheckAdapter.php
[Zend\Authentication\Adapter\DbTable\CredentialTreatmentAdapter] => /Applications/XAMPP/xamppfiles/htdocs/zend/vendor/ZF2/library/Zend/Authentication/Adapter/DbTable/CredentialTreatmentAdapter.php
[Zend\Authentication\Adapter\DbTable\Exception\ExceptionInterface] => /Applications/XAMPP/xamppfiles/htdocs/zend/vendor/ZF2/library/Zend/Authentication/Adapter/DbTable/Exception/ExceptionInterface.php
[Zend\Authentication\Adapter\DbTable\Exception\InvalidArgumentException] => /Applications/XAMPP/xamppfiles/htdocs/zend/vendor/ZF2/library/Zend/Authentication/Adapter/DbTable/Exception/InvalidArgumentException.php
[Zend\Authentication\Adapter\DbTable\Exception\RuntimeException] => /Applications/XAMPP/xamppfiles/htdocs/zend/vendor/ZF2/library/Zend/Authentication/Adapter/DbTable/Exception/RuntimeException.php
[Zend\Authentication\Adapter\DbTable] => /Applications/XAMPP/xamppfiles/htdocs/zend/vendor/ZF2/library/Zend/Authentication/Adapter/DbTable.php
[Zend\Authentication\Adapter\Digest] => /Applications/XAMPP/xamppfiles/htdocs/zend/vendor/ZF2/library/Zend/Authentication/Adapter/Digest.php
[Zend\Authentication\Adapter\Exception\ExceptionInterface] => /Applications/XAMPP/xamppfiles/htdocs/zend/vendor/ZF2/library/Zend/Authentication/Adapter/Exception/ExceptionInterface.php
[Zend\Authentication\Adapter\Exception\InvalidArgumentException] => /Applications/XAMPP/xamppfiles/htdocs/zend/vendor/ZF2/library/Zend/Authentication/Adapter/Exception/InvalidArgumentException.php
[Zend\Authentication\Adapter\Exception\RuntimeException] => /Applications/XAMPP/xamppfiles/htdocs/zend/vendor/ZF2/library/Zend/Authentication/Adapter/Exception/RuntimeException.php
[Zend\Authentication\Adapter\Exception\UnexpectedValueException] => /Applications/XAMPP/xamppfiles/htdocs/zend/vendor/ZF2/library/Zend/Authentication/Adapter/Exception/UnexpectedValueException.php
[Zend\Authentication\Adapter\Http\ApacheResolver] => /Applications/XAMPP/xamppfiles/htdocs/zend/vendor/ZF2/library/Zend/Authentication/Adapter/Http/ApacheResolver.php
)
)
)

如上可以看出若要加载一个类文件,如 Zend\Authentication\Adapter\AbstractAdapter

若使用 StandardAutoloader 方式来加载

则内部原理为 在 Zend\Loader\StandardAutoloader 对象中获取 注册的namespaces数组

[Zend\] => /Applications/XAMPP/xamppfiles/htdocs/zend/vendor/ZF2/library/Zend/

中的 /Applications/XAMPP/xamppfiles/htdocs/zend/vendor/ZF2/library/Zend/

替换到 Zend\Authentication\Adapter\AbstractAdapter

最后为 /Applications/XAMPP/xamppfiles/htdocs/zend/vendor/ZF2/library/Zend/Authentication/Adapter/AbstractAdapter

在加上.php的后缀就为类的实际路径

ClassMapAutoloader 的加载方式是直接在 Zend\Loader\ClassMapAutoloader 对象的 map数组映射表中寻找,最后获得实际物理路径.

关于插件的加载日后补充!

Node.js MVC框架

Node.js是JavaScript中最为流行的框架之一,易于创建可扩展的Web应用。Node.js包含不同类型框架,包括MVC, full-stack,REST API以及Generators。借助这些框架使Node.js更加易于使用,它还支持众多特性功能,您只需几个步骤就可快速搭建强大的Web应用。

本文分享十款最佳的JavaScript框架。

  1. Sails.js

    Sall.js

    Sails易于开发定制企业级、现代化的Node.js 应用,同时,它也适用于创建图表、仪表盘及各种游戏应用。

  1. Total.js

    Total.js

    Total.js是另一款伟大的框架,用来帮助创建Web页面及Web应用,支持MVC架构。它是利用HTML、JavaScript及CSS创建网站的一款开源的现代化框架。

  2. Partial.js

    Total.js

    Partial js,利用HTML、CSS和JavaScript开发者可创建大量的Web扩展应用以及网站。

  3. Koa. js

    Koa.js

    Kao.js是由Express开发而来,旨在创建更小的、更具表现力Web应用及API。

  4. Locomotive. js

    Locomotive.js

    Locomotive支持MVC模式、RESTful。主要功能如下:优先配置,Routing Helpers,MVC架构,连接任意数据等。

更多参考:node js框架