之前業務上寫日誌記錄的時候都是同步處理,日誌處理模塊總是要浪費一些時間的,導致系統整體響應較慢,上 kafka 那種級別的東西又有點殺雞牛刀,於是打算上 Redis,利用 List 做一下隊列,東西不難,記個思路。
前提:
1. 安裝Redis 2. 安裝 php_redis 擴展
思路:
代碼:
\application\common\command\Log.php
<?php
// +----------------------------------------------------------------------
// | Author: Liu Xiaoyu <[email protected]>
// +----------------------------------------------------------------------
// | Date: 2019/10/15 8:16
// +----------------------------------------------------------------------
namespace app\common\command;
use think\console\Command;
use think\console\Input;
use think\console\Output;
use think\Exception;
class Log extends Command
{
protected function configure()
{
$this -> setName('log:start') -> setDescription('Start Log Server By Redis');
}
protected function execute(Input $input, Output $output)
{
$redis = new \Redis();
$redis -> connect('127.0.0.1', 6379);
// 獲取 數據庫方法
// 我這的目的 後邊有個地方 要根據之前傳的參數 找對應方法 扔到 redis裏存一下, hash 讀起來快
if (!$redis -> hLen('coa_method')) {
$method = db('method') -> field('name, en_name, method') -> select();
$hash = [];
foreach ($method as $v) {
$hash[$v['method']] = serialize($v);
}
$redis -> hMSet('coa_method', $hash);
}
while (true) {
try {
// 取出隊列頭
$task = $redis->lPop('coa_log');
if(!$task) {
// 沒有數據 睡3秒, 防止 不斷循環 整死了
sleep(3);
continue;
}
$log = unserialize($task);
// dump($log);
// 這個地方是一個小邏輯
for ($i = 0; $i < strlen($log['controller']); $i++) {
echo $log['controller'][$i];
if ( (ord($log['controller'][$i]) >= ord('A')) && (ord($log['controller'][$i]) <= ord('Z')) && $i !== 0) {
// 有大寫字符, 插一下
$log['controller'] = substr_replace($log['controller'], '_',$i, 0);
$i++;
}
}
// 獲取方法名所對中文
$method_str = $log['module'].'/'.$log['controller'].'/'.$log['action'];
$arr_str = [
'name' => '',
'en_name' => '',
];
$method_str = strtolower($method_str);
if ($redis -> hExists('coa_method', $method_str)) {
$hash_str = $redis -> hGet('coa_method', $method_str);
$arr_str = unserialize($hash_str);
}
$log['cn_name'] = $arr_str['name'];
$log['en_name'] = $arr_str['en_name'];
// save
db('log') -> insert($log);
} catch (\RedisException $exception) {
echo $exception -> getMessage();
}
}
}
}
在 \application\command.php 加入
return [
'LogServer' => 'app\common\command\Log'
];
至此,輪詢進程(消費者)已經寫完,根目錄下執行
php think LogServer
沒有反應就對了,因爲現在隊列裏是空的,sleep了,可以在 sleep 那裏加上echo 看看 什麼反應。
現在開始寫 任務
\application\common\behavior\Log.php
<?php
namespace app\common\behavior;
use think\facade\Request;
class Log
{
public function run(Request $request = null)
{
// 獲取信息
try {
$userinfo = session('userinfo');
$info = [
'module' => Request::module(),
'controller' => Request::controller(),
'action' => Request::action(),
'param' => serialize(Request::param()),
'username' => $userinfo['username'],
'userid' => $userinfo['id'],
'is_admin' => $userinfo['is_admin'],
'time' => time()
];
// 加入 redis 隊列
$redis = new \Redis();
$redis -> connect('127.0.0.1', 6379);
// 完畢
$redis -> rPush('coa_log', serialize($info));
} catch (\RedisException $exception) {
// echo $exception -> getMessage();
}
}
}
\application\tags.php 在 app_begin 這裏加上
// 應用開始
'app_begin' => [
'\app\common\behavior\Log',
],
好了,前面開始跑業務吧,看看剛纔 php think LogServer 的命令行是不是輸出東西了,裏面有一些業務邏輯,根據實際更改即可。
代碼是在 Win下開發的,linux下同理。