没有不值得去解决的问题,也没有不值得去学习的技术!

基于 yiisoft/yii2-app-advanced,在 GitHub 上新建仓库 yii2-app-advanced,日志消息的自动定时删除

由于日志消息是存储于 MySQL 的 log 表中,在生产环境中,累积了大量的数据,log 表的数据长度已经达到 数百 GB ,因此,决定基于控制台命令行实现日志消息的定时删除,开发环境的 log 表的数据长度为 14.64 GB

Yii2 Advanced 实战系列:RESTful API + RPC 服务 + 国际化 + 日志与测试

新建 api 目录、配置和环境、测试、Vagrant 等的支持。

(1) 基于 yiisoft/yii2-app-advanced,在 GitHub 上新建仓库 yii2-app-advanced,新建接口应用(实现 RESTful 风格的 Web Service 服务的 API),新建api目录、配置和环境、测试、Vagrant等的支持

(2) 基于 yiisoft/yii2-app-advanced,在 GitHub 上新建仓库 yii2-app-advanced,新建接口应用(实现 RESTful 风格的 Web Service 服务的 API),实现模型分层:数据层、逻辑层,明确公共目录、应用、模块的继承、引用关系

在 Postman 中,GET http://api.github-shuijingwan-yii2-app-advanced.localhost/v1/users ,200响应,message为简体中文

(3) 基于 yiisoft/yii2-app-advanced,在 GitHub 上新建仓库 yii2-app-advanced,新建接口应用(实现 RESTful 风格的 Web Service 服务的 API),实现 RESTful Web 服务,支持国际化(动态地设置目标语言,默认为简体中文)

运行测试,获取详细的输出,可看到一步一步的行为报告,符合预期

(4) 基于 yiisoft/yii2-app-advanced,在 GitHub 上新建仓库 yii2-app-advanced,新建接口应用(实现 RESTful 风格的 Web Service 服务的 API),在 api 的 tests 目录中准备用户相关操作的一些自动化测试的样例(API 测试),确保应用程序在改变或增加新的功能时不会影响现有的功能

在 Postman 中,GET http://api.github-shuijingwan-yii2-app-advanced.localhost/v1/logs?filter[level]=4&filter[category][like]=api\behaviors\RequestLogBehavior&filter[prefix][like]=app-api&filter[log_time][gte]=1528090828&filter[log_time][lte]=1529564924.6648 ,200响应,空数组已经被自动转换为空对象,以保证字段格式的统一,GET http://api.github-shuijingwan-yii2-app-advanced.localhost/v1/logs/3

(5) 基于 yiisoft/yii2-app-advanced,在 GitHub 上新建仓库 yii2-app-advanced,新建接口应用(实现 RESTful 风格的 Web Service 服务的 API),调整默认字符集为:utf8mb4,接口响应格式的调整,空数组自动转换为空对象,在接口应用中收集请求日志消息(1个请求对应1条日志消息)至数据库,且实现日志功能的相应接口:日志列表(设置数据过滤器以启用筛选器处理)、日志详情

在开发环境中,执行数据库迁移命令失败:1071 Specified key was too long; max key length is 767 bytes

(6) 基于 yiisoft/yii2-app-advanced,在 GitHub 上新建仓库 yii2-app-advanced,新建接口应用(实现 RESTful 风格的 Web Service 服务的 API),调整默认字符集为:utf8mb4,接口响应格式的调整,空数组自动转换为空对象,在接口应用中收集请求日志消息(1个请求对应1条日志消息)至数据库,且实现日志功能的相应接口:日志列表(设置数据过滤器以启用筛选器处理)、日志详情(二)

浏览 user 表数据,status、updated_at 已经更新

(7) 基于 yiisoft/yii2-app-advanced,在 GitHub 上新建仓库 yii2-app-advanced,新建接口应用(实现 RESTful 风格的 Web Service 服务的 API),实现 ActiveRecord 的软删除,生成 ActiveQuery,自定义查询类

执行数据库迁移命令,查看数据库表 user 结构,符合预期

(8) 基于 yiisoft/yii2-app-advanced,在 GitHub 上新建仓库 yii2-app-advanced,新建接口应用(实现 RESTful 风格的 Web Service 服务的 API),实现 ActiveRecord 的软删除,生成 ActiveQuery,自定义查询类(二)

在 Postman 中 POST 请求,http://api.github-shuijingwan-yii2-app-advanced.localhost/v1/users ,输入格式:application/json

