OpenTelemetry Learning
Protocols và backends

Zipkin

Dùng Zipkin compatibility có chủ đích: phân biệt B3 với export protocol, chuyển OTLP qua Collector và hiểu các giới hạn semantic.

Zipkin là một hệ thống distributed tracing đồng thời là tên của data model và HTTP API ingest lịch sử. OpenTelemetry Collector có thể chuyển spans OTLP sang Zipkin v2 để giữ một backend Zipkin hiện hữu. Đường này là một compatibility boundary — ranh giới tương thích — chứ không phải phép chuyển đổi bảo toàn đầy đủ OpenTelemetry.

Không dùng direct Zipkin exporter cho thiết kế mới

Tài liệu transformation của OpenTelemetry đã đánh dấu Zipkin SDK exporter là deprecated và dự kiến loại khỏi specification vào tháng 12 năm 2026. Với hệ thống còn cần Zipkin, ưu tiên OpenTelemetry SDK → OTLP → Collector → Zipkin exporter → Zipkin API v2, hoặc đánh giá module OTLP của Zipkin. Cách này cô lập conversion khỏi application và tạo một điểm migration rõ ràng.

Mục lục

Zipkin compatibility giải quyết bài toán gì

Compatibility hữu ích khi application đang chuyển sang OpenTelemetry nhưng tổ chức chưa thể thay backend Zipkin, storage, UI hoặc quy trình vận hành. Application phát OTLP chuẩn; chỉ Collector chịu trách nhiệm chuyển sang model Zipkin. Khi bỏ Zipkin, bạn thay exporter tại gateway thay vì sửa từng service.

Đừng dùng compatibility chỉ vì tên “Zipkin” quen thuộc. Nếu backend đích nhận OTLP native và bạn không có contract Zipkin bắt buộc, OTLP end-to-end giữ semantic OpenTelemetry tốt hơn và giảm một bước chuyển đổi.

Data model và API Zipkin v2

Một Zipkin span là object mô tả góc nhìn của một host về operation. Các field cốt lõi gồm:

Field ZipkinÝ nghĩa
traceIdID 64 hoặc 128 bit dùng chung cho toàn trace
idparentIdSpan ID 64 bit và vị trí trong cây trace
nameTên operation low-cardinality
kindCLIENT, SERVER, PRODUCER, CONSUMER hoặc không đặt
timestampdurationThời điểm bắt đầu và thời lượng, đơn vị microsecond
localEndpointService, IP và port đã ghi span
remoteEndpointPeer của RPC hoặc messaging operation nếu biết
annotationsCác mốc {timestamp, value} bên trong span
tagsMap phẳng từ string sang string để hiển thị và tìm kiếm

Endpoint trong Zipkin là network context, không phải URL ingest. Ví dụ localEndpoint.serviceName=checkout-api cho biết service ghi span; còn http://zipkin:9411/api/v2/spans là endpoint HTTP Collector dùng để gửi batch.

Zipkin v2 API quan trọng trong bài:

  • POST /api/v2/spans: upload một danh sách spans bằng JSON hoặc Protobuf;
  • GET /api/v2/services: liệt kê service names;
  • GET /api/v2/traces: tìm traces theo service, span name, tags, duration và time;
  • GET /api/v2/trace/{traceId}: lấy một trace cụ thể.

HTTP 202 Accepted từ POST /api/v2/spans nghĩa là Zipkin đã chấp nhận request. Nó không tạo bảo đảm exactly-once xuyên qua SDK, Collector, network và storage.

Trace backend không phải backend đa signal

Zipkin data model và API trên dành cho traces. Zipkin exporter của Collector cũng chỉ có stability cho trace signal. Metrics và logs phải đi qua pipeline và backend khác.

traces  ──► zipkin exporter ──► Zipkin
metrics ──► OTLP hoặc Prometheus exporter ──► metrics backend
logs    ──► OTLP exporter ──► log backend

