ThinkPHP项目慢请求分析与优化

wen PHP项目 3

本文目录导读:

ThinkPHP项目慢请求分析与优化

  1. 问题诊断方法
  2. 常见性能瓶颈及优化
  3. 框架配置优化
  4. 服务器层面优化
  5. 性能监控方案
  6. 常见问题快速解决方案

我来系统地分析ThinkPHP项目慢请求的问题和优化方案。

问题诊断方法

开启调试模式分析

// .env 或 config/app.php
'debug' => true,
'trace' => [
    'type' => 'html',  // 或 'console'
],

使用性能分析工具

// 在控制器中添加性能分析
public function index()
{
    // 开始计时
    $startTime = microtime(true);
    $startMemory = memory_get_usage();
    // 业务代码...
    // 结束分析
    $endTime = microtime(true);
    $endMemory = memory_get_usage();
    trace('执行时间:' . ($endTime - $startTime) . '秒');
    trace('内存使用:' . ($endMemory - $startMemory) . '字节');
    return view();
}

日志分析

// config/log.php
return [
    'type' => 'File',
    'path' => '../runtime/log/',
    'level' => ['error', 'warning', 'sql', 'info'],
    'json' => false,
];

常见性能瓶颈及优化

数据库查询优化

问题示例

// 低效查询
$users = Db::name('users')->select();  // 全表查询
foreach($users as $user) {
    $orders = Db::name('orders')->where('user_id', $user['id'])->select(); // N+1问题
}
// 优化方案
$users = Db::name('users')->select();
$userIds = array_column($users, 'id');
$orders = Db::name('orders')->whereIn('user_id', $userIds)->select();
$orderMap = [];
foreach($orders as $order) {
    $orderMap[$order['user_id']][] = $order;
}

优化建议

// 1. 使用查询构造器优化
Db::name('users')
    ->field('id, name, email')  // 只查需要的字段
    ->where('status', 1)
    ->limit(20)
    ->select();
// 2. 使用模型关联预加载
User::with(['orders' => function($query) {
    $query->where('status', 1);
}])->select();
// 3. 使用原生SQL复杂查询
$result = Db::query("SELECT id, COUNT(*) as count FROM orders GROUP BY user_id HAVING COUNT(*) > 10");

缓存优化

配置Redis缓存

// config/cache.php
return [
    'type' => 'Redis',
    'host' => '127.0.0.1',
    'port' => 6379,
    'password' => '',
    'select' => 0,
    'timeout' => 0,
    'expire' => 3600,
    'persistent' => false,
    'prefix' => 'think_',
];
// 使用缓存
use think\facade\Cache;
// 缓存首页数据
if (!Cache::has('home_data')) {
    $data = Db::name('articles')->select();
    Cache::set('home_data', $data, 3600);
}
$data = Cache::get('home_data');

缓存策略示例

class ArticleService
{
    public function getArticleList($page = 1)
    {
        $cacheKey = "article_list_{$page}";
        // 先从缓存读取
        $list = Cache::get($cacheKey);
        if (empty($list)) {
            // 缓存不存在,查询数据库
            $list = Article::with(['author', 'tags'])
                ->where('status', 1)
                ->order('create_time', 'desc')
                ->paginate(10);
            // 写入缓存
            Cache::set($cacheKey, $list, 600);
        }
        return $list;
    }
}

代码优化

优化循环处理

// 不推荐
$result = [];
foreach($list as $item) {
    $item['time'] = date('Y-m-d', strtotime($item['create_time']));
    $result[] = $item;
}
// 推荐:使用批量处理
$ids = array_column($list, 'id');
$allData = Db::name('data')->whereIn('id', $ids)->select();
$dataMap = array_column($allData, null, 'id');

减少冗余操作

// 避免重复查询
$product = Db::name('product')->find(1); // 第一次查询
// ... 业务逻辑
$product = Db::name('product')->find(1); // 第二次查询,应该用变量
// 正确做法
$product = Db::name('product')->find(1);
$productData = $product; // 使用变量复用

页面静态化

public function index()
{
    $html = Cache::get('page_home');
    if (empty($html)) {
        ob_start();
        // ... 渲染视图
        echo view('index/index')->getContent();
        $html = ob_get_clean();
        Cache::set('page_home', $html, 600);
    }
    return $html;
}

