Latest Notes

把日常问题写成可复用的答案。

这里收集技术实践、排错记录、阅读札记和一些生活观察。每一篇都尽量留下清晰的上下文、判断和解决路径。

Today 持续记录,慢慢变好

技术笔记、项目复盘、阅读摘录和问题清单。

数据库 17 阅读

MySQL 查询突然变慢:从统计信息失真到执行计划稳定的排查实践

## 适用场景 本文适用于 MySQL 8.0 使用 InnoDB 的生产环境。典型场景是 SQL 和索引近期都没有修改,但一次批量导入、归档删除或数据分布变化后,原本几十毫秒的查询突然变成数秒;`EXPLAIN` 显示优化器改走了低选择性索引、错误的连接顺序,甚至全表扫描。 这类问题容易被误判为“数据库负载太高”

阅读全文
开发 52 阅读

TypeScript 请求已超时却仍占用连接:用 AbortController 建立可取消的重试边界

## 适用场景 本文适用于 Node.js 20.3 及以上版本使用原生 `fetch` 调用内部 API、第三方服务或网关的 TypeScript 项目。示例使用该版本提供的 `AbortSignal.any()`;更早版本可以用等价的信号组合函数替代。典型现象是:业务层已经返回“请求超时”,但下游仍持续收到请求;

阅读全文
Python 85 阅读

Python 异步服务日志串号:用 ContextVar 隔离 request_id 与后台任务上下文

## 适用场景 FastAPI、Django ASGI 或自研 `asyncio` 服务会在同一线程交错处理多个请求。团队希望所有日志自动带上 `request_id`,却发现并发压测时标识偶尔串到另一个请求,或请求结束后启动的后台任务仍携带旧用户上下文。 本文用 Python 标准库复现并修复这个问题。重点不是某

阅读全文
数据库 124 阅读

PostgreSQL 表越删越大且查询变慢:从死元组取证到 autovacuum 治理

## 适用场景 本文适用于更新、删除频繁的订单、任务、消息、审计记录等 PostgreSQL 表。典型现象是:业务已经清理大量历史数据,但表文件没有缩小;索引扫描和备份越来越慢;监控中的磁盘使用持续上涨;执行 `VACUUM` 后空间仍未归还操作系统。 本文重点解决三个问题:如何确认膨胀来自死元组,为什么 auto

阅读全文
安全 125 阅读

JWT 密钥轮换后批量 401:用 kid 双钥并行实现无感切换与可回滚发布

## 适用场景 业务使用 RS256 JWT 在网关、API 服务和后台任务之间传递身份。为了满足密钥泄露应急、合规轮换或证书到期要求,需要定期替换签名私钥,但又不能让尚未过期的旧令牌突然失效。 本文给出一套可直接落地的轮换方法:令牌头携带 `kid`,验证端同时信任新旧公钥,签发端再切换当前私钥,最后根据令牌最长

阅读全文
监控 151 阅读

Prometheus 告警反复抖动:用 for、keep_firing_for 与规则测试稳定通知

## 适用场景 本文适用于 Prometheus 根据错误率、延迟、资源使用率等指标触发告警,并通过 Alertmanager 发送通知的场景。典型问题是:指标在阈值附近波动,告警几分钟内反复触发和恢复;短暂采集缺口被误判为恢复;值班人员收到大量重复通知,却难以判断故障是否真正结束。 目标不是简单地“把告警调迟”,

阅读全文
开发 226 阅读

Go HTTP 调用超时后吞吐下降:从取消传播到连接复用的治理实践

## 适用场景 本文适用于 Go 服务通过 `net/http` 调用内部 API、第三方接口或对象存储的场景。典型现象是:下游偶发变慢后,请求大量超时;下游恢复后,调用方吞吐仍然偏低;连接数、TIME_WAIT 或新建 TLS 连接数明显上升;日志只看到 `context deadline exceeded`,却无

阅读全文
数据库 178 阅读

MySQL 深分页越来越慢:从 OFFSET 扫描到游标分页的改造实践

## 适用场景 本文适用于按时间倒序展示订单、流水、审计日志或消息列表的接口。典型特征是:第一页很快,翻到几千页后响应时间明显上升;数据库 CPU 和磁盘读取随页码增长;接口仍使用 `LIMIT offset, size`。 示例使用 MySQL 8.0,表结构如下: ```sql CREATE TABLE or

阅读全文