什么是链路追踪
- 链路追踪一般常用于分布式架构中,当实现一个功能的同时,可能会依次调用多个接口,那么此时这一些列的接口调用,称为调用链。想要实现调用链,那么就需要对每次调用的链接进行标识也就是pointId,方便出现调用问题的时候排查问题,但是有调用并不是同级,所以还需要用parentId来标识上下级关系。具体请查看链接 一文读懂链路追踪
EasySwoole中实现Api链路追踪
- 安装组件
composer require easyswoole/tracker
- onRequest事件(请求开始)
public static function onRequest(Request $request, Response $response): bool
{
//链路追踪
$point = PointContext::getInstance()->createStart('onRequest');
$point->setStartArg([
'uri' => $request->getUri()->__toString(),//获取请求的url
'get' => $request->getQueryParams(),//get参数(注意:若POST与GET存在同键名参数,则以GET为准)
'post'=> $request->getRequestParam()//post参数
]);
return true;
}
- 创建数据库
CREATE TABLE `api_tracker_point_list` (
`point_id` varchar(50) NOT NULL,
`parent_id` varchar(50) DEFAULT NULL,
`point_name` varchar(255) DEFAULT NULL COMMENT '请求名称',
`is_next` int(11) NOT NULL DEFAULT '0',
`depth` int(11) NOT NULL DEFAULT '0',
`status` varchar(10) NOT NULL DEFAULT '' COMMENT '状态',
`ip` varchar(50) NOT NULL DEFAULT '' COMMENT '请求ip',
`url` varchar(1000) NOT NULL DEFAULT '' COMMENT '请求地址',
`result` text COMMENT '请求结果',
`data` text COMMENT '请求参数',
`add_time` varchar(15) NOT NULL DEFAULT '0' COMMENT '访问时间',
`start_time` varchar(15) NOT NULL DEFAULT '0' COMMENT '请求开始时间',
`end_time` varchar(15) NOT NULL DEFAULT '0' COMMENT '请求结束时间',
`spend_time` decimal(15,3) DEFAULT '0.000' COMMENT '调用耗时',
PRIMARY KEY (`point_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
- afterRequest事件(请求结束)
public static function afterRequest(Request $request, Response $response): void
{
//获取当前ip
$serv = ServerManager::getInstance()->getSwooleServer();
$client = $serv->getClientInfo($request->getSwooleRequest()->fd);
$clientAddress = $client['remote_ip'];
$xri = $request->getHeader('x-real-ip');
$xff = $request->getHeader('x-forwarded-for');
if ($clientAddress === '127.0.0.1'){
if (!empty($xri)) { // 如果有xri 则判定为前端有NGINX等代理
$clientAddress = $xri[0];
} elseif (!empty($xff)) { // 如果不存在xri 则继续判断xff
$list = explode(',', $xff[0]);
if (isset($list[0])) $clientAddress = $list[0];
}
}
$point = PointContext::getInstance()->startPoint();
$point->end();
$array = Point::toArray($point);
$data = [];
foreach ($array as $v)
{
$data['point_id'] = $v['pointId'];
$data['point_name'] = $v['pointName'];
$data['parent_id'] = $v['parentId'];
$data['depth'] = $v['depth'];
$data['is_next'] = $v['isNext'] ? 1 : 0;
$data['start_time'] = $v['startTime'];
$data['end_time'] = $v['endTime'];
$data['spend_time'] = $v['endTime']-$v['startTime'];
$data['status'] = $v['status'];
$arg = $v['startArg'];
$data['url'] = explode(':9503',$arg['uri'])[1];
unset($arg['uri']);
$data['result'] = $response->getBody()->__toString();
$data['data'] = json_encode($arg);
$data['add_time'] = time();
$data['ip'] = $clientAddress;
//此处应做个白名单来处理那些api接口调用需要记录到表
if(strpos(strtolower($data['url']),'api/admin') === false )
{
ApiTrackerModel::create($data)->save();
}
}
}
- 效果图
此时简单的链路追踪已实现,并没有多次调用链接,如果想要实现复杂的链路追踪,请移步easyswoole官网->组件->链路追踪组件查看,其次此组件可以当成甩锅神器(前端接口出现的问题)以及系统性能排查来使用
来自北溟有鱼QAQ https://www.umdzz.cn