我把夜间 cron 迁到 FunctionGraph

举报
yd_292017662 发表于 2026/11/04 11:11:44 2026/11/04
【摘要】 我把一台长期跑 cron 的 ECS 下线,改成 FunctionGraph 定时触发 Python 任务。迁移过程踩到三个坑:执行超时、OBS 代码包权限不足、VPC 连 RDS 超时。文里记录了真实日志、配置片段、工时和费用对比,也写了当前还没处理完的幂等问题。

9月我值夜班时,账务同步任务又漏跑一次,偏偏这任务要给内部报表补齐前一小时订单,晚了就只能手工补。任务原来挂在华为云 ECS,机型 s6.large.2,2 vCPU 4 GiB,Ubuntu 22.04.4 LTS,系统盘 40 GiB ESSD,1M 公网带宽。crontab 里是每 5 分钟跑一次 Python 脚本,Python 3.10.12,单次执行平时 1.2 到 2.1 秒。我之前一直觉得这台机子还能顺带跑两个小脚本,钱花得过去,直到它 00:11 重启后 cron 没把新路径吃进去。

那天晚上我盯日志到 01:40。

老机器上的 cron 现状

我按现场还原顺序查了 crontab、systemd、部署脚本和目录权限。漏跑不是业务代码抛异常,是部署脚本把目录从 /opt/job 挪到 /srv/job,cron 仍然指着老路径。syslog 连续刷错 37 分钟,告警里一共漏了 7 个时间片。值班群里每 5 分钟就跳一条失败告警,消息时间是 00:58、01:03、01:08 这种整点节奏,看着就知道是调度层问题,不是 SQL 抖动。

$ crontab -l
*/5 * * * * /usr/bin/python3 /opt/job/sync_bill.py >> /var/log/sync_bill.log 2>&1

$ systemctl status cron -n 8
Active: active (running) since Thu 2024-09-12 00:11:03 CST
Sep 12 00:58:01 ip-172-16-2-19 CRON[28411]: (root) CMD (/usr/bin/python3 /opt/job/sync_bill.py >> /var/log/sync_bill.log 2>&1)
/usr/bin/python3: can't open file '/opt/job/sync_bill.py': [Errno 2] No such file or directory
Sep 12 01:03:01 ip-172-16-2-19 CRON[28974]: (root) CMD (/usr/bin/python3 /opt/job/sync_bill.py >> /var/log/sync_bill.log 2>&1)

我当晚做过一次失败补救,想偷懒用软链接兜住路径变更,命令是 ln -s /srv/job /opt/job。手工跑了两次都过,日志里有 sync done, affected_rows=213, cost_ms=1642 和 affected_rows=206, cost_ms=1518,我当时以为完事了。结果 00:30 自动部署又把 /opt/job 先 rm -rf 再重建空目录,链接被删,cron 到 01:05 又报同一个错。

# deploy.sh 里的片段
rm -rf /opt/job
mkdir -p /opt/job
chown root:root /opt/job
# 真实代码已经改到 /srv/job,下面这步复制在夜间包里漏了
# cp -r /srv/job/* /opt/job/

我也试过直接把 crontab 改成 /srv/job 路径,这一步是 01:12 做的,命令是 crontab -e,改完执行 service cron reload。第一次触发又挂了,报错换成 ModuleNotFoundError: No module named 'psycopg2'。原因很土,交接同事把依赖装在 /opt/job/.venv,我把脚本搬走后没同步虚拟环境,cron 又不会读我当前 shell 的 PATH。我补了 /srv/job/.venv/bin/python 才跑起来,但这台机子已经被我改得到处是补丁,回头看继续修也不稳。

我翻了近 3 个月账单,8 月这台 ECS 165.08 元,计算 132.48 元,系统盘 9.60 元,带宽 23.00 元。按 288 次/天算,任务本身每天 CPU 时间约 288×1.7 秒,只有 489.6 秒,也就是 8.16 分钟。Cloud Eye 里这台机子 24 小时 CPU 均值 2.4%,绝大多数时间在空转。

