Laravel中GraphQL接口请求频率实战记录(2)

<?php namespace App\Helpers; use Illuminate\Support\Facades\Redis; class RequestCounter { const PRECISION = [5, 60, 1800, 3600, 86400]; const REQUEST_COUNTER_CACHE_KEY = 'request:counter'; /** * 更新请求计数器 * * @param string $opName * @param integer $count * @return void */ public static function updateRequestCounter(string $opName, $count = 1) { $now = microtime(true); $redis = self::getRedisConn(); if ($redis) { $pipe = $redis->pipeline(); foreach (self::PRECISION as $prec) { //计算时间片 $pnow = intval($now / $prec) * $prec; //生成一个hash key标识 $hash = self::counterCacheKey($opName, $prec); //增长接口请求数 $pipe->hincrby($hash, $pnow, 1); // 添加到集合中,方便后续数据查询 $pipe->zadd(self::REQUEST_COUNTER_CACHE_KEY, [$hash => 0]); } $pipe->execute(); } } /** * 获取Redis连接 * * @return object */ public static function getRedisConn() { $redis = Redis::connection('cache'); try { $redis->ping(); } catch (Exception $ex) { $redis = null; //丢给sentry报告 app('sentry')->captureException($ex); } return $redis; } /** * 获取接口访问计数 * * @param string $opName * @param integer $prec * @return array */ public static function getRequestCounter(string $opName, int $prec) { $data = []; $redis = self::getRedisConn(); if ($redis) { $hash = self::counterCacheKey($opName, $prec); $hashData = $redis->hgetall($hash); foreach ($hashData as $k => $v) { $date = date("Y/m/d", $k); $data[] = ['timestamp' => $k, 'value' => $v, 'date' => $date]; } } return $data; } /** * 清理请求计数 * * @param integer $clearDay * @return void */ public static function clearRequestCounter($clearDay = 7) { $index = 0; $startTime = microtime(true); $redis = self::getRedisConn(); if ($redis) { //可以清理的情况下 while ($index < $redis->zcard(self::REQUEST_COUNTER_CACHE_KEY)) { $hash = $redis->zrange(self::REQUEST_COUNTER_CACHE_KEY, $index, $index); $index++; //当前hash存在 if ($hash) { $hash = $hash[0]; //计算删除截止时间 $cutoff = intval(microtime(true) - ($clearDay * 24 * 60 * 60)); //优先删除时间较远的数据 $samples = array_map('intval', $redis->hkeys($hash)); sort($samples); //需要删除的数据 $removes = array_filter($samples, function ($item) use (&$cutoff) { return $item <= $cutoff; }); if (count($removes)) { $redis->hdel($hash, ...$removes); //如果整个数据都过期了的话,就清除掉统计的数据 if (count($removes) == count($samples)) { $trans = $redis->transaction(['cas' => true]); try { $trans->watch($hash); if (!$trans->hlen($hash)) { $trans->multi(); $trans->zrem(self::REQUEST_COUNTER_CACHE_KEY, $hash); $trans->execute(); $index--; } else { $trans->unwatch(); } } catch (\Exception $ex) { dump($ex); } } } } } dump('清理完成'); } } public static function counterCacheKey($opName, $prec) { $key = "request:counter:{$prec}:$opName"; return $key; } }

在Middleware中使用.

<?php namespace App\Http\Middleware; use App\Helpers\RequestCounter; use Closure; class GraphQLRecord { /** * Handle an incoming request. * * @param \Illuminate\Http\Request $request * @param \Closure $next * @return mixed */ public function handle($request, Closure $next) { $opName = $request->get('operationName'); if (!empty($opName)) { RequestCounter::updateRequestCounter($opName); } return $next($request); } }

结尾

上诉代码就实现了基于GraphQL的请求频率记录,但是使用不止适用于GraphQL接口,也可以基于Rest接口、模块计数等统计行为,只要有唯一的operation name即可。

到此这篇关于Laravel中GraphQL接口请求频率的文章就介绍到这了,更多相关Laravel中GraphQL接口请求频率内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:http://www.heiqu.com/39e084fc61619d359482fd87e1e7415e.html