Không thêm metrics hoặc logs pipeline vào zipkin exporter rồi mong Collector tự đổi signal. Collector sẽ từ chối cấu hình không tương thích hoặc signal không có đường xuất hợp lệ.

Pipeline OpenTelemetry đến Zipkin

Sơ đồ có hai loại traffic độc lập:

  1. Service A → Service Bpropagation trong request nghiệp vụ. Header giúp B biết remote parent.
  2. Service → Collector → Zipkinexport ngoài luồng request. Nó gửi spans đã hoàn tất tới nơi thu thập và lưu trữ.

Collector translator chuyển pdata — data model nội bộ của Collector — thành Zipkin v2 span. Sau bước này, các field chỉ tồn tại trong OpenTelemetry có thể bị làm phẳng, mã hóa vào string hoặc không còn là semantic field hạng nhất.

Propagation khác export protocol

Propagation format trả lời “trace ID, parent span ID và sampling state đi qua request nghiệp vụ như thế nào?”. Export protocol trả lời “batch spans đã ghi được gửi đến collector/backend như thế nào?”. Hai lựa chọn không ràng buộc nhau.

Propagation giữa servicesExport đến CollectorExport từ CollectorHợp lệ?
W3C traceparentOTLPZipkin v2Có; đây là pipeline migration phổ biến
B3 SingleOTLPOTLPCó; backend không quyết định header application
B3 MultiZipkin APIZipkin v2Có trong hệ thống legacy
W3C traceparentOTLPOTLPCó; lựa chọn phù hợp cho greenfield

Quy tắc nhớ nhanh

Header trên request nghiệp vụ không phải payload export. Thấy b3 không chứng minh spans được gửi bằng Zipkin API; thấy OTLP exporter cũng không chứng minh services đang propagate W3C đúng.

W3C Trace Context

OpenTelemetry mặc định phổ biến dùng W3C Trace Context với traceparenttracestate, cộng W3C Baggage nếu bật baggage. Ví dụ:

traceparent: 00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01

traceparent chứa version, trace ID 128 bit, parent ID 64 bit và trace flags. Receiver extract header trước khi tạo server span. Server span dùng ID trong header làm remote parent và tự tạo span ID mới.

Một cấu hình environment phổ biến là:

export OTEL_PROPAGATORS=tracecontext,baggage

Mức hỗ trợ environment variable và propagator package khác nhau theo ngôn ngữ. Luôn kiểm tra SDK đang dùng và startup diagnostics; đừng suy ra cấu hình có hiệu lực chỉ vì process không crash.

B3 Single và B3 Multi

B3 là propagation specification của hệ sinh thái Zipkin. Nó có hai encoding HTTP:

B3 Single dùng một header b3:

b3: 80f198ee56343ba864fe8b2a57d3eff7-e457b5a2e4d86bd1-1-05e3ac9a4f6e3b90

B3 Multi dùng nhiều header:

X-B3-TraceId: 80f198ee56343ba864fe8b2a57d3eff7
X-B3-SpanId: e457b5a2e4d86bd1
X-B3-ParentSpanId: 05e3ac9a4f6e3b90
X-B3-Sampled: 1

B3 cho phép trace ID 64 hoặc 128 bit và span ID 64 bit. Sampling state có thể là Defer, Deny, Accept hoặc Debug. Debug là trạng thái đặc thù B3; không nên giả định nó round-trip chính xác qua W3C trace flags.

Trong environment specification của OpenTelemetry, tên thường gặp là b3 cho B3 Single và b3multi cho B3 Multi:

# Chỉ dùng khi runtime có B3 propagator và contract downstream yêu cầu.
export OTEL_PROPAGATORS=tracecontext,baggage,b3

