搞生产限流排障的人都有体会:大部分限流告警,最后都是靠日志定的罪。今天就说 Sentinel 的 record.log——限流事件发生后的第一现场。很多同学一遇到接口被限流就去翻 Dashboard 曲线,曲线只能告诉你“被拦了一部分”,但到底是被哪条规则拦的、什么时候开始拦的、拦的时候当前指标是多少,Dashboard 不一定会给你足够细的信息,而 record.log 会。它能帮你回答三个问题:是不是 QPS 超了阈值、是不是并发线程数被打满、是不是热点参数命中了限流规则。这篇文章就围绕这三个问题,把 record.log 怎么找、怎么看、怎么用说清楚,适合负责限流排障的后端开发、SRE 和刚上手 Sentinel 的同学。
1. record.log 到底在哪,先认全 Sentinel 的日志家族
1.1 Sentinel 不是只有一个 record.log
刚接触 Sentinel 的同学经常把日志文件搞混。在默认配置下,Sentinel 会在应用运行目录下生成一组以csp为路径关键字的日志文件,最常见的几个分别是:
sentinel-record.log:也就是我们常说的 record.log,Sentinel 在拦截到请求后输出的核心记录文件,包含时间、资源名、规则类型、当前指标值、阈值等关键信息。sentinel-block.log:记录被 BlockHandler 处理过的拦截请求,如果业务里配置了自定义的 fallback 或 blockHandler,被处理后的记录会写到这里。sentinel-degrade.log:熔断降级相关的记录,比如慢调用比例、异常比例、异常数阈值触发降级时,会输出到该文件。sentinel-param-flow.log:热点参数限流的专项记录。sentinel-error.log:Sentinel 自身初始化、规则下发、检查异常时输出的错误日志。
我见过不少人排查限流问题,先打开sentinel-error.log,发现里面没有内容,就以为 Sentinel 没有工作。这是把日志文件的理解搞反了:限流发生时先写record.log,只有规则拦截后进入自定义处理阶段才写block.log,而error.log记录的是框架自身的问题,不是业务限流问题。所以定位限流原因的主战场,就是sentinel-record.log。
1.2 日志目录和文件命名规则,别再找错路径
默认情况下,Sentinel 日志写在${user.home}/logs/csp/目录下。注意这个user.home是 JVM 启动时取到的系统属性,不是操作系统的 HOME 变量,所以在 Linux 上部署时,如果启动脚本不显式指定,很可能跑到/root/logs/csp,而你在tomcat/logs或应用目录下怎么找都找不到。
生产环境建议在 JVM 参数里固定日志目录,有两个参数值得提前设置:
-Dcsp.sentinel.log.dir=/data/logs/csp -Dcsp.sentinel.log.use.pid=true第一个参数把日志输出目录固定到挂载盘,方便采集和排查;第二个参数会在文件名后面加上进程 PID,例如sentinel-record.log.2024-06-18.12345。这个 PID 后缀特别重要,同一个服务器上部署多个实例时,没有 PID 后缀日志会互相覆盖,到时候看到的拦截记录到底来自哪个服务都说不清。
日志文件按天滚动,当天文件是sentinel-record.log,历史文件带日期后缀。滚动策略在日志文件变大后尤其重要,默认的滚轮频次在高 QPS 场景下可能一天生成好几个 GB,后面我会在排查技巧里专门讲保留策略。
2. 看懂 record.log 里的一行记录,比读十遍文档都管用
2.1 一条限流记录里的核心字段
打开sentinel-record.log,一开始会看到不少带 Exception 堆栈的内容,不用慌,那是因为 Sentinel 在拦截的同时也会输出异常堆栈,便于开发定位触发拦截图的位置。真正有价值的是异常堆栈前面那一段竖线分隔的结构化记录。以下是我在环境里整理过的一行典型内容,为了方便理解做了字段拆分:
2024-06-18 14:32:10.895|order-service|POST:/order/create|FLOW|order_create_flow_rule|default|10.24.8.3|2814|1000各字段的含义如下表所示:
| 字段位置 | 含义 | 说人话 |
|---|---|---|
| 时间 | 拦截发生的精确时间 | 标记该请求是在哪个时刻被拦下的 |
| 服务名 | 当前应用的 appName | 确认是你的服务,不是别的服务串过来的日志 |
| 资源名 | 被 Sentinel 保护的资源字符串 | 一般就是接口路径或方法名,告诉你拦在哪个入口 |
| 规则类型 | FLOW/DEGRADE/ PARAM_FLOW/SYSTEM/AUTHORITY | 告诉你命中了哪类规则 |
| 规则 ID | 规则配置里的名称,没有配置时显示 default | 回到配置中心能精确找到对应规则 |
| 来源应用 | 调用方标识,未配置时显示 default | 判断是不是某一个来源应用打过来的流量 |
| 来源 IP | 调用方 IP | 后续按 origin 维度排查时很有用 |
| 当前值 | 触发拦截时的实时指标值 | 比如当前 QPS 到了多少 |
| 阈值 | 规则配置的上限 | 和当前值一对比,限流原因立刻清楚 |
需要说明的是,不同版本 Sentinel 的 record.log 字段顺序和分隔符可能略有不同,但“什么时间、哪个资源、被什么规则拦、当前值和阈值是多少”这五要素一定都在。如果你拿不准某一行里的数字对应什么,最简单的办法是把规则 ID 拿到 Dashboard 或配置中心里对一下,规则详情里显示的阈值和日志里的阈值能对上,就证明是这条规则拦的。
2.2 规则类型与日志关键字映射,先判断是哪类限流
record.log里最前面的规则类型字段,是后续排查的分叉口。不同的规则类型,背后代表的性能瓶颈完全不同,定位方向也完全不同。我整理了一张对应表:
| 规则类型 | 触发原因 | 日志关键字 | 典型场景 |
|---|---|---|---|
| FLOW 流控规则 | QPS 或并发线程数超过阈值 | FlowException | 瞬时流量高峰、预热不足 |
| DEGRADE 熔断降级 | 慢调用比例、异常比例超标 | DegradeException | 下游接口变慢,导致错误率上升 |
| PARAM_FLOW 热点规则 | 某个参数值访问量超限 | ParamFlowException | 某个商品 ID、某个 userId 被高频访问 |
| SYSTEM 系统保护 | 系统负载、CPU、RT 超保护阈值 | SystemBlockException | 机器整体压力过高 |
| AUTHORITY 授权规则 | 来源应用被黑白名单拒绝 | AuthorityException | 某个调用方不应再访问该接口 |
在实际排查时,我建议看到日志后先不要急着去看流量大小,先把规则类型读出来。有一次告警显示下单接口被限流,大家第一反应是流量太高,结果打开 record.log 一看是DegradeException,说明不是流量大,而是下游 DB 响应变慢导致慢调用比例超标,才触发了熔断。方向搞错了,整个排查就会跑偏。
3. 从 record.log 定位限流原因的标准实操流程
3.1 三分钟找到日志并过滤出可疑记录
排查的第一步永远是确认日志存在、文件在更新。我的习惯是先进目录,然后看最近修改时间:
cd /data/logs/csp/ ls -lht sentinel-record.log*如果有文件且时间戳是几分钟前,说明 Sentinel 拦截记录在正常写入。接下来按资源名过滤,比如下单接口的资源名是POST:/order/create:
grep "POST:/order/create" sentinel-record.log.* | tail -n 200为什么要加tail?因为拦截记录有时候会很多,如果你直接 grep 出一整天的记录,输出量会很大,反而找不到最接近当前问题的内容。先看最近 200 行,确认拦截是不是正在发生的。
如果日志里什么都没搜到,除了要考虑人是不是找对了方向,还要检查资源名是否与服务端配置一致。Sentinel 默认埋点不一定用接口路径,可能是doOrder这样的方法名或自定义埋点字符串。不确定资源名时,可以先tail -n 200 sentinel-record.log,看最近在记录哪些资源,再从中找目标。
3.2 统计时间维度的拦截量,区分“持续超限”还是“瞬时脉冲”
单看一行记录只能说明“这个请求被拦了”,要判断限流原因,还得看拦截的分布。我常用的一个命令是按分钟聚合一下:
grep "POST:/order/create" sentinel-record.log | awk -F'|' '{print $1}' | cut -c1-16 | uniq -c$1是时间字段,cut -c1-16截取到分钟,uniq -c统计每分钟拦截了多少次。输出结果大概长这样:
156 2024-06-18 14:30 284 2024-06-18 14:31 512 2024-06-18 14:32 533 2024-06-18 14:33看到拦截量从 156 一路涨到 500 多,这是明显的流量突增过程。如果拦截量一直很平稳,比如每天都固定在某个时段出现几十次,那更可能是规则阈值设得太低,而不是流量风暴。
另一个值得对比的是“当前值”字段。比如一条记录显示当前 QPS 2814、阈值 1000,那么限流原因非常直接:流量已经超过了阈值配置。另一种情况是当前值只有 900,阈值 1000,却被拦了,那说明阈值在逐步生效,比如流控效果配置了匀速排队,这时候要去看是否是预热规则导致的冷启动限制。
3.3 一个完整案例:一次下单接口限流排查的全过程
拿一个真实项目里的场景来说。某天下午订单服务告警,提示POST:/order/create接口被限流,用户侧开始出现“系统繁忙”的提示。当时团队的反应是打开 Dashboard 曲线,看到限流拦截的柱状图确实很高,但光从图上看不出到底为什么限。完整的排查步骤是这样的:
第一步,登录服务节点,进到/data/logs/csp,确认sentinel-record.log.2024-06-18存在且大小在增长。
第二步,grep 资源名,看到大量如下记录:
2024-06-18 14:32:08.110|order-service|POST:/order/create|FLOW|order_create_flow_rule|default|10.24.8.3|2876|1000 2024-06-18 14:32:08.133|order-service|POST:/order/create|FLOW|order_create_flow_rule|default|10.24.8.3|2814|1000规则类型是FLOW,规则 ID 是order_create_flow_rule,当前值 2800 左右,阈值 1000。到这里已经基本确定:单机 QPS 瞬时突破了 1000 的规则阈值。
第三步,去配置中心找order_create_flow_rule这条规则,确认阈值确实是 1000,流控效果是“直接拒绝”,统计维度是 QPS。注意这里还有一个细节:规则里配置的阈值是单机阈值还是集群阈值。如果是集群流控,那 record.log 里记录的是节点视角的数据,其他节点的流量可能也与会话有关,要结合集群数据源再看。
第四步,统计时间分布。用上面提到的按分钟聚合命令发现 14:30 之前的拦截量几乎为 0,14:30 之后陡增。再看业务侧,正好此刻营销活动页发布了秒杀按钮,短时间涌入大量流量。结论就出来了:流量瞬时突增导致 QPS 超阈值。
第五步,处理措施。因为流量峰值可能会持续一段时期,我们在配置中心里把阈值临时调到 2000,并开启了预热(warm up)机制,让阈值从低值缓慢拉伸到高值,避免冷启动直接顶满限流。调完后 record.log 里的拦截记录明显下降,业务恢复正常。
这个案例里,record.log 的作用不是告诉你“要调多少阈值”,而是帮你在最短时间内把“哪条规则”、“当前值多少”、“阈值多少”这三个事实锁定,再结合业务时间线定位根因。Dashboard 看的是宏观趋势,record.log 看的是微观现场,两者配合才是完整的排障闭环。
4. 排障中常见问题与实战技巧
4.1 高频问题速查表
排障过程中很多人会遇到“日志里明明没有东西,业务却被限流”之类的迷惑情况。我把这几年踩过的坑整理成了一张速查表:
| 现象 | 可能原因 | 排查方法 |
|---|---|---|
| record.log 里搜不到目标资源 | 资源名不匹配,或者埋点没生效 | tail -n 200 sentinel-record.log看最近在记录哪些资源名 |
| 业务告警限流,日志文件不更新 | 日志目录被映射到别的路径 | 检查-Dcsp.sentinel.log.dir实际指向哪里 |
| 日志时间与业务日志不一致 | 容器时区问题或 JVM 时区配置不一致 | 检查user.timezone和容器时区,统一设置为东八区 |
| record.log 很大,磁盘告警 | 默认滚动策略不够,文件未及时清理 | 配置 logrotate 按天或按大小滚动,保留 7~15 天 |
| 拦截记录很多但业务没有报错 | 自定义 BlockHandler 吃了异常没有上抛 | 查sentinel-block.log,看自定义处理是否记录 |
| 多实例日志混在一起 | 没有开启 PID 后缀 | 在 JVM 参数中增加-Dcsp.sentinel.log.use.pid=true |
| 规则 ID 始终显示 default | 规则未配置名称,或规则未按预期下发 | 去 Dashboard 或配置中心核对实际下发规则 |
这张表里,“日志不更新”和“资源名不匹配”是新手最容易卡住的点。我建议生产环境启动脚本统一加上-Dcsp.sentinel.log.use.pid=true,并且约定每个服务把 log.dir 固定到/data/logs/csp,这样排查时能直接跳到固定目录,不用在服务器上到处找文件。
4.2 独家技巧与避坑建议
最后分享几个我在实际操作中积累的经验,常规文档里不会写这么细:
不要把record.log当成唯一依据。record.log是拦截后的现场快照,它告诉你“拦了”,但不一定会告诉你“为什么拦”的全部背景。比如系统保护规则触发时,阈值字段是动态计算出来的,日志里的数字并不直观,你还需要到 Dashboard 看系统负载曲线。所以 record.log 是用来缩小范围的,不是用来取代监控的。
让 BlockHandler 把日志也带上。如果你的业务配置了自定义blockHandler,我强烈建议在处理函数里把资源名、规则配置、当前请求的 traceId 或 requestId 一起打出来。这样业务日志和 Sentinel 日志能通过同一个 ID 关联起来,排查速度会快非常多。我见过太多项目,业务日志和 Sentinel 日志各记各的,出了问题时两边对不上时间线。
热点参数限流不要死盯 record.log。如果排到一半发现规则类型是PARAM_FLOW,赶紧去翻sentinel-param-flow.log,那里记录了具体的参数值和参数索引。继续在record.log里抠字段,能获得的信息量会少一大截。
文件滚动策略要在上线前就配好。record.log一旦积压到几个 GB,grep 一次要等好几秒,排障效率极低。用 logrotate 按天切割,保留 15 天,历史文件单独归档到日志平台,线上服务器只留少量当天文件。否则促销季流量上来,磁盘被日志塞满,还没等你定位到限流原因,机器先被日志写挂了。
写到这里想多说一句,我用 record.log 排查限流问题越久,越觉得限流原因不是玄学,而是“规则配置、实时流量、时间窗口”三者的乘积。Dashboard 曲线是宏观印象,配置中心里的规则是静态定义,真正把两者联系起来的,就是那一行一行有准确时间戳和拦截细节的记录。团队里如果能把日志路径约定、保留策略、自定义 blockHandler 日志规范这三点做好,后续不管是限流调优、容量评估还是事故复盘,都能事半功倍。