迁到 FunctionGraph 后的排查和账单

这个方案我一开始是拒绝的。

我担心函数连不上内网 RDS,也担心冷启动把 5 分钟窗口挤爆,但夜里再漏一次单就要补两百多条数据,我还是动手迁了。运行时用 FunctionGraph Python3.9,初始配置是内存 512 MB、超时 10 秒、实例并发 1、预留并发 1,触发器 cron 写成 0 */5 * * * ?。依赖只有 requests 2.31.0 和 psycopg2-binary 2.9.9,打包后 zip 14.7 MB,上传到 OBS 桶 ops-artifact,再从 OBS 发版。迁移总工时 3 小时 20 分钟,我自己干了 2 小时 40 分钟,同事帮我看网络策略 40 分钟,真正改业务代码不到 30 分钟。

python3.9 -m venv .venv
source .venv/bin/activate
pip==24.2
pip install -r requirements.txt -t build
cp handler.py build/
cd build && zip -r ../sync-bill-fg-20240912.zip .
./obsutil cp ../sync-bill-fg-20240912.zip obs://ops-artifact/functions/

第一版上线后直接超时,日志里同一批 request_id 连着报 Runtime exited with error: signal: killed 和 Task timed out after 10.00 seconds。我去 LTS 拉了 12 次调用,冷启动 11.2、10.8、11.5 秒,热启动 2 秒左右。我先只把超时从 10 秒提到 20 秒,这个尝试失败了,20 次里还有 3 次被系统杀进程。后面我把内存从 512 MB 提到 768 MB,超时改到 30 秒,同时把数据库连接参数 connect_timeout 从 3 秒改成 5 秒,代码里还加了连接前打点,方便看卡在哪一步。改完又跑 50 次压测,冷启动落在 2.8 到 4.6 秒,热启动 1.1 到 1.9 秒,没再被 kill。

第二个坑是发版权限,控制台报 FG.0105,原文案是 agency has no permission to access OBS object。我沿用别的项目委托,只配了 obs:bucket:ListBucket,函数能看到桶,拿不到对象。补了 GetObject 和 BucketLocation 后才过,这里卡了 26 分钟。

Action:
  - obs:bucket:GetBucketLocation
  - obs:object:GetObject
Resource:
  - obs:*:*:bucket:ops-artifact
  - obs:*:*:object:ops-artifact/functions/*
Effect: Allow

第三个问题最耗时。函数能启动,连 RDS for PostgreSQL 13.12 一直超时,报错是 psycopg2.OperationalError: connection to server at 10.23.4.17, port 5432 failed: timeout expired。我先怀疑路由,查 VPC 路由表和 ACL 都正常,又在函数里临时加了 socket.create_connection(('10.23.4.17', 5432), 3),返回 timed out。卡点在安全组,RDS 入方向没有放行 sg-fg-sync。补一条 TCP 5432 入规则,源安全组设成 sg-fg-sync,下一次调用就成功返回 affected_rows=247, cost_ms=1386。这一步排查花了 1 小时 15 分钟,比打包和发版都久。

我跑了 30 天再看,统计窗口 2024-09-13 到 2024-10-12,触发 8652 次,重试 19 次,成功率 99.78%,p95 3.9 秒,p99 5.4 秒。费用按同窗口算,FunctionGraph 请求 0.91 元,计算 5.26 元,LTS 日志 3.17 元,合计 9.34 元。对比原来单独保 ECS,每月固定成本少 155 元左右,值班里漏跑补单告警从每月 3 到 4 次降到 0 次。

现在还没收干净的是幂等,上游接口返回 502 时函数会重试,偶发把同一批订单写两次。我现在靠 PostgreSQL 唯一键硬拦,业务层去重还没补,下周准备把请求流水号写进 DCS Redis 6.0,key 先按 bill_sync:{merchant_id}:{hour_slot}:{req_id} 组织,TTL 先设 7200 秒,观察一周再决定是否拉到 21600 秒。

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0)

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。