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

Giao thức ​

Đây là nguồn sự thật của giao thức giữa agent và collector, và của API nội bộ giữa Access Hub và collector. Phiên bản giao thức hiện tại: 1. Giao thức giữa collector và Access Hub là API v1 của Access Hub, mô tả ở 06-access-hub-integration và lấy từ OpenAPI do Scramble sinh ra.

17 phút đọcCập nhật 02/10/2026access-hub-collector, docs/03-protocol.md

1. Quy ước chung (agent -> collector) ​

  • Cơ sở URL: https://<collector>/agent/v1. Chỉ TLS 1.2 trở lên, HTTP/1.1 hoặc HTTP/2.
  • Agent chỉ kết nối đi ra. Không có cổng nghe trên agent.
  • Nội dung chính là protobuf (Content-Type: application/x-protobuf), nén bằng zstd hoặc gzip qua Content-Encoding. Collector luôn chấp nhận không nén. JSON (application/json) chỉ được chấp nhận khi collector bật debug.accept_json, dùng để gỡ lỗi.
  • Thời gian: số nguyên mili giây từ epoch UTC.
HeaderBắt buộcÝ nghĩa
Authorization: Bearer <agent_token>Mọi API trừ enroll và pingToken của agent
X-AH-ProtoCóPhiên bản giao thức agent hỗ trợ, ví dụ 1
X-AH-Agent-VersionCóSemver của agent, ví dụ 1.4.2
X-Request-IdKhuyến nghịUUID mỗi request, xuất hiện trong log hai phía
Content-Type, Content-EncodingKhi có bodyNhư trên

Danh tính (agent, công ty, máy chủ) chỉ lấy từ token qua registry. Mọi trường danh tính nằm trong body (nếu có) bị bỏ qua khi ghi số liệu.

Giới hạn ​

Giới hạnGiá trị mặc địnhVượt thì
Kích thước body sau nén1 MiB413
Kích thước sau giải nén8 MiB413
Số series khác nhau của một agent (hoạt động trong 1 giờ)500Series mới bị bỏ, trả cảnh báo trong response, tăng metric series_limit_dropped
Số series khác nhau của một công ty trên một node ingest (COL-11)Tắt (ingest.limits.max_series_per_company: 0)Series mới bị bỏ với cảnh báo company series limit reached, lý do company_series_limit
Số điểm trong một request20.000413
Tên chỉ số^[a-z][a-z0-9_]{0,63}$Series bị bỏ
Khóa nhãn^[a-z][a-z0-9_]{0,31}$Series bị bỏ
Giá trị nhãntối đa 128 byte UTF-8Cắt bớt
Nhãn dành riêng (company_id, server_id, agent_id)Không được gửiBị bỏ và ghi log
Cửa sổ thời gian điểm dữ liệuKhông cũ hơn 24 giờ, không quá 5 phút ở tương laiĐiểm bị bỏ, đếm vào response
Tốc độ4 request/phút/agent (burst 10) cho metrics, config 2/phút429

Mã trạng thái và lỗi ​

Lỗi trả JSON: {"error":{"code":"<mã>","message":"<mô tả>"}}, có thể kèm Retry-After (giây).

HTTPcodeÝ nghĩaAgent làm gì
200/202Thành côngXóa lô khỏi bộ đệm
304Cấu hình không đổiGiữ nguyên
400bad_requestBody sai định dạngBỏ lô (không thử lại), ghi log
401unauthorizedToken sai hoặc hết hạnNgừng gửi, thử lại config mỗi 10 phút, báo trạng thái unauthorized
403agent_revokedAgent đã bị thu hồiNgừng vĩnh viễn cho đến khi enroll lại
409already_enrolled, token_usedXung đột khi enrollBáo lỗi, không thử lại tự động
413too_largeVượt giới hạnTách nhỏ lô rồi gửi lại một lần, nếu vẫn lỗi thì bỏ
422binding_failed, quota_exceeded, invalid_seriesKhông ghép được máy chủ, gói của công ty đã đủ số agent (monitoring_agents, do Access Hub kiểm tra lúc enroll), hoặc dữ liệu không hợp lệLỗi enroll: báo, không thử lại tự động. Lỗi dữ liệu: bỏ phần lỗi
426upgrade_requiredGiao thức agent quá cũTiếp tục gửi nếu có thể, báo cần nâng cấp
429rate_limitedQuá tốc độTôn trọng Retry-After, backoff
500, 502, 503, 504server_error, unavailableLỗi phía hubGiữ lô, backoff
Lỗi mạng, timeoutGiữ lô, backoff

