ข้ามไปยังเนื้อหา

Metadata

request และ response message ถือข้อมูล domain ของคุณ — user, order แต่ข้อมูลบางอย่างเป็นเรื่อง เกี่ยวกับตัว call เอง: ใครเป็นคนเรียก, call นี้อยู่ใน trace ไหน, จะ log ด้วย request id อะไร ถ้าเอาพวกนี้ยัดเข้าไปในทุก message จะทำให้ schema รก gRPC ให้ช่องแยกต่างหาก: metadata

metadata คือชุดของคู่ key/value ที่ส่งไปพร้อม call เหมือน HTTP header เป๊ะ — ซึ่งจริง ๆ แล้วก็กลายเป็น header บน HTTP/2 wire นั่นเอง

metadata มาในสองตำแหน่ง:

  • header เดินทาง ก่อน message ตอนเริ่ม call ที่นี่คือที่ที่ client ใส่ auth token หรือ trace id — อะไรก็ตามที่ server ต้องรู้ตั้งแต่ต้น
  • trailer เดินทาง หลัง response ตอนจบ call ที่นี่คือที่ที่ server ใส่ข้อมูลที่รู้ก็ต่อเมื่อทำงานเสร็จแล้ว — เช่น รายละเอียด status สุดท้ายหรือ metrics ฝั่ง server response แบบ streaming พึ่ง trailer เป็นพิเศษ เพราะ status รู้ได้ก็หลัง message สุดท้ายเท่านั้น
flowchart LR
  client["client"] -->|"headers: authorization, x-trace-id"| server["server"]
  server -->|"response message(s)"| client
  server -->|"trailers: final status, metrics"| client
ตำแหน่งของ header และ trailer ใน call

client ตั้ง header ก่อน call; server อ่าน header เหล่านั้น และส่ง header กับ trailer กลับได้

// Client: attach metadata to the outgoing call.
ctx := metadata.AppendToOutgoingContext(ctx,
"authorization", "Bearer "+token,
"x-request-id", reqID,
)
resp, err := client.GetUser(ctx, req)
// Server: read incoming metadata.
md, _ := metadata.FromIncomingContext(ctx)
reqID := md.Get("x-request-id")
  • key เป็นตัวพิมพ์เล็ก gRPC normalize key ของ metadata เป็น lowercase ASCII; ให้ปฏิบัติแบบ case-insensitive
  • value แบบ binary ใช้ suffix -bin key ที่ลงท้ายด้วย -bin (เช่น trace-context-bin) ถูกมองเป็น raw bytes และ base64-encode บน wire ส่วนอย่างอื่นต้องเป็น ASCII string ที่ถูกต้อง
  • อย่าใช้ key ที่สงวนไว้ซ้ำ key ที่ขึ้นต้นด้วย grpc- ถูกสงวนโดย framework — อย่าตั้งเอง
  • metadata ไม่ได้เข้ารหัสในตัวเอง — ความเป็นส่วนตัวมาจาก TLS บน channel token ใน metadata บน channel ที่ insecure ถือว่าเปิดเผย

metadata คือวิธีที่ context ไหลผ่าน chain ของ service เมื่อ service A เรียก B ที่เรียก C คุณมักจะ propagate trace id และ request id: แต่ละ hop อ่าน metadata ขาเข้าและ copy key ที่เกี่ยวข้องไปยัง call ขาออก ปกติทำใน interceptor เพื่อไม่ให้ handler ต้องจำ นั่นคือวิธีที่ distributed trace ยังเชื่อมกันได้ข้าม gRPC หลาย hop

metadata ใน gRPC ใช้ทำอะไร?
ความต่างระหว่าง header กับ trailer คืออะไร?
key ของ metadata ที่ลงท้ายด้วย `-bin` หมายความว่าอะไร?
trace id ยังต่อกันได้ข้าม A → B → C ได้ยังไง?