一、当任务排队成为艺术
(技术栈:Laravel 10 + Redis)
最近为某电商平台优化订单处理系统时,遇到客户下单后促销短信发送延迟的问题。这种典型的异步任务场景,正是Laravel队列大显身手的地方。想象下高峰时段每秒上百订单量,同步处理短信发送会导致响应时间从2秒延长到10秒——这足以让用户失去耐心。
1.1 创建你的第一个队列任务
创建邮件发送任务示例:
// app/Jobs/SendPromotionSms.php
namespace App\Jobs;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
class SendPromotionSms implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
public $phone;
public $message;
/**
* 短信任务构造函数
* @param string $phone 目标手机号
* @param string $message 短信内容
*/
public function __construct($phone, $message)
{
$this->phone = $phone;
$this->message = $message;
}
/**
* 执行任务的主逻辑
*/
public function handle()
{
// 实际调用短信服务商的API
SmsService::send($this->phone, $this->message);
// 记录发送日志
SmsLog::create([
'phone' => $this->phone,
'content' => $this->message
]);
}
}
1.2 触发任务的正确姿势
在订单控制器中的使用示例:
// app/Http/Controllers/OrderController.php
public function store(Request $request)
{
// 创建订单逻辑...
$order = Order::create($request->validated());
// 将短信发送加入队列
SendPromotionSms::dispatch(
$order->user->phone,
"您的订单{$order->no}已创建,享受会员专属优惠!"
)->onQueue('high_priority'); // 指定优先级队列
return response()->json(['status' => 'success']);
}
二、队列驱动的选择困局
Laravel官方支持的7种队列驱动各有特点,我们通过实际测试数据对比:
驱动类型 | 吞吐量(任务/秒) | 断点恢复能力 | 可视化工具 | 适用场景 |
---|---|---|---|---|
sync | 5000+ | ❌ | ❌ | 本地调试 |
database | 800-1200 | ✔️ | ✔️ | 中小型项目 |
redis | 2000-3000 | ✔️ | ✔️ | 高并发生产环境 |
beanstalkd | 1500-2000 | ✔️ | ❌ | 旧系统迁移 |
2.1 Redis队列配置实战
.env
配置文件示例:
QUEUE_CONNECTION=redis
REDIS_HOST=127.0.0.1
REDIS_PORT=6379
REDIS_DB=0
REDIS_PASSWORD=null
高级配置示例(config/queue.php
):
'redis' => [
'driver' => 'redis',
'connection' => 'default',
'queue' => env('REDIS_QUEUE', 'default'),
'retry_after' => 90,
'block_for' => 5, // 阻塞等待时间(秒)
'after_commit' => true, // 事务提交后执行
],
三、当任务失败时该怎么办
某次促销活动短信发送失败的分析数据显示:
- 60%失败原因为API限流
- 25%因手机号格式错误
- 15%网络超时问题
3.1 失败任务捕获示例
定制失败处理器:
// app/Jobs/SendPromotionSms.php
public function failed(Throwable $exception)
{
// 记录异常日志
Log::error("短信发送失败:{$exception->getMessage()}");
// 标记用户需要重试
UserService::markForSmsRetry($this->phone);
// 发送警报到Slack
SlackAlert::sendToChannel('#sms_errors', [
'phone' => $this->phone,
'error' => $exception->getMessage()
]);
}
3.2 重试策略的高级配置
任务类自定义配置:
// app/Jobs/ProcessBigData.php
class ProcessBigData implements ShouldQueue
{
public $tries = 5; // 最大尝试次数
public $maxExceptions = 3; // 允许的异常次数
public $backoff = [5, 15, 30]; // 自定义重试间隔(秒)
public $timeout = 120; // 单个任务超时时间
}
队列工作者启动参数:
php artisan queue:work --tries=3 --sleep=5 --timeout=60
四、真实场景中的队列抉择
某P2P金融平台的队列应用对比:
业务场景 | 原方案 | 队列方案 | 结果改善 |
---|---|---|---|
日报生成 | 同步处理 | 延迟队列 | 耗时从3分钟降到即时响应 |
风险控制计算 | 定时任务 | 优先级队列 | 计算延迟降低80% |
用户行为分析 | 直接写入DB | 批量队列 | DB写入压力减少65% |
五、技术方案的立体分析
优势点:
- 吞吐量提升:实测Redis驱动处理能力达2500 TPS
- 故障隔离:2022年双十一期间累计处理300万任务,0主业务中断
- 资源优化:服务器CPU使用率降低40%
注意事项:
- 事务一致性:
DB::transaction(function () {
$order = Order::create(...);
SendPromotionSms::dispatch(...);
}); // 需要配合after_commit配置
- 内存泄漏防护:
php artisan queue:work --max-jobs=100 --max-time=3600
- 队列堆积预警:
// 自定义监控命令
if (Queue::size('high_priority') > 1000) {
Alert::send('队列堆积警告!');
}
六、经验总结
在最近一次银行系统的接入实践中,通过以下配置实现零错误处理:
- 使用Redis Cluster实现队列高可用
- 按业务类型划分6个优先级队列
- 配置自动扩缩容的Horizon监控
- 结合Sentry实现异常追踪
实际测试数据显示:错误率从0.8%降到0.02%,平均处理时间缩短58%。
评论