Backoff của agent: khởi đầu 5 giây, nhân đôi mỗi lần, tối đa 300 giây, full jitter (chọn ngẫu nhiên trong [0, backoff]), luôn tôn trọng Retry-After nếu lớn hơn. Reset sau lần thành công đầu tiên.

Jitter khởi động: thời điểm gửi đầu tiên và pha của chu kỳ lệch ngẫu nhiên xác định theo hash(agent_id) mod interval, để hàng nghìn agent khởi động cùng lúc không đồng loạt gửi cùng một giây.

2. Các endpoint agent -> collector ​

2.1 GET /agent/v1/ping ​

Không xác thực. Trả 200 {"server_time_ms":..., "proto_min":1, "proto_max":1}. Dùng cho check-config và kiểm tra kết nối lúc cài.

2.2 POST /agent/v1/enroll ​

Không dùng Authorization. Body EnrollRequest: license, hostname, ip_addresses[], machine_id, os {family, name, version, kernel, arch}, agent_version.

Response EnrollResponse: agent_id, agent_token (chỉ hiện đúng lần này), collector_url, config (cấu hình khởi tạo, xem 2.4), server_time_ms.

Quy tắc ghép máy chủ (quyết định ở Access Hub, collector chỉ chuyển tiếp):

  1. License gắn sẵn server_id: ghép thẳng, khuyến nghị dùng.
  2. Không gắn sẵn: thử khớp ip_addresses với Server.ip_address trong công ty của token, sau đó khớp hostname.
  3. Không khớp: theo cấu hình công ty, hoặc trả 422 binding_failed, hoặc tạo Server nháp cần duyệt (mặc định tắt).

machine_id (Linux: /etc/machine-id, Windows: MachineGuid) dùng để phát hiện cùng một máy enroll lại và để phát hiện máy nhân bản từ image (cùng machine_id nhưng khác hostname).

2.3 POST /agent/v1/metrics ​

Body MetricsBatch:

MetricsBatch {
  uint64 seq            // tăng dần theo agent, dùng để gỡ lỗi và chống lặp
  int64  sent_at_ms
  repeated Series series
  AgentStats stats      // số liệu tự thân của agent
}
Series { string name; map<string,string> labels; repeated Point points }
Point  { int64 ts_ms; double value }

Response MetricsAck: server_time_ms (để agent tính độ lệch đồng hồ), ack_seq, config_etag (khác etag hiện có thì agent gọi config ngay), accepted_points, dropped_points, warnings[].

Gửi lặp cùng một điểm là an toàn: TSDB khử trùng theo (series, ts). Gói metrics đồng thời là heartbeat: mỗi lần nhận thành công cập nhật last_seen. Agent không có gì để gửi vẫn phải gửi gói rỗng đúng chu kỳ.

2.4 GET /agent/v1/config ​

Hỗ trợ If-None-Match: <etag>. Trả 304 hoặc 200 AgentConfig:

AgentConfig {
  string etag
  uint32 interval_seconds         // 10..300, 0 = không đặt (agent giữ giá trị cục bộ, mặc định 30)
  CollectorsConfig collectors     // bật tắt từng bộ thu, lọc mount, lọc interface
  repeated Check checks           // port, tcp, http, cert, service (xem 03-metrics-catalog của agent)
  Limits limits                   // max_series, max_batch_bytes, buffer_bytes
  string min_agent_version        // dưới ngưỡng này thì cảnh báo cần nâng cấp
  string collector_url            // đổi giá trị này để chuyển agent sang collector khác
  string log_level
}

Checks (COL-20): collector kéo check từ Access Hub (06 mục 4.8) và điền checks theo cặp (company_id, server_id) của agent đã xác thực, không bao giờ theo nội dung request. checks tối đa 50, mỗi check chỉ mang trường của đúng loại, timeout_seconds mặc định 5, expect_status mặc định 200. ETag cấu hình phụ thuộc tập check, đổi thì MetricsAck.config_etag đổi và agent tải lại. Chưa có GET /checks ở Access Hub thì checks rỗng.

Trường không đặt (AGT-10): giá trị 0, chuỗi rỗng hoặc thông điệp vắng nghĩa là trung tâm không quản lý trường đó, agent giữ giá trị cục bộ: interval_seconds = 0, collectors vắng (khi có thì thay toàn bộ cờ bật tắt cpu, memory, disk, net, uptime; danh sách lọc rỗng giữ danh sách cục bộ), limits.max_series = 0, checks rỗng. limits.max_series chỉ là trần (agent lấy giá trị nhỏ hơn). log_level và collector_url không thuộc danh sách trắng của agent ở GĐ 1 và 2. Khi Access Hub chưa quản lý cấu hình cho agent, collector chỉ trả limits và collector_url (thông tin), mọi agent chạy theo agent.yaml của mình. Giá trị ngoài miền (chu kỳ, regex sai hoặc dài quá 200 ký tự) bị bỏ từng khóa kèm cảnh báo; nếu kết quả vẫn làm cấu hình agent không hợp lệ thì agent bỏ cả bản và giữ cấu hình cục bộ. min_agent_version luôn được đọc (chỉ để cảnh báo), kể cả khi allow_remote_config: false.

Agent gọi config mỗi 300 giây (jitter cộng trừ 20%, pha lệch theo agent_id) và khi config_etag trong MetricsAck đổi (tối đa một lần mỗi 30 giây). Bản hợp lệ gần nhất lưu ở remote-config.pb trong thư mục trạng thái (0600) và được áp ngay khi khởi động lại. Cấu hình cục bộ có thể khóa (allow_remote_config: false), khi đó bỏ qua toàn bộ cấu hình từ xa, chỉ giữ min_agent_version (chỉ dùng để cảnh báo). Thay đổi collector_url từ xa chỉ được chấp nhận từ giai đoạn 3 và với điều kiện: kênh https, chữ ký Ed25519, collector mới trả lời ping hợp lệ (quy tắc này được cả hai bên tuân thủ), và không áp dụng cho agent đã khóa cấu hình từ xa.

2.5 POST /agent/v1/inventory ​

Body InventoryFacts: os {...}, cpu {model, cores, threads}, memory_total_bytes, disks[] {mount, fstype, total_bytes}, nics[] {name, ips[]}, boot_time_ms, timezone, agent_build {version, commit, go_version}. Địa chỉ MAC mặc định không gửi. Gửi khi khởi động, mỗi 6 giờ, và khi băm nội dung thay đổi. Collector chuyển tiếp lô sang Access Hub. Access Hub không tự ghi đè Server (xem 06).

2.6 POST /agent/v1/credentials/renew ​

Cần Authorization hiện tại. Trả agent_token mới. Token cũ còn hiệu lực thêm 24 giờ để agent chuyển đổi an toàn. Agent gọi mỗi 30 ngày (cấu hình được), và gọi lại khi lần lưu token mới ra đĩa thất bại (dùng token cũ trong thời gian chồng lấn).

2.7 GET /agent/v1/update (giai đoạn 3) ​

Query os, arch, version, channel. Trả manifest {version, url, sha256, signature_ed25519, min_version, rollout_percent, released_at} hoặc 204. Cohort theo hash(agent_id) mod 100 < rollout_percent. Có công tắc dừng khẩn cấp ở phía collector.

3. Phiên bản hóa ​

  • X-AH-Proto là số nguyên chính. Collector hỗ trợ N và N-1 tối thiểu 12 tháng.
  • Thêm trường protobuf theo quy tắc tương thích (không đổi số trường, không tái dùng số đã xóa). Trường mới do agent cũ không gửi phải có mặc định an toàn.
  • Endpoint mới hoặc đổi ngữ nghĩa không tương thích: tăng v trong đường dẫn (/agent/v2) và giữ v1 theo chính sách trên.
  • buf breaking chạy trong CI của cả hai repo để chặn thay đổi phá vỡ.