Bật composite như trên có thể inject cả W3C và B3. Nó làm header lớn hơn và tạo xung đột nếu hai format chứa IDs khác nhau. B3 specification quy định Single có precedence trước Multi khi cả hai B3 encoding xuất hiện, nhưng precedence giữa W3C và B3 phụ thuộc SDK/composite implementation. Phải integration-test runtime thực tế.

Chọn propagator trong migration

Dùng quy trình sau thay vì bật mọi format vô thời hạn:

1. Inventory từng boundary

Ghi lại service, proxy, mesh, SDK version và format hiện đang inject/extract. Capture headers trong test environment đã redact.

2. Chọn canonical format

Dùng W3C tracecontext,baggage cho traffic mới. Chỉ giữ B3 tại boundary có consumer legacy chưa đọc W3C.

3. Bật composite có thời hạn

Test cả request chỉ có W3C, chỉ có B3 và có hai format xung đột. Ghi rõ precedence mong đợi, owner và ngày gỡ B3.

4. Đo rồi loại bỏ format cũ

Theo dõi trace fragmentation và tỷ lệ request còn cần B3. Chuyển consumer trước, sau đó ngừng inject B3 và cuối cùng ngừng extract nếu không còn traffic legacy.

Propagation migration và backend migration có thể diễn ra độc lập. Bạn có thể chuyển toàn bộ services sang W3C hôm nay nhưng tiếp tục export Zipkin v2 ở Collector trong lúc backend chưa thay đổi.

Chuyển đổi semantic và giới hạn

Phần này mô tả ý nghĩa cần kỳ vọng, không cam kết mọi version translator tạo payload byte-for-byte giống nhau. OpenTelemetry Zipkin transformation specification đã deprecated và còn các mục từng được đánh dấu TBD. Collector translator tiếp tục có implementation riêng, feature gates và thay đổi theo semantic conventions.

Bảng ánh xạ chính

OpenTelemetryZipkin v2Điều cần nhớ
trace_id, span_id, parent_span_idtraceId, id, parentIdOTel dùng trace ID 128 bit và span ID 64 bit, phù hợp Zipkin v2
Span namenameGiữ tên low-cardinality; Zipkin chuẩn hóa span name về lowercase
CLIENT, SERVER, PRODUCER, CONSUMERkind tương ứngINTERNAL không có kind tương ứng và thường được bỏ kind
Start và end timestamp nanotimestampduration microsecondDuration được tính từ end trừ start; mất độ chính xác dưới microsecond
Resource service.namelocalEndpoint.serviceNameĐây là field chính để Zipkin group và tìm service
Resource, scope và span attributesChủ yếu thành tags stringPhạm vi và kiểu dữ liệu có thể bị làm phẳng
Span eventsannotationsAnnotation chỉ có timestamp và value; event attributes phải được encode vào text
Span statusCác tags như otel.status_codeerrorKhông còn nguyên status object của OTel
Peer semantic attributesremoteEndpoint khi translator suy ra đượcThiếu peer field có thể làm dependency graph không đầy đủ
TraceState và linksKhông có field Zipkin tương đương đầy đủCollector có thể dùng tags opaque; consumer Zipkin khác không hiểu semantic đó

service.namespace không được ghép tự động vào service name theo specification; nó thường còn là tag. Nếu cần tên duy nhất, chuẩn hóa service.name ở Resource trước conversion thay vì dựa vào UI ghép field.

Những chỗ chuyển đổi bị lossy

