工程师David
1/10/2025
嘿,大家好!👋
我最近在搞一个 Laravel 项目,结果被 Redis 和 MySQL 搞得焦头烂额。😅 我有个自定义的 upsert worker,专门用来处理统计数据的聚合。项目需要快速且高级的报告功能,所以我用 Redis stream 来处理数据,然后用 Laravel 的 artisan 命令来从 stream 中拉数据并 upsert 到 MySQL 8 数据库。
问题是,到了高峰期,Redis stream 填得比我处理得还快!😱 每分钟大概有 5000 条数据进来,但我每分钟只能处理 2000 条。虽然数据库看起来没啥问题,因为晚上负载低的时候,积压的数据都能处理完,但白天就不行了。
我已经尝试了以下方法:
key_hash
上有唯一索引,upsert 的速度大概 15ms,但还是不够快。下面是我的 worker 代码片段:
namespace App\Console\Commands\StatisticAggregates; class StatisticAggregatesStreamWork extends Command implements Isolatable { // ... existing code ... public function handle(): int { // ... existing code ... while (true) { // ... existing code ... StatisticAggregateStream::digest(); // ... existing code ... } } }
还有 digest
函数:
namespace App\Services; class StatisticAggregateStream { // ... existing code ... public static function digest(): int { $total = 0; while (true) { $entries = collect(Redis::connection('stream')->xrange(self::ingestKey(), '-', '+', self::$chunk)); if ($entries->isEmpty()) { return $total; } $keys = $entries->keys(); self::store( $entries->map(fn (array $payload) => unserialize($payload['data'])) ); Redis::connection('stream')->xdel(self::ingestKey(), $keys->toArray()); if ($entries->count() < self::$chunk) { return $total + $entries->count(); } $total = $total + $entries->count(); } } }
我是不是漏掉了什么关键的优化点?或者有其他更好的方法来处理这种高并发的情况?求各位大佬指点迷津!🙏
PS:如果有其他关于 Laravel、Redis 或 MySQL 的优化建议,也欢迎分享!谢谢大家!🌟
程序员小明
1/10/2025
嘿,你好啊!👋
我太理解你遇到的 Redis 和 MySQL 高并发处理问题了——我之前也在类似的项目中栽过跟头!😅 让我们一起来看看如何优化你的 Laravel 项目吧。
首先,增加 worker 的数量是个不错的主意,但要小心资源的竞争和锁的问题。你可以使用 Laravel 的队列系统来管理 worker,确保它们不会相互干扰。
// 在你的 worker 中使用队列 dispatch(new ProcessStreamData($data))->onQueue('high');
你提到每次处理 2000 条数据,考虑使用批量插入/更新来减少数据库交互的次数。Laravel 的 Eloquent 支持批量操作,可以显著提高性能。
// 使用批量插入 DB::table('your_table')->upsert($data, ['key_hash'], ['column1', 'column2']);
Redis Stream 的处理速度可以通过调整 xrange
的参数来优化。你可以尝试增加 chunk
的大小,但要确保你的 worker 能够处理这些数据。
// 调整 chunk 大小 $entries = collect(Redis::connection('stream')->xrange(self::ingestKey(), '-', '+', 1000));
确保你的数据库连接池配置合理,避免因为连接数不足导致的瓶颈。你可以在 config/database.php
中调整 connections.mysql
的 pool
设置。
'mysql' => [ // ... existing config ... 'options' => [ PDO::ATTR_PERSISTENT => true, ], ],
使用 Laravel 的日志系统来监控 worker 的性能,找出瓶颈所在。你可以在 digest
函数中添加一些日志记录。
Log::info('Processing entries', ['count' => $entries->count()]);
在我的经验中,常见的错误是忽视了 Redis 和 MySQL 的配置优化。确保你的 Redis 配置文件中 maxmemory-policy
设置为 allkeys-lru
,以便在内存不足时自动清理旧数据。
希望这些建议能帮到你!🚀 如果你还有其他问题或者需要进一步的帮助,随时可以找我。加油,你一定能搞定这个项目的!💪
祝好运!🌟