Laravel 13 性能优化指南

性能优化是提升用户体验和降低服务器成本的关键。本文将介绍 Laravel 13 的各种性能优化技巧。

配置缓存

缓存配置

1
php artisan config:cache

缓存路由

1
php artisan route:cache

缓存视图

1
php artisan view:cache

缓存事件

1
php artisan event:cache

清除缓存

1
php artisan optimize:clear

数据库优化

查询优化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// 避免 N+1 查询
$posts = Post::with(['user', 'comments'])->get();

// 选择需要的字段
$users = User::select(['id', 'name', 'email'])->get();

// 使用 chunk 处理大数据
User::chunk(1000, function ($users) {
foreach ($users as $user) {
// 处理用户
}
});

// 使用 cursor 节省内存
foreach (User::cursor() as $user) {
// 处理用户
}

索引优化

1
2
3
4
5
6
7
8
// 迁移中添加索引
Schema::create('users', function (Blueprint $table) {
$table->id();
$table->string('email')->unique();
$table->string('name');
$table->index(['name', 'email']);
$table->index('created_at');
});

数据库连接池

1
2
3
4
5
6
7
8
9
10
// config/database.php
'connections' => [
'mysql' => [
'driver' => 'mysql',
'pool' => [
'max_connections' => 100,
'min_connections' => 10,
],
],
],

缓存策略

缓存查询结果

1
2
3
4
5
6
7
8
9
10
11
12
use Illuminate\Support\Facades\Cache;

$users = Cache::remember('users.active', 3600, function () {
return User::where('active', true)->get();
});

$stats = Cache::rememberForever('site.stats', function () {
return [
'users' => User::count(),
'posts' => Post::count(),
];
});

标签缓存

1
2
3
Cache::tags(['users', 'posts'])->put('dashboard', $data, 3600);

Cache::tags(['users'])->flush();

原子锁

1
2
3
4
5
6
7
8
9
10
11
use Illuminate\Support\Facades\Cache;

$lock = Cache::lock('process-order', 10);

if ($lock->get()) {
try {
// 处理订单
} finally {
$lock->release();
}
}

队列优化

异步处理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
use App\Jobs\ProcessPodcast;
use App\Jobs\SendNotification;

// 分发到队列
ProcessPodcast::dispatch($podcast);

// 链式队列
Bus::chain([
new ProcessPodcast($podcast),
new SendNotification($user),
])->dispatch();

// 批量处理
Bus::batch([
new ProcessFile(1),
new ProcessFile(2),
new ProcessFile(3),
])->dispatch();

队列配置

1
2
3
4
5
6
7
8
9
10
// config/queue.php
'connections' => [
'redis' => [
'driver' => 'redis',
'connection' => 'default',
'queue' => env('REDIS_QUEUE', 'default'),
'retry_after' => 90,
'block_for' => 5,
],
],

Eloquent 优化

延迟加载 vs 预加载

1
2
3
4
5
6
7
8
9
10
11
// N+1 问题
$posts = Post::all();
foreach ($posts as $post) {
echo $post->user->name; // 每次都查询
}

// 预加载解决
$posts = Post::with('user')->get();
foreach ($posts as $post) {
echo $post->user->name; // 不额外查询
}

嵌套预加载

1
2
3
4
5
$posts = Post::with(['user', 'comments.user'])->get();

$posts = Post::with(['user' => function ($query) {
$query->select('id', 'name');
}])->get();

避免不必要的查询

1
2
3
4
5
6
7
8
9
// 使用 exists 而不是 count
if ($user->posts()->exists()) {
// 用户有文章
}

// 使用 whereHas
$users = User::whereHas('posts', function ($query) {
$query->where('published', true);
})->get();

视图优化

视图缓存

1
php artisan view:cache

组件缓存

1
2
3
4
5
6
7
8
9
10
11
12
13
use Illuminate\Support\Facades\Cache;

class RecentPostsComponent extends Component
{
public function render()
{
$posts = Cache::remember('recent.posts', 3600, function () {
return Post::latest()->take(5)->get();
});

return view('components.recent-posts', compact('posts'));
}
}

资源优化

资源打包

1
npm run build

资源预加载

1
2
<link rel="preload" href="{{ asset('css/app.css') }}" as="style">
<link rel="preload" href="{{ asset('js/app.js') }}" as="script">

图片优化

1
2
3
4
5
6
7
8
use Intervention\Image\Facades\Image;