数据库配置优化

// config/database.php
return [
    'type' => 'mysql',
    'host' => '127.0.0.1',
    'database' => 'thinkphp',
    'username' => 'root',
    'password' => '',
    // 连接池配置
    'connectionPool' => [
        'enabled' => true,
        'max_connections' => 100,
        'min_connections' => 10,
        'wait_timeout' => 3,
    ],
    // 读写分离
    'read' => [
        'host' => ['127.0.0.1'],
    ],
    'write' => [
        'host' => ['127.0.0.1'],
    ],
];

框架配置优化

优化自动加载

// composer.json 优化
"autoload": {
    "psr-4": {
        "app\\": "app"
    },
    "classmap": [
        "app/common"
    ]
}
// 执行命令
composer dump-autoload -o

关闭不必要功能

// config/app.php
'environment' => 'product',  // 生产环境
'debug' => false,            // 关闭调试模式
'default_timezone' => 'Asia/Shanghai',
'error_reporting' => E_ALL & ~E_DEPRECATED & ~E_NOTICE,
// 关闭路由缓存(生产环境开启)
'route' => [
    'check_cache' => true,
],

服务器层面优化

PHP配置优化

; php.ini
memory_limit = 256M
max_execution_time = 30
opcache.enable = 1
opcache.memory_consumption = 128
opcache.interned_strings_buffer = 8
opcache.max_accelerated_files = 4000
realpath_cache_size = 4096K
realpath_cache_ttl = 600

Nginx配置优化

# nginx配置
worker_processes auto;
worker_connections 1024;
fastcgi_cache_path /var/cache/nginx levels=1:2 keys_zone=phpcache:100m inactive=60m;
server {
    location ~ \.php$ {
        fastcgi_pass unix:/var/run/php/php7.4-fpm.sock;
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        # 启用缓存
        fastcgi_cache phpcache;
        fastcgi_cache_valid 200 60m;
        fastcgi_cache_key $host$request_uri;
    }
}

MySQL优化

-- 优化查询
CREATE INDEX idx_user_id ON orders(user_id);
CREATE INDEX idx_create_time ON articles(create_time);
-- 分析查询
EXPLAIN SELECT * FROM orders WHERE user_id = 100;
-- 开启慢查询日志
SET GLOBAL slow_query_log = ON;
SET GLOBAL long_query_time = 2;

性能监控方案

自定义性能监控中间件

// app/middleware/PerformanceMonitor.php
class PerformanceMonitor
{
    public function handle($request, \Closure $next)
    {
        $start = microtime(true);
        $response = $next($request);
        $end = microtime(true);
        $cost = ($end - $start) * 1000; // ms
        // 记录慢请求
        if ($cost > 1000) {
            \think\facade\Log::warning('慢请求', [
                'url' => $request->url(),
                'cost' => $cost . 'ms',
                'ip' => $request->ip(),
                'time' => date('Y-m-d H:i:s')
            ]);
        }
        $response->header('X-Trace-Time', $cost);
        return $response;
    }
}

SQL性能监控

// 在数据库配置中启用
'query_log' => true,
// 或自定义监听
Db::listen(function ($sql, $time, $explain) {
    if ($time > 0.1) {
        Log::write("SQL耗时" . $time . "s: " . $sql, 'sql');
    }
});

常见问题快速解决方案

N+1查询问题

// 问题代码
$articles = Article::select();
foreach ($articles as $article) {
    $article->author; // 每次触发查询
}
// 优化代码
$articles = Article::with('author')->select();
foreach ($articles as $article) {
    $article->author; // 已预加载
}

大数据量处理

// 使用分块处理
Db::name('large_table')->chunk(100, function($records) {
    foreach ($records as $record) {
        // 处理记录
    }
});

图片/文件加载优化

// 使用懒加载
// 模板中
<img src="__STATIC__/img/loading.gif" data-src="__IMG__/{$img.src}" class="lazyload">
// 配合JS库实现懒加载

建议持续监控请求响应时间,建立性能基线,定期分析和优化,使用性能监控工具(如Xdebug、Blackfire.io)进行深度分析,找出瓶颈所在。

抱歉,评论功能暂时关闭!