---一、核心障碍清单 ┌────────────────┬─────────────────────────┬──────────┐ │ 障碍 │ 原因 │ 严重程度 │ ├────────────────┼─────────────────────────┼──────────┤ │ 文件系统依赖 │ Lambda 无持久化本地磁盘 │ 🔴 高 │ ├────────────────┼─────────────────────────┼──────────┤ │ 数据库连接耗尽 │ 每次调用创建新连接 │ 🔴 高 │ ├────────────────┼─────────────────────────┼──────────┤ │ Session 失效 │ 文件型 Session 不跨实例 │ 🔴 高 │ ├────────────────┼─────────────────────────┼──────────┤ │ 长任务超时 │ Lambda 最长15分钟 │ 🟡 中 │ ├────────────────┼─────────────────────────┼──────────┤ │ Cron 任务 │ 无系统级 crontab │ 🟡 中 │ ├────────────────┼─────────────────────────┼──────────┤ │ 冷启动延迟 │ PHP 冷启动2-4s │ 🟡 中 │ ├────────────────┼─────────────────────────┼──────────┤ │ WebSocket │ 无持久连接 │ 🟡 中 │ └────────────────┴─────────────────────────┴──────────┘---二、迁移路线图(渐进式,非大爆炸) 推荐顺序:从最容易到最难 第1步 Cron 定时任务 ── 最简单,改动最小 第2步 后台队列/异步任务 ── SQS 替换 第3步 文件上传 ── 迁到 S3 第4步 Session ── 迁到 Redis/DynamoDB 第5步 只读 API ── 无状态,轻松迁移 第6步 写入 API ── 需 RDS Proxy 第7步 Web 页面路由 ── 最后处理(依赖上面全部) 绞杀者模式(Strangler Fig)— 生产安全 用户请求 ↓ ALB/API Gateway ↓ 路由规则:/api/v2/* → Lambda(新) /* → 原有服务器(旧) 新旧并行,逐步切流,可随时回滚。 --- 三、各障碍具体解决方案 1. 本地文件系统 // ❌ 旧写法 move_uploaded_file($tmpFile, '/var/www/uploads/' . $filename); file_put_contents('/var/log/app.log', $message); // ✅ 新写法 — 上传走 S3 Storage::disk('s3')->put('uploads/' . $filename, $content); // ✅ 临时文件用 /tmp(不跨调用,单次可用) $tmpPath = '/tmp/' . uniqid() . '.jpg'; // 处理完立即上传 S3,然后删除 unlink($tmpPath); // ✅ 日志走 CloudWatch(直接 error_log 即可) error_log(json_encode(['level' => 'info', 'msg' => $message])); 预签名 URL(推荐)— 让浏览器直传 S3,Lambda 不经手文件流: $url = Storage::disk('s3')->temporaryUploadUrl( 'uploads/' . $filename, now()->addMinutes(10) ); // 返回给前端,前端直接 PUT 到 S3 return response()->json(['upload_url' => $url]); --- 2. 数据库连接耗尽 问题:100 个并发 Lambda = 100 个新 DB 连接 → 超出 RDS 上限 三层防护: // 层1: 连接复用(Lambda 热启动时重用连接) // bootstrap/app.php 或 config/database.php 外部静态连接 // 层2: config/database.php — 减小连接池 'mysql' => [ 'options' => [ PDO::ATTR_PERSISTENT => true, // 持久连接 ], 'pool' => [ 'min' => 1, 'max' => 5, // 单 Lambda 实例最多 5 连接 ], ], // 层3: 连接目标改为 RDS Proxy DB_HOST=my-proxy.proxy-xxx.us-east-1.rds.amazonaws.com vapor.yml 开启 RDS Proxy: # vapor.yml environments: production: database: my-rds-instance database-proxy: true # 一行搞定 --- 3. Session 迁移 // ❌ 旧:文件型 Session(跨实例失效) SESSION_DRIVER=file // ✅ 新:Redis SESSION_DRIVER=redis REDIS_HOST=my-elasticache.xxx.cache.amazonaws.com // ✅ 更好:数据库型(无需额外基础设施) SESSION_DRIVER=database php artisan session:table && php artisan migrate // ✅ 最佳(API):无状态 JWT,彻底消灭 Session // 用 laravel/sanctum token 替代 session --- 4. 定时任务(Cron) // ❌ 旧:服务器 crontab // * * * * * php /var/www/artisan schedule:run // ✅ 新:EventBridge + Lambda vapor.yml 配置: environments: production: scheduler: true # Vapor 自动创建 EventBridge 规则 每分钟触发 Laravel 调度器,App\Console\Kernel 正常写: // app/Console/Kernel.php — 无需改动 protected function schedule(Schedule $schedule) { $schedule->command('reports:daily')->dailyAt('08:00'); $schedule->command('cache:clear')->hourly(); } --- 5. 后台队列/异步任务 // ❌ 旧:本地 Redis + Horizon worker 常驻进程 // ✅ 新:SQS — Serverless 原生方案 QUEUE_CONNECTION=sqs SQS_PREFIX=https://sqs.us-east-1.amazonaws.com/xxx SQS_QUEUE=default // 代码无需改动,dispatch() 照常用 ProcessOrder::dispatch($order)->onQueue('orders'); vapor.yml 配置队列 worker: environments: production: queues: - orders # SQS 队列名 - emails --- 6. 长任务(超过 15 分钟) 选项A:拆分成链式小任务(Step Functions 编排) 选项B:SQS 分批处理(每批 < 14 分钟) 选项C:ECS Fargate 处理真正的长任务 // 批处理模式:每次处理一小块,完成后重新入队 class ProcessLargeExport implements ShouldQueue { public function handle() { $batch = Item::where('status', 'pending') ->limit(500) // 每次 500 条 ->get(); // 处理这 500 条... if (Item::where('status', 'pending')->exists()) { // 还有数据,重新入队 ProcessLargeExport::dispatch(); } } } --- 7. 冷启动优化 # 预编译路由和配置 php artisan config:cache php artisan route:cache php artisan view:cache php artisan event:cache // composer.json — 排除开发依赖,减小包体积 { "scripts": { "vapor:deploy": "composer install --no-dev --optimize-autoloader" } } # vapor.yml — 配置 Provisioned Concurrency(预热实例,消灭冷启动) environments: production: concurrency: 5 # 常驻 5 个热实例 --- 四、Bref vs Laravel Vapor 选择 ┌──────────────┬───────────────────────┬───────────────────────┐ │ │ Bref │ Laravel Vapor │ ├──────────────┼───────────────────────┼───────────────────────┤ │ 适用框架 │ 任意 PHP │ 仅 Laravel │ ├──────────────┼───────────────────────┼───────────────────────┤ │ 费用 │ 仅 AWS 费用 │ $12-50/月 + AWS │ ├──────────────┼───────────────────────┼───────────────────────┤ │ 配置复杂度 │ 较高(YAML 手写) │ 低(Dashboard 操作) │ ├──────────────┼───────────────────────┼───────────────────────┤ │ 自定义灵活性 │ 最高 │ 中等 │ ├──────────────┼───────────────────────┼───────────────────────┤ │ 内置队列支持 │ 手动配 SQS │ 一键开启 │ ├──────────────┼───────────────────────┼───────────────────────┤ │ 适合场景 │ 多框架混合 / 重度定制 │ 纯 Laravel / 快速上线 │ └──────────────┴───────────────────────┴───────────────────────┘ --- 五、本地测试 Serverless 环境 # 方案1:Laravel Sail + LocalStack(最简单) docker run -d -p 4566:4566 \ -e SERVICES=s3,sqs,dynamodb \ localstack/localstack # .env.local AWS_ENDPOINT=http://localhost:4566 AWS_ACCESS_KEY_ID=test AWS_SECRET_ACCESS_KEY=test # 方案2:Bref 本地运行 ./vendor/bin/bref local # 方案3:SAM CLI 完整模拟 sam local start-api --docker-network host --- 六、迁移前检查清单 改造前 □ 梳理所有文件读写点 □ 统计 DB 最大并发连接数 □ 列出所有 cron 任务 □ 确认第三方库的 Lambda 兼容性 □ 评估估算 AWS 成本 改造中 □ 开启 RDS Proxy □ Session 切换到 Redis/DB □ 上传迁移到 S3 □ Cron 迁移到 EventBridge □ 队列迁移到 SQS □ 用 Strangler Fig 灰度上线 改造后 □ CloudWatch 告警配置 □ Sentry 错误监控接入 □ 冷启动时间监控 □ 数据库连接数监控 □ 成本趋势追踪 --- 核心原则:改造不是重写,是逐步替换基础设施依赖。从无状态的边缘任务(cron、队列)开始,最后才动核心 Web 路由,每步可独立验证、回滚。php方案 传统php应用serverless改造
张小明
前端开发工程师
微信聊天记录导出指南:如何安全备份你的数字记忆
微信聊天记录导出指南:如何安全备份你的数字记忆 【免费下载链接】WeChatExporter 一个可以快速导出、查看你的微信聊天记录的工具 项目地址: https://gitcode.com/gh_mirrors/wec/WeChatExporter 在数字时代,微信聊天记录承载着我们的工作沟通、…
如何将小爱音箱打造成智能音乐中心:Xiaomusic完全指南
如何将小爱音箱打造成智能音乐中心:Xiaomusic完全指南 【免费下载链接】xiaomusic 使用小爱音箱播放音乐,音乐使用 yt-dlp 下载。 项目地址: https://gitcode.com/GitHub_Trending/xia/xiaomusic Xiaomusic是一款开源工具,能够将普通的…
Matplotlib中文字体缺失终极指南:从安装到配置的完整解决方案
1. 为什么Matplotlib会找不到中文字体? 很多朋友第一次用Matplotlib画中文图表时,都会遇到那个经典的方框乱码问题。这其实是因为Matplotlib默认使用的字体库不包含中文字符集。就像你电脑里没有安装中文输入法就打不出汉字一样,Matplotlib也…
5个来自谷歌的Agent Skill设计模式
随着 OpenClaw 深度融入我们这家小型 AI Native 创业公司的业务,我们正持续高强度地自研与调试面向自身及客户的技能(Skill)。在不断落地业务、吃透底层技术原理的过程中,我们发现了一个造成大量 Token 浪费的核心症结:…
终极Joplin大纲插件使用指南:5分钟掌握高效笔记导航技巧
终极Joplin大纲插件使用指南:5分钟掌握高效笔记导航技巧 【免费下载链接】joplin-outline A markdown outline (TOC) sidebar plugin for Joplin. 项目地址: https://gitcode.com/gh_mirrors/jo/joplin-outline 你是否经常在Joplin中编写长篇笔记时迷失方向&…
别再傻傻分不清!嵌入式工程师选型指南:从MCU到SoC,5分钟搞懂你的项目该用啥芯片
嵌入式芯片选型实战:从智能家居到工业控制的核心决策逻辑 当你面对琳琅满目的芯片型号时,是否常陷入"选择困难症"?ST的Cortex-M系列、NXP的i.MX系列、TI的C2000 DSP...每个厂商都在强调自家产品的优势,但真正决定项目成…