$image = Image::make($file)
->resize(800, null, function ($constraint) {
$constraint->aspectRatio();
$constraint->upsize();
})
->encode('webp', 80);

OPcache 优化

PHP 配置

1
2
3
4
5
6
7
; php.ini
opcache.enable=1
opcache.memory_consumption=256
opcache.interned_strings_buffer=16
opcache.max_accelerated_files=10000
opcache.validate_timestamps=0
opcache.revalidate_freq=0

预加载

1
2
3
4
5
6
7
8
9
10
11
// config/preload.php
<?php

return [
'enabled' => true,
'classes' => [
App\Models\User::class,
App\Models\Post::class,
App\Services\UserService::class,
],
];

Redis 优化

配置 Redis

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// config/database.php
'redis' => [
'default' => [
'url' => env('REDIS_URL'),
'host' => env('REDIS_HOST', '127.0.0.1'),
'password' => env('REDIS_PASSWORD'),
'port' => env('REDIS_PORT', '6379'),
'database' => env('REDIS_DB', '0'),
'options' => [
'persistent' => true,
'read_timeout' => 60,
],
],
],

使用 Pipeline

1
2
3
4
5
6
7
use Illuminate\Support\Facades\Redis;

Redis::pipeline(function ($pipe) {
for ($i = 0; $i < 1000; $i++) {
$pipe->set("key:{$i}", $i);
}
});

日志优化

条件日志

1
2
3
4
5
6
if (app()->environment('local')) {
Log::debug('Debug information', $data);
}

// 使用懒加载
Log::debug('User data', ['user' => fn() => $user->toArray()]);

日志级别

1
2
// 生产环境使用更高的日志级别
'level' => env('LOG_LEVEL', app()->environment('production') ? 'error' : 'debug'),

内存优化

使用生成器

1
2
3
4
5
6
7
8
9
10
function getLargeDataset()
{
for ($i = 0; $i < 1000000; $i++) {
yield $i;
}
}

foreach (getLargeDataset() as $item) {
// 处理数据
}

懒惰集合

1
2
3
4
5
6
7
8
9
10
11
use Illuminate\Support\LazyCollection;

LazyCollection::make(function () {
$handle = fopen('large-file.csv', 'r');
while ($line = fgets($handle)) {
yield str_getcsv($line);
}
fclose($handle);
})->chunk(1000)->each(function ($chunk) {
// 处理数据块
});

监控和分析

性能分析

1
2
3
4
5
6
7
8
9
10
11
use Illuminate\Support\Facades\DB;

DB::listen(function ($query) {
if ($query->time > 100) {
Log::warning('Slow query', [
'sql' => $query->sql,
'bindings' => $query->bindings,
'time' => $query->time,
]);
}
});

调试栏

1
composer require barryvdh/laravel-debugbar --dev

Telescope

1
2
3
composer require laravel/telescope --dev
php artisan telescope:install
php artisan migrate

生产环境优化清单

部署前优化

1
2
3
4
5
6
7
8
9
10
11
# 安装依赖
composer install --no-dev --optimize-autoloader

# 缓存配置
php artisan config:cache
php artisan route:cache
php artisan view:cache
php artisan event:cache

# 优化自动加载
composer dump-autoload --optimize

环境配置

1
2
3
4
5
6
7
8
9
10
11
APP_ENV=production
APP_DEBUG=false
APP_KEY=your-key

# 使用更快的缓存驱动
CACHE_DRIVER=redis
QUEUE_CONNECTION=redis
SESSION_DRIVER=redis

# 数据库连接池
DB_POOL_SIZE=10

性能测试

基准测试

1
2
3
4
5
6
use Illuminate\Support\Benchmark;

Benchmark::dd([
'Scenario 1' => fn () => User::with('posts')->get(),
'Scenario 2' => fn () => User::join('posts', 'users.id', '=', 'posts.user_id')->get(),
]);

负载测试

1
2
3
4
5
# 使用 Apache Bench
ab -n 1000 -c 10 http://localhost/api/users

# 使用 Siege
siege -c 10 -t 1M http://localhost/api/users

总结

Laravel 13 性能优化涉及多个方面,包括配置缓存、数据库优化、缓存策略、队列处理等。通过合理使用这些优化技巧,可以显著提升应用程序的性能。记住在生产环境中关闭调试模式、启用配置缓存、使用高效的缓存驱动,并持续监控应用程序的性能指标。性能优化是一个持续的过程,需要根据实际负载情况进行调整和改进。