解释“死锁日志”在 Cloud Logging 中的字段结构。

解读

在国内面试中,这道题考察的是候选人是否真正“用过”Cloud SQL,而不仅是“看过文档”。
面试官通常先问“你遇到过死锁吗?怎么排查?”——如果你答“看日志”,就会顺势追问“日志长什么样?字段怎么解析?”
答不出字段细节,会被判定为“只背过概念,没实操”。
因此,必须给出可检索、可告警、可仪表盘的字段级说明,并指出与国内自建 MySQL 日志的差异(格式、字段命名、缺失值处理)。

知识点

  1. Cloud SQL 死锁日志本质:是 MySQL/PostgreSQL 引擎 InnoDB 死锁检测器的 JSON 输出,被 Cloud Logging 接收后自动注入 GCP 资源标签,与自建实例的 text 格式完全不同。
  2. 日志桶位置:默认落在 _Default 桶,logName 固定为
    projects/PROJECT_ID/logs/cloudsql.googleapis.com%2Fmysql.err%2Fpostgres.log
  3. 关键字段分三层
    • GCP 元数据层(monitoredResource、timestamp、severity、labels)——做全局过滤。
    • 引擎事件层(jsonPayload 下的 message、errorCode、thread_id)——做内容过滤。
    • 死锁详情层(jsonPayload 内嵌的 deadlock 结构体)——做根因分析。
  4. 国内合规注意:死锁详情里可能出现业务敏感字段值,需通过日志路由器(Log Router) 做脱敏或转存至中国境内 Bucket,避免跨境传输风险。

答案

在 Cloud Logging 中,一条死锁日志的 JSON 结构如下(以 MySQL 5.7 为例,字段顺序无关):

{
  "insertId": "1a2b3c4d",
  "logName": "projects/PROJECT_ID/logs/cloudsql.googleapis.com%2Fmysql.err",
  "timestamp": "2024-06-01T08:15:30.123456Z",
  "severity": "ERROR",
  "resource": {
    "type": "cloudsql_database",
    "labels": {
      "project_id": "PROJECT_ID",
      "database_id": "PROJECT_ID:INSTANCE_ID",
      "region": "us-central1"
    }
  },
  "jsonPayload": {
    "errorCode": "MY-012138",
    "message": "InnoDB: transactions deadlock detected, dumping detailed information.",
    "thread_id": 123456,
    "deadlock": {
      "transaction_1": {
        "thread_id": 123456,
        "query": "update order set status='PAID' where order_id=98765",
        "lock_mode": "X locks rec but not gap",
        "holds": ["lock on db.order.PRIMARY, id 98765"],
        "waiting": ["lock on db.inventory.PRIMARY, id 54321"]
      },
      "transaction_2": {
        "thread_id": 123457,
        "query": "update inventory set stock=stock-1 where sku='SKU123'",
        "lock_mode": "X locks rec but not gap",
        "holds": ["lock on db.inventory.PRIMARY, id 54321"],
        "waiting": ["lock on db.order.PRIMARY, id 98765"]
      },
      "victim": 123457
    }
  },
  "labels": {
    "RECEIVER": "cloudsql_mysql"
  }
}

字段含义与用法(面试时需口头点到):

  • jsonPayload.errorCode:值固定为 MY-012138,可快速过滤死锁。
  • jsonPayload.deadlock.victim:被回滚的事务线程 ID,直接对应连接池里的异常连接。
  • resource.labels.database_id:格式为 项目:实例,在 SCC(Security Command Center)里做统一资源路径告警。
  • timestamp:Cloud SQL 采用 UTC+0,与国内业务系统做关联时需**+8 小时**转北京时间。
  • jsonPayload.deadlock.transaction_x.query:如果业务用了 ORM,SQL 会被截断到 1024 字节,需要回代码里补全。

拓展思考

  1. 如何基于上述字段在 Log Explorer 写一条过滤语句,只输出过去 1 小时 victim 为 123457 的死锁
    答:

    resource.type="cloudsql_database"
    jsonPayload.errorCode="MY-012138"
    jsonPayload.deadlock.victim=123457
    timestamp >= "2024-06-01T07:15:30Z"
    
  2. 如果业务要求死锁超过 5 次/分钟就电话告警,但日志量太大,怎样避免误报?
    思路:用 Log-Based Metrics 聚合 jsonPayload.errorCode="MY-012138",按 resource.labels.database_id 分组,设置对齐时间窗口 60 秒、阈值 5,再叠加 Alert Policy 的 MQL 去抖参数(duration=120s)即可。

  3. 国内金融客户常问:“死锁日志里会不会泄露持卡人卡号?”
    标准回答:Cloud SQL 只记录当前持有和等待的索引记录主键值,如果主键是卡号明文就会泄露。解决方案:

    • 主键改用哈希或令牌化列
    • 通过 Log Router北京/上海区域的 Sink 里用 CEL 函数 replace() 做脱敏;
    • 开启 CMEK 让日志落地即加密,满足《个人金融信息保护技术规范》。
  4. 阿里云 RDS 死锁日志对比:

    • 阿里云仍用文本格式,需要正则解析;Cloud SQL 直接 JSON,BigQuery 一键直查
    • 阿里云日志延迟约 1–2 分钟,Cloud SQL 通过 Cloud Logging API 实时拉流,延迟 <10 秒,对高频交易场景更友好。