Logging Stack 故障排查

本页面按我们在 ACP 4.4 Logging Stack 的实际安装中遇到的故障模式编排,并以 SRE 首先看到的症状为索引。每个条目都会指出我们已确认存在问题的代码路径或资源,因此你可以直接跳转到修复方法,而不必逐步二分排查。

排序遵循安装流程:先是存储前置条件,然后是 operator,接着是数据路径,最后是查询路径。

零接触要求

v4.4 安装以及 v4.3 → v4.4 升级都应当实现零接触。如果以下任何操作步骤要求你手动创建本应由 operator 创建的资源,那是代码缺陷,而不是文档缺失——请提交问题,而不是采用临时解决方法。唯一的例外是 Installation 中列出的由 SRE 编写的 secrets(Kafka mq-conn,以及对于外部 OpenSearch / ClickHouse 路径而言的 storage-conn secrets),这些内容按设计需要用户输入。

Kafka broker 无法在 Alauda OS / FIPS 主机上启动

症状:应用示例 YAML 后,RdsKafka/cpaas-kafka 变为 Ready=False,并且 entity operator 日志或 strimzi-cluster-operator 日志针对一个或多个 KafkaUsers 报告 UnacceptableCredentialException。

根本原因:在 Alauda OS 和经过 FIPS 加固的主机上,SCRAM-SHA-512 后端会拒绝长度小于 32 字节的密码。Installation 中的示例 YAML 已对此进行标记,但如果你在 SASL password Secret 中自行生成了密码,请确认每个密码的长度。

修复方法:

kubectl -n cpaas-system get secret platform-default-mq-conn -o jsonpath='{.data.password}' | base64 -d | wc -c
# must print >= 32

使用 openssl rand -base64 24 | tr -d '\n' 重新生成所有过短的密码,修补 Secret,然后等待 operator 在下一次 reconcile 时获取更改。每个 KafkaUser 都有一个 SCRAM 密码,因此请记得检查所定义的每个 KafkaUser;多个用户共享同一个密码会触发相关故障,导致除一个用户外的所有用户都被拒绝。

Kafka broker 拒绝超过默认 1 MiB 的日志记录

症状:aggregate-vector 记录 RecordTooLargeException 并在摄取时出现延迟,或者 collection cluster 上 nevermore 的磁盘缓冲区已填满。

根本原因:broker 的 message.max.bytes 和 replica.fetch.max.bytes 必须同时调高——平台提供的基线值为 10 MiB。Installation 中的示例 YAML 会设置这两个值。如果你使用自有的 Kafka 集群,并且只遵循了较短的检查清单,这两个设置可能仍为 Kafka 默认值 1048588。

修复方法:修补 RdsKafka spec.kafka.config,将这两个限制至少提高到 10485760,然后让 operator 重启 brokers。producerCompressionType 也应设置为 zstd,这样即使是 10 MiB 的记录也能足够快速地发送,从而使 aggvec 摄取窗口保持关闭。

PlatformLogForward 保持为 Provisioning

在 .status.conditions 下,查看哪个子条件卡在 False。条件名称会告诉你 operator 的 reconcile 哪个子步骤尚未完成,通常可以使用 kubectl describe 确定根本原因。

卡在 False 的条件operator 正在等待的内容下一步查看位置
MessageQueueReadycpaas-system 中的 platform-default-mq-conn Secret——其 bootstrap、username、password、sasl_mechanism、topics.log/topics.event/topics.audit 以及(对于 TLS)tls.ca 字段必须解析为 operator 可以访问的 Kafka 集群,并且 SCRAM 预检必须成功。kubectl get secret platform-default-mq-conn -o yaml 以及 operator 日志中的 preflight 行。请参阅 Installation 中的约定。
StorageReadyPLF 引用的外部存储端点——operator 会打开一个普通 HTTP 或 HTTPS 握手;对于 ClickHouse,随后还会运行 schema-migrations Job。对于 ClickHouse:先查看 kubectl -n cpaas-system get jobs -l job=schema-migrations,然后查看最新一次运行中的 logs。对于 OpenSearch:查看 kubectl -n cpaas-system get jobs -l job=opensearch-init。
CollectorReadyaggregate-vector Deployment 尚未达到就绪副本数。先查看 init container wait-for-schema-migrations;它会阻塞 Pod,直到 schema-migrations Job 变为 Complete(ClickHouse),或直接短路(OpenSearch,根据 Bug 167)。
RazorReady存储集群上的 razor Deployment 尚未达到就绪副本数。常见原因:存储后端拒绝了 razor 的连接,或者它挂载的 log-policy-config ConfigMap 缺失。
SchemaMigratedauto-migration Runnable 尚未报告 Converged。查看 kubectl -n cpaas-system logs deploy/log-storage-operator,获取 AutoMigrationRunnable 重试循环最近一次 tick 的原因。