4. API nội bộ Access Hub -> collector (vai trò admin) ​

Tiền tố /internal/v1. Xác thực Authorization: Bearer <collector_admin_token> (bí mật riêng, xoay được), chỉ mở trong mạng nội bộ, đi qua TLS. Access Hub luôn truyền company_id tường minh; collector tự chèn bộ lọc nhãn company_id, server_id vào mọi truy vấn.

Method, đường dẫnÝ nghĩa
PUT /internal/v1/agents/{agent_id}Đẩy bản ghi registry mới hoặc cập nhật (token_hash, company_id, server_id, state)
DELETE /internal/v1/agents/{agent_id}Thu hồi ngay: xóa khỏi cache, từ chối request kế tiếp
POST /internal/v1/reload/rulesYêu cầu kéo lại luật từ Access Hub ngay
POST /internal/v1/reload/settingsNạp lại cấu hình theo công ty (interval mặc định, giới hạn series)
GET /internal/v1/servers/{server_id}/status?company_id=Trạng thái, last_seen, giá trị mới nhất của các chỉ số chính
GET /internal/v1/servers/{server_id}/series?company_id=&metric=&from=&to=&step=&agg=Chuỗi thời gian, tự chọn raw hoặc rollup theo khoảng thời gian. metric phải thuộc danh sách trắng (xem catalog). agg thuộc avg,min,max,last
GET /internal/v1/companies/{company_id}/summarySố máy online, offline, số alert đang mở (cho tổng quan)
DELETE /internal/v1/companies/{company_id}/dataXóa toàn bộ series, registry, trạng thái của công ty
DELETE /internal/v1/servers/{server_id}/data?company_id=Xóa dữ liệu của một máy chủ
GET /internal/v1/statusPhiên bản, vai trò, độ trễ bus, độ sâu outbox, số agent online

