Access Hub Collector
Đồng bộ từ mã nguồn lúc 15:42, 03/10/2026
Skip to content

L3 - Nền tảng giám sát máy chủ - Collector - Ingest API ​

Quy ước tên: L3 - <P&L> - <Hệ thống L2> - <Thành phần>. P&L: chưa chỉ định. Hệ thống L2: Collector. Thành phần: Ingest API (giao diện HTTP dành cho agent, internal/ingest).

Trạng thái
Bản nháp
Phiên bản
0.1, ngày 30/09/2026
Tài liệu cha
L2 SAD Collector
Cấp độ hệ thống
Cấp 3, đề xuất

Ghi chú: khi tài liệu và mã khác nhau, mã thắng

Đã làm nghĩa là có mã và kiểm thử trong repo. Chỉ thiết kế nghĩa là có trong tài liệu nhưng chưa có mã. Chỗ lệch được ghi ở mục nợ kỹ thuật.

Quy ước đánh dấu: "Đã làm" là có mã và kiểm thử. "Chỉ thiết kế" là chỉ có trong docs/. "Đề xuất" là ý của tác giả bản nháp. Đường dẫn tương đối với gốc repo access-hub-collector. Khi tài liệu thiết kế và mã khác nhau, mã thắng.


0. Front matter ​