Lossy mapping là chuyển đổi không thể tái tạo chính xác dữ liệu nguồn. Các điểm quan trọng nhất của OTLP → Zipkin gồm:

  1. Kiểu attribute bị mất. Zipkin tags là string → string. Integer 3, boolean true, array và string có thể chỉ còn biểu diễn text. Query không còn chắc kiểu gốc.
  2. Ranh giới Resource, scope và span bị làm phẳng. Một số Resource fields trở thành endpoint; nhiều field còn lại đi vào tags. Consumer chỉ nhìn Zipkin có thể không biết field ban đầu thuộc Resource hay span.
  3. Độ chính xác thời gian giảm. OpenTelemetry timestamp dùng nanosecond; Zipkin v2 dùng microsecond nguyên. Operation cực ngắn và event sát nhau có thể cùng timestamp sau conversion.
  4. Event attributes không còn cấu trúc hạng nhất. Collector hiện có thể serialize tên, attributes và dropped count vào annotation value. Zipkin UI xem nó như text; query theo từng event attribute không tương đương query OTel.
  5. Links không có model tương đương. Collector hiện mã hóa links vào synthetic tags kiểu otlp.link.N. Đây là implementation detail để giữ thông tin đọc được, không biến link thành quan hệ trace native của Zipkin.
  6. TraceState không còn contract Zipkin hạng nhất. Nó có thể tồn tại dưới dạng tag opaque, nhưng Zipkin query hoặc exporter khác không bắt buộc diễn giải.
  7. Status và error bị thu gọn. Zipkin dựa nhiều vào error tag. Một mapping sai như gửi error=false vẫn có thể bị Zipkin hiểu là span lỗi theo convention.
  8. Shared-span semantics khác nhau. Một số tracer Zipkin/Brave legacy có mô hình client và server cùng góp vào shared span. OpenTelemetry thường tạo client và server spans riêng. Trộn hai mô hình có thể làm cây hoặc dependency count khác mong đợi.
  9. Chỉ traces đi qua. Metrics, logs, exemplars và correlation metadata ngoài span không có đích trong Zipkin exporter.

Round trip không phải phép đồng nhất

OTLP → Zipkin → OTLP không bảo đảm trả lại cùng Resource, scope, kiểu attribute, events, links, status hoặc timestamps ban đầu. Nếu một field là contract bắt buộc, hãy viết golden test qua đúng version Collector và backend, không chỉ kiểm tra “trace xuất hiện”.

Hệ quả khi truy vấn và round trip

Ví dụ OTel source:

{
  "resource": {"service.name": "checkout-api", "service.version": "1.4.0"},
  "span": {
    "name": "POST /checkout",
    "attributes": {
      "checkout.cart.items": 3,
      "checkout.expedited": true,
      "checkout.channels": ["web", "campaign"]
    }
  }
}

Sau conversion, Zipkin có thể biểu diễn tương đương về mặt hiển thị như:

{
  "name": "post /checkout",
  "localEndpoint": {"serviceName": "checkout-api"},
  "tags": {
    "service.version": "1.4.0",
    "checkout.cart.items": "3",
    "checkout.expedited": "true",
    "checkout.channels": "[\"web\",\"campaign\"]"
  }
}

Ba giá trị trong tags đều là string. Vì vậy, query số học theo checkout.cart.items hoặc phân biệt boolean với string không còn portable. Nói ngắn gọn: thiết kế query theo model Zipkin sau conversion, nhưng giữ source schema OpenTelemetry và test migration để không khóa application vào hạn chế đó.

Lab Collector đến Zipkin

Lab dùng Zipkin memory storage và OpenTelemetry Collector Contrib. Collector nhận OTLP từ host, chuyển traces sang Zipkin v2 JSON và gửi HTTP tới Zipkin.

Lab không phải production

Zipkin memory storage không bền vững và không phù hợp tải thực tế. Kết nối trong Compose là plaintext, không có authentication. Chỉ dùng để quan sát conversion và API v2 trên máy local.

Tạo file Compose

Lưu thành docker-compose.yaml:

services:
  zipkin:
    image: openzipkin/zipkin:3.6.1
    ports:
      - "9411:9411"

  collector:
    image: otel/opentelemetry-collector-contrib:0.157.0
    command:
      - "--config=/etc/otelcol-contrib/config.yaml"
    volumes:
      - ./collector-config.yaml:/etc/otelcol-contrib/config.yaml:ro
    depends_on:
      - zipkin
    ports:
      - "4317:4317"
      - "4318:4318"