Ghi chú triển khai (COL-7):

  • Mọi phản hồi thành công bọc trong {"data": ...}, lỗi dạng {"error":{"code","message"}} với mã bad_request, unauthorized, not_found, method_not_allowed, not_implemented, unavailable. Token admin so sánh hằng thời gian và là bí mật riêng, khác token hub.
  • PUT /agents/{id} nhận AgentRecord (company_id, server_id, state là pending|active|revoked, token_hash là SHA-256 hex thường, prev_token_hash, prev_token_expires_at, version). DELETE idempotent, luôn trả 204, agent bị thu hồi nhận 403 ở lần gửi kế tiếp. Với Redis registry, các node ingest có thể còn cache tối đa redis.cache_ttl (mặc định 15 giây).
  • POST /reload/rules (COL-8) kéo lại luật từ Access Hub ngay và trả 202 {"data":{"reload":"rules","accepted":true}}. Khi admin chạy cùng tiến trình với worker, 202 nghĩa là đã kéo và áp xong (503 unavailable nếu Access Hub không gọi được, bộ luật đang chạy giữ nguyên). Khi admin chạy tách tiến trình khỏi worker, lệnh tăng bộ đếm Redis <prefix>rules:reload và các worker nạp lại trong vòng khoảng 2 giây. POST /reload/silences (COL-9) kéo lại silence, cùng cơ chế (202, hoặc bộ đếm Redis <prefix>silences:reload khi admin tách tiến trình). POST /reload/checks (COL-20) kéo lại check trung tâm, cùng cơ chế (202, hoặc bộ đếm Redis <prefix>checks:reload khi admin tách tiến trình khỏi ingest); GET /status có thêm mục checks (loaded, invalid, disabled, servers, truncated, since, last_sync_at, last_sync_error). POST /reload/settings (COL-9, mở rộng ở COL-10) xóa cache cài đặt theo công ty: giới hạn retention theo gói của tiến trình admin, ngưỡng group_down của worker cùng tiến trình, và khi admin tách tiến trình thì tăng bộ đếm Redis <prefix>settings:reload để các worker xóa cache trong khoảng 2 giây. Trả 202, chỉ trả 501 not_implemented khi không có Access Hub. GET /status có thêm mục silences (active, loaded, since, last_sync_at, last_sync_error) và rules.flapping. GET /status có thêm mục rules (loaded, invalid, pending, firing, no_data, since, last_sync_at, last_sync_error, invalid_rules).
  • series: from, to là RFC3339 (dùng Z, dấu + trong URL phải mã hóa) hoặc epoch giây, mặc định 1 giờ gần nhất. Khoảng tối đa 400 ngày khi collector có tsdb.long_url (rollup), 31 ngày khi không có. step là duration (5m) hoặc số giây, tối thiểu 30s, tối đa 11000 điểm; bỏ trống thì collector chọn khoảng chia 500 điểm. Truy vấn luôn ràng buộc cả company_id lẫn server_id, nên gọi chéo công ty trả về rỗng.
  • series chọn nguồn (COL-10): from cách hiện tại không quá 7 ngày đọc vm-raw; xa hơn đọc rollup có ô (5 phút hoặc 1 giờ) lớn nhất mà không rộng hơn step, và step được làm tròn lên bội số của ô. Mỗi điểm gộp lại các ô trong step bằng cùng hàm (max của các ô max, ...), nên đỉnh không bị mất. Rollup trống mà khoảng còn nằm trong retention thô (30 ngày) thì đọc lại vm-raw. step_seconds trong phản hồi là bước thực dùng, có thể lớn hơn bước yêu cầu.
  • series theo gói (COL-10, ân hạn từ Q17): collector cắt from về now - giới hạn đọc, với giới hạn đọc = metrics_retention_previous_days khi còn ân hạn (metrics_retention_grace_until ở tương lai), ngược lại metrics_retention_days (mục 5.1). Phản hồi có thêm retention_days (retention hiện tại, chỉ khi công ty có giới hạn); trong ân hạn có thêm retention_previous_days (vắng nếu trước đó không giới hạn), retention_grace_until và retention_locked_before (dữ liệu trước mốc này chỉ đọc, sẽ bị xóa khi hết ân hạn: giao diện nên tô khác vùng này). from là giá trị sau khi cắt. Khoảng nằm trọn ngoài giới hạn trả 200 với series rỗng. Collector cache 5 phút, POST /reload/settings xóa cache. Không gọi được Access Hub thì giữ chính sách đã biết, công ty chưa từng biết thì không cắt.
  • GET /status có thêm mục retention (lần quét gần nhất của janitor: at, companies, skipped, days_deleted, legacy_samples_moved, errors, dry_run, duration_seconds), chỉ số tổng, không có company_id.
  • status trả 404 nếu máy chủ không thuộc công ty. state là online, down hoặc unknown (chưa từng có tín hiệu thật hoặc im lặng nhưng chưa bị kết luận mất).
  • summary trả agents_total, online, offline. Chưa có open_alerts: số alert đang mở do Access Hub tính từ monitoring_alerts, collector chỉ giữ trạng thái đánh giá nội bộ (xem GET /status, mục rules).
  • Xóa dữ liệu (COL-11): collector ghi bia mộ cho công ty hoặc máy trước (Redis <prefix>purge:tombstones, sống 15 phút), rồi xóa registry (agent ngừng gửi được), rồi xóa TSDB (vm-raw và vm-long), và tự xóa TSDB thêm một lần sau 10 giây. Worker đọc bia mộ mỗi 2 giây (ngay lập tức nếu cùng tiến trình với admin): bỏ mọi lô của công ty hoặc máy đó còn trên bus hoặc trong bộ đệm ghi, quên trạng thái alert, flapping và nhóm group_down của nó không phát sự kiện (Access Hub tự xóa alert khi purge). Phản hồi có tombstone_until. Không ghi được bia mộ thì trả 503 và chưa xóa gì, Access Hub gọi lại. Gọi lặp là an toàn (idempotent).

Định dạng trả về của series (trong data):

