php Swoole和FPM性能对比
早闻Swoole因其持久化的特性有高性能高并发和语法简单的特点,突发奇想试着把汇率API项目的API部分用Swoole处理,在这里对比一下两者的性能差异
E5 2650V2 4核心 KVM虚拟化无超开
8G内存
程序代码和运行在SATA SSD内进行
系统:CentOS 7.9
PHP版本:8.1开启JIT,FPM使用opache
压测机配置:
i5 10400F+16G内存,好吧其实就是我自己的电脑。
压测程序:https://github.com/link1st/go-stress-testing
首先是php内置函数1w发测试:
FPM代码:
<?php echo 'use PHP-FPM.#'.mt_rand(1000,9999);
Swoole代码在异步模式下的代码:
<?php $http = new Swoole\Http\Server('0.0.0.0', 9501); $http->on('Request', function ($request, $response) { $response->header('Content-Type', 'text/html; charset=utf-8'); $response->end('<h1>Hello Swoole. #' . mt_rand(1000, 9999) . '</h1>');} ); $http->start();
FPM测试结果:
Swoole异步测试结果:
Swoole异步下tp99对比FPM有了三倍的性能提升
接下来是Swoole协程模式下,下面是代码:
<?php use Swoole\Coroutine\Http\Server; use function Swoole\Coroutine\run; run(function () { $server = new Server('127.0.0.1', 9502, false); $server->handle('/', function ($request, $response) { $response->end('<h1>Hello Swoole. #' . rand(1000, 9999) . '</h1>'); }); $server->start(); });
测试结果:
和异步模式下几乎无差别。
接下来是redis取值+循环输出数组,PHP-FPM代码如下:
<?php $redis_config=array( 'host' => "127.0.0.1", //数据库服务器 'port' => 6379, //数据库端口 ); $arraylist = array("GBP", "HKD", "USD", "CHF", "DEM", "FRF", "SGD", "SEK", "DKK", "NOK", "JPY", "CAD", "AUD", "EUR", "MOP", "PHP", "THB", "NZD", "KRW", "RUB", "MYR", "TWD", "ESP", "ITL", "NLG", "BEF", "FIM", "INR", "IDR", "BRL", "AED", "ZAR", "SAR", "TRY", "time"); $redis = new Redis(); $redis->pconnect($redis_config['host'],$redis_config['port']); $arList = $redis->mget($arraylist); $array_result=array(); foreach($arList as $k => $v){ $currency = $arraylist["$k"]; $array_result[$currency] = $v; } print_r(json_encode($array_result));
Swoole:
httpServer.php:
<?php use Swoole\Coroutine; $http = new Swoole\Http\Server('0.0.0.0', 9501); Coroutine::set(['hook_flags'=> SWOOLE_HOOK_ALL]); ini_set('memory_limit','-1'); include_once('api/autoload.php'); $http->set([ 'buffer_output_size' => 128 * 1024 * 1024, //必须为数字 ]); $http->on('Request', function ($request, $response) { if ($request->server['path_info'] == '/favicon.ico' || $request->server['request_uri'] == '/favicon.ico') { $response->end(); return; } list($controller, $action) = explode('/', trim($request->server['request_uri'], '/')); //根据 $controller, $action 映射到不同的控制器类和方法。 if (method_exists($controller,$action)){ $result_route = (new $controller)->$action($request, $response); $response->end($result_route); }else{ $response->header('Content-Type', 'text/html; charset=utf-8'); $response->end("API服务正常,请求内容不存在"); } }); $http->start();
/api/autoload.php
<?php // API自动加载器 spl_autoload_register(function ($class) { include $class.'.php'; },false);
/api/exchangeRate.php
<?php /** * 汇率操作功能类 */ include(dirname(__DIR__).'/db/db.php'); class exchangeRate{ public function index($request, $response){ $arraylist = array("GBP", "HKD", "USD", "CHF", "DEM", "FRF", "SGD", "SEK", "DKK", "NOK", "JPY", "CAD", "AUD", "EUR", "MOP", "PHP", "THB", "NZD", "KRW", "RUB", "MYR", "TWD", "ESP", "ITL", "NLG", "BEF", "FIM", "INR", "IDR", "BRL", "AED", "ZAR", "SAR", "TRY", "time"); $redis = new redisController(); $arList = $redis->mget($arraylist); $array_result=array(); foreach($arList as $k => $v){ $currency = $arraylist["$k"]; $array_result[$currency] = $v; } return json_encode($array_result); }
/db/db.php
<?php include_once(dirname(__DIR__).'/db/redisController.php');
/db/redisController.php
<?php /** * Redis操作类 */ class redisController{ public function mget($keys){ include('config.php'); $redis = new Redis(); $redis->pconnect($redis_config['host'],$redis_config['port']); $value = $redis->mget($keys); return $value; } }
测试结果:
FPM:
tp99:6.1s 但是已经出现502了(意味着有部分请求FPM是无响应的)
tp99:3s,无502,4s处理完所有请求
Swoole原理:
php中用swoole框架写好代码,在cli模式下启动后swoole会常驻后台,这样就达到了持久化,性能天生就比fpm高……
同时启动的时候就将php代码加载完毕转为机器码,对比fpm处理一次请求就要加载一次代码然后再处理的效率要高。
Swoole使用C++编写,支持一键协程化,自然效率高于FPM