(9) 基于 yiisoft/yii2-app-advanced,在 GitHub 上新建仓库 yii2-app-advanced,新建接口应用(实现 RESTful 风格的 Web Service 服务的 API),application/x-www-form-urlencoded 和 multipart/form-data 输入格式,默认支持,新增 application/json 输入格式的支持

打开 Windows PowerShell,执行 init 命令并选择 dev 作为环境,api应用所需环境配置文件自动生成

(10) 基于 yiisoft/yii2-app-advanced,在 GitHub 上新建仓库 yii2-app-advanced,新建远程过程调用应用(实现基于 Hprose 2.0 for PHP 的 RPC 服务端),新建 rpc 目录、配置和环境、测试、Vagrant等的支持

出现以上原因是因为 Windows 下 nginx php 环境,不支持并发的原因,当同时访问多个域名,并且同时指向你本地服务的时候,就不支持并发了。nginx.conf 里面 对不同 server 修改 fastcgi_pass 的端口号,启动多个 php-cgi。

(11) 基于 yiisoft/yii2-app-advanced,在 GitHub 上新建仓库 yii2-app-advanced,新建远程过程调用应用(实现基于 Hprose 2.0 for PHP 的 RPC 服务端),在 rpc 目录中实现 页面 的相应 RPC 服务,且在 api 目录中的 API 实现 RPC 客户端

执行数据库迁移,查看表结构,基于 Gii 重新生成模型文件

(12) 基于 yiisoft/yii2-app-advanced,在 GitHub 上新建仓库 yii2-app-advanced,UUID 的实现

由于日志消息是存储于 MySQL 的 log 表中,在生产环境中,累积了大量的数据,log 表的数据长度已经达到 数百 GB ,因此,决定基于控制台命令行实现日志消息的定时删除,开发环境的 log 表的数据长度为 14.64 GB

(13) 基于 yiisoft/yii2-app-advanced,在 GitHub 上新建仓库 yii2-app-advanced,日志消息的自动定时删除

1、由于日志消息是存储于 MySQL 的 log 表中,在生产环境中,累积了大量的数据,log 表的数据长度已经达到 数百 GB ,因此,决定基于控制台命令行实现日志消息的定时删除,开发环境的 log 表的数据长度为 14.64 GB,如图1

由于日志消息是存储于 MySQL 的 log 表中,在生产环境中,累积了大量的数据,log 表的数据长度已经达到 数百 GB ,因此,决定基于控制台命令行实现日志消息的定时删除,开发环境的 log 表的数据长度为 14.64 GB
图1

2、编辑 \console\controllers\LogController.php,获取服务器当前时间,判断范围([0点,1点)),如果不在范围内,则延缓执行 10 * 60 秒,再退出

<?php
/**
 * Created by PhpStorm.
 * User: Qiang Wang
 * Date: 2019/10/08
 * Time: 13:36
 */
 
namespace console\controllers;
 
use Yii;
use console\models\Log;
use yii\console\Controller;
use yii\console\ExitCode;
use yii\helpers\ArrayHelper;
use yii\web\HttpException;
use yii\web\ServerErrorHttpException;
 
/**
 * 日志
 *
 * @author Qiang Wang <shuijingwanwq@163.com>
 * @since  1.0
 */
class LogController extends Controller
{
    const SLEEP_TIME = 10 * 60; // 延缓执行 10 * 60 秒
    /**
     * 日志的删除
     *
     */
    public function actionDelete()
    {
        /* 获取服务器当前时间,判断范围([0点,1点)),如果不在范围内,则延缓执行 10 * 60 秒,再退出 */
        $time = time();
        $zeroTime = strtotime("today"); // 0点
        $oneTime = strtotime("today +1 hours"); // 1点
        echo $time . " ";
        echo date('Y-m-d H:i:s', $time) . " ";
        echo $zeroTime . " ";
        echo date('Y-m-d H:i:s', $zeroTime) . " ";
        echo $oneTime . " ";
        echo date('Y-m-d H:i:s', $oneTime) . " ";
        exit;
        if (!($time >= $zeroTime && $time < $oneTime)) {
            // 延缓执行 10 * 60 秒
            sleep(static::SLEEP_TIME);
 
            return ExitCode::OK;
        }
 
        echo 1;
        exit;
 
 
    }
}

PS E:\wwwroot\github-shuijingwan-yii2-app-advanced> ./yii log/delete
1570518464 2019-10-08 15:29:17 1570464000 2019-10-08 00:00:00 1570467600 2019-10-08 01:00:00


