
本文环境 CentOS8.0,PHP8.1,Nginx1.8,Workerman 4.0\ 不懂的可以评论 著作权归OwenZhang所有。商业转载请联系OwenZhang获得授权,非商业转载请注明出处。

Workerman是一款纯PHP开发的开源高性能的PHP 应用容器。
Workerman不是重复造轮子,它不是一个MVC框架,而是一个更底层更通用的服务框架,你可以用它开发tcp代理、梯子代理、做游戏服务器、邮件服务器、ftp服务器、甚至开发一个php版本的redis、php版本的数据库、php版本的nginx、php版本的php-fpm等等。Workerman可以说是PHP领域的一次创新,让开发者彻底摆脱了PHP只能做WEB的束缚。
实际上Workerman类似一个PHP版本的nginx,核心也是多进程+Epoll+非阻塞IO。Workerman每个进程能维持上万并发连接。由于本身常驻内存,不依赖Apache、nginx、php-fpm这些容器,拥有超高的性能。同时支持TCP、UDP、UNIXSOCKET,支持长连接,支持Websocket、HTTP、WSS、HTTPS等通讯协议以及各种自定义协议。拥有定时器、异步socket客户端、异步Redis、异步Http、异步消息队列等众多高性能组件。
TransferStatistics 使用webman开发的一个应用监控系统,用于查看应用调用记录、请求量、调用耗时、调用分析等。
系统使用UDP接收上报数据;使用Redis存储、汇总数据
由于是使用redis存储,所以我做了个定时删除一周前的数据
定时删除redis db7 statistic key