Zipkin phục vụ UI, ingest và query API trên cùng port 9411. Application không gửi vào port đó trong lab; nó chỉ biết Collector 4317 hoặc 4318.

Tạo cấu hình Collector

Lưu file cạnh Compose với tên collector-config.yaml:

receivers:
  otlp:
    protocols:
      grpc:
        endpoint: 0.0.0.0:4317
      http:
        endpoint: 0.0.0.0:4318

processors:
  memory_limiter:
    check_interval: 1s
    limit_mib: 256
  batch:
    send_batch_size: 512
    timeout: 1s

exporters:
  debug:
    verbosity: basic
  zipkin:
    endpoint: http://zipkin:9411/api/v2/spans
    format: json
    default_service_name: unknown-service
    sending_queue:
      enabled: true
      queue_size: 2048
    retry_on_failure:
      enabled: true
      initial_interval: 1s
      max_interval: 10s
      max_elapsed_time: 1m

service:
  pipelines:
    traces:
      receivers: [otlp]
      processors: [memory_limiter, batch]
      exporters: [debug, zipkin]

format: json làm payload dễ inspect; exporter cũng hỗ trợ proto. Đổi format không loại bỏ semantic conversion vì cả hai serialization vẫn dùng Zipkin v2 data model.

default_service_name chỉ là fallback khi Resource thiếu service identity. Đừng dựa vào unknown-service trong production. Hãy bắt buộc service.name tại SDK hoặc policy Collector để search và ownership ổn định.

Khởi động stack

1. Render Compose

docker compose config

2. Khởi động containers

docker compose up -d
docker compose ps

3. Kiểm tra server và logs

curl --fail http://localhost:9411/health
curl --fail http://localhost:9411/info
docker compose logs --tail=100 collector
docker compose logs --tail=100 zipkin

/health chứng minh Zipkin process sẵn sàng. Nó chưa chứng minh một span đã đi qua translator và được storage chấp nhận.

Nếu Collector báo unknown type: zipkin, distribution đang chạy không chứa Zipkin exporter hoặc version/component ID không khớp. Kiểm tra components của binary/image; không chuyển conversion vào từng SDK để né lỗi distribution.

Gửi trace mẫu và xác minh

Gửi OTLP JSON

Ví dụ này gửi một server span có Resource, typed attributes và event. Sau khi conversion, bạn có thể so OTLP source với JSON Zipkin lấy từ query API.

trace_id="$(openssl rand -hex 16)"
span_id="$(openssl rand -hex 8)"
now_ns=$(( $(date +%s) * 1000000000 ))
start_ns=$(( now_ns - 500000000 ))
end_ns=$(( now_ns - 100000000 ))
event_ns=$(( start_ns + 250000000 ))

curl --fail-with-body --silent --show-error \
  -X POST \
  -H 'Content-Type: application/json' \
  --data-binary @- \
  http://localhost:4318/v1/traces <<JSON
{
  "resourceSpans": [{
    "resource": {
      "attributes": [
        {"key": "service.name", "value": {"stringValue": "zipkin-compat-demo"}},
        {"key": "service.version", "value": {"stringValue": "1.0.0"}},
        {"key": "deployment.environment.name", "value": {"stringValue": "local"}}
      ]
    },
    "scopeSpans": [{
      "scope": {"name": "zipkin-page-demo", "version": "1.0.0"},
      "spans": [{
        "traceId": "${trace_id}",
        "spanId": "${span_id}",
        "name": "POST /checkout",
        "kind": "SPAN_KIND_SERVER",
        "startTimeUnixNano": "${start_ns}",
        "endTimeUnixNano": "${end_ns}",
        "attributes": [
          {"key": "http.request.method", "value": {"stringValue": "POST"}},
          {"key": "http.route", "value": {"stringValue": "/checkout"}},
          {"key": "http.response.status_code", "value": {"intValue": "200"}},
          {"key": "checkout.cart.items", "value": {"intValue": "3"}},
          {"key": "checkout.expedited", "value": {"boolValue": true}},
          {"key": "checkout.channels", "value": {
            "arrayValue": {"values": [
              {"stringValue": "web"},
              {"stringValue": "campaign"}
            ]}
          }}
        ],
        "events": [{
          "timeUnixNano": "${event_ns}",
          "name": "cart.validated",
          "attributes": [
            {"key": "validation.rules", "value": {"intValue": "4"}}
          ]
        }],
        "status": {"code": "STATUS_CODE_OK"}
      }]
    }]
  }]
}
JSON

export TRACE_ID="${trace_id}"
printf 'TRACE_ID=%s\n' "${TRACE_ID}"

Collector receiver success mới là bằng chứng hop OTLP đầu tiên. Đợi batch flush khoảng một giây, rồi kiểm tra debug exporter và Zipkin.

Xác minh bằng UI

Mở Zipkin UI:

  1. chọn service zipkin-compat-demo;
  2. chọn span name post /checkout nếu cần; Zipkin chuẩn hóa tên operation về lowercase dù OTLP source dùng POST /checkout;
  3. giữ lookback bao phủ vài phút gần nhất;
  4. bấm Run Query rồi mở trace.

Kiểm tra duration khoảng 400 ms, HTTP attributes, event/annotation cart.validated và service version. Trong UI, typed values có thể nhìn giống dữ liệu gốc dù thực tế chúng đã là Zipkin tag strings. API ở bước sau cho thấy model đã lưu rõ hơn.

Xác minh bằng Zipkin API

Liệt kê service:

curl --fail --silent http://localhost:9411/api/v2/services | jq .

Lấy trace theo ID:

curl --fail --silent \
  "http://localhost:9411/api/v2/trace/${TRACE_ID:?hãy gửi trace trước}" \
  | jq .

Tìm trace theo service qua API:

curl --fail --silent --get \
  --data-urlencode 'serviceName=zipkin-compat-demo' \
  --data-urlencode 'spanName=post /checkout' \
  --data-urlencode 'lookback=3600000' \
  --data-urlencode 'limit=10' \
  http://localhost:9411/api/v2/traces \
  | jq .

Trong JSON trả về, xác nhận:

  • traceId bằng $TRACE_IDid dài 16 hex;
  • localEndpoint.serviceNamezipkin-compat-demo;
  • timestamp, duration và annotation timestamp dùng microsecond;
  • checkout.cart.items, checkout.expeditedcheckout.channels nằm trong tags dưới dạng string;
  • event trở thành một annotation với value chứa tên và dữ liệu đã serialize;
  • status và instrumentation scope xuất hiện theo tags của translator version.

API verification quan trọng hơn việc chỉ nhìn screenshot. Nó cho biết field nào thực sự được lưu và query contract nào consumer Zipkin nhận được.

Troubleshooting

Không có dữ liệu ở Zipkin

Đi theo thứ tự sau:

  1. curl /health của Zipkin có thành công không?
  2. OTLP request có thành công và debug exporter có thấy span không?
  3. Collector có log retry, 404, 415, timeout hoặc DNS failure không?
  4. Endpoint exporter có đúng tuyệt đối là /api/v2/spans không?
  5. Zipkin có tăng collector messages/spans và storage có drop không?
  6. Query time range có chứa timestamp của span không?
  7. service.name có bị thiếu hoặc đổi thành fallback không?
