网站上线流量归零?Ruby运维盲区在吃掉用户
|
跟老板拍桌子那天是周三,下午三点零七分,他咖啡杯沿沾着半圈奶泡,我手机还亮着 Lighthouse 跑分截图——发到 Ruby-ops 群里四小时没回,PM 在底下补了句“先上线再看”,我点了个????就撤了。这图现在还在相册最底下,文件名是 lighthouse_2026-01-08T150342.png,但谁他妈在乎时间戳? 首屏救火?救个屁。用户进来看不到按钮,不是因为 render 崩了,是因为 asset_host 写死了 dev-cdn.example.com,而 DNS 解析卡在 TTL 三小时,我们凌晨两点切的 prod 配置,三点上线,四点开始收 503,六点我才摸到那行 config/environments/production.rb 里藏得比 Rails 7.1 的 autoload_paths 还深的 url_options[:asset_host]。我原以为是 CDN 缓存没刷,结果是连 DNS 记录都压根没推——运维说“等自动同步”,我查了下那个 Ansible playbook 最后一次成功运行是去年十月十七号,脚本里写着 # FIXME: sync on deploy —— 他写的,他删的注释,他忘的。 三百七十二 KB 的 application.js 里塞了三个不同版本的 chart.js,一个从 vendor/assets 拉,一个用 esbuild 打,一个由 webpacker 加载——没人动过,但没人敢删。上周前端提了个 MR,勾选合并请求、填完描述、点两次确认(中间他去倒水,回来发现按钮灰了)、又刷新页面重新点提交,PR 才真正进 pipeline。CI 里跑的是 bundle exec rails assets:precompile --trace,最后一行日志是 "Compiled assets/manifest-xxx.json (34ms)",然后静音了十七秒,再出来一句 "Exiting with code 0"。exit 0?它连 manifest 文件都没写全。可日志里没报错,它甚至没报 warning,它就是不写,就像当年你老婆说“我没事”一样准。 桌面那个没关的录屏软件,录了二十七分钟,声音是静音的,但小红点一直亮着。我边盯 New Relic dashboard 边看那个点,突然想起上个月 SRE 推的 “Ruby GC 自适应调优白皮书”,PDF 第十九页画了个漂亮的内存抖动曲线,底下标注:“建议将 RUBY_GC_HEAP_INIT_SLOTS 设为物理内存的 0.83%”。我照做了。结果上线第三天 puma worker 全跪,日志里全是 "stack level too deep" —— 不是递归爆了,是 GC 在每次 minor sweep 时多分配了两百个 slot,凑巧把某个 gem 的 Thread.current[:__rack_env] hash 键撑出了碰撞链,链长十三层,刚好越过 Ruby 3.2 的默认嵌套限制。这个我敢打包票,我 debug 到第七层的时候,在 irb 里手动执行了 ObjectSpace.each_object(Hash) {|h| p h.keys if h.size > 12 },它真吐出来一个带 :rack_version 的哈希,key 是 symbol,value 是 Proc,Proc 里又闭包了另一个 Hash。你没法 reproduce,除非你电脑风扇转速和我当时一模一样:左侧出风孔嗡嗡震得鼠标垫发颤。
文章配图,仅供参考 反常识结论?不是反常识,是常识失效。我们都信 YAML 能当配置语言用,信 database.yml 里 password: 安全,信 dotenv 会自动加载。可去年十一月上线的那个新环境,env 文件被部署脚本硬编码写进了 /tmp/.env.tmp,路径权限是 644,Puma 启动前 chmod 755 了一下,然后——你猜怎么着?它读了,但它把那个 .env.tmp 当作主配置,覆盖掉了 /config/database.yml 里所有的 production 配置,包括 pool: 5 和 timeout: 5000,最后留下的只有 host: localhost 和 username: postgres。所以前三百个请求能连上,第四百个就开始排队,第八百个开始超时,一千二以后全挂。而 DBA 监控告警阈值设的是连接数 > 95%,它从来没触发过——因为连接池永远卡在四十九,永远不到五十。 CDN 账单上周涨了四倍。不是攻击,不是爬虫,是 asset_host 写错后浏览器疯狂重试 /assets/logo-abc123.svg,而 Nginx 日志里 status=404 的请求数占总流量的 68%,这些请求全被 Cloudflare 转发到 origin,origin 上又没配 404 缓存规则,所以每秒三百次 GET /assets/ 就这么撞进 Rails router。Rails router 还真认真匹配了——它走了一遍所有 route.rb 里的 get/post/put,最后在 match 'path' 那里兜底返回 404。那一行代码存在了八年,没人动过,就它在扛流量。你说这是性能问题?不,这是配置幻觉。你以为你在控制流量,其实你在喂一条咬自己尾巴的蛇。 后端兄弟今天换了一根 USB-C 充电线,黑色,编织纹,接口处有点松。他说旧线充 MacBook 总断连,换完之后 Jenkins 构建速度莫名其妙快了两秒。我不信,重跑了五次 pipeline,平均下来确实是 2.3 秒——但第六次跑出来 4.1 秒,因为 Jenkins Agent 正好在那一刻清理了 /tmp 下的临时 gemspec 缓存。KPI 折算公式是按“平均构建耗时 ≤ 3 秒”算 bonus,他们组上季度达标了,但这周还没报上去。我说别报,等三天。他说为什么。我说等我看看那根充电线会不会哪天自己变紧。 优胜劣汰?对。但这汰法不是靠 benchmark,是靠谁能先发现那段被注释掉的 preload_config!在 config/initializers/load_settings.rb 最底下,有五行被 # 号封印的代码,其中一行是 ActiveRecord::Base.logger = Logger.new(STDOUT),下面紧跟着 # TODO: restore once we fix log rotation —— 注释人是我三年前写的,执行人是我昨天删的。删完立刻生效。没有重启 puma,没有 reload env,就删了五行,FCP 从八百毫秒掉到一百二十毫秒。我看着 New Relic 的瀑布图唰一下往下塌,手还在抖。原来我们不是缺监控,是缺敢删的人。 所以我现在每天上午十一点十五分,固定打开 Chrome DevTools 的 Network tab,Filter 输入“svg”,然后盯着看十秒钟。不分析,不截屏,不导出。就看。看有没有那种请求,status 是 200,size 显示 0 B,timing 里 TTFB 占了整条横杠的 92%。如果有,我就去翻 routes.rb 第四百一十八行——那里一定藏着一个 map.draws_resources :icons, only: [:index],它生成的 route 实际上绑到了 ActionDispatch::Routing::RouteSet::NamedRouteCollection,而这个 collection 在 Rails 7.2 有个已知 bug:若 controller 方法不存在,它不会 raise NoMethodError,它只是把 path helper 返回空字符串。空字符串被当成 URL,于是 href="https://www.shaguniang.cn/html/baike/2026-10-14/493044.html",于是浏览器不断 GET 当前页面。就这么个小洞,吃掉八成流量。我不修,我先记下来,等周五下午茶时间,把它贴在茶水间白板上,标题就写:“这周谁删掉它,谁请喝霸王茶姬”。 (编辑:站长网) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |




