Laravel集成AWS SES/SNS大规模邮件通知服务器负载过高优化咨询
解决SES+SNS批量邮件通知导致服务器资源耗尽的问题
针对你用Laravel+AWS SDK开发邮件营销系统时,一万条SEND/DELIVERY通知拉满服务器CPU和内存的问题,我给你几个实用的解决方案,从AWS配置到Laravel代码优化都有覆盖:
1. 开启SES的批量事件通知(最直接的减少通知数量方法)
AWS SES本身支持将多个相同类型的事件合并成一个SNS通知发送,不用再逐条推送。你可以通过配置集(Configuration Set)来开启这个功能,设置批量大小和等待间隔:
代码配置(用AWS SDK for PHP)
use Aws\Ses\SesClient; // 初始化SES客户端 $sesClient = new SesClient([ 'version' => 'latest', 'region' => '你的AWS区域', // 比如us-east-1 'credentials' => [ 'key' => env('AWS_ACCESS_KEY_ID'), 'secret' => env('AWS_SECRET_ACCESS_KEY'), ], ]); // 更新配置集的事件目标,开启批量通知 $sesClient->updateConfigurationSetEventDestination([ 'ConfigurationSetName' => '你的营销活动配置集名称', 'EventDestination' => [ 'Name' => 'SnsNotificationDestination', 'Enabled' => true, 'MatchingEventTypes' => ['send', 'delivery'], // 你需要监听的事件类型 'SnsDestination' => [ 'TopicARN' => '你的SNS主题ARN', ], 'BatchConfigurations' => [ 'BatchSize' => 100, // 每攒够100条事件就发送一个通知 'BatchInterval' => 300, // 最多等待5分钟(300秒),到点不管够不够都发送 ], ], ]);
这样原本一万条的通知会被合并成最多100个(按100条/批),直接把请求量降到原来的1%,服务器压力会大幅降低。
2. 用Laravel队列异步处理通知
即使开启了批量通知,短时间内的批量请求还是可能压垮服务器,这时候把通知处理逻辑放到队列里异步执行是必须的:
步骤1:创建队列任务
生成一个处理SES通知的任务类:
php artisan make:job ProcessSesBatchNotification
然后在任务类里处理批量事件:
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; use Aws\Sns\MessageValidator; class ProcessSesBatchNotification implements ShouldQueue { use Dispatchable, InteractsWithQueue, Queueable, SerializesModels; protected $snsPayload; public function __construct(array $snsPayload) { $this->snsPayload = $snsPayload; } public function handle() { // 先验证SNS消息的真实性,防止伪造请求 $validator = new MessageValidator(); $validator->validate($this->snsPayload); // 解析SNS消息内容 $messageContent = json_decode($this->snsPayload['Message'], true); // 如果是批量通知,Messages是事件数组;否则是单条事件 $events = isset($messageContent['Messages']) ? $messageContent['Messages'] : [$messageContent]; // 批量收集统计数据,减少数据库操作 $notificationRecords = []; foreach ($events as $event) { $parsedEvent = json_decode($event['Message'], true); $notificationRecords[] = [ 'message_id' => $parsedEvent['mail']['messageId'], 'event_type' => $parsedEvent['eventType'], 'timestamp' => $parsedEvent['timestamp'], 'created_at' => now(), 'updated_at' => now(), ]; } // 批量插入数据库,比逐条插入高效得多 if (!empty($notificationRecords)) { \App\Models\SesNotification::insert($notificationRecords); } } }
步骤2:配置SNS Webhook路由
在routes/api.php里添加接收SNS通知的路由,直接把请求丢到队列:
use App\Jobs\ProcessSesBatchNotification; use Illuminate\Http\Request; Route::post('/ses/sns/webhook', function (Request $request) { // 立即分发任务到队列,快速响应SNS,避免超时 ProcessSesBatchNotification::dispatch($request->all()); // 返回200给SNS,确认接收 return response()->json(['status' => 'received'], 200); });
3. 可选:用Lambda中转处理通知
如果你的服务器资源还是紧张,可以加一层AWS Lambda作为中转:
- 让SNS把批量通知推送给Lambda
- Lambda把所有事件整理后,一次性批量调用Laravel的API(或者直接写入数据库)
- Laravel只需要处理少量的批量请求,彻底避免高频请求的压力
这种方式适合超大规模的邮件活动,能进一步解耦通知接收和业务处理。
关键注意事项
- 一定要验证SNS消息:防止恶意请求伪造通知,上面的代码里已经包含了验证逻辑,不要省略。
- 优化队列配置:用Supervisor管理Laravel队列worker,设置合适的进程数(比如根据CPU核心数设置),避免队列堆积。
- 测试批量效果:先发送100条邮件测试,确认SNS确实会合并成一个通知,再跑大规模活动。
内容的提问来源于stack exchange,提问作者Ivan Vasilega
相关产品推荐
相关产品推荐