#!/bin/bash
redis-cli <<END
select 7
flushdb
ENDTCP/IP模型的运输层有两个不同的协议:UDP用户数据报协议与TCP传输控制协议。
运输层无法保证数据的可靠传输,只能通过应用层来实现了,实现的方式可以参照TCP可靠性传输的方式,只是实现不在传输层,实现转移到了应用层,主要通过实现确认机制、重传机制、窗口确认等机制来实现可靠传输,有RUDP、RTP、UDT等开源程序利用UDP实现了可靠的数据传输,此外有结合TCP的可靠与UDP速度的权衡KCP协议。
由于TCP本身是面向字节流的,无法理解上层的业务数据,所以在底层是无法保证数据包不被拆分和重组的,这个问题只能通过上层的应用协议栈设计来解决。
消息定长:发送端将每个数据包封装为固定长度(不够的可以通过补0填充),这样接收端每次接收缓冲区中读取固定长度的数据就自然而然的把每个数据包拆分开来。
设置消息边界:服务端从网络流中按消息边界分离出消息内容,在包尾增加回车换行符进行分割,例如FTP协议。
将消息分为消息头和消息体:消息头中包含表示消息总长度(或者消息体长度)的字段。
https://github.com/hsk99/transfer-statistics
PHP版本不低于7.3,并安装 Redis 拓展
创建项目
composer create-project hsk99/transfer-statistics
1、下载 或git clone https://github.com/hsk99/transfer-statistics
2、执行命令composer install
1、config/redis.php 设置 Redis
<?php
return [
'default' => [
'host' => env('REDIS_HOST', '127.0.0.1'),
'password' => env('REDIS_PASSWORD', ''),
'port' => env('REDIS_PORT', '6379'),
'database' => 7,
'prefix' => 'statistic:',
],
];2、config/app.php 设置 登录用户名、密码
<?php
return [
'debug' => true,
'default_timezone' => 'Asia/Shanghai',
'admin_name' => 'root',
'admin_password' => 'owenzhang',
];3、config/server.php 设置 WebServer
<?php
return [
'listen' => 'http://127.0.0.1:8788',
'transport' => 'tcp',
'context' => [],
'name' => 'server',
'count' => 1,
'user' => '',
'group' => '',
'pid_file' => runtime_path() . '/master.pid',
'stdout_file' => runtime_path() . '/stdout.log',
'log_file' => runtime_path() . '/master.log',
'max_request' => 1000000,
'max_package_size' => 100 * 1024 * 1024,
];4、config/process.php 设置 采集服务
<?php
return [
// File update detection and automatic reload
'monitor' => [
'handler' => process\FileMonitor::class,
'reloadable' => false,
'constructor' => [
// Monitor these directories
'monitor_dir' => [
app_path(),
config_path(),
base_path() . '/process',
base_path() . '/support',
base_path() . '/resource',
base_path() . '/.env',
base_path() . '/expand',
base_path() . '/Protocols',
],
// Files with these suffixes will be monitored
'monitor_extensions' => [
'php', 'html', 'htm', 'env'
]
],
'bootstrap' => []
],
// Statistic
'statistic' => [
'handler' => process\Statistic::class,
'listen' => 'statistic://0.0.0.0:55674',
'count' => 1,
'transport' => 'udp',
'bootstrap' => []
],
];执行命令php start.php start
浏览器访问http://ip地址:8788
添加上报地址
'statisticAddress' => 'udp://127.0.0.1:55674', // udp上报地址 一般用于api接口请求添加上报中间件
'admin' => [
\app\middleware\Statistic::class, // 接口请求即时上报
\app\middleware\StatisticSQL::class, // SQL监控即时上报
\app\middleware\ApiRoute::class,
\app\middleware\ApiBaseRequest::class,
\app\middleware\ActionHook::class,
],添加接口请求即时上报类
<?php
namespace app\middleware;
use Webman\MiddlewareInterface;
use Webman\Http\Response;
use Webman\Http\Request;
use app\extend\Client\StatisticClient;
class Statistic implements MiddlewareInterface
{
public function process(Request $request, callable $next): Response
{
$ip = $request->getRealIp(true);
$controller = $request->controller;
$action = $request->action;
$transfer = $controller . '::' . $action;
$project = '充电动画项目';
// 开始计时
$unique = StatisticClient::tick($project, $ip, $transfer);
$response = $next($request);
$code = $response->getStatusCode();
$success = $code < 400;
$details = [
'ip' => $request->getRealIp(true) ?? '', // 请求客户端IP
'url' => $request->fullUrl() ?? '', // 请求URL
'method' => $request->method() ?? '', // 请求方法
'request_param' => $request->all() ?? [], // 请求参数
'request_header' => $request->header() ?? [], // 请求头
'cookie' => $request->cookie() ?? [], // 请求cookie
'session' => $request->session()->all() ?? [], // 请求session
'response_code' => $response->getStatusCode() ?? '', // 响应码
'response_header' => $response->getHeaders() ?? [], // 响应头
'response_body' => $response->rawBody() ? json_decode($response->rawBody(), true) : [], // 响应数据(发生异常)
];
// 数据上报
StatisticClient::report($unique, $project, $ip, $transfer, $success, $code, json_encode($details, JSON_PRESERVE_ZERO_FRACTION | JSON_NUMERIC_CHECK | JSON_UNESCAPED_UNICODE));
return $response;
}
}开启ThinkORM SQL监听配置
// 监听SQL
'trigger_sql' => true,文档网址:
https://static.kancloud.cn/manual/think-orm/1257999
添加SQL监控即时上报类(ThinkORM )
<?php
namespace app\middleware;
use Webman\MiddlewareInterface;
use Webman\Http\Response;
use Webman\Http\Request;
use app\extend\Client\StatisticClient;
class StatisticSQL implements MiddlewareInterface
{
public function process(Request $request, callable $next): Response
{
$response = $next($request);
// SQL监控
\think\facade\Db::listen(function ($sql, $runtime, $master) {
if ($sql == 'select 1') return true;
$ip = \request()->getRealIp(true) ?? '';
$project = '充电动画项目SQL';
switch (true) {
case is_numeric($runtime):
$transfer = $sql;
$cost = $runtime;
break;
case !is_numeric($runtime) && 'CONNECT' === substr($sql, 0, 7):
@preg_match("/UseTime:([0-9]+(\\.[0-9]+)?|[0-9]+(\\.[0-9]+))/", $sql, $result);
if (count($result) > 1) {
$transfer = substr($sql, strpos($sql, "s ] ") + 4);
$cost = $result[1];
} else {
$transfer = $sql;;
$cost = 0;
}
break;
default:
$transfer = $sql;;
$cost = 0;
break;
}
StatisticClient::report('', $project, $ip, $transfer, true, 1, json_encode([
'sql' => $sql,
'runtime' => $cost . 's',
'master' => $master,
], 320), $cost);
});
return $response;
}
}

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。