Triệu chứngNguyên nhân thường gặpCách xử lý
Collector nhận span, Zipkin trốngSai endpoint, backend chưa sẵn sàng hoặc storage lỗiKiểm tra exporter logs, Zipkin logs và /api/v2/spans
HTTP 404Dùng OTLP path /v1/traces ở phía ZipkinCollector → Zipkin phải dùng /api/v2/spans
HTTP 415 hoặc decode errorformat không khớp Content-Type/payloadĐể exporter tạo request; chọn json hoặc proto được hỗ trợ
UI không có serviceThiếu service.name hoặc query lookback quá hẹpInspect Resource ở debug và gọi /api/v2/services
API theo ID có trace, search không cóSearch/index bị tắt, chậm hoặc field service saiKiểm tra SEARCH_ENABLED, storage index và local endpoint
unknown type: zipkinCollector distribution thiếu exporterDùng distribution có component hoặc build custom distribution

Zipkin exporter gửi batch HTTP. Một response ingest thành công không chứng minh UI index đã cập nhật tức thì; dùng trace-by-ID để tách lỗi write khỏi lỗi search.

Trace bị đứt giữa các service

Nếu mỗi service tạo một trace riêng, đừng chỉnh Zipkin exporter trước. Exporter chỉ chuyển spans đã record; nó không nối lại parent relation bị mất.

Kiểm tra bốn điểm:

  • sender có inject traceparent hoặc B3 sau khi outgoing span active không;
  • proxy/mesh có giữ header không;
  • receiver có extract đúng format trước khi tạo server span không;
  • khi có cả W3C và B3, hai format có cùng trace/parent IDs và precedence đã test không.

Nếu B3 sender gọi W3C-only receiver, dùng composite propagator tại boundary trong thời gian migration. Không bật B3 ở Collector exporter để sửa propagation; exporter không nằm trên request nghiệp vụ.

Sampling mismatch cũng có thể tạo trace rời rạc. B3 Debug, B3 Defer và W3C sampled flag không có mapping một-một. Chọn sampler ownership, test quyết định qua từng hop và không dùng trace headers làm authentication.

Tags và topology không như mong đợi

Khi tag đổi kiểu hoặc không query được, so payload ở ba điểm:

OTLP source → Collector debug/pdata → GET Zipkin /api/v2/trace/{traceId}

Một integer trở thành string là giới hạn model dự kiến, không phải lỗi JSON. Một link thành synthetic tag cũng không tạo edge trong trace tree. Nếu business logic phụ thuộc typed field hoặc link, Zipkin compatibility không phải contract phù hợp.

Dependency graph cần CLIENT/PRODUCER span cùng remote endpoint hoặc cặp spans mà Zipkin có thể suy ra. Đặt semantic attributes peer/server đúng theo version instrumentation. service.name phải nhất quán trên các spans cùng local service. Với storage production, Zipkin có thể cần zipkin-dependencies job để tổng hợp service links; UI trống không nhất thiết nghĩa traces không tồn tại.

Nếu event attributes xuất hiện trong annotation text, đó là conversion dự kiến. Đừng tạo một tag cardinality cao cho từng event chỉ để làm UI dễ lọc; cân nhắc giữ backend OTLP nếu event query có cấu trúc là yêu cầu.

HTTP, TLS và queue

Zipkin exporter dùng HTTP client. Các lỗi thường gặp:

  • DNS zipkin chỉ tồn tại trong Compose network; từ host phải dùng localhost;
  • endpoint https://... yêu cầu CA và hostname certificate đúng;
  • proxy có thể giới hạn body size và trả 413 khi batch quá lớn;
  • 401/403 thường do reverse proxy hoặc gateway authentication, không do data model Zipkin;
  • timeout có thể xảy ra sau khi backend đã nhận, sau đó retry gây duplicate;
  • queue đầy làm Collector từ chối enqueue; retry không cứu record chưa vào queue.

Tune send_batch_size, queue, timeout và retry bằng load test. Giảm batch nếu proxy giới hạn body, nhưng đừng giảm mù quáng tới mức tạo quá nhiều request. Với outage cần chịu qua restart, dùng persistent queue và volume bền vững của Collector; memory queue trong lab mất khi process dừng.

