从一次接口超时看后端排查顺序
从一次接口超时看后端排查顺序接口超时最怕一上来就猜原因。数据库慢、缓存抖动、下游服务不可用、线程池打满、网关限流,都可能表现成相似的现象。更稳的做法是先把问题从一团雾拆成可验证的几条线。 先确认影响面我会先确认是单个接口慢,还是一类接口都慢;是所有用户都受影响,还是只有特定账号、特定参数、特定时间段受影响。这个步骤不是走流程,而是在缩小搜索范围。 如果只有一个接口慢,重点看接口内部链路。如果同一服务下多个接口同时变慢,要看公共依赖...
日志不是越多越好
日志不是越多越好很多项目一开始都会把日志当成安全感:关键方法打一行,进入分支打一行,异常再打一行。短期看起来信息很全,真正排查时却会发现日志像流水账,想找一条有价值的线索反而更难。 日志要服务于问题我判断一条日志有没有价值,通常看它能不能回答问题。比如请求是谁发起的、操作了哪个业务对象、走到了哪个关键阶段、失败时外部依赖返回了什么。 如果日志只是在说明代码运行到某一行,但没有业务语义,也没有上下文,那么它在生产环境里大概率只是噪音...
接口返回值要为前端留出判断空间
接口返回值要为前端留出判断空间接口设计不只是把数据库字段吐出去。一个好用的接口,应该让前端容易判断状态、容易展示文案、容易处理空数据,也容易在业务变化时扩展。 不要只返回布尔值很多业务一开始喜欢返回 enabled、passed、finished 这类布尔字段。它们简单直接,但表达空间太小。页面后来可能需要区分待处理、处理中、已完成、已失败、已取消,布尔值就不够用了。 我更倾向于返回明确的状态码和状态文案。状态码给程序判断,状态文...
DTO 和 Entity 之间应该有边界
DTO 和 Entity 之间应该有边界Entity 代表数据持久化结构,DTO 代表接口传输结构。它们有时字段很像,但职责并不一样。如果直接把 Entity 暴露给接口,短期省事,长期会让数据库变化牵动接口变化。 Entity 关注存储Entity 更关心字段如何落库、如何关联、如何被 ORM 管理。它可能包含内部状态、删除标记、审计字段、版本字段,也可能存在为了查询性能而加入的冗余字段。 这些字段不一定适合出现在接口里。用户不...
缓存一致性要先讲业务容忍度
缓存一致性要先讲业务容忍度缓存一致性没有一种方案适合所有业务。商品详情、账户余额、权限配置、运营活动,它们对新鲜度和错误容忍度都不一样。方案选择之前,应该先问业务能不能接受短暂不一致。 先判断数据性质如果数据只是展示类,短暂延迟通常可以接受,重点是缓存命中和更新及时性。如果数据影响支付、权限、库存这类关键动作,就不能只依赖缓存结果做最终判断。 缓存适合加速读取,不适合承担唯一事实来源。真正可靠的数据判断,仍然要回到数据库或具备强约...
Redis Key 设计也需要规范
Redis Key 设计也需要规范Redis 用起来很轻,但 key 设计如果随意,后面排查会很痛苦。不同模块各写各的命名方式,缓存内容没人知道来源,过期策略不统一,最后 Redis 会变成一个难以治理的黑盒。 命名要能看出归属一个 key 最好能看出业务域、数据类型和定位字段。这样排查时看到 key,就能大致知道它属于哪个模块、存的是什么、应该找谁确认。 命名不需要追求花哨,但要稳定。不要今天用 user,明天用 account...
慢 SQL 排查不要只盯索引
慢 SQL 排查不要只盯索引遇到慢 SQL,很多人的第一反应是加索引。索引当然重要,但慢查询不一定只是索引问题。查询目标不清、返回字段太多、分页方式不合适、业务调用过于频繁,都可能让 SQL 变慢。 先看查询目的排查前先问这个 SQL 想解决什么问题。是列表查询、详情查询、统计查询,还是后台导出。不同目标对返回字段、排序方式、实时性和数据范围的要求不一样。 如果一个列表页只展示少量字段,却查询了完整大对象,问题可能不在索引,而在接...
事务边界要围绕业务动作设计
事务边界要围绕业务动作设计事务不是哪里涉及数据库就随手加。事务边界设计不好,要么锁持有太久,要么状态更新不完整,要么异常后数据留下半成品。事务应该围绕一个完整的业务动作来设计。 先定义业务完成点一个业务动作什么时候算完成,要先说清楚。比如创建订单,可能要写订单主表、写明细、扣减额度、记录操作日志。哪些步骤必须一起成功,哪些步骤可以异步补偿,要先区分。 只有完成点清楚,事务边界才有依据。 不要把外部调用包进长事务如果事务里包含远程调...