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

浏览:1458次阅读
没有评论

使用场景

使用 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 ($
正文完
 0
包子
版权声明:本站原创文章,由 包子 于2021-11-17发表,共计3993字。
转载说明:除特殊说明外本站文章皆由CC-4.0协议发布,转载请注明出处。
评论(没有评论)