json
{
  "server_id": "srv_a", "company_id": "co_a", "metric": "cpu_usage_percent",
  "agg": "avg", "from": "2026-01-01T00:00:00Z", "to": "2026-01-01T01:00:00Z", "step_seconds": 60,
  "series": [{"labels": {}, "points": [[1767225600000, 12.4], [1767225660000, 13.1]]}]
}

Điểm là [ts_ms, value]. Không có trường source (raw hay rollup do collector tự chọn). Trường tùy chọn retention_days xuất hiện khi gói của công ty giới hạn thời gian đọc (COL-10). Mọi thay đổi ở mục này là bổ sung, tương thích ngược với Access Hub đang gọi.

5. API collector -> Access Hub ​

Danh sách đầy đủ và hợp đồng ở 06-access-hub-integration mục "API dành cho collector". Tóm tắt: enroll, agents (đồng bộ registry), rules (đồng bộ luật), events, seen, inventory, collectors/heartbeat. Tất cả idempotent, có phiên bản since, giới hạn tốc độ riêng.

5.1 Hợp đồng retention trong GET /settings/{company_id} (phiên bản hợp đồng 2, ngày 02/10/2026) ​

Bổ sung tương thích ngược vào phản hồi của 06 mục 4.4. Mọi trường là tùy chọn, null hoặc vắng có nghĩa như cột "Vắng".

TrườngKiểuÝ nghĩaVắng
metrics_retention_dayssố nguyên 1 đến 3650Retention của gói đang hiệu lựcKhông giới hạn theo gói
metrics_retention_previous_dayssố nguyên 1 đến 3650Retention ngay trước lần giảm gần nhất còn trong ân hạn (lớn nhất nếu giảm nhiều lần trong ân hạn)Trước đó không giới hạn (chỉ có nghĩa khi có grace_until)
metrics_retention_grace_untilRFC3339 UTCHết ân hạn 30 ngày tính từ lần giảm gần nhấtKhông có ân hạn

Ngữ nghĩa phía collector (chính sách Q17, ADR 0016):

  1. Đọc: trong ân hạn, công ty đọc được tới previous_days (không giới hạn nếu trước đó không giới hạn); hết ân hạn thì tới metrics_retention_days.
  2. Vùng khóa: dữ liệu cũ hơn now - metrics_retention_days không bao giờ được ghi thêm (worker bỏ mẫu), kể cả trong ân hạn.
  3. Xóa vật lý: janitor xóa cả ngày (UTC) nằm hoàn toàn ngoài cửa sổ đọc, ở cả kho thô và kho rollup, chạy mỗi giờ. Trong ân hạn không xóa gì trong cửa sổ previous_days. Dữ liệu rời đĩa muộn nhất khoảng 1 ngày sau khi ra khỏi cửa sổ.
  4. An toàn: không xóa khi Access Hub không trả lời; luôn giữ ít nhất 1 ngày; công ty mới thấy chờ 24 giờ trước lần xóa đầu; collector tự nhớ retention lớn nhất thấy trong 30 ngày qua và không xóa dưới mức đó (phòng khi Access Hub quên gửi ân hạn). Tăng retention có hiệu lực ngay cho đọc; dữ liệu đã xóa không lấy lại được.
  5. Access Hub gọi POST /internal/v1/reload/settings sau mỗi lần đổi để đọc có hiệu lực ngay (janitor luôn hỏi lại Access Hub, không dùng cache).

6. Tệp .proto ​

Đặt trong proto/accesshub/agent/v1/agent.proto, gói accesshub.agent.v1, sinh mã Go cho cả agent và collector bằng buf generate. Bản nháp đã có ở proto/accesshub/agent/v1/agent.proto (hạng mục X-2 sẽ chốt, go_package còn là giá trị giữ chỗ chờ quyết định Q1). Repo collector là chủ sở hữu, agent phụ thuộc qua Go module dùng chung .../proto hoặc sao chép có kiểm tra CI (xem 13-risks-open-questions, câu hỏi về Go module path).

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 10:57, 03/10/2026. Khi tài liệu và mã khác nhau, mã thắng.