Theo dõi cả hai phía:

  • Collector accepted/refused spans, send failed, enqueue failed và queue size;
  • Zipkin /metrics hoặc /prometheus, đặc biệt messages/spans received và dropped;
  • storage write latency/error, disk, index và query latency.

Khi nào nên dùng Zipkin compatibility

Tình huốngQuyết định
Đang migrate instrumentation sang OTel nhưng phải giữ Zipkin UI/storageDùng Collector Zipkin exporter làm boundary tạm thời
Vendor hoặc platform nội bộ chỉ nhận Zipkin v2 APIDùng có kiểm thử, ghi rõ field bắt buộc và loss budget
Cần chạy song song backend cũ và mới trong migrationCó thể dùng fan-out Zipkin + OTLP, nhưng theo dõi partial failure riêng
Hệ thống greenfield và backend nhận OTLP nativeKhông nên dùng Zipkin conversion
Cần metrics, logs hoặc full-fidelity links, typed attributes và TraceStateKhông phù hợp; chọn backend/đường OTLP bảo toàn signal
Chỉ bật B3 vì backend là ZipkinKhông cần thiết; propagation độc lập với export
Muốn direct Zipkin exporter trong mọi SDK mớiTránh; exporter spec đã deprecated, đưa conversion vào Collector

Compatibility phải có ngày kết thúc

Ghi owner, trường semantic chấp nhận mất, golden tests, traffic còn phụ thuộc, rollback plan và tiêu chí gỡ exporter. Một adapter không có exit plan sẽ trở thành protocol mặc định ngoài ý muốn.

Một migration an toàn có thể fan-out cùng trace từ Collector tới Zipkin và backend OTLP mới. Hai exporter có queue/retry độc lập; một bên thành công không rollback bên còn lại. So trace count, parent tree, status, events và field bắt buộc trong một cửa sổ canary trước khi chuyển query/dashboard.

Ghi chú production

Zipkin image mặc định dùng memory storage để quickstart. Production cần:

  • external storage được version Zipkin hỗ trợ, thường là Elasticsearch/OpenSearch hoặc Cassandra theo deployment và capacity plan;
  • retention, shards/replicas, backup, restore và index lifecycle đã test;
  • zipkin-dependencies hoặc cơ chế tương ứng để tạo dependency links khi storage yêu cầu;
  • authentication/authorization và TLS tại gateway hoặc trust boundary phù hợp;
  • network policy chặn public access trực tiếp tới ingest, query và management API;
  • queue/retry có giới hạn ở Collector cùng persistent storage nếu outage budget yêu cầu;
  • resource, batch size, payload limit và rate limit được load-test;
  • pin version Collector/Zipkin và chạy golden conversion tests khi nâng cấp;
  • theo dõi feature gates của Zipkin translator vì semantic convention cũ/mới có thể làm tag đổi tên hoặc xuất hiện đồng thời;
  • data governance cho tags và annotations: redact secret, token, PII và payload nghiệp vụ trước conversion;
  • dashboard riêng cho Collector export failures, Zipkin dropped spans, storage writes, query latency và JVM health;
  • canary trace kiểm tra ID, parent, service, error, event, typed attribute và remote endpoint sau mỗi deploy.

Zipkin tags thường được index hoặc dùng để search tùy storage. Cardinality cao làm tăng chi phí và giảm hiệu năng. Dùng route template, operation name ổn định và allowlist business tags. Không đưa UUID động vào span name.

Nếu mục tiêu dài hạn là OpenTelemetry native, đánh giá module zipkin-otel của Zipkin hoặc backend OTLP khác. Ngay cả khi Zipkin nhận OTLP qua module, vẫn phải kiểm tra storage/query model có bảo toàn các field cần thiết; “nhận OTLP” không tự động đồng nghĩa full-fidelity end-to-end.

Nguồn chính thức và bài liên quan

Nguồn chính được dùng cho API, B3 và conversion trong bài:

On this page