有两种上游故障模式值得特别说明,因为它们过去常常让此排查过程产生误判:

  • 外部 ClickHouse 通过 HTTPS 使用的 schema-migrations Job 需要 CA。如果 CH 端点使用自签名证书,而你未将 CA 附加到 platform-default-ch-conn Secret,operator 会回退到 insecure_skip_verify=true(并记录该信息)。如果 TLS 仍然失败,Job 的 Pod 日志会显示确切的握手错误。

  • 用于 log-center 的 Feature CR 曾将 platformURL(global platform entry)硬编码为其 SecureAddress,而 razor-api 日志路径无法跨集群访问该地址。operator 此后已修复为解析存储集群上的本地 ALB 地址。如果你的安装版本是 4.4 beta.x,且 Feature 仍指向 global platform,请升级 operator image。

OpenSearch 安装:模板 PUT 失败并返回 strict 400

症状。OpenSearch 3.7 上的 opensearchinit runner Job 失败,HTTP 400 响应正文在可组合模板 PUT 中提到 strict。

根本原因。OpenSearch 3.7 禁止在可组合模板解析中的 strict 下使用 template.settings.index.lifecycle。operator 的 opensearchinit runner 过去会在可组合模板正文中保留此键,现在 runner 会在 PUT 之前将其删除。

修复方法。将 operator 升级到包含此删除逻辑的版本(请参阅 operator 变更日志中的 Bug 200)。除了升级 operator image 外,无需执行其他操作。

OpenSearch 全新安装在 AggregateVectorReady 处失败

症状。在使用 PLF.spec.externalStorage.type: opensearch 的全新安装中,aggvec Pod 因 Init 中的 wait-for-schema-migrations 进入 CrashLoop。schema-migrations Job 列表中没有任何内容。

根本原因。OpenSearch 场景没有 schema-migrations Job(没有需要迁移的关系型 schema)。initContainer 应在 OpenSearch 分支上直接短路。较旧的 operator image 将 initContainer 硬编码为等待 ClickHouse 风格的 schema-migrations Job 达到 Complete,因此在 OpenSearch 上会无限等待。

修复方法。将 operator 升级到在 opensearchinit 和 aggvec 启动门控中加入 OpenSearch 分支的版本(Bug 167)。

PLF 为 Ready,但没有任何内容写入存储

最常见的情况是 Kafka 侧的授权静默失败,因为 vector kafka source 将 GroupAuthorizationFailed 视为可恢复错误,并持续轮询而不报告条件。

修复方法。读取 aggregate-vector Pod 中 vector kafka source 自身的错误日志。每次被拒绝的 fetch 都会输出一行日志,其中使用的 SASL 用户名来自 platform-default-mq-conn Secret。允许该用户从日志主题消费的 KafkaUser ACL 必须是通配符,或者必须匹配 razor 的 KafkaUser 所声明的 razor- 前缀。如果你按照 Installation 中的示例 YAML 操作,则此配置已经正确;如果使用的是自定义 KafkaUser,请将 ACL 与 mq-conn Secret 中的主题列表进行交叉检查。

租户的 LogForward CR 不转发任何内容

症状。租户在 cpaas-system 中创建 LogForward。其 Deployment 为 Ready=True,但外部目标未收到任何内容。

常见原因(按可能性排序):

  • input.filter 表达式静默地不匹配任何内容。空谓词分支现在已由 CEL webhook 捕获(Bug 173 pt1),但任何始终不会计算为 true 的表达式,都会生成一个从 Kafka 读取但不写入任何内容的 Vector pipeline。使用 vector vrl -i -p -o 针对单条记录测试该表达式。
  • input.classify 从租户无权消费的主题读取数据。vector kafka source 将其视为可恢复错误,不会设置 Ready=False 条件。在 LogForward Pod 的 vector 日志中查找 spec.input.classify.consumerGroupPrefix 前缀上的 GroupAuthorizationFailed。
  • output.type 使用 advancedSink,而 escape-hatch payload 在语法上是有效的 Vector 配置,但在语义上为空。对 payload 执行 vector validate 可以捕获其中的大多数情况。

跨集群日志查询在 collection 集群上返回 401

症状。在 global 集群上,对 storage 集群执行的日志查询在安装后的几分钟内返回 401,之后开始正常工作。

根本原因。collection 集群上的 log-callback-secret 由 cluster-transformer 在跨集群范围内同步,同步窗口较短,但过去曾为五分钟;razor-api 的负令牌缓存过去会保留这一窗口,并在此期间拒绝查询(Bug 51 + Bug 52 + Bug 83)。

修复方法。在当前 operator 基线中,该窗口已缩短为一分钟,负缓存的保留时间也已缩短。如果完整一分钟后仍然看到 401,请检查 storage 集群的 cluster-transformer 日志,确认 log-callback-secret 同步成功。另一个常见原因是 razor 的 KafkaUser 密码已轮换,而 razor 未执行热加载(Bug 98)——滚动重启 razor 即可加载新密码。

ClickHouse 向 S3 的层级迁移静默无操作

症状。PLF 规格将 tieredPolicy 与 coldTTL 一同设置,但 ClickHouse 的 <log_data> 表中的数据在 TTL 到期时不会迁移到冷卷,而是被 DELETE。

根本原因。如果 razor 的 schema-init 与 operator 的存储策略配置发送发生竞态,表创建时就不会包含 storage_policy,后续的 ALTER ... TO VOLUME 'cold' 会失败,并返回 CH 450。razor 过去通过读取 exception 列来检测失败,但 CH 25.8 不会公开该列,因此它会静默记录“TTL updated successfully”(参见 operator 仓库备注中的 [[project_v4_4_storage_policy_race]])。

修复方法。v4.4.4 operator 镜像会为每条语句注入存储策略 JSON,然后运行 schema-migrations(Bug 188 v2 + Bug 189);AutoMigrationRunnable 会持续重试,直到 CH 报告表中已存在目标策略(Bug 190)。如果使用的是较旧的 beta 版本,请升级 operator 镜像,然后重新应用 PLF 的 tieredPolicy 字段。

OpenSearch 查询会丢弃中文或 IP 风格的搜索词

症状。在 OpenSearch 后端中,针对 中文 或 192.168.1.1 的日志查询返回零条结果,即使日志记录已建立索引。针对 error 或 root 的查询可以正常工作。

根本原因。razor 的查询构建器会将 * 附加到每个非 SQS 特殊词项,以保留前缀匹配功能。对于非 ASCII 词项以及包含 tokenizer 分隔符的词项,生成的前缀查询会绕过 analyzer,因此永远无法匹配任何已建立索引的 token(参见 razor 的 buildSQSTerm hotfix,MR!245)。

修复方法。在 storage 集群上使用 razor v4.4.4 或更高版本的镜像(通过 PLF.spec.razor.image 或 Subscription config.env)。不要直接修改 Deployment——operator 会将其恢复。

OpenSearch 查询按 containerName 进行筛选且始终返回零结果

症状。带有 containerName 筛选条件的 OpenSearch 日志查询返回零条结果,即使针对已知容器也是如此。移除该筛选条件后,结果会恢复。

根本原因。aggregate-vector 的 OpenSearch pipeline 过去只写入 .kubernetes_container_name,而 razor 的读取端词项查询针对的是 .docker_container_name.keyword。两者并未关联。

修复方法。现在,aggvec VRL 在 OpenSearch 路径上会同时写入两个字段(release-4.4 对应 log-storage-operator MR!92,master 对应 MR!93)。请将 operator 升级到包含这些合并内容的构建版本。

日志导出产生字面字符串 <nil>

症状。导出的 .txt / .csv 文件中,字段缺失的单元格包含字面字符串 <nil>。对于同一个缺失字段,查询界面返回空字符串。

根本原因。razor 的归档路径使用 fmt.Sprintf("%v", …) 格式化每个字段,对于缺失的 map key,这会产生字面字符串 <nil>,而不是空字符串(参见 razor MR!247)。

修复方法。使用 razor v4.4.4 或更高版本。

OpenSearch 会忽略项目范围的保留策略

症状。租户通过 cpaas.io/project.hotDataRetentionDays 和 cpaas.io/project.logPolicyEnabled annotations 设置项目级保留策略。该设置对 OpenSearch 后端没有影响,每个项目都会保留平台默认的保留期限。

根本原因。这是设计如此:operator 的 OpenSearch 分支不会生成 log-policy-config,而用于在 OpenSearch 上协调 ISM 策略的 razor-api cron 只会读取该值,从不写入。参见 OpenSearch 后端限制。

修复方法。如果每个项目的保留策略是合规要求,请选择 ClickHouse 后端。目前没有任何配置开关可以让 OpenSearch 支持项目级保留策略。

诊断入口

如果某个症状与上述情况均不匹配,请从采集端开始沿着流水线排查,并在第一个看起来异常的跳点处停止:

  1. 采集集群上的 nevermore:kubectl -n cpaas-system logs -l app=nevermore --tail=200。查找 VRL / target.json 错误或“buffer full”消息。
  2. Kafka:kubectl -n cpaas-system exec sts/cpaas-kafka -- bin/kafka-topics.sh --bootstrap-server localhost:9092 --describe —— 确认日志 topic 存在,且分区数符合预期。
  3. 存储集群上的 aggregate-vector:kubectl -n cpaas-system logs -l app=aggregate-vector --tail=200。查找 kafka source 的每个 topic 的状态,以及任何 sink 4xx/5xx 错误。
  4. 存储后端:ClickHouse 上的 SELECT count() FROM <log_data> 或 OpenSearch 上的 GET _cat/indices。分别使用无界时间范围和有界时间范围进行比较;两者之间存在较大差距,说明 OpenSearch 出现时间戳覆盖问题(参见 OpenSearch 后端限制)。
  5. 存储集群上的 razor:kubectl -n cpaas-system logs -l app=razor --tail=200。这里出现 401 表示存在上述令牌同步问题。
  6. global 集群上的 razor-api:kubectl -n cpaas-system logs -l app=razor-api --tail=200。parseDatabase 错误识别后端(log-clickhouse 与 log-opensearch)时,会在错误的方言上执行 SQL,并显示为 SQL 错误。