Thông tin tài liệu đầy đủ
Trạng tháiBẢN NHÁP, phiên bản 0.1, 2026-09-30. Người phê duyệt: chưa chỉ định
Thành phần (Component)Ingest API: các điểm cuối /agent/v1/*, kiểm tra header, xác thực Bearer, giải nén, kiểm tra và làm sạch số liệu, giới hạn tốc độ, đẩy lô lên bus, chuyển tiếp kiểm kê
Truy vết L2L2 SAD Collector: thành phần "Ingest API" (mục 2.3, 6.1), FR 1, 3, 6, 7 (mục 3), NFR 1, 2, 8, 9 (mục 4), rủi ro AR-004 (mục 16). Mục tiêu L1: G1, G4, G5 (qua L2)
Tài liệu chaL2 SAD Collector
Tài liệu anh emRegistry, Enroll, Bus, Worker, TSDB
TierĐề xuất Cấp 3 (kế thừa L2, chưa xác nhận)
Phân loại dữ liệu (Data classification)Nội bộ (Internal). Bearer token là bí mật: không lưu rõ, không log
Blast radiusIngest chết: agent không gửi được, tự đệm WAL trên đĩa và gửi bù. Một node chết: LB chuyển sang node còn lại. Lỗi kiểm tra sai có thể làm mất mẫu của mọi tenant trên node đó
Sign-off gateChưa chỉ định. Không có ai đã sign-off

Truy vết mục L3 đến thành phần L2:

Mục L3Thành phần hoặc mục L2
1 Phạm vi2.3 Các thành phần chính (Ingest API)
2 Yêu cầu3 Functional, 4 NFR
3 Kiến trúc6.1 Component table
5 Hợp đồng API6.2 Integration table (Agent đến Ingest)
7 Thuật toán8.1 Business flow (enroll, ingest)
8, 9 Lỗi và suy thoái6.3 Resilience, 12.2 Reliability
11 Bảo mật9 Security
12 Cấu hình10 Deployment
13 Telemetry13 Observability
14, 15 Kiểm thử, lộ trình15 Testing

1. Scope and Non-Goals ​

1.1 Vai trò ​

Ingest API là điểm vào duy nhất của agent. Nó không tin nội dung agent: danh tính (công ty, máy chủ) lấy từ registry theo băm token, số liệu phải nằm trong danh mục và nhãn cho phép. Nó không ghi TSDB (việc của worker) và không quyết định trạng thái agent (việc của Access Hub).

1.2 Context diagram ​

mermaid
flowchart LR
    classDef bc fill:#1f3a5f,stroke:#4a90d9,color:#fff;
    classDef owned fill:#2d4a3e,stroke:#5fb37a,color:#fff;
    classDef entity fill:#3a3320,stroke:#d9b84a,color:#fff;
    classDef datastore fill:#3a2d4a,stroke:#a06fd9,color:#fff;

    AG(["Agent (ext)"]):::entity
    HUB(["Access Hub (ext)"]):::entity
    ING["Ingest API"]:::bc
    RG["Registry"]:::owned
    PS["Presence"]:::owned
    BUS[["Bus"]]:::datastore

    AG -->|"đẩy số liệu, enroll"| ING
    ING -->|"tra danh tính"| RG
    ING -->|"chuyển tiếp enroll, kiểm kê"| HUB
    ING -->|"cập nhật lần thấy cuối"| PS
    ING -.->|"lô mẫu theo shard"| BUS
ChiềuBênNội dung
VàoAgentGET /agent/v1/ping, POST /agent/v1/enroll, POST /agent/v1/metrics, GET /agent/v1/config, POST /agent/v1/inventory, POST /agent/v1/credentials/renew (stub)
RaRegistry, ResolverTra danh tính theo băm token, ghi agent sau enroll (L3 Registry)
RaAccess HubChuyển tiếp enroll (timeout 20 giây), lô kiểm kê
RaPresenceTouch sau khi publish, gọi OnAgentUp khi agent vừa hết down
RaBusPublish lô đã chuẩn hóa (L3 Bus)

1.3 Trong phạm vi ​

  • Kiểm tra X-AH-Proto, X-AH-Agent-Version, Content-Type, Content-Encoding, kích thước.
  • Xác thực Bearer, ánh xạ lỗi xác thực sang mã HTTP.
  • Kiểm tra số liệu theo danh mục (internal/catalog), làm sạch nhãn, giới hạn series, cửa sổ thời gian.
  • Giới hạn tốc độ theo agent và theo IP.
  • Cấu hình mặc định và ETag cho agent, kiểm kê có khử trùng, chuyển tiếp lô kiểm kê.

1.4 Ngoài phạm vi ​

Nội dungKhông thuộc BCThuộc về
Ghi TSDB, gom lôCóL3 Bus, Worker, TSDB
Lưu và đồng bộ danh tính agent, tra ngược Access HubCóL3 Registry, Enroll
Xác thực License, tạo agent, ràng buộc máy chủCóAccess Hub (HUB-*)
Phát hiện mất tín hiệu, sự kiệnCóL3 Alerting, Outbox
Cấu hình agent theo máy, ConfigFor thực tếCóChưa làm (luật ngưỡng đã xong ở COL-8, nằm trong worker)
Xoay token (credentials/renew)CóChưa làm, hiện stub 503
Kết thúc TLS, cân tảiCóLoad balancer (nginx ở dev)

2. Requirements ​

2.1 Functional Requirements ​

#Trách nhiệmGiải thíchHiện thực ở
FR-ING-01PingTrả server_time_ms, proto_min, proto_max (đều 1), không cần xác thực, không kiểm tra headerinternal/ingest/handlers.go, TestPingNeedsNoAuthOrHeaders
FR-ING-02Kiểm tra giao thứcX-AH-Proto phải là "1" (thiếu 400, khác 426 upgrade_required); X-AH-Agent-Version khớp ^[0-9A-Za-z][0-9A-Za-z.+_-]{0,63}$internal/ingest/http.go, TestHeaderChecks
FR-ING-03Xác thực BearerToken tối đa 256 ký tự, băm SHA-256, tra registry; ánh xạ lỗi (mục 5.3)internal/ingest/http.go, TestAuth, TestRevokedAgentGets403, TestHubDownGives503NotUnauthorized
FR-ING-04Nhận số liệuGiải nén, kiểm tra, làm sạch, gắn danh tính từ registry, publish bus, trả ackinternal/ingest/handlers.go, TestMetricsAcceptedAndTenantIdentityFromRegistry
FR-ING-05Chống giả mạo danh tínhBỏ nhãn company_id, server_id, agent_id do agent gửi và đếmTestReservedLabelsAreStripped
FR-ING-06Giới hạn series mỗi agentChấp nhận series mới đến max_series trong cửa sổ trượtinternal/ingest/series.go, TestSeriesLimitPerAgent, TestForgetAgentReleasesSeriesBudget
FR-ING-07Thống kê agentChuyển AgentStats thành series agent_*, không bị giới hạn seriesinternal/ingest/handlers.go
FR-ING-08Cấu hình agentTrả mặc định, ETag, 304 với If-None-Matchinternal/ingest/agentconfig.go, TestConfigETag
FR-ING-09Kiểm kêNhận, trả 202, khử trùng 1 giờ, chuyển tiếp lôinternal/ingest/inventory.go, TestInventoryForwardedAndDeduped
FR-ING-10Enroll proxyChuyển tiếp sang Access Hub, ánh xạ lỗi, lưu agent vào registryinternal/ingest/handlers.go, TestEnrollProxy, TestEnrollErrors (chi tiết ở L3 Registry)
FR-ING-11Giới hạn tốc độTheo agent (metrics, config, inventory) và theo IP (enroll)internal/ratelimit, TestMetricsRateLimit, TestConfigRateLimit, TestEnrollRateLimitPerIP
FR-ING-12Cấp lại tokenStub: 503 unavailable, Retry-After: 300TestRenewIsAStub (chưa làm)

2.2 Non-Functional Requirements ​

Allocated (phân bổ từ L2):

NFR L2TargetCách đáp ứng ở L3
NFR-01 sức chứa10.000 agent, p99 không quá 250 msXử lý không trạng thái, giới hạn giải nén, publish không chặn. Chưa đo
NFR-11 TLS1.2 trở lênKhi bật TLS tự quản: MinVersion TLS 1.2
NFR-12 cô lập tenantKhông lẫn tenantDanh tính từ registry, TestTwoTenantsNeverMix
NFR-15 quan sátMetric, log có request_idMục 13

Inherited (kế thừa nền chung, không định nghĩa lại ở đây): timeout máy chủ (ReadHeaderTimeout 10s, ReadTimeout 30s, WriteTimeout 30s, IdleTimeout 120s, MaxHeaderBytes 64 KiB) từ internal/httpx và internal/app.

Owned (do thành phần này sở hữu):

IDTargetParent L2-NFRSatisfied-by
NFR-ING-01Body nén tối đa 1 MiB (max_body_bytes), giải nén tối đa 8 MiB, tối đa 20.000 điểm và 500 series mỗi requestNFR-01, NFR-12internal/ingest/decode.go, TestBodyLimits
NFR-ING-02Từ chối có kiểm soát: bus đầy thì 503 kèm Retry-After: 5, Access Hub tạm mất thì 503 kèm Retry-After: 30NFR-08TestBusFullGives503WithRetryAfter, TestHubDownGives503NotUnauthorized
NFR-ING-03Handler panic được bắt và trả 500, không sập tiến trìnhNFR-02internal/ingest/http.go
NFR-ING-04Không log token, AuthorizationNFR-11Xem mục 11

2.3 Acceptance Criteria ​

ACGiven / When / ThenTest ID
AC-ING-01Given agent hợp lệ, When gửi metrics đúng danh mục, Then 200 kèm ack và mẫu đến bus với company_id, server_id từ registryTestMetricsAcceptedAndTenantIdentityFromRegistry
AC-ING-02Given agent gửi nhãn company_id, When nhận, Then nhãn bị bỏ và đếmTestReservedLabelsAreStripped
AC-ING-03Given token đã thu hồi, When gửi metrics, Then 403 agent_revokedTestRevokedAgentGets403
AC-ING-04Given Access Hub không truy cập được và token chưa cache, When gửi metrics, Then 503 chứ không 401TestHubDownGives503NotUnauthorized
AC-ING-05Given bus đầy, When gửi metrics, Then 503 Retry-After: 5TestBusFullGives503WithRetryAfter
AC-ING-06Given body vượt giới hạn nén hoặc giải nén, When gửi, Then 413 too_largeTestBodyLimits
AC-ING-07Given hai tenant, When cả hai gửi, Then dữ liệu không lẫnTestTwoTenantsNeverMix
AC-ING-08Given X-AH-Proto khác 1, When gọi, Then 426 upgrade_requiredTestHeaderChecks
AC-ING-09Given If-None-Match trùng ETag, When lấy config, Then 304TestConfigETag

2.4 Quality Attribute Scenarios ​

NguồnKích thíchMôi trườngPhản hồiThước đo
AgentGửi lô 30 giây một lầnTải bình thườngTrả ack, mẫu vào busp99 không quá 250 ms (mục tiêu NFR-01, chưa đo)
Agent bị hỏngGửi nhãn company_id giảBất kỳBỏ nhãn, danh tính giữ nguyên0 mẫu sai tenant
Bus đầyNhiều agent gửiTSDB chậm503 kèm Retry-After: 5, không mất mẫu đã ackKhông có mẫu ack rồi mất do ingest
Access Hub tạm mấtToken mới chưa cacheSự cố Access Hub503 kèm Retry-After: 30, agent tự thử lại0 phản hồi 401 sai
Kẻ tấn côngBom giải nén (gzip, zstd)Bất kỳ413 sau khi chạm trần giải nénBộ nhớ cấp phát không quá 8 MiB mỗi request

3. Application Architecture ​

3.1 Kiến trúc thời chạy (C&C) ​

mermaid
flowchart LR
    classDef bc fill:#1f3a5f,stroke:#4a90d9,color:#fff;
    classDef owned fill:#2d4a3e,stroke:#5fb37a,color:#fff;
    classDef datastore fill:#3a2d4a,stroke:#a06fd9,color:#fff;

    RT["Router và middleware"]:::bc
    AU["Xác thực Bearer"]:::bc
    DC["Giải nén và kiểm tra"]:::bc
    SL["Bộ giới hạn series"]:::bc
    RL["Bộ giới hạn tốc độ"]:::owned
    RG["Resolver"]:::owned
    PS["Presence"]:::owned
    BUS[["Bus"]]:::datastore
    INV["Forwarder kiểm kê"]:::bc

    RT --> AU
    AU --> RG
    RT --> RL
    RT --> DC
    DC --> SL
    DC --> PS
    DC -.-> BUS
    RT --> INV

Mũi tên chỉ chiều khởi tạo lời gọi. Ingest là bên gọi Registry, Presence và Bus.

Thành phầnTrách nhiệmVòng đời
Router và middlewareĐịnh tuyến /agent/v1, header, X-Request-Id, bắt panic, Cache-Control: no-store, X-Content-Type-Options: nosniffTheo tiến trình
Xác thực BearerCắt token, băm, gọi Resolver, ánh xạ lỗiTheo request
Giải nén và kiểm traChọn decoder (identity, gzip, zstd, có pool), giới hạn kích thước, kiểm tra danh mụcTheo request
Bộ giới hạn seriesĐếm series mới mỗi agent trong cửa sổ trượt, khóa FNV-64, dọn mỗi 5 phútTheo tiến trình, trong bộ nhớ
Bộ giới hạn tốc độToken bucket 16 shard, tối đa 65.536 khóa mỗi shard, dọn khóa rảnh 10 phút, quét 1 phútTheo tiến trình, trong bộ nhớ
Forwarder kiểm kêGiữ báo cáo mới nhất mỗi agent, gửi lô 100, tick 2 giâyTheo tiến trình
Kết nốiKiểuChi tiết
Ingest đến ResolverĐồng bộ, trong tiến trìnhLookup(hash) trả AgentRecord hoặc lỗi
Ingest đến BusBất đồng bộ (không chặn)Publish(shard, batch); đầy hoặc đóng thì ErrFull rồi 503
Ingest đến Access HubĐồng bộChỉ enroll (20 giây) và forwarder kiểm kê
Ingest đến PresenceĐồng bộTouch sau publish thành công

3.2 Module view ​

mermaid
flowchart TB
    classDef bc fill:#1f3a5f,stroke:#4a90d9,color:#fff;
    classDef owned fill:#2d4a3e,stroke:#5fb37a,color:#fff;

    APP["internal/app (wiring)"]:::bc
    ING["internal/ingest"]:::bc
    CAT["internal/catalog"]:::owned
    RGS["internal/registry"]:::owned
    PRE["internal/presence"]:::owned
    BUSP["internal/bus"]:::owned
    RLP["internal/ratelimit"]:::owned
    MET["internal/metrics"]:::owned
    HX["internal/httpx"]:::owned
    HC["internal/hubclient"]:::owned

    APP --> ING
    ING --> CAT
    ING --> RGS
    ING --> PRE
    ING --> BUSP
    ING --> RLP
    ING --> MET
    ING --> HX
    ING --> HC

Tệp trong internal/ingest: http.go (router, xác thực, header), handlers.go (ping, enroll, metrics, config, renew), decode.go (giải nén), series.go (giới hạn series), agentconfig.go (cấu hình mặc định, ETag), inventory.go (khử trùng, forwarder), ingest.go (tùy chọn và khởi tạo).


4. Domain Model ​

mermaid
classDiagram
    class MetricsBatch {
        <<wire>>
        seq
        sent_at_ms
        series
        stats
    }
    class Series {
        <<wire>>
        name
        labels
        points
    }
    class Point {
        <<wire>>
        ts_ms
        value
    }
    class AgentStats {
        <<wire>>
        cpu_percent
        rss_bytes
    }
    class SampleBatch {
        <<internal>>
        company_id
        server_id
        agent_id
        received_ms
        series
    }
    class AgentRecord {
        <<registry>>
        agent_id
        company_id
        server_id
        state
    }
    MetricsBatch "1" --> "*" Series
    Series "1" --> "*" Point
    MetricsBatch "1" --> "0..1" AgentStats
    AgentRecord "1" --> "*" SampleBatch : gắn danh tính
    MetricsBatch ..> SampleBatch : chuẩn hóa

Các thông điệp wire khớp docs/03-protocol.md. Tệp proto/accesshub/agent/v1/agent.proto là bản nháp (TD-009 của L2). SampleBatch là kiểu nội bộ của internal/bus; định dạng dây Redis: c (company), s (server), a (agent), r (received), d[n,l,p] (tên, nhãn, điểm).


5. API Contract ​

5.1 Operations ​

Tiền tố /agent/v1. Mọi điểm cuối trừ ping yêu cầu X-AH-Proto: 1 và X-AH-Agent-Version.

MethodPathXác thựcMô tảThành công
GET/pingKhôngKiểm tra sống và lệch đồng hồ200
POST/enrollKhông (License trong body)Đổi License lấy agent token200
POST/metricsBearerGửi lô số liệu200 kèm ack
GET/configBearerLấy cấu hình, hỗ trợ ETag200 hoặc 304
POST/inventoryBearerGửi báo cáo kiểm kê202
POST/credentials/renewBearerCấp lại token (chưa làm)503 unavailable, Retry-After: 300

Content-Type: application/x-protobuf. application/json chỉ được chấp nhận khi ingest.accept_json bật. Content-Encoding: identity, gzip hoặc zstd.

5.2 Request và Response schema ​

Ký hiệu: ! bắt buộc, ? tùy chọn.

POST /metrics

Request (MetricsBatch):
  seq!: uint64
  sent_at_ms!: int64
  series![]: { name!: string, labels?: map<string,string>, points![]: { ts_ms!: int64, value!: double } }
  stats?: AgentStats
Response 200 (MetricsAck):
  server_time_ms!: int64
  ack_seq!: uint64
  config_etag!: string
  accepted_points!: uint32
  dropped_points!: uint32
  warnings?: string[]   # tối đa 10 mục, mỗi mục tối đa 160 ký tự
Errors: 400 bad_request, 401 unauthorized, 403 agent_revoked, 413 too_large,
        426 upgrade_required, 429 rate_limited, 503 unavailable

POST /enroll

Request (EnrollRequest):
  license!: string (tối đa 256)
  hostname!: string (tối đa 253)
  machine_id!: string (tối đa 128, băm SHA-256)
  ip_addresses?: string[] (tối đa 32)
  os?: { family, name, version, kernel, arch } (mỗi trường tối đa 128)
  agent_version?: string
Response 200 (EnrollResponse):
  agent_id!, agent_token!, collector_url!, config!, server_time_ms!
Errors: 400 bad_request, 401 unauthorized, 409 already_enrolled | token_used,
        422 binding_failed, 429 rate_limited (Retry-After 60), 503 unavailable

GET /config: If-None-Match? gửi ETag. Response 200 (AgentConfig) hoặc 304. ETag là 8 byte đầu của SHA-256 trên bản mã hóa protobuf xác định, dạng hex.

POST /inventory (InventoryFacts): 202, không nội dung. Trùng nội dung trong 1 giờ vẫn trả 202 nhưng không chuyển tiếp lại.

Định dạng lỗi (mọi điểm cuối): đối tượng ErrorResponse { code, message, retry_after_seconds }, kèm header Retry-After khi có.

5.3 Error codes ​

MãHTTPÝ nghĩaGhi chú
bad_request400Header, body, trường saiX-AH-Proto thiếu cũng 400
unauthorized401Token không tìm thấy, hết hạn, ở trạng thái pendingAgent phải enroll lại
agent_revoked403Token thuộc agent đã thu hồiAgent dừng gửi
already_enrolled409Máy đã enrollTừ Access Hub
token_used409License đã dùngTừ Access Hub
too_large413Vượt max_body_bytes, max_decoded_bytes, max_points hoặc max_series
binding_failed422Ràng buộc máy chủ thất bạiTừ Access Hub
upgrade_required426X-AH-Proto khác "1"
rate_limited429Vượt tốc độKèm Retry-After
server_error500, 503Lỗi nội bộ hoặc lỗi không phân loại từ registryHandler panic thành 500
unavailable503Bus đầy hoặc đóng, Access Hub tạm mất, renew stubRetry-After 5, 30 hoặc 300 giây
not_found404Đường dẫn không cóĐịnh dạng JSON
method_not_allowed405Sai methodĐịnh dạng JSON

Kiểm thử: TestRoutingErrorsAreJSON.

5.4 Versioning ​

Phiên bản giao thức nằm ở header X-AH-Proto. Hiện chỉ có phiên bản 1 (proto_min 1, proto_max 1 từ ping). Mục tiêu N và N-1 (NFR-14) chưa có cơ chế thực tế vì chưa có N+1. Quy tắc đề xuất: thêm trường protobuf là tương thích ngược, đổi nghĩa hoặc xóa trường thì tăng X-AH-Proto. Cấu hình mẫu buf breaking chưa có (TD-012 của L2).

5.5 Authz ​

Điểm cuốiCơ chếVai
ping, enrollKhông Bearer. enroll bị giới hạn theo IPẨn danh
metrics, config, inventory, credentials/renewBearer token agentAgent, danh tính từ registry
Chủ thểpingenrollmetricsconfiginventoryrenew
Ẩn danhCóCó (giới hạn IP)KhôngKhôngKhôngKhông
Agent hợp lệCóCóCóCóCóStub
Agent đã thu hồiCóCó403403403403

Ghi chú: agent đã thu hồi vẫn gọi được ping và enroll (enroll bị Access Hub từ chối nếu token không hợp lệ).


6. Physical Data Schema ​

6.1 Mapping ​

Ingest không có lược đồ dữ liệu bền vững. Trạng thái trong bộ nhớ của tiến trình:

Cấu trúcKhóaGiá trịGiới hạn
Bộ giới hạn seriesagent id, băm FNV-64 của khóa seriesThời điểm thấymax_series (500) trong cửa sổ series_window (1 giờ), dọn mỗi 5 phút
Bộ giới hạn tốc độ(endpoint, agent hoặc IP)Token bucket16 shard, 65.536 khóa mỗi shard, dọn khóa rảnh 10 phút
Bộ khử trùng kiểm kêagent idSHA-256 của protobuf xác định, thời điểm1 giờ
Hàng chờ kiểm kêagent idBáo cáo mới nhấtChỉ giữ một mỗi agent

Toàn bộ mất khi tiến trình khởi động lại. Hệ quả vô hại: series limiter cho phép lại series, bucket đầy lại, kiểm kê có thể chuyển tiếp trùng (Access Hub xử lý idempotent, xem ADR 0011).

6.2 Phân loại và lưu giữ ​

Dữ liệuPhân loạiLưu giữ
Băm token (trong bộ nhớ, từ Authorization)Nhạy cảmChỉ trong request
Báo cáo kiểm kê chờ gửiNội bộ (hostname, IP, cấu hình)Đến khi gửi hoặc bị thay bằng báo cáo mới hơn
Bộ đếm series, bucketKhông nhạy cảmTheo tiến trình

7. Algorithms ​

7.1 Sequences (đường thành công) ​

mermaid
sequenceDiagram
    participant AG as Agent (ext)
    participant RT as Router
    participant AU as Xác thực
    participant DC as Kiểm tra số liệu
    participant BS as Bus
    participant PS as Presence

    AG->>RT: POST /agent/v1/metrics
    RT->>RT: kiểm tra header, tốc độ theo agent
    RT->>AU: băm token, tra registry
    AU-->>RT: agent, công ty, máy chủ
    RT->>DC: giải nén, kiểm tra danh mục, nhãn, cửa sổ, series
    DC--)BS: publish theo shard của server_id
    RT->>PS: Touch(agent)
    RT-->>AG: 200 ack (ack_seq, config_etag, accepted, dropped)

7.2 Sequences (đường lỗi) ​

mermaid
sequenceDiagram
    participant AG as Agent (ext)
    participant RT as Router
    participant AU as Xác thực
    participant RG as Resolver
    participant HB as Access Hub (ext)
    participant BS as Bus

    AG->>RT: POST /agent/v1/metrics
    RT->>AU: xác thực
    AU->>RG: tra băm token
    alt token thu hồi
        RG-->>AU: ErrRevoked
        AU-->>AG: 403 agent_revoked
    else Access Hub tạm mất
        RG->>HB: LookupAgent
        HB--)RG: lỗi hoặc quá tải
        RG-->>AU: ErrHubUnavailable
        AU-->>AG: 503 Retry-After 30
    else bus đầy
        RT--)BS: publish
        BS--)RT: ErrFull
        RT-->>AG: 503 Retry-After 5
    end

7.3 State machines ​

Không áp dụng: Ingest không giữ trạng thái bền. Trạng thái agent (pending, active, revoked) thuộc L3 Registry.

7.4 Core algorithms ​

Vấn đềGiải phápTrade-off
Bom giải nénĐặt trần giải nén max_decoded_bytes (8 MiB); decoder gzip và zstd có poolChi phí CPU giải nén; tăng trần làm tăng bộ nhớ mỗi request
Agent giả nhãn tenantBỏ nhãn dành riêng, danh tính lấy từ registry, tenant do worker gắn cuối cùng (internal/tsdb/vm.go)Không cho agent tự đặt nhãn agent_id
Bùng nổ cardinalityDanh mục 61 chỉ số, danh sách nhãn cho phép theo chỉ số, giá trị nhãn cắt 128 byte, giới hạn 500 series mỗi agent theo cửa sổ 1 giờSeries hợp lệ vượt giới hạn bị bỏ (đếm ahc_ingest_series_limit_dropped_total)
Mẫu sai thời gianBỏ điểm cũ hơn max_point_age (24 giờ), tương lai hơn max_point_future (5 phút), NaN, InfAgent lệch đồng hồ lớn mất mẫu; clock_skew_seconds trong AgentStats để chẩn đoán
Tra Access Hub khi missCache âm 60 giây, giới hạn toàn cục 50/s, single-flight (L3 Registry)Token mới có thể chờ tối đa vài giây
Lấy IP client sau proxyLấy mục bên phải nhất của X-Forwarded-For không thuộc trusted_proxies, chỉ khi peer tin cậyCần cấu hình trusted_proxies đúng (dev: 127.0.0.0/8)
Kiểm kê trùngBăm SHA-256 của protobuf xác định, bỏ trong 1 giờ; chỉ giữ báo cáo mới nhấtCó thể mất báo cáo trung gian (chấp nhận, kiểm kê là trạng thái mới nhất)
Cấu hình đổiETag là 8 byte đầu SHA-256, agent hỏi If-None-MatchVa chạm 64 bit không đáng kể
Enroll spamGiới hạn 6/phút mỗi IP, burst 10IP chung sau NAT có thể bị chặn nhầm

8. Error Handling ​

8.1 Bảng lỗi theo bước ​

Bước lỗiNguyên nhânCơ chế xử lýTrạng thái cuối
HeaderX-AH-Proto thiếu, sai; version sai định dạng400 hoặc 426Không xử lý tiếp
Xác thựcToken sai, hết hạn, pending401Agent phải enroll lại
Xác thựcToken thu hồi403 agent_revokedAgent dừng
Xác thựcAccess Hub tạm mất, bị giới hạn, lỗi khác503 Retry-After: 30 (lỗi không phân loại: 503 server_error)Agent thử lại
Giới hạn tốc độVượt bucket429 Retry-AfterAgent chờ
Giải nénEncoding không hợp lệ, body sai, vượt trần400 hoặc 413Bỏ request
Kiểm traTên chỉ số, nhãn ngoài danh mục; điểm ngoài cửa sổ; series vượt giới hạnBỏ mẫu, đếm, thêm warningsAck vẫn 200 với dropped_points
PublishBus đầy hoặc đóng503 Retry-After: 5, ahc_ingest_publish_failures_totalAgent giữ WAL
PresenceTouch lỗiGhi log, không làm hỏng ack (đề xuất: xác nhận từ mã)Lần thấy cuối trễ
PanicLỗi lập trìnhBắt, trả 500Tiến trình tiếp tục

8.2 Fail-fast ​

  • Cấu hình sai (giới hạn, trusted_proxies không phải CIDR) làm tiến trình không khởi động (thoát mã 3). Xem TestNewValidatesOptions.
  • Ingest role không có registry hoặc bus hợp lệ: từ chối khi khởi động (internal/app).

8.3 Race conditions ​

Tình huốngXử lý
Hai request cùng token miss cùng lúcSingle-flight ở Resolver, một lần gọi Access Hub (TestConcurrentMissesCollapse)
Agent gửi hai lô trùngBus at-least-once, mẫu idempotent theo timestamp nên ghi lại vô hại
OnAgentUp chạy song song hai nodeChỉ node thắng SADD ở presence sở hữu chuyển trạng thái (L3 Alerting)

9. Degradation ​

Nguyên tắc: ingest thà từ chối có kiểm soát (503 kèm Retry-After) còn hơn nhận rồi mất; không bao giờ trả 401 khi nguyên nhân là hạ tầng.

9.1 Dependency matrix ​

Dependency lỗiHành viKiểu suy thoáiHệ quả
Access HubToken đã cache vẫn dùng được. Miss thì 503 Retry-After: 30. Enroll trả 503Giảm chức năngAgent mới không enroll được, agent cũ vẫn gửi
Redis (registry)Lỗi đọc thành ErrNotFound, hỏi Access Hub có giới hạn; cache nút còn cache_ttl 15 giâyGiảm chức năngTăng tải lên Access Hub
Redis (bus)Publish lỗi thì 503Từ chốiAgent đệm WAL
Bus đầy503 Retry-After: 5Từ chốiAgent đệm WAL
PresenceĐề xuất xác nhận: lỗi ghi presence chỉ ghi logGiảm chức năngCó thể báo down nhầm khi Redis mất lâu
TSDBKhông ảnh hưởng ingest trực tiếp; đệm bus đầy dầnGián tiếp503 khi bus đầy

9.2 Backup và recovery ​

Ingest không có dữ liệu cần sao lưu. RTO khởi động lại tiến trình: chưa đo, đề xuất vài giây (nhờ không trạng thái). RPO: mẫu đã ack đã nằm trong bus (bền theo AOF Redis, xem L3 Bus); mẫu chưa ack agent còn giữ trong WAL.


10. Concurrency ​

10.1 Ranh giới giao dịch ​

Không có giao dịch. Mỗi request độc lập. Thứ tự: publish bus rồi Presence.Touch rồi trả ack. Ack đã trả nghĩa là mẫu đã vào bus.

10.2 Cơ chế ​

Cơ chếMô tảMối nguy
Token bucket theo khóa, 16 shardMỗi shard một khóa (mutex)Tranh chấp khóa thấp nhờ 16 shard
Bộ giới hạn seriesKhóa mutex theo agent hoặc shard, dọn 5 phútDọn chậm khi nhiều agent
Pool decoder gzip, zstdsync.PoolRò bộ nhớ nếu không trả lại decoder (đã có kiểm thử giới hạn)
Single-flight tra Access HubGộp lời gọi trùngMột lỗi làm hỏng mọi người chờ, chấp nhận
Forwarder kiểm kêMột goroutine, map có khóaMất báo cáo chờ khi chết (chấp nhận)

11. Security ​

11.1 Ba lớp ​

LớpBiện pháp
Truyền thôngTLS 1.2 trở lên khi Collector tự kết thúc TLS. Dev: TLS ở nginx, ingest lắng nghe HTTP nội bộ. trusted_proxies chỉ tin X-Forwarded-For từ proxy khai báo
MãDanh mục và nhãn cho phép, giới hạn kích thước, bỏ nhãn dành riêng, làm sạch giá trị nhãn UTF-8 và cắt 128 byte, nosniff, no-store, bắt panic, X-Request-Id chỉ nhận mẫu ^[A-Za-z0-9._-]{1,64}$
Dữ liệuToken chỉ ở dạng băm SHA-256; không log token; danh tính tenant do registry cấp

11.2 Pipeline phân quyền năm bước ​

  1. Kiểm tra header giao thức và phiên bản agent.
  2. Trích Bearer (tối đa 256 ký tự) và băm SHA-256.
  3. Resolver.Lookup (registry, rồi cache âm, rồi giới hạn, rồi Access Hub).
  4. Kiểm tra trạng thái: active và còn hạn; ngược lại 401 hoặc 403.
  5. Gắn company_id, server_id, agent_id từ bản ghi registry vào lô; nội dung agent không thể ghi đè.

11.3 Chỉ mục neo (nguyên tắc L2 đến biện pháp) ​

Nguyên tắc L2Biện pháp nội bộ
P1 danh tính từ registryBước 5 của pipeline, TestReservedLabelsAreStripped
P2 nhãn tenant gắn sau cùnginternal/tsdb/vm.go (xem L3 Bus, Worker, TSDB)
P5 từ chối có kiểm soát503 kèm Retry-After
9.4 kiểm tra đầu vàoMục 7.4

12. Configuration ​

12.1 Tunables ​

Khóa YAML dưới ingest:. Biến môi trường chỉ có cho vài khóa (AHC_INGEST_LISTEN, AHC_INGEST_TLS_CERT_FILE, AHC_INGEST_TLS_KEY_FILE, AHC_INGEST_PUBLIC_URL); phần còn lại chỉ YAML.

Tham sốDefaultÝ nghĩa và tác độngMục liên quan
ingest.listen:8443Địa chỉ lắng nghe3.1
ingest.public_urlrỗngcollector_url trả cho agent khi enroll5.2
ingest.tls_cert_file, tls_key_filerỗngĐặt cùng nhau, bật TLS tự quản11.1
ingest.trusted_proxiesrỗngDanh sách CIDR proxy tin cậy7.4
ingest.accept_jsonfalseCho phép application/json5.1
ingest.limits.max_body_bytes1 MiBTrần body nén; vượt thì 4137.4
ingest.limits.max_decoded_bytes8 MiBTrần sau giải nén7.4
ingest.limits.max_points20.000Số điểm mỗi request7.4
ingest.limits.max_series500Series mỗi agent trong cửa sổ7.4
ingest.limits.series_window1 giờCửa sổ trượt của series7.4
ingest.limits.max_point_age24 giờĐiểm cũ hơn bị bỏ7.4
ingest.limits.max_point_future5 phútĐiểm tương lai hơn bị bỏ7.4
ingest.limits.metrics_per_minute, metrics_burst4, 10Giới hạn metrics mỗi agent7.4
ingest.limits.config_per_minute, config_burst2, 2Giới hạn config mỗi agent7.4
ingest.limits.inventory_per_minute, inventory_burst2, 2Giới hạn inventory mỗi agent7.4
ingest.limits.enroll_per_minute, enroll_burst6, 10Giới hạn enroll mỗi IP client7.4
hub.lookup_per_second50Trần tra Access Hub toàn nút7.4

Timeout máy chủ HTTP cố định trong mã: đọc header 10 giây, đọc 30 giây, ghi 30 giây, rảnh 120 giây, header tối đa 64 KiB.

Tên khóa lấy từ internal/config/config.go.

12.2 Feature flags ​

Không có feature flag. Cờ tương đương: ingest.accept_json (mặc định tắt), TLS tự quản (bật khi đặt cả cert và key).


13. Telemetry ​

13.1 Metrics ​

TênKiểuNhãnNgữ nghĩa
ahc_ingest_requests_totalcounterendpoint, codeSố request
ahc_ingest_request_duration_secondshistogramendpointThời gian xử lý
ahc_ingest_auth_failures_totalcounterreasonXác thực thất bại
ahc_ingest_rate_limited_totalcounterendpointBị giới hạn tốc độ
ahc_ingest_points_accepted_totalcounterĐiểm nhận
ahc_ingest_points_dropped_totalcounterreasonĐiểm bỏ
ahc_ingest_series_limit_dropped_totalcounterBỏ do vượt series
ahc_ingest_reserved_labels_totalcounterNhãn dành riêng bị bỏ
ahc_ingest_publish_failures_totalcounterPublish bus lỗi
ahc_ingest_enroll_totalcounterresultKết quả enroll
ahc_ingest_bus_depthgaugeĐộ sâu bus lấy mẫu
ahc_ingest_inventory_pendinggaugeBáo cáo kiểm kê chờ
ahc_inventory_forwarded_totalcounterresultĐã chuyển tiếp
ahc_inventory_dropped_totalcounterreasonKhông chuyển tiếp

Nhãn lấy từ khai báo trong internal/ingest/ingest.go. ahc_inventory_forwarded_total có nhãn result, ahc_inventory_dropped_total có nhãn reason. Cổng ops còn phơi bày ahc_build_info{version,commit}, ahc_uptime_seconds, ahc_goroutines. Tài liệu docs/10 dùng tên khác (ví dụ ahc_ingest_duration_seconds, ahc_samples_accepted_total, ahc_auth_failures_total): mã thắng.

13.2 Log schema ​

JSON một dòng (khi log.format: json), trường tối thiểu: time, level, msg, request_id, collector_id. Không có Authorization. Ví dụ:

json
{"time":"2026-09-30T00:00:00Z","level":"WARN","msg":"ingest publish failed","request_id":"abc123","collector_id":"dev-ingest-1"}

13.3 Cảnh báo đến runbook ​

Bộ luật cảnh báo chưa có trong repo (L2 mục 13). Đề xuất: cảnh báo khi ahc_ingest_publish_failures_total tăng, ahc_ingest_auth_failures_total tăng đột biến, ahc_ingest_bus_depth cao kéo dài. Runbook: docs/09 mục 6.

13.4 Probes ​

ProbeĐiểm cuốiÝ nghĩa
StartupTiến trình nghe cổng opsCấu hình hợp lệ, ExecStartPre chạy collector -check
Liveness/healthz (cổng ops)Tiến trình sống
Readiness/readyz (cổng ops), kiểm tra "redis" và "tsdb"503 khi đang tắt êm hoặc phụ thuộc lỗi

13.5 Trace propagation ​

Chỉ X-Request-Id (sinh nếu thiếu, nhận nếu khớp mẫu). Chưa có trace phân tán.


14. Test Plan ​

LoạiKiểm thửVị trí
Đơn vịTestPingNeedsNoAuthOrHeaders, TestHeaderChecks, TestAuth, TestRevokedAgentGets403, TestHubDownGives503NotUnauthorizedinternal/ingest/ingest_test.go
Đơn vịTestMetricsAcceptedAndTenantIdentityFromRegistry, TestEmptyBatchIsAHeartbeat, TestReservedLabelsAreStripped, TestSeriesValidation, TestPointTimeWindowAndValues, TestSeriesLimitPerAgent, TestForgetAgentReleasesSeriesBudgetnhư trên
Đơn vịTestBodyLimits, TestCompressedBodies, TestJSONOnlyWhenEnabled, TestMetricsRateLimit, TestBusFullGives503WithRetryAfter, TestAgentUpCallbacknhư trên
Đơn vịTestConfigETag, TestConfigRateLimit, TestInventoryForwardedAndDeduped, TestRenewIsAStub, TestEnrollProxy, TestEnrollErrors, TestEnrollRateLimitPerIP, TestEnrollWithoutHub, TestClientIPHonoursTrustedProxiesOnly, TestRoutingErrorsAreJSON, TestNewValidatesOptionsnhư trên
Hai tenantTestTwoTenantsNeverMixinternal/ingest/ingest_test.go
Tích hợpTestTwoTenantIsolationThroughIngestAndAdminAPI, TestIngestToTSDBPipelineKeepsTenantsApart, TestIngestIsServedOnTheIngestListenerinternal/app
Chưa cóFuzz giải mã protobuf, tải (agentsim), golden protobuf, buf breakingKế hoạch ở docs/12

Lệnh chạy có thể dùng (không đụng Redis 6380 hay VictoriaMetrics thật): go test ./internal/ingest/.... Bản nháp này không chạy kiểm thử.


15. Implementation Sequence ​

15.1 Milestone matrix ​

MilestoneNội dungPhụ thuộcĐóng góp nghiệm thu
COL-1Khung dự án Go, cấu hình, log, /healthz /readyz /metrics, tắt êmKhôngNFR-15
COL-3Ingest: xác thực token, registry (Redis và Access Hub), giới hạn, lần thấy cuốiCOL-1AC-ING-01, 02, 03, 04, 06, 08
COL-4Enroll proxy, đồng bộ registry, thu hồi (renew là stub 503)COL-3AC-ING-03
COL-5Bus, worker, ghi TSDBCOL-3AC-ING-05
COL-7API adminCOL-4Không thuộc Ingest
COL-RTách tiến trình qua RedisCOL-3, COL-5AC-ING-07
COL-8Luật ngưỡng (worker). ConfigFor theo máy vẫn chưa làmCOL-RKhông thuộc Ingest
Renew (chưa làm)credentials/renew thật (cần endpoint Access Hub)COL-4FR-ING-12

Ánh xạ COL-x theo docs/11-roadmap.md (kiểm kê và cấu hình mặc định thuộc phạm vi COL-3 và COL-4 theo mã, roadmap không có dòng riêng).

15.2 Dependency flowchart ​

mermaid
flowchart LR
    C1["COL-1 khung dự án"] --> C3["COL-3 ingest, registry"]
    C3 --> C4["COL-4 enroll, đồng bộ"]
    C3 --> C5["COL-5 bus, worker, TSDB"]
    C4 --> C7["COL-7 admin"]
    C3 --> CR["COL-R tách vai trò"]
    C5 --> CR
    CR --> C8["COL-8 luật (xong, ConfigFor chưa)"]
    C4 --> RN["renew (chưa làm)"]

Appendix A. Open Questions ​

#Câu hỏiHành vi tạm thờiOwnerMã theo dõi
1Presence Touch lỗi thì có nên trả lỗi hay chỉ ghi log?Đề xuất ghi log (cần xác nhận trong mã)Chưa chỉ địnhOQ-ING-1
2ConfigFor theo máy lấy từ đâu (chưa thuộc COL-8 phần luật)?Trả mặc địnhChưa chỉ địnhOQ-ING-2
3Khi có protocol phiên bản 2, cơ chế N và N-1 thế nào?Chỉ hỗ trợ 1Chưa chỉ địnhOQ-ING-3
4Có nên giới hạn tốc độ dùng chung qua Redis?Chỉ theo từng nodeChưa chỉ địnhOQ-ING-4
5Bộ luật cảnh báo cho các metric ahc_ingest_*Chưa cóChưa chỉ địnhOQ-ING-5

Appendix B. ADR nội bộ ​

Mã ADRQuyết địnhTrạng tháiDriver
ADR 0002HTTPS + protobuf, không gRPCChấp nhậnQua proxy
ADR 0007Token mờ, tra registry, tra ngược Access HubChấp nhậnThu hồi nhanh
ADR 0011Kiểm kê không ghi vào ServerChấp nhậnAn toàn dữ liệu
ADR 0012 (đề xuất)Bus Redis StreamsĐề xuấtCOL-R
ADR nội bộ (đề xuất)Ack chỉ sau khi publish bus thành côngĐề xuất, đang là hành vi mãKhông mất mẫu đã ack

Appendix C. Section Profile ​

Phân mụcHồ sơTrạng thái điềnGiải trình
0 đến 3Bắt buộcĐã điền
4 Domain modelBắt buộcĐã điền
5 API contractBắt buộcĐã điền
6 Physical dataTùy chọnĐiền tối thiểuKhông có lưu trữ bền
7.1, 7.2Bắt buộcĐã điền
7.3 State machineTùy chọnKhông áp dụngKhông giữ trạng thái bền
7.4Bắt buộcĐã điền
8, 9, 10Bắt buộcĐã điền
11Bắt buộcĐã điền
12Bắt buộcĐã điềnTên khóa lấy từ internal/config/config.go
13Bắt buộcĐã điềnNhãn lấy từ khai báo metric trong mã
14Bắt buộcĐã điềnKiểm thử chưa chạy trong bản nháp
15Bắt buộcĐã điềnTên COL-x theo docs/11-roadmap.md
Trang này có giúp được bạn không?
Sửa trang này

Nội dung đồng bộ từ kho mã access-hub-collector lúc 15:42, 03/10/2026. Khi tài liệu và mã khác nhau, mã thắng.