3、查询 1 条记录的日志时间($logTime),基于 日志时间 升序排列,如果不存在,则延缓执行 10 * 60 秒,再退出


        /* 查询 1 条记录的日志时间($logTime),基于 日志时间 升序排列,如果不存在,则延缓执行 10 * 60 秒,再退出 */
        $logItem = Log::find()->select(['log_time'])->orderBy(['log_time' => SORT_ASC])->limit(1)->one();
        if (!isset($logItem)) {
            // 延缓执行 10 * 60 秒
            sleep(static::SLEEP_TIME);

            return ExitCode::OK;
        }
        $logTime = $logItem->log_time;


4、获取服务器当前时间的前 15 天(默认值,可自定义)的值($reservedTime:保留时间,0点),如果 $logTime 大于等于 $reservedTime,则延缓执行 10 * 60 秒,再退出


        /* 获取服务器当前时间的前 15 天(默认值,可自定义)的值($reservedTime:保留时间,0点),如果 $logTime 大于等于 $reservedTime,则延缓执行 10 * 60 秒,再退出 */
        $reservedTime = strtotime("today -15 days"); // 保留时间,0点
        echo $logTime . " ";
        echo date('Y-m-d H:i:s', $logTime) . " ";
        echo $reservedTime . " ";
        echo date('Y-m-d H:i:s', $reservedTime) . " ";
        if ($logTime >= $reservedTime) {
            echo 0;
            exit;
            // 延缓执行 10 * 60 秒
            sleep(static::SLEEP_TIME);

            return ExitCode::OK;
        }
        echo 1;
        exit;



PS E:\wwwroot\github-shuijingwan-yii2-app-advanced> ./yii log/delete
1567046168.2703 2019-08-29 10:36:08 1569168000 2019-09-23 00:00:00 1


5、获取 1 条记录的日志时间($logTime)的后 1 天的值($deadlineTime:截止时间,0点),如果 $deadlineTime 大于 $reservedTime,则将 $reservedTime 赋值给 $deadlineTime(后 1 天的值时,此条件永远不满足,大于 1 天时,此条件可能满足)


        /* 获取 1 条记录的日志时间($logTime)的后 1 天的值($deadlineTime:截止时间,0点),如果 $deadlineTime 大于 $reservedTime,则将 $reservedTime 赋值给 $deadlineTime(后 1 天的值时,此条件永远不满足,大于 1 天时,此条件可能满足) */
        $logDate = date('Y-m-d', $logTime);
        $deadlineTime = strtotime("$logDate +1 days"); // 截止时间,0点
        echo $logDate . " ";
        echo date('Y-m-d H:i:s', $deadlineTime) . " ";
        if ($deadlineTime > $reservedTime) {
            $deadlineTime = $reservedTime;
            echo 1;
            exit;
        }
        echo date('Y-m-d H:i:s', $deadlineTime) . " ";
        echo 2;
        exit;



PS E:\wwwroot\github-shuijingwan-yii2-app-advanced> ./yii log/delete
2019-08-29 2019-08-30 00:00:00 2019-08-30 00:00:00 2


6、执行删除 SQL(),条件(日志时间 小于 $deadlineTime),即命令行 1 次运行仅删除 1 天的日志消息,延缓执行 60 秒,再退出。
注:执行删除 SQL(),DELETE FROM `cpa_log` WHERE `log_time` < 1570590733,删除 26 万余条记录(1 天的日志消息),发现执行时间长达 1 分余钟,如图2

执行删除 SQL(),DELETE FROM `cpa_log` WHERE `log_time` < 1570590733,删除 26 万余条记录(1 天的日志消息),发现执行时间长达 1 分余钟
图2
<?php
/**
 * Created by PhpStorm.
 * User: Qiang Wang
 * Date: 2019/10/08
 * Time: 13:36
 */
 
namespace console\controllers;
 
use Yii;
use console\models\Log;
use yii\console\Controller;
use yii\console\ExitCode;
use yii\helpers\ArrayHelper;
use yii\web\HttpException;
use yii\web\ServerErrorHttpException;
 
/**
 * 日志
 *
 * @author Qiang Wang <shuijingwanwq@163.com>
 * @since  1.0
 */
class LogController extends Controller
{
    const SLEEP_TIME = 10 * 60; // 延缓执行 10 * 60 秒
    /**
     * 日志的删除
     *
     */
    public function actionDelete()
    {
        /* 获取服务器当前时间,判断范围([0点,1点]),如果不在范围内,则延缓执行 10 * 60 秒,再退出 */
        $time = time(); // 当前时间
        $zeroTime = strtotime("today"); // 0点
        $oneTime = strtotime("today +1 hours"); // 1点
        if (($time >= $zeroTime && $time <= $oneTime)) {
            // 延缓执行 10 * 60 秒
            echo 0;
            exit;
            sleep(static::SLEEP_TIME);
 
            return ExitCode::OK;
        }
 
        /* 查询 1 条记录的日志时间($logTime),基于 日志时间 升序排列,如果不存在,则延缓执行 10 * 60 秒,再退出 */
        $logItem = Log::find()->select(['log_time'])->orderBy(['log_time' => SORT_ASC])->limit(1)->one();
        if (!isset($logItem)) {
            // 延缓执行 10 * 60 秒
            echo 1;
            exit;
            sleep(static::SLEEP_TIME);
 
            return ExitCode::OK;
        }
        $logTime = $logItem->log_time;
 
        /* 获取服务器当前时间的前 15 天(默认值,可自定义)的值($reservedTime:保留时间,0点),如果 $logTime 大于等于 $reservedTime,则延缓执行 10 * 60 秒,再退出 */
        $reservedTime = strtotime("today -15 days"); // 保留时间,0点
        echo $logTime . " ";
        echo date('Y-m-d H:i:s', $logTime) . " ";
        echo $reservedTime . " ";
        echo date('Y-m-d H:i:s', $reservedTime) . " ";
        if ($logTime >= $reservedTime) {
            echo 2;
            exit;
            // 延缓执行 10 * 60 秒
            sleep(static::SLEEP_TIME);
 
            return ExitCode::OK;
        }
 
        /* 获取 1 条记录的日志时间($logTime)的后 1 天的值($deadlineTime:截止时间,0点),如果 $deadlineTime 大于 $reservedTime,则将 $reservedTime 赋值给 $deadlineTime(后 1 天的值时,此条件永远不满足,大于 1 天时,此条件可能满足) */
        $logDate = date('Y-m-d', $logTime);
        $deadlineTime = strtotime("$logDate +1 days"); // 截止时间,0点
        echo $logDate . " ";
        echo date('Y-m-d H:i:s', $deadlineTime) . " ";
        if ($deadlineTime > $reservedTime) {
            $deadlineTime = $reservedTime;
        }
        echo date('Y-m-d H:i:s', $deadlineTime) . " ";
 
        /* 执行删除 SQL(),条件(日志时间 小于 $deadlineTime),即命令行 1 次运行仅删除 1 天的日志消息,延缓执行 60 秒,再退出 */
        Log::deleteAll(['<', 'log_time', $deadlineTime]);
        // 延缓执行 60 秒
        //sleep(60);
        //return ExitCode::OK;
        echo 3;
        exit;
    }
}
 

PS E:\wwwroot\github-shuijingwan-yii2-app-advanced> ./yii log/delete
1567046168.2703 2019-08-29 10:36:08 1569168000 2019-09-23 00:00:00 2019-08-29 2019-08-30 00:00:00 2019-08-30 00:00:00 3
PS E:\wwwroot\github-shuijingwan-yii2-app-advanced> ./yii log/delete
1567094579.432 2019-08-30 00:02:59 1569168000 2019-09-23 00:00:00 2019-08-30 2019-08-31 00:00:00 2019-08-31 00:00:00 3
PS E:\wwwroot\github-shuijingwan-yii2-app-advanced> ./yii log/delete
1567180800.2962 2019-08-31 00:00:00 1569168000 2019-09-23 00:00:00 2019-08-31 2019-09-01 00:00:00 2019-09-01 00:00:00 3
PS E:\wwwroot\github-shuijingwan-yii2-app-advanced> ./yii log/delete
1567267282.2226 2019-09-01 00:01:22 1569168000 2019-09-23 00:00:00 2019-09-01 2019-09-02 00:00:00 2019-09-02 00:00:00 3
PS E:\wwwroot\github-shuijingwan-yii2-app-advanced> ./yii log/delete
1568958887.1824 2019-09-20 13:54:47 1569168000 2019-09-23 00:00:00 2019-09-20 2019-09-21 00:00:00 2019-09-21 00:00:00
PS E:\wwwroot\github-shuijingwan-yii2-app-advanced> ./yii log/delete
1569832928.1543 2019-09-30 16:42:08 1569168000 2019-09-23 00:00:00 2
PS E:\wwwroot\github-shuijingwan-yii2-app-advanced> ./yii log/delete
1569832928.1543 2019-09-30 16:42:08 1569168000 2019-09-23 00:00:00 2


7、设置参数,日志的定时删除的保留时间(前 15 天),单位为天,编辑 \console\config\params-local.php

