总结一些实际项目中的优化案例
2018-10-22 本文已影响0人
守望星空l
SWOOLE
之前的项目里有2个php写的统计接口,一天的访问量在3500W左右,
项目的总接口访问量在7000W多点。
在这种情况下,我尝试用swoole重写了这2个统计接口,效果非常明显。
优化前是12台4核服务器 CPU占用40%, 优化后12台服务器的CPU占用减少了一半。
部分代码如下;
<?php
/**
* Created by PhpStorm.
* User: xueyb
* Date: 2018/08/01
* Time: 下午14:52
*/
date_default_timezone_set('PRC');
define("ROOT_PATH", __DIR__ . '/../..');
use Swoole\Table;
class CooStat
{
public $server;
const TASK_TYPE_VC_ONLINE = 1;
private $redisConfig = [];
private $memConfig = [];
public function run()
{
ini_set('display_errors', 1);
error_reporting(E_ALL);
$this->redisConfig = include(ROOT_PATH . '/config/redis.php');
$this->memConfig = include(ROOT_PATH . '/config/memcache.php');
$serverConfig = include(ROOT_PATH . '/config/cooStatSetting.php');
$serverConfig['log_file'] = $serverConfig['log_file'] ?: ROOT_PATH . '/logs/swoole.log';
$config = include(ROOT_PATH . '/config/config.php');
$this->server = new swoole_http_server("0.0.0.0", 9501);
$this->server->set($serverConfig);
// $this->server->on('connect', [$this, 'onConnect']);
$this->server->on('request', [$this, 'onRequest']);
// $this->server->on('close', [$this, 'onClose']);
$this->server->on('WorkerStart', [$this, 'onWorkerStart']);
$this->server->on('task', [$this, 'onTask']);
$this->server->on('finish', [$this, 'onFinish']);
//创建内存表 存储验证失败的
$checkFailTable = new Table(65536);
$checkFailTable->column('netbarId', Table::TYPE_INT, 4);
$checkFailTable->column('tokenMd5', Table::TYPE_STRING, 32);
$checkFailTable->column('updateTime', Table::TYPE_INT, 4);
$checkFailTable->create();
$this->server->checkFailTable = $checkFailTable;
$this->server->otherConfig = $config;
$this->server->start();
}
public function onWorkerStart($serv, $worker_id)
{
include_once(ROOT_PATH . '/src/function/CooStat.php');
include_once(ROOT_PATH . '/src/function/Comm.php');
if ($worker_id >= 4) {
$serv->redisOnline = redisConn($this->redisConfig['online']);
$serv->redisTerminalList = redisConn($this->redisConfig['terminal_list']);
$serv->redisTerminalInfo = redisConn($this->redisConfig['terminal_info']);
$serv->memPrime = memcacheConn($this->memConfig['prime']);
// $serv->tick(3000, [$this, 'connNumTimer'], ['serv' => $serv]);
}
}
public function onRequest($request, $response)
{
$method = $request->server['request_method'];
$pathInfo = $request->server['path_info'];
$routerPath = strtolower($method) . ':' . strtolower($pathInfo);
switch ($routerPath) {
case 'post:/vc/online':
$res = vcOnlineDealRequest($this->server, $request);
break;
case 'get:/swoole_server_status':
$res = 'server status: ' . json_encode($this->server->stats()) . ' swoole_table_count : ' . $this->server->checkFailTable->count();
break;
case 'post:/clientlistvc/info':
$res = vcClientDealRequest($this->server, $request);
break;
default:
$res = 'no router match';
}
$response->end($res);
/* 协程测试
go(function () use ($serv, $fd, $data) {
$http = new Co\Http\Client("www.baidu.com", 443, true);
$http->setHeaders([]);
$http->set(['timeout' => 3]);
$ret = $http->get('/');
if ($http->statusCode < 0) {
echo $http->errCode . PHP_EOL;
}
});
*/
}
public function onTask($serv, int $task_id, int $src_worker_id, array $params = [])
{
$type = $params['type'];
switch ($type) {
case 'vcOnline':
$res = vcOnlineTask($serv, $task_id, $src_worker_id, $params);
break;
case 'vcClient':
$res = vcClientTask($serv, $task_id, $src_worker_id, $params);
break;
default :
$res = 'no type match';
}
return $res;
}
public function onFinish(swoole_server $serv, int $task_id, string $data)
{
}
public function onClose($serv, $fd)
{
}
}
$server = new CooStat();
$server->run();
重写第一个接口时负载变化:
Redis
有时候我们需要连续多次操作redis 如:
<?php
for($i=0; $i<100; $i++) {
//伪代码 举个例子
Redis::set(...)
}
如果访问量小,怎么写都无所谓,但如果是流量比较大的项目,这样的代码肯定是有性能问题的。
redis pipeline (ps:主要是总结实践过的案例,不对原理做过多的介绍...) 用在这样的场景下就非常合适,经过实测,性能比普通方式提升4-5倍 不仅明显提升php的执行速度 还能大幅降低redis服务器的压力。
以下是实际项目使用pipeline前后的性能对比:
可以看到 一台 每秒执行30000次左右命令的redis server 在使用了pipeline 之后,cpu 由80% 降低到 30% ,效果是非常明显的。