使用NGINX解决 客户端下载PHP服务端大文件时(kodbox) 服务器CPU爆满问题

使用场景

使用kodbox进行NAS文件管理,开始还好好的,下载一个gho系统镜像 一下子把NAS服务器干死,反馈给可道云官方,并没有实际效果,还让我了解两款产品(可道云,filebrowser)的构成 = =

无语之下,自行解决

先看看效果吧
处理前-Cpu提供4个 全部爆红

使用NGINX解决 客户端下载PHP服务端大文件时(kodbox) 服务器CPU爆满问题

最终效果-CPU波澜不惊

使用NGINX解决 客户端下载PHP服务端大文件时(kodbox) 服务器CPU爆满问题

解决方案

  1. 增加NGINX配置

    #NGINX大文件下载加速
    location /dresource {
        alias  /mnt/user/Resource;# 此处修改对应挂载的下载目录
        internal; # 设置只允许nginx内部处理 用户无法直接直接下载文件
    }
    #NGINX大文件下载加速END

    注:此处我看百度很多都是 root /mnt/user/Resource 此时 nginx会访问/mnt/user/Resource/dresource 去找文件 alias 则nginx会访问/mnt/user/Resource此目录

    搞了一会儿404才发现这个问题

  2. PHP 代码逻辑处理

    原来代码类似如下 直接通过PHP来读取文件 导致读取IO过高 最终CPU也干死了

    /*
     原来代码类似如下直接通过PHP来读取文件
    file_get_contents();
    fread();
    */

    修改为如下代码即可 简单方便快捷 香喷喷

    $filePath = '/mnt/user/Resource/text.txt';// 绝对路径
    $filePathMap = $filePath;
    $httpSpeedFileMap = '/mnt/user/Resource:/dresource;';//$GLOBALS["config"]["settings"]["upload"]["httpSendFileMap"]; 后面为kodbox替换变量
    $arr = explode(';', $httpSpeedFileMap);
    foreach ($arr as $item){
        $itemArr = explode(':', $item);
        //>> 获取服务器配置的路径映射
        $filePathMap = str_replace($itemArr[0], $itemArr[1], $filePathMap);
    }
    //////////////////////////////////
    header("X-Accel-Redirect: " . $filePathMap);// 此时地址应该为 /dresource/test.txt
    

    此处还可以返回header头部 来控制下载速度 X-Accel-Limit-Rate 或者

    location /dresource {
        limit_rate_after 500k;
        limit_rate       50k;
    }

注:

Kodbox 可以在 \PathDriverBase::fileOut 方法中 strtolower($_SERVER["SERVER_SOFTWARE"]) 下方if判断中 增加以上代码

system_option 增加配置 httpSendFileMap=/mnt/user/Resource:/dresource; httpSendFile=1
\userIndex::initSetting 方法中取消屏蔽 $upload['httpSendFile'] = $sysOption['httpSendFile'] == '1' 在此代码下方增加一行$upload['httpSendFileMap'] = $sysOption['httpSendFileMap'];

kodbox 修改位置 index.class.php

\userIndex::initSetting
private function initSetting(){
        if(!defined('STATIC_PATH')){
            define('STATIC_PATH',$GLOBALS['config']['settings']['staticPath']);
        }
        $sysOption = Model('SystemOption')->get();
        $upload = &$GLOBALS['config']['settings']['upload'];
        if(isset($sysOption['chunkSize'])){ //没有设置则使用默认;
            $upload['chunkSize']  = floatval($sysOption['chunkSize']);
            $upload['ignoreName'] = trim($sysOption['ignoreName']);
            $upload['chunkRetry'] = intval($sysOption['chunkRetry']);
            /////////////////////////修改这里
             $upload['httpSendFile']  = $sysOption['httpSendFile'] == '1'; //前端默认屏蔽;
             $upload['httpSendFileMap']  = $sysOption['httpSendFileMap']; //前端默认屏蔽;
             /////////////////////////

            // 上传限制扩展名,限制单文件大小;
            $role = Action('user.authRole')->userRoleAuth();
            if($role && $role['info']){
                $roleInfo = $role['info'];
                // if(isset($roleInfo['ignoreExt'])){
                //  $upload['ignoreExt']  = $roleInfo['ignoreExt'];
                // }

美化代码

 //>> 载入文件
        $code = file_get_contents($fileName);
        //>> 创建解析器
        $parser = (new ParserFactory())->create(ParserFactory::PREFER_PHP7);

        //>>节点
        $traverser = new NodeTraverser();

        try {
            $start = microtime(true);
            echo $fileName . "开始解析".PHP_EOL;
            //>>
            // 解析代码
            $ast = $parser->parse($code);
            echo $fileName . "解析完成".PHP_EOL;
            //>> 获取节点
            $satrt_ast = $traverser->traverse($ast);
            echo $fileName . "节点获取完成".PHP_EOL;

            $contentCode = (new PhpParser\PrettyPrinter\Standard())->prettyPrint($satrt_ast);
            echo $fileName . "代码美化完成".PHP_EOL;
            $contentCode = "<?php" . "\n" . $contentCode;
            $this->writeFile( $fileName, $contentCode);
            echo $fileName . "格式化成功 耗时:".(microtime(true) - $start).PHP_EOL;

        } catch (Error $error) {
            echo "Parse error: {$error->getMessage()}\n";
            return;
        }

修改位置2:\PathDriverBase::fileOut


        $softWare = strtolower($_SERVER["SERVER_SOFTWARE"]);
        if ($driveType && $softWare && $httpSendFile) {
            ////////////////////////////////// 增加我这个代码 具体变量名我自己定义的 其他自行处理
            $filePathMap = $filePath;
            $httpSpeedFileMap = $GLOBALS["config"]["settings"]["upload"]["httpSendFileMap"];
            $arr = explode(';', $httpSpeedFileMap);
            foreach ($arr as $item){
                $itemArr = explode(':', $item);
                //>> 获取服务器配置的路径映射
                $filePathMap = str_replace($itemArr[0], $itemArr[1], $filePathMap);
            }
            //////////////////////////////////

            if (strstr($softWare, "nginx")) {
                //down-resource
                header("X-Accel-Redirect: " . $filePathMap);
            } else {
                if (strstr($softWare, "apache")) {
                    header("X-Sendfile: " . $filePathMap);
                } else {
                    if (strstr($softWare, "http")) {
                        header("X-LIGHTTPD-send-file: " . $filePathMap);
                    }
                }
            }
            if ($

给TA打赏
共{{data.count}}人
人已打赏
Linux技术技巧

unraid docker中安装思源笔记方法

2021-10-18 18:15:30

Linux技术技巧

unraid 中的Docker qBittorrent下载视频后的 Sonarr Radarr文件硬链接方案

2021-12-14 15:54:39

0 条回复A文章作者M管理员
    暂无讨论,说说你的看法吧
个人中心
购物车
优惠劵
今日签到
有新私信 私信列表
搜索

Warning: error_log(/www/wwwroot/blog.52nyg.com/wp-content/plugins/spider-analyser/#log/log-0316.txt): failed to open stream: No such file or directory in /www/wwwroot/blog.52nyg.com/wp-content/plugins/spider-analyser/spider.class.php on line 2900