- 测试条件: I3 380M + 4G + Windows7 + iis7 + PHP5.4(fastcgi) + Zend2.3
- 网站设置: 使用默认的模块和控制器,配置config和module缓存. 不连接任何服务和数据库.为避免带宽不足清空view
- 测试软件: Jmeter 20并发用户.测试机和被测试机是不同的电脑,它们之间用100M5类线直连
在测试结果中,平均响应时间需要0.637秒,每秒处理30个请求.这个数据比zf1低一半. 同一台机zf1可以达到每秒60多个请求
我看到这个测试结果后有点想放弃zf2,可是在开发灵活和便捷性上zf2确实要比zf1要好得多. 分析发现,在zf2中路由,派遣和服务注册,模块注册拖累了整个速度. 以前做项目用到过yaf,发现yaf性能挺好的,于是计划用yaf代替zf2的mvc模块.
一. 在yaf项目中加载zf2类库
首先你得有一个能正常运行的yaf项目.在这个基础上改动以增加zf2支持.可以参考yaf官方教程做一个yaf的基本架构站点. 这里假设你已按照官方教程架设好yaf站点
1. 在yaf项目中使用composer
yaf官网示范中默认没有zf2的类加载器,考虑到今后还要加载其它的类库代码,这里使用composer加载zf2依赖. 要在yaf项目中引用composer需要对yaf项目的/public/index.php和/conf/application.ini做少量改动.
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | <?php /** * This makes our life easier when dealing with paths. Everything is relative * to the application root now. */ chdir(dirname(__DIR__)); // Decline static file requests back to the PHP built-in webserver if (php_sapi_name() === 'cli-server' && is_file(__DIR__ . parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH))) { return false; } // Setup autoloading require 'init_autoloader.php'; // Define path to application directory define("APP_PATH", dirname(__DIR__)); // Create application, bootstrap, and run $app = new Yaf_Application(APP_PATH . "/conf/application.ini"); $app->bootstrap() ->run(); |
改动后的文件和yaf默认文件主要的区别:
- 要增加chdir(dirname(__DIR__)). 目的是让zf2能正常读取配置文件
- require ‘init_autoloader.php’; 这个文件是在ZendSkeletonApplication.zip中复制出来的,目的是引用composer, zf2类库就要通过这个文件加载进来.
- $app->bootstrap() 必须要有引导器,因为后面要在bootstrap里面加载zf2配置和服务
因为yaf默认会禁用spl加载器,这会造成无法加载非yaf前缀命名的类.所以我们还需要更改yaf运行配置.在/conf/application.ini中设置 application.system.use_spl_autoload = true
2 3 4 5 | [product] application.directory = APP_PATH "/application/" application.dispatcher.catchException = true application.system.use_spl_autoload = true |
总结一下,你需要更改 index.php,application.ini增加init_autoloader.php文件,哦!别忘记了编辑composer.json在其中增加zf2依赖配置. 我这里用的是zf2.3. 然后更新composer依赖. 等待composer依赖更新完成后测试项目,看看在yaf项目中是否可以用zf2的类库,这里应该可以引用,如果还是不行就请下载本文后面提供的完整代码.
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 | <?php /** * Zend Framework (http://framework.zend.com/) * * @link http://github.com/zendframework/ZendSkeletonApplication for the canonical source repository * @copyright Copyright (c) 2005-2013 Zend Technologies USA Inc. (http://www.zend.com) * @license http://framework.zend.com/license/new-bsd New BSD License */ /** * This autoloading setup is really more complicated than it needs to be for most * applications. The added complexity is simply to reduce the time it takes for * new developers to be productive with a fresh skeleton. It allows autoloading * to be correctly configured, regardless of the installation method and keeps * the use of composer completely optional. This setup should work fine for * most users, however, feel free to configure autoloading however you'd like. */ // Composer autoloading if (file_exists('vendor/autoload.php')) { $loader = include 'vendor/autoload.php'; } $zf2Path = false; if (is_dir('vendor/ZF2/library')) { $zf2Path = 'vendor/ZF2/library'; } elseif (getenv('ZF2_PATH')) { // Support for ZF2_PATH environment variable or git submodule $zf2Path = getenv('ZF2_PATH'); } elseif (get_cfg_var('zf2_path')) { // Support for zf2_path directive value $zf2Path = get_cfg_var('zf2_path'); } if ($zf2Path) { if (isset($loader)) { $loader->add('Zend', $zf2Path); } else { include $zf2Path . '/Zend/Loader/AutoloaderFactory.php'; Zend\Loader\AutoloaderFactory::factory(array( 'Zend\Loader\StandardAutoloader' => array( 'autoregister_zf' => true ) )); } } if (!class_exists('Zend\Loader\AutoloaderFactory')) { throw new RuntimeException('Unable to load ZF2. Run `php composer.phar install` or define a ZF2_PATH environment variable.'); } |
2 3 4 5 | "require": { "php": ">=5.3.3", "zendframework/zendframework": "2.3.*" } |
2. 让Yaf项目中的zf2配置文件起作用
上面的改动完成后在yaf中可以使用zf2的类库了,这还不够,我们还要在项目中使用zf2的框架配置和服务管理器. 在改动前需要先了解yaf的限制.
yaf是c语言写的mvc框架,配置文件默认是applicatin.ini. yaf并不像zf2那样包含各种功能模块,特别是yaf不能直接使用zf2的配置文件.也就是说zf2的配置在yaf上是没有效果的.为了让zf2配置起作用,我们需要在yaf中调用zf2的服务管理模块以读取配置, 然后把配置好的服务模块注册到yaf_register中.
zf2如果除开mvc模块(这里我们用yaf代替了zf2-mvc),最核心的就是servermanager。所有的配置项,所有的服务类,包括事件等都是由servermanager管理,如需在yaf中使用zf2配置,就要把servermanager移植到yaf中. 在zf2中servermanager是最先被执行的,并且把实例作为参数由各种后续对象传递,在yaf中我们使用yaf_regisger传递servermanager实例. 由于我们用yaf代替了zf2的mvc模块,所以在我们移植后的项目中zf2配置中的mvc部分是没有作用的
我们先把zf2的配置文件复制到/conf中,注意zf2配置文件默认在/config目录,而yaf配置是在/conf中,为了让配置文件能正常工作,请把zf2应用配置文件application.config.php中的config_glob_paths配置文件路径由/config改为/conf. 除此以外其它的配置项不需要做任何更改.
接下来需要改动yaf的Bootstrap.php文件,还记得index.php中的bootstrap()么?,那就是为了运行这个文件准备的. 在这个文件中所有_init开头的方法都会被自动执行,我们把注册servermanager和读取zf2配置的方法写在这里,这样yaf项目启动的时候配置文件就起作用了. 然后在这里把通过配置生成的servermanager对象注册给yaf_regisger.这样在整个yaf中就可以像zf2那样使用服务管理器调用各种功能(不能调用mvc相关模块).
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 | <?php use Zend\ServiceManager\ServiceManager; use Zend\Mvc\Service\ServiceManagerConfig; use Zend\ModuleManager\Listener\ConfigListener; use Zend\ModuleManager\Listener\ListenerOptions; use Zend\ModuleManager\ModuleEvent; class Bootstrap extends Yaf_Bootstrap_Abstract { public function _initConfig() { $config = Yaf_Application::app()->getConfig(); Yaf_Registry::set("config", $config); } public function _initServiceManager() { $configuration = require APP_PATH . '/conf/application.config.php'; $smConfig = isset($configuration['service_manager']) ? $configuration['service_manager'] : array(); $serviceManager = new ServiceManager(new ServiceManagerConfig($smConfig)); $serviceManager->setService('ApplicationConfig', $configuration); $configListener = new ConfigListener(new ListenerOptions($configuration['module_listener_options'])); // If not found cache, merge config if (!$configListener->getMergedConfig(false)) $configListener->onMergeConfig(new ModuleEvent); // If enabled, update the config cache if ($configListener->getOptions()->getConfigCacheEnabled() && !file_exists($configListener->getOptions()->getConfigCacheFile())) { $configFile = $configListener->getOptions()->getConfigCacheFile(); $content = "<?php\nreturn " . var_export($configListener->getMergedConfig(false), 1) . ';'; file_put_contents($configFile, $content); } $serviceManager->setService('config', $configListener->getMergedConfig(false)); Yaf_Registry::set('ServiceManager', $serviceManager); } public function _initSessionManager() { Yaf_Registry::get('ServiceManager')->get('Zend\Session\SessionManager'); } public function _initPlugin(Yaf_Dispatcher $dispatcher) { $user = new UserPlugin(); $dispatcher->registerPlugin($user); } } |
二. 在yaf项目使用zf2服务管理器调用数据库,cache,日志
调用各种zf2的服务功能时,需要先确保你的zf2配置中有对应的设置,具体设置参考zf2官方手册,本文后面也有示例代码下载.
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 | <?php use Zend\Session\Container as SessionContainer; use Zend\Db\TableGateway\TableGateway; class IndexController extends Yaf_Controller_Abstract { public function indexAction() { if (!isset($session->n)) { $session->n = 0; } $session->n++; echo $session->n; $adapter = $this->getDbAdapter(); $table = new TableGateway('admin', $adapter); $entities = $table->select(); foreach ($entities as $entity) { var_dump($entity->username); } $cache = $this->getStorage(); $cache->setItem('asdfas', 'asdfasdf'); $this->getLogger()->alert('asdfasd'); $this->getView()->assign("content", "Hello World"); } /** * db adapter * @return \Zend\Db\Adapter\Adapter */ public function getDbAdapter() { return Yaf_Registry::get('ServiceManager')->get('Zend\Db\Adapter\Adapter'); } /** * storage * @return \Zend\Cache\Storage\StorageInterface */ protected function getStorage() { return Yaf_Registry::get('ServiceManager')->get('Zend\Cache\Storage\StorageInterface'); } /** * logger * @return \Zend\Log\Zend\Log\Logger */ protected function getLogger() { return Yaf_Registry::get('ServiceManager')->get('Zend\Log\Logger'); } } |
三. 测试yaf集成zf2后的性能
我们使用jmeter测试改动后的yaf项目性能,测试条件和参数与上次测试zf2相同,结果如下:
现在测试数据好看多了,平均响应时间提高到81毫秒, 每秒响应请求数提高到241个. 其实我还测试过没有集成zf2服务管理器的yaf性能,每秒请求数可以达到1200(这是11年的I3移动版CPU的老笔记本电脑,每秒1200已经很强了),但是不提供服务的项目性能再好都没有意义.
这是一个完整的yaf集成zf2的项目示例.下载后请把把其中的dist配置文件复制并去掉.dist扩展名.yaf-sample-d771c9a.tar
Leave a Reply