<?php
return [
    'logDeleteReservedTime' => 15, // 日志的定时删除的保留时间(前 15 天),单位为天
];

8、最终的代码实现,开发环境的 log 表的数据长度为 2.36 GB,符合预期,如图3

最终的代码实现,开发环境的 log 表的数据长度为 2.36 GB,符合预期
图3
<?php
/**
 * Created by PhpStorm.
 * User: Qiang Wang
 * Date: 2019/10/08
 * Time: 13:36
 */
 
namespace console\controllers;
 
use Yii;
use console\models\Log;
use yii\console\Controller;
use yii\console\ExitCode;
 
/**
 * 日志
 *
 * @author Qiang Wang <shuijingwanwq@163.com>
 * @since  1.0
 */
class LogController extends Controller
{
    const SLEEP_TIME = 10 * 60; // 延缓执行 10 * 60 秒
    /**
     * 日志的删除
     */
    public function actionDelete()
    {
        /* 获取服务器当前时间,判断范围([0点,1点]),如果不在范围内,则延缓执行 10 * 60 秒,再退出 */
        $time = time(); // 当前时间
        $zeroTime = strtotime("today"); // 0点
        $oneTime = strtotime("today +1 hours"); // 1点
        if (!($time >= $zeroTime && $time < $oneTime)) {
            // 延缓执行 10 * 60 秒
            sleep(static::SLEEP_TIME);
 
            return ExitCode::OK;
        }
 
        /* 查询 1 条记录的日志时间($logTime),基于 日志时间 升序排列,如果不存在,则延缓执行 10 * 60 秒,再退出 */
        $logItem = Log::find()->select(['log_time'])->orderBy(['log_time' => SORT_ASC])->limit(1)->one();
        if (!isset($logItem)) {
            // 延缓执行 10 * 60 秒
            sleep(static::SLEEP_TIME);
 
            return ExitCode::OK;
        }
        $logTime = $logItem->log_time;
 
        /* 获取服务器当前时间的前 15 天(默认值,可自定义)的值($reservedTime:保留时间,0点),如果 $logTime 大于等于 $reservedTime,则延缓执行 10 * 60 秒,再退出 */
        $logDeleteReservedTime = Yii::$app->params['logDeleteReservedTime'];
        $reservedTime = strtotime("today -$logDeleteReservedTime days"); // 保留时间,0点
        if ($logTime >= $reservedTime) {
            // 延缓执行 10 * 60 秒
            sleep(static::SLEEP_TIME);
 
            return ExitCode::OK;
        }
 
        /* 获取 1 条记录的日志时间($logTime)的后 1 天的值($deadlineTime:截止时间,0点),如果 $deadlineTime 大于 $reservedTime,则将 $reservedTime 赋值给 $deadlineTime(后 1 天的值时,此条件永远不满足,大于 1 天时,此条件可能满足) */
        $logDate = date('Y-m-d', $logTime);
        $deadlineTime = strtotime("$logDate +1 days"); // 截止时间,0点
        if ($deadlineTime > $reservedTime) {
            $deadlineTime = $reservedTime;
        }
 
        /* 执行删除 SQL(),条件(日志时间 小于 $deadlineTime),即命令行 1 次运行仅删除 1 天的日志消息,延缓执行 60 秒,再退出 */
        Log::deleteAll(['<', 'log_time', $deadlineTime]);
        // 延缓执行 60 秒
        sleep(60);
        return ExitCode::OK;
    }
}
 

 

基于 yiisoft/yii2-app-advanced,在 GitHub 上新建仓库 yii2-app-advanced,UUID 的实现

PHP / Yii2 老项目维护与长期技术支持

如果你的 Yii2 项目已经上线,但遇到原开发离职、Bug 长期无人修复、接口不稳定、性能下降、代码难以接手等问题,可以联系我做一次远程技术排查。

适合以下情况:
✅ Yii2 老项目无人维护
✅ 后台管理系统 Bug 修复
✅ RESTful API 接口排查
✅ 小功能迭代与历史代码接手
✅ MySQL / Redis / Nginx 性能问题
✅ 长期远程兼职维护

可先从一次小问题开始:
✅ 线上报错排查
✅ 接口异常分析
✅ 慢查询与性能瓶颈定位
✅ 代码结构初步评估
✅ 部署环境与日志检查

如需咨询,请联系我,并注明:Yii2 维护咨询

联系方式:
Telegram:@shuijingwan
微信:13980074657
邮箱:shuijingwanwq@gmail.com

评论

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

这个站点使用 Akismet 来减少垃圾评论。了解你的评论数据如何被处理