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

L2 - Nền tảng giám sát máy chủ - Collector (data plane) ​

Tên trang theo quy ước: L2 - <Tên P&L> - <Tên hệ thống>. P&L: chưa chỉ định. Hệ thống: Collector, tầng thu nhận và xử lý số liệu của nền tảng giám sát máy chủ. Một tài liệu L2 chỉ mô tả đúng một hệ thống (Collector). Access Hub (control plane) và Agent có L2 riêng.

Trạng thái
Bản nháp
Phiên bản
0.1, ngày 30/09/2026
Tài liệu cha
L1 - Collector
Tài liệu con
5 tài liệu L3
Rà soát gần nhất
30/09/2026, chưa có người duyệt
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.

Sơ đồ thành phần ​

Ba vai trò của cùng một binary, scale độc lập. Access Hub là nguồn sự thật; Collector không giữ dữ liệu nghiệp vụ lâu dài, registry, presence, bus và outbox đều dựng lại hoặc gửi lại được.

Số liệuGọi Access HubAccess Hub gọi collectorĐọc, xóa số liệu
  1. Agent đẩy số liệu và enroll qua HTTPS 443, đường dẫn /agent/v1/*.
  2. Load balancer kết thúc TLS, chia tải, chỉ gửi tới node có /readyz sẵn sàng.
  3. Ingest xác thực token qua registry, đẩy lô mẫu theo shard lên Redis Streams.
  4. Worker đọc lô của các shard mình giữ, chia theo server_id.
  5. Worker ghi VictoriaMetrics bằng /api/v1/import (ADR 0015).
  6. Ingest chuyển tiếp enroll và tra ngược token lạ tới Access Hub.
  7. Worker gửi sự kiện đổi trạng thái và last_seen qua outbox, khử trùng theo event_id.
  8. Access Hub đẩy registry, nạp lại luật, truy vấn và xóa dữ liệu qua admin.
  9. Admin đọc chuỗi thời gian và xóa series theo công ty, cập nhật registry trong Redis.
Thông tin tài liệu đầy đủ
Trạng tháiBẢN NHÁP (chưa sẵn sàng trình thẩm định)
Phiên bản và nhật ký thay đổi0.1 (2026-09-30): bản nháp đầu tiên, dựng từ mã nguồn internal/**, cmd/**, kiểm thử, docs/00 đến docs/13, ADR 0001 đến 0011 và deploy/dev, deploy/systemd của repo Collector. Khi tài liệu thiết kế và mã khác nhau, mã thắng và chỗ lệch được ghi ở mục 16.2 (nợ kỹ thuật)
Chủ sở hữu (Owner)Chưa chỉ định
Bên thẩm định / Phê duyệtChưa chỉ định. Người phê duyệt: chưa chỉ định. Không có ai đã sign-off, không mục nào được ghi APPROVED
Tài liệu L1 (Parent)L1 - Collector. Bảng truy vết mục L2 đến mục tiêu L1 ở phần "Truy vết" bên dưới
Tài liệu L3 (Child)L3 - Ingest API, L3 - Registry, Enroll, Presence, L3 - Bus, Worker, TSDB, L3 - Cảnh báo mất tín hiệu và Outbox, L3 - Admin API
Tiêu chuẩn tham chiếuKhung tài liệu 3 tầng L1, L2, L3; Danh mục tiêu chuẩn diagram (STD-DIAG); ADR 0001 đến 0011 của Collector (docs/adr/); docs/03-protocol.md là nguồn sự thật của hợp đồng agent, collector
Lần rà soát cuối2026-09-30 (bản nháp đầu tiên, chưa có rà soát của con người). Chu kỳ rà soát đề xuất: 12 tháng hoặc khi đổi ranh giới hệ thống
Cấp độ hệ thống (System Tier)Đề xuất, chưa xác nhận: Cấp 3, Business Operational, kế thừa đề xuất của L1 mục 12 (OQ-7 của L1 còn mở)

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

Trạng thái hiện thực (tóm tắt): đã làm COL-1 đến COL-7 và COL-R (tách vai trò). Đã làm thêm COL-8 (luật ngưỡng, nạp lại luật POST /internal/v1/reload/rules). Chưa làm: cài đặt theo công ty (reload/settings trả 501), bus JetStream, cấp lại token (POST /agent/v1/credentials/renew là stub trả 503), silence và bảo trì (COL-9).

Truy vết (mục L2 đến mục tiêu L1). Mục tiêu L1 lấy từ L1 mục 2, chỉ số chất lượng từ L1 mục 4.

Mục L2Mục tiêu L1 (mục 2)Ghi chú
1 Mục tiêu nghiệp vụ, 2 Tổng quanG1 trạng thái gần thời gian thực, G4 scale ngangCollector là data plane
3 Yêu cầu chức năngG1, G2, G3Cảnh báo ngưỡng (G3): agent_down và luật ngưỡng (COL-8) đã có, chống nhiễu nâng cao chờ COL-9
4 Yêu cầu phi chức năngG4, G5Bám NFR-01 đến NFR-15
5 Công nghệG4Chọn TSDB, bus, giao thức
6 Tích hợpG1, G3Tích hợp với Agent và Access Hub
7 Dữ liệuG2, G5Mô hình dữ liệu, cô lập tenant
8 Luồng nghiệp vụG1, G3Enroll, ingest, mất tín hiệu
9 Bảo mậtG5Token, admin token, cô lập tenant
10 Triển khaiG4, G6Topology dev và production
11, 12 Sức chứa, mở rộng, độ tin cậyG464 shard, vai trò tách rời
13 Quan sátG1, G4ahc_*, /readyz
14 Sẵn sàng vận hànhG4RTO, RPO, DR
15 Kiểm thửG5Kiểm thử hai tenant
16 Rủi romục 10 của L1R1, R2, R11, R15, R16

1. Business Objectives ​

Collector là data plane của nền tảng giám sát: nhận số liệu từ hàng nghìn agent, xác thực bằng token mờ qua registry, gắn danh tính tenant do chính Collector quyết định, ghi vào kho chuỗi thời gian, phát hiện máy mất tín hiệu và gửi sự kiện về Access Hub. Access Hub là control plane và là nguồn sự thật (công ty, máy chủ, agent, luật). Collector không giữ dữ liệu nghiệp vụ lâu dài (ADR 0004): registry, presence, bus, outbox là trạng thái vận hành có thể dựng lại hoặc gửi lại.

Lý do tách: quy mô hàng nghìn máy mỗi công ty, MySQL của Access Hub không được ghi số liệu (ADR 0004, ADR 0005).

1.1 In scope ​

NhómPhạm viTrạng thái
Ingestping, enroll (proxy sang Access Hub), metrics, config, inventory cho agent, giới hạn và kiểm tra đầu vàoĐã làm
RegistryBản sao đọc danh tính agent (token băm), đồng bộ từ Access Hub, cache âm, tra ngược một lầnĐã làm
Bus và worker64 shard theo server_id, bus in-process hoặc Redis streams, worker ghi TSDB theo lôĐã làm
TSDBGhi và truy vấn VictoriaMetrics qua adapter, gắn nhãn company_id, server_id, chọn nguồn thô hoặc rollup, xóa theo tenantĐã làm
Mất tín hiệuPhát hiện agent.down, agent.up, gửi last_seen, heartbeatĐã làm
OutboxSự kiện bền vững, gửi lô idempotent, dead-letterĐã làm
Admin APIĐẩy registry, thu hồi, trạng thái, truy vấn số liệu, xóa dữ liệu tenant, trạng thái collectorĐã làm
Luật ngưỡngKéo luật, biên dịch, đánh giá, trạng thái, snapshot (internal/rules)Đã làm (COL-8)
Cài đặt theo công ty, group_down, flapping, silence, cấu hình agent theo máyChỉ thiết kế (COL-9 và sau)
Bus JetStreamĐệm bền vững 2 giờ khi mất TSDB (NFR-07)Chỉ thiết kế
Cấp lại tokenXoay token agent chồng lấn 24 giờ (FR-04)Chỉ thiết kế (stub 503)

1.2 Out of scope ​

Nội dungThuộc vềLý do
Quản lý công ty, máy chủ, người dùng, luật, thông báo, chuông realtime, auditAccess Hub (hệ thống ngoài)Control plane, nguồn sự thật (ADR 0004)
Thu thập số liệu trên máy chủ, WAL đệm đĩa, kiểm tra port, tcp, http, certAgent (hệ thống ngoài)Chạy trên máy được giám sát
Gửi email, webhookAccess HubCollector chỉ phát sự kiện
Thực thi lệnh từ xaKhông làm (ADR 0010)Giảm bề mặt tấn công
Ghi dữ liệu vào bảng Server từ kiểm kêKhông làm (ADR 0011)Kiểm kê chỉ chuyển tiếp, Access Hub quyết định
Log tập trung, APM, giám sát không agentGiai đoạn 4Ngoài phạm vi giai đoạn 1 đến 3
PromQL thô từ bên ngoàiKhông cung cấpCô lập tenant (internal/admin)

2. Architecture Overview and Principles ​

2.1 Nguyên tắc kiến trúc ​

MãNguyên tắcHiện thực và bằng chứng
P1Danh tính chỉ đến từ registry, không tin nội dung agentinternal/ingest bỏ nhãn dành riêng company_id, server_id, agent_id; danh tính lấy từ registry.Resolver theo băm token. Kiểm thử TestReservedLabelsAreStripped, TestMetricsAcceptedAndTenantIdentityFromRegistry
P2Nhãn tenant do Collector gắn sau cùng và thắng mọi nhãn khácinternal/tsdb/vm.go đặt company_id, server_id cuối; CheckTenant kiểm tra định dạng id
P3Truy vấn và xóa luôn có company_id bắt buộc, không PromQL thôinternal/admin/admin.go, internal/tsdb
P4Ingest không trạng thái, scale ngang; trạng thái dùng chung nằm ở Redisinternal/registry/redis.go, internal/presence/redis.go, internal/bus/redis.go, internal/outbox/redis.go
P5Từ chối có kiểm soát thay vì nhận rồi mấtBus đầy hoặc đóng thì 503 kèm Retry-After: 5; Access Hub tạm mất thì 503 kèm Retry-After: 30, không trả 401
P6Sự kiện đi qua outbox bền vững, gửi tối thiểu một lần, Access Hub khử trùng theo event_idinternal/outbox, internal/events
P7Một binary, chọn vai trò khi chạycmd/collector, internal/app: ingest, worker, admin, all
P8Không thêm thư viện nặng khi tự viết được gọnClient Redis tự viết internal/redisx (RESP2), registry số liệu internal/metrics (định dạng Prometheus), không dùng client Prometheus

2.2 Sơ đồ tích hợp (BC map) ​

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

    subgraph COL["Collector"]
        ING["Ingest"]:::bc
        WRK["Worker"]:::bc
        ADM["Admin"]:::bc
    end

    RED[("Redis")]:::datastore
    VM[("VictoriaMetrics")]:::datastore

    AG -->|"đẩy số liệu, enroll"| ING
    ING -->|"chuyển tiếp enroll, tra token"| HUB
    ING -.->|"lô mẫu theo shard"| RED
    RED -.->|"lô mẫu"| WRK
    WRK -->|"ghi lô mẫu"| VM
    WRK ==>|"gửi sự kiện, last_seen"| HUB
    HUB -->|"đẩy registry, truy vấn, xóa"| ADM
    ADM -->|"đọc số liệu, xóa series"| VM
    ADM -->|"cập nhật registry"| RED
NútÝ nghĩa
Ingest, Worker, AdminBa vai trò của cùng một binary, scale độc lập (internal/app/wiring.go)
RedisRegistry, presence, bus, outbox, lease gửi (tiền tố ah:)
VictoriaMetricsHai instance: thô (tsdb.url) và dài hạn (tsdb.long_url)

2.3 Các thành phần chính ​

Thành phầnVai tròL3 chi tiết
Ingest APINhận HTTP từ agent, kiểm tra, xác thực, đẩy lên busL3 Ingest API
Registry, Resolver, Enroll proxy, PresenceDanh tính agent, tra ngược Access Hub, theo dõi lần thấy cuốiL3 Registry, Enroll
Bus, Worker, TSDB adapterĐệm, ghi lô, chọn nguồn truy vấnL3 Bus, Worker, TSDB
Detector, Emitter, Outbox, SenderMất tín hiệu, sự kiện, gửi bền vữngL3 Alerting, Outbox
Admin APICổng nội bộ cho Access HubL3 Admin API
Nền chunginternal/config, internal/app, internal/httpx, internal/ratelimit, internal/metrics, internal/catalog, internal/redisxMục 12, 13 của tài liệu này

3. Functional Requirements ​

Mã FR lấy từ docs/02-requirements.md. Cột trạng thái là hiện trạng mã.

STTNhóm chức năngMô tảTrạng thái
1Enroll agent (FR-02, FR-05)Nhận License từ agent, chuyển tiếp sang Access Hub, lưu agent vào registry, trả token một lầnĐã làm (internal/ingest/handlers.go)
2Thu hồi agent (FR-03)Admin API đẩy trạng thái thu hồi, ingest trả 403 agent_revokedĐã làm (internal/admin, internal/registry)
3Nhận số liệu (FR-14)Giải nén, kiểm tra danh mục, nhãn, cửa sổ thời gian, giới hạn series, gắn danh tính, đẩy busĐã làm
4Ghi TSDB (FR-14)Gom lô 5000 mẫu hoặc 500 ms, thử lại, gắn nhãn tenantĐã làm
5Rollup (FR-15)Truy vấn chọn nguồn thô hoặc rollup 5 phút, 1 giờ theo tuổi của from và step, gộp lại ô, đọc lại thô khi rollup trống. Luật rollup sinh bởi collector -rollup-rules, chạy trong vmalertĐã làm phía truy vấn, luật rollup ở deploy/
6Kiểm kê (FR-16)Nhận, khử trùng trong 1 giờ, chuyển tiếp lô sang Access Hub, chỉ giữ báo cáo mới nhất mỗi agentĐã làm (internal/ingest/inventory.go)
7Cấu hình agentTrả cấu hình mặc định kèm ETag, agent gửi If-None-Match nhận 304Đã làm (mặc định, chưa theo máy)
8Mất tín hiệu và phục hồi (FR-20)agent.down sau max(3 x interval, down_min), agent.up khi có lạiĐã làm (internal/alerting)
9Gửi sự kiện (FR-24)Outbox bền vững, gửi lô tối đa 200, dead-letterĐã làm (internal/outbox)
10last_seen và heartbeatGửi theo lô 500, heartbeat mỗi phútĐã làm
11Truy vấn cho giao diện (FR-30, FR-31)Trạng thái máy, chuỗi thời gian, tổng quan công ty qua Admin APIĐã làm
12Xóa dữ liệu (FR-43)Xóa agent trong registry và series TSDB theo máy hoặc theo công tyĐã làm
13Luật ngưỡng, check, flapping, group_down, silence, bảo trì (FR-21 đến FR-25)Đánh giá luật trên luồng mẫuLuật ngưỡng và check đã làm (COL-8). Flapping, group_down, silence, bảo trì chưa làm (COL-9)
14Cấp lại token (FR-04)Xoay token, chồng lấn 24 giờChỉ thiết kế

4. Non-Functional Requirements ​

Mục tiêu lấy nguyên văn từ docs/02 (NFR-xx). Cột "Hiện trạng" nêu việc đã có bằng chứng trong mã. Không có số đo tải thực tế nào được thực hiện cho bản nháp này (kiểm thử agentsim chưa có, xem mục 15).

STTCategoryRequirementTargetHiện trạng
1PerformanceSức chứa ingest (NFR-01)10.000 agent, chu kỳ 30 giây, 3 node ingest 4 vCPU và 8 GB: p99 ingest không quá 250 ms, không mất mẫu đã xác nhậnChưa đo. Có histogram ahc_ingest_request_duration_seconds để đo
2AvailabilitySẵn sàng ingest (NFR-02)99,9% mỗi tháng, mất một node không mất dữ liệu đã xác nhậnIngest không trạng thái, /readyz cho LB, chưa đo
3DetectabilityPhát hiện mất tín hiệu (NFR-03)Không quá 3 x interval + 30 giâyMã dùng max(3 x agent_interval, down_min) với down_min 90 giây, quét mỗi 10 giây. Với interval 30 giây, ngưỡng là 90 giây, thỏa NFR-03
4LatencyĐộ tươi (NFR-05)Giá trị mới nhất trên giao diện không quá 45 giây sau lúc thu thậpChưa đo. VictoriaMetrics ẩn 30 giây gần nhất khỏi truy vấn (-search.latencyOffset, ghi ở deploy/dev/vmcheck), là yếu tố cần tính
5QueryTruy vấn (NFR-06)Chuỗi 24 giờ p95 không quá 500 ms, 30 ngày qua rollup p95 không quá 1,5 giâyChưa đo
6ResilienceChịu mất TSDB (NFR-07)Đệm ít nhất 2 giờChưa đạt. Bus Redis bị chặn bởi bus.queue_per_shard, worker dừng nhận khi đệm quá 4 lần cỡ lô. Cần JetStream hoặc tăng đệm (AR-004)
7ResilienceChịu mất Access Hub (NFR-08)Outbox giữ ít nhất 24 giờ, ingest chạy bằng registry cacheĐạt theo thiết kế: outbox.retention mặc định 24 giờ, registry Redis không TTL
8SecurityBảo mật truyền tải (NFR-11)TLS 1.2 trở lênMã đặt MinVersion TLS 1.2 khi bật ingest.tls_*. Dev: TLS kết thúc ở nginx
9SecurityCô lập tenant (NFR-12)Không đường nào đọc, ghi, xóa dữ liệu công ty khác, có kiểm thử tự độngCó internal/app/tenant_test.go, TestTwoTenantsNeverMix, TestDeleteDataIsTenantScoped
10RecoveryKhôi phục (NFR-13)Khởi động lại không mất cảnh báo đang mởagent.down qua presence trong Redis. Cảnh báo ngưỡng qua snapshot trạng thái (Redis, tệp hoặc bộ nhớ, 30 giây một lần và khi tắt êm), sập cứng trong cửa sổ đó có thể phát lại một alert.opened
11CompatibilityGiao thức N và N-1 (NFR-14)Hỗ trợ N và N-1Hiện chỉ phiên bản 1 (X-AH-Proto: 1, proto_min 1, proto_max 1)
12ObservabilityQuan sát (NFR-15)/metrics, /healthz, /readyz, log JSON có request_idĐã làm trên cổng ops (internal/httpx)

5. Technology Stack ​

STTPhương ánApproachƯu điểmNhược điểmKết luận
1Go, một binary, nhiều vai tròMột chương trình, chọn vai trò bằng cờ hoặc cấu hìnhBinary tĩnh, dễ đóng gói, ít phụ thuộcĐội cần quen Go (R12)SELECTED (ADR 0003, ADR 0004)
2HTTPS + protobuf, nén zstd hoặc gzipAgent đẩy POST /agent/v1/*Qua proxy, tường lửa dễ, gọn, dễ cân tảiBảo trì .proto chung hai repo (R17)SELECTED (ADR 0002)
3gRPCLuồng hai chiềuSinh mã sẵnKhó qua proxy doanh nghiệpREJECTED (ADR 0002)
4VictoriaMetrics (hai instance thô và dài hạn)Ghi bằng import JSON line, truy vấn bằng HTTP query_rangeNén tốt, vận hành đơn giảnOSS không downsampling, retention toàn cụm (R11)SELECTED (ADR 0005, lệch cách ghi so với ADR, xem TD-001)
5MySQL, TimescaleDB, InfluxDB, Prometheus, ClickHouseLưu số liệuNhiều lựa chọn sẵn cóMySQL tranh chấp với ứng dụng nghiệp vụREJECTED (ADR 0005). Báo cáo lựa chọn chi tiết: báo cáo TSDB (do L1 viết)
6Bus Redis streams, consumer group workersMỗi shard một stream, XREADGROUP, XAUTOCLAIMBền vững theo AOF, nhiều worker chia việc, không cần thêm thành phầnĐệm bị chặn bởi bộ nhớ Redis, cap mềmSELECTED (mã, docs/09). ADR 0009 chưa cập nhật (TD-002)
7Bus in-process (channel có giới hạn)Một bộ chứa mỗi shardĐơn giản, nhanhKhông bền, chỉ một tiến trìnhSELECTED cho dev một tiến trình, tự chọn khi không có redis.addr
8Bus NATS JetStreamStream lưu file, nhân bảnĐệm 2 giờ, consumer bềnThêm thành phần vận hànhChưa làm, phương án mở rộng
9KafkaBusSức chứa lớnNặng vận hànhREJECTED (ADR 0009)
10Redis (Valkey tương thích) làm registry, presence, bus, outboxMột Redis dùng chung, tiền tố ah:Một thành phần cho mọi trạng thái nóngĐiểm chung của nhiều chức năng (AR-005)SELECTED
11Client Redis tự viết internal/redisx (RESP2)Không thêm thư viện, danh sách lệnh bị chặnÍt phụ thuộc, chặn lệnh nguy hiểmTự bảo trìSELECTED (docs/04 ghi chú COL-3)
12Outbox Redis, file, bộ nhớoutbox.backend: auto chọn redis rồi file rồi memoryBền theo môi trườngFile không dùng chung giữa tiến trìnhSELECTED cả ba, Discard khi không có hub
13Token mờ, tra registryBăm SHA-256, tra Redis rồi Access HubThu hồi nhanh, danh tính đáng tinCần đồng bộ registrySELECTED (ADR 0007)
14JWT tự chứa, mTLS bắt buộcXác thực không tra cứuKhông cần registryKhó thu hồi, cần PKIREJECTED (ADR 0007), mTLS tùy chọn giai đoạn 3

5.1 ADR Log ​

Các ADR nằm ở docs/adr/ (repo Collector). Chỉ mục ADR của toàn nền tảng do L1 giữ ở ./adr/README.md.

IDQuyết địnhStatus
ADR 0001Agent đẩy (push), chỉ kết nối đi raChấp nhận
ADR 0002HTTPS + protobuf, không gRPCChấp nhận
ADR 0003Ngôn ngữ GoChấp nhận
ADR 0004Tách control plane (Access Hub) và data plane (Collector)Chấp nhận
ADR 0005VictoriaMetrics làm TSDB, gọi là remote-writeChấp nhận, cần sửa: mã dùng /api/v1/import JSON (TD-001)
ADR 0006Chỉ số dạng gauge, tốc độ tính ở agentChấp nhận
ADR 0007Token mờ và đồng bộ registryChấp nhận
ADR 0008Chỉ gửi sự kiện đổi trạng thái về Access HubChấp nhận
ADR 0009Trừu tượng hóa Bus, phân shard theo máy chủChấp nhận, cần sửa: mã dùng Redis streams, không có lease shard (TD-002, TD-003)
ADR 0010Không thực thi mã từ xaChấp nhận
ADR 0011Kiểm kê không bao giờ ghi vào ServerChấp nhận
ADR 0012 (mới, ở chỉ mục ADR)Bus Redis Streams, outbox dùng chung trong Redis, lease bộ gửi (thay một phần ADR 0009)Đề xuất, chưa ai phê duyệt
ADR 0013 (mới)Dev mô phỏng đầy đủ sản xuấtĐề xuất
ADR 0014 (mới)Giữ VictoriaMetrics làm TSDBĐề xuất
ADR 0015 (mới)Ghi VictoriaMetrics bằng /api/v1/import JSON thay cho remote-write (lệch ADR 0005)Đề xuất

6. Integration ​

6.1 Component table ​

ComponentResponsibilityDataTechStorageExternal exposure
IngestNhận và xác thực request agent, kiểm tra giới hạn, đẩy busLô mẫu, enroll, kiểm kêGo net/http, protobufKhông (Redis dùng chung)Cổng ingest :8443 mặc định, qua LB TLS. Không lộ trực tiếp ở dev
Registry, ResolverDanh tính agent theo băm tokenAgentRecord (agent, công ty, máy chủ, trạng thái, hạn)Go, RedisRedis reg:*, cache nútKhông
PresenceLần thấy cuối, trạng thái up hoặc downHash và zset theo agentGo, RedisRedis pres:*Không
BusĐệm lô mẫu theo shardSampleBatchGo, Redis streams hoặc channelRedis bus:s:<n>Không
WorkerGom lô, ghi TSDBtsdb.BatchGoBộ nhớ (đệm ngắn)Chỉ cổng ops
TSDB adapterGhi, truy vấn, xóaSeries ah_*Go net/httpVictoriaMetricsKhông
Detector, EmitterPhát hiện mất tín hiệu, tạo sự kiệnEventGoPresence trong RedisKhông
Outbox, SenderHàng đợi sự kiện bền vững, gửi lôEntry (JSON)Go, RedisRedis ob:* hoặc tệpKhông
AdminAPI nội bộ cho Access HubJSONGo net/httpKhôngCổng admin 127.0.0.1:9101 mặc định, chỉ mạng nội bộ
Ops/healthz, /readyz, /metricsText Prometheusinternal/httpxKhôngCổng ops 127.0.0.1:9100 mặc định

6.2 Integration table ​

InterfaceProtocolContractScopeSync/Async
Agent đến IngestHTTPS, protobuf, /agent/v1docs/03-protocol.md, proto/accesshub/agent/v1/agent.proto (bản nháp), L3 IngestBên ngoài (Agent)Sync
Ingest đến Access Hub (enroll, tra token)HTTPS, JSON, <hub>/api/v1/monitoring/collectorinternal/hubclient, docs/06Bên ngoài (Access Hub)Sync
Ingest đến WorkerRedis streams (hoặc channel)internal/bus, L3 BusNội bộAsync
Worker đến VictoriaMetricsHTTP POST /api/v1/import, NDJSONinternal/tsdb/vm.goNội bộSync (theo lô)
Worker đến Access Hub (sự kiện, last_seen, heartbeat, kiểm kê)HTTPS, JSONinternal/hubclient, internal/outbox/sender.goBên ngoàiAsync (qua outbox)
Access Hub đến AdminHTTP, JSON, /internal/v1, BearerL3 AdminBên ngoài, mạng nội bộSync
Access Hub đến Registry (đồng bộ)HTTPS, JSON, GET /agents?since=internal/registry/resolver.go (Syncer)Bên ngoàiSync (kéo định kỳ)
Admin đến VictoriaMetricsHTTP, query_range, query, delete_seriesinternal/tsdb/vm.goNội bộSync
Prometheus đến OpsHTTP /metricsinternal/metricsNội bộSync
LB đến Ops (kiểm tra)HTTP /readyzinternal/httpxNội bộSync

6.3 Resilience table ​

Giá trị lấy từ config.Default() và mã. Ô "không có" nghĩa là chưa hiện thực.

ChặngTimeoutRetryBackoffCircuit breaker
Ingest đến Access Hub (tra token)hub.timeout 10 giâyKhông thử lại trong request; cache âm 60 giây, giới hạn hub.lookup_rate 50/s, single-flightCache âmKhông có, thay bằng giới hạn tốc độ và cache âm
Ingest đến Access Hub (enroll)20 giây (mã)Không (agent tự thử lại)Agent full jitterKhông có
Worker đến VictoriaMetricstsdb.timeout 10 giâyLỗi tạm (5xx, 408, 429, mạng) thử lại đến khi thành công200 ms nhân đôi đến tsdb.retry_max 30 giâyKhông có, thay bằng chặn đọc bus khi đệm quá 4 lần cỡ lô
Registry đến Redis500 ms (mặc định)Không; lỗi Redis đọc như ErrNotFound rồi hỏi Access HubKhôngKhông có
Publish bus RedisTimeout client RedisKhông; đầy thì ErrFull rồi 503AgentKhông có
Sender đến Access Hubhub.timeoutLỗi tạm thử lại, lỗi 4xx vĩnh viễn tách lô rồi dead-letteroutbox.backoff_min 1 giây đến backoff_max 5 phútKhông có
Forwarder kiểm kê đến Access Hubhub.timeout4xx vĩnh viễn thì bỏ lôĐến 1 phútKhông có
Admin đến TSDBtsdb.timeoutKhôngKhôngKhông có

Tài liệu thiết kế (docs/08) đề xuất cầu chì quanh Access Hub, TSDB, Redis. Chưa hiện thực (TD-006).


7. Data Architecture ​

7.1 Data Model ​

Collector không có cơ sở dữ liệu quan hệ. Mỗi "aggregate root" thuộc một kho riêng và chỉ tham chiếu Access Hub qua id. Sơ đồ quyền sở hữu dữ liệu:

mermaid
flowchart TB
    classDef owned fill:#2d4a3e,stroke:#5fb37a,color:#fff;
    classDef sensitive fill:#5a2d2d,stroke:#d96f6f,color:#fff;
    classDef entity fill:#3a3320,stroke:#d9b84a,color:#fff;

    subgraph HUBBC["Access Hub (nguồn sự thật, ngoài Collector)"]
        CO["Company"]:::entity
        SV["Server"]:::entity
    end

    subgraph COLBC["Collector"]
        AR["AgentRecord"]:::sensitive
        PR["PresenceEntry"]:::owned
        SB["SampleBatch"]:::owned
        SE["Series"]:::owned
        EV["OutboxEntry"]:::owned
    end

    AR -.->|"ref company_id"| CO
    AR -.->|"ref server_id"| SV
    PR -.->|"ref agent_id"| AR
    SB -.->|"ref server_id"| SV
    SE -.->|"ref company_id"| CO
    SE -.->|"ref server_id"| SV
    EV -.->|"ref server_id"| SV
AggregateKhoKhóaVòng đờiNhạy cảm
AgentRecord (băm token, trạng thái, hạn, phiên bản)Redis reg:tok:{hash}, reg:agent:{id}, tập reg:srv:{co}:{s}, reg:co:{co}, reg:allBăm token, agent_idKhông TTL. Xóa qua đồng bộ, Admin API, DeleteServer, DeleteCompany. Băm thu hồi giữ làm tombstone để trả 403Có (băm token). Không lưu token rõ
PresenceEntryRedis pres:a:{agent}, pres:up, pres:up:{co}, pres:down, pres:down:{co}, pres:unrepagent_idXóa khi thu hồi hoặc xóa máy chủThấp
SampleBatchRedis stream bus:s:<0..63>ShardXóa (XACK và XDEL) sau khi worker xử lýSố liệu của tenant, tạm thời
SeriesVictoriaMetrics (ah_<metric>{company_id,server_id,...})NhãnRetention theo instance (thô 30 ngày, dài hạn 400 ngày trong dev, theo docs/04)Số liệu của tenant
OutboxEntryRedis ob:q, ob:e, ob:dead hoặc tệp outbox.log, deadletter.jsonlevent_id (UUIDv7)Xóa khi Access Hub xác nhận, dead-letter khi hết hạn 24 giờ hoặc bị từ chốiTrung bình (định danh máy chủ, công ty)

Nhãn hệ thống trong TSDB: company_id, server_id, do Collector gắn. Không dùng agent_id, hostname làm nhãn (tránh bùng nổ cardinality, docs/04). Tên chỉ số có tiền tố ah_. Danh mục chỉ số và nhãn cho phép nằm ở internal/catalog/metrics.yaml (61 chỉ số, bản máy đọc của danh mục chỉ số chuẩn mà Agent và Collector dùng chung theo hợp đồng docs/03-protocol.md).

7.2 DFD ​

mermaid
flowchart TD
    classDef bc fill:#1f3a5f,stroke:#4a90d9,color:#fff;
    classDef entity fill:#3a3320,stroke:#d9b84a,color:#fff;
    classDef datastore fill:#3a2d4a,stroke:#a06fd9,color:#fff;
    classDef process fill:#1f3a5f,stroke:#4a90d9,color:#fff;

    AG(["Agent"]):::entity
    HUBSRC(["Access Hub nguồn lệnh"]):::entity
    HUBDST(["Access Hub nhận sự kiện"]):::entity

    P1["Ingest: xác thực và kiểm tra"]:::process
    P2["Worker: ghi TSDB"]:::process
    P3["Detector: mất tín hiệu"]:::process
    P4["Sender: gửi sự kiện"]:::process
    P5["Admin: registry và truy vấn"]:::process

    D1[("Registry Redis")]:::datastore
    D2[("Presence Redis")]:::datastore
    D3[("TSDB")]:::datastore
    D4[("Outbox")]:::datastore

    AG -->|"1 số liệu, enroll, kiểm kê"| P1
    HUBSRC -->|"10 đẩy registry, thu hồi, xóa"| P5

    P1 -->|"2 ghi agent sau enroll"| D1
    P1 -->|"3 cập nhật lần thấy cuối"| D2
    P1 -->|"4 lô mẫu theo shard"| P2
    P2 -->|"5 ghi lô mẫu"| D3
    P2 -->|"6 lô mẫu (đọc lần thấy)"| P3
    P3 -->|"7 sự kiện mất tín hiệu"| D4
    D4 -->|"8 sự kiện chờ gửi"| P4
    P4 -->|"9 sự kiện, last_seen"| HUBDST
    P5 -->|"11 cập nhật agent"| D1
    P5 -->|"12 xóa series"| D3

Ghi chú theo chuẩn DFD: bus không vẽ (là broker), luồng 4 là đường ingest đến worker qua bus. Datastore chỉ có mũi tên đi vào ở phần ghi, đường đọc mô tả bằng bảng. Access Hub được tách hai nút (nguồn lệnh và nơi nhận sự kiện) để entity chỉ có mũi tên một chiều. Luồng 6 đưa mẫu đến Detector (thực tế Detector đọc presence trong Redis, mẫu cập nhật presence ở luồng 3), giữ để thể hiện phụ thuộc thứ tự.

LuồngNội dungĐường đọc kèm theo
1Body protobuf nén, header xác thựcIngest đọc Registry (D1) để tra danh tính, Access Hub khi miss
3Presence.Touch sau khi publish busDetector đọc D2 khi quét
5Lô mẫu đã gắn company_id, server_idAdmin đọc D3
7, 8Outbox.Append rồi PeekSender đọc D4

7.3 Privacy / PII ​

Hạng mụcCó / KhôngGhi chú
Lưu thông tin định danh cá nhân (họ tên, email, số điện thoại)KhôngKhông có trường nào trong mô hình Collector
Lưu định danh máy chủ (hostname, IP)Có (tạm thời)Chỉ trong lô kiểm kê chuyển tiếp và trường enroll (hostname, tối đa 32 IP, machine_id băm), không lưu lâu dài ở Collector
Lưu token agent rõKhôngChỉ băm SHA-256
Lưu log chứa tokenKhôngBộ lọc che và tiêu chuẩn log (mục 9.4)
Số liệu chứa dữ liệu nhạy cảmKhôngChỉ số tổng hợp, không có dòng lệnh, nội dung tệp, biến môi trường (docs/07 mục 8)
Dữ liệu tenant phải xóa khi xóa công ty hoặc máy chủCóDELETE /internal/v1/servers/{id}/data, DELETE /internal/v1/companies/{id}/data
Truyền dữ liệu ra khỏi hệ thốngCóSự kiện và kiểm kê về Access Hub, cùng tổ chức

7.4 Chi tiết riêng tư ​

Hostname và IP được coi là dữ liệu vận hành nội bộ của công ty (docs/07). Địa chỉ MAC mặc định không gửi. Retention là toàn cụm, không theo công ty (Q4). Chính sách lưu trữ hiển thị chỉ đọc trong Access Hub.


8. Business Flow ​

ActorVai trò
AgentĐẩy số liệu, enroll, kiểm kê
Quản trị Access HubTạo License, thu hồi agent, xem sức khỏe máy
Access Hub (dịch vụ)Xác thực enroll, đồng bộ registry, nhận sự kiện, gọi Admin
Vận hànhChạy và giám sát Collector, Redis, TSDB

8.1 Sequence ​

Luồng enroll ​

mermaid
sequenceDiagram
    participant AG as Agent (ext)
    participant IN as Ingest
    participant HB as Access Hub (ext)
    participant RG as Registry

    AG->>IN: POST /agent/v1/enroll (License, hostname, IP)
    IN->>IN: kiểm tra header, giới hạn trường, tốc độ theo IP
    IN->>HB: POST /enroll (chuyển IP client)
    alt hub chấp nhận
        HB-->>IN: agent_id, company_id, server_id, token băm
        IN->>RG: Put agent active, xóa cache âm
        IN-->>AG: agent_token, collector_url, config
    else hub từ chối
        HB-->>IN: 409, 422 hoặc 429
        IN-->>AG: already_enrolled, token_used, binding_failed, rate_limited
    end

Luồng nhận số liệu ​

mermaid
sequenceDiagram
    participant AG as Agent (ext)
    participant IN as Ingest
    participant RG as Registry
    participant BS as Bus
    participant WK as Worker
    participant TS as TSDB

    AG->>IN: POST /agent/v1/metrics (protobuf nén)
    IN->>RG: tra băm token
    RG-->>IN: agent, công ty, máy chủ
    IN->>IN: giải nén, kiểm tra, gắn danh tính
    IN--)BS: publish lô theo shard
    IN-->>AG: ack (ack_seq, config_etag, accepted, dropped)
    BS--)WK: lô mẫu
    WK->>TS: import theo lô 5000 mẫu hoặc 500 ms

Luồng mất tín hiệu ​

mermaid
sequenceDiagram
    participant DT as Detector
    participant PS as Presence
    participant OB as Outbox
    participant SN as Sender
    participant HB as Access Hub (ext)

    loop mỗi scan 10 giây
        DT->>PS: lấy agent quá hạn
        PS-->>DT: danh sách agent down (một chủ duy nhất)
        DT->>OB: append agent.down (event_id, seq)
    end
    SN->>OB: peek tối đa 200
    SN->>HB: POST /events
    HB-->>SN: accepted, rejected
    SN->>OB: ack hoặc dead-letter

8.2 State ​

Trạng thái bền của một agent trong presence và của một sự kiện trong outbox:

mermaid
stateDiagram-v2
    direction LR
    state "Chờ (pending)" as PEND
    state "Hoạt động (active)" as ACT
    state "Thu hồi (revoked)" as REV
    [*] --> PEND
    PEND --> ACT: enroll thành công
    ACT --> REV: admin thu hồi hoặc đồng bộ
    REV --> [*]: xóa máy chủ hoặc công ty
    ACT --> [*]: xóa máy chủ hoặc công ty
mermaid
stateDiagram-v2
    direction LR
    state "Trực tuyến (up)" as UP
    state "Mất tín hiệu (down)" as DOWN
    state "Chờ gửi (queued)" as Q
    state "Đã gửi (acked)" as ACK
    state "Thư chết (dead)" as DEAD
    [*] --> UP
    UP --> DOWN: quá hạn ngưỡng
    DOWN --> UP: nhận lại lô hợp lệ
    [*] --> Q
    Q --> ACK: hub chấp nhận
    Q --> DEAD: bị từ chối hoặc hết hạn
    ACK --> [*]

Trạng thái pending của bản ghi agent hiện có trong mô hình nhưng ingest luôn coi là 401 (chưa dùng được).


9. Security ​

9.1 Identity ​

Đối tượngCơ chếNguồn sự thật
AgentToken mờ (Bearer), tối đa 256 ký tự, băm SHA-256, tra registry. Đề xuất định dạng ahat_<base64url> (ADR 0007, phía Access Hub sinh)Access Hub
EnrollLicense do Access Hub kiểm tra, Collector chỉ chuyển tiếp, giới hạn theo IPAccess Hub
Access Hub gọi AdminBearer admin token riêng, so sánh hằng thời gian trên băm SHA-256, tối thiểu 24 ký tự khi cấu hìnhCấu hình collector
Collector gọi Access HubBearer hub.token (dịch vụ)Access Hub cấp
Người dùngKhông bao giờ chạm Collector trực tiếp, đi qua Access HubAccess Hub

9.2 AuthZ ​

Cơ chếMô tả
Danh tính từ registryMọi API agent (trừ ping, enroll) dùng danh tính tra được; nội dung body không ghi đè
Tenant trong Admincompany_id bắt buộc cho mọi API theo máy chủ, kiểm tra tsdb.CheckTenant, matcher TSDB luôn chứa cả company_id và server_id
Một token admin cho toàn bộ Admin APIKhông có phân quyền chi tiết (đề xuất: xem TD-007)
Chủ thểIngest /agent/v1/*Admin /internal/v1/*Ops (/metrics, /readyz)
Agent (token hợp lệ)Cho phép theo APIKhôngKhông
Access Hub (admin token)KhôngCho phépKhông
Prometheus, LBKhôngKhôngCho phép, mạng nội bộ
Không xác thựcChỉ ping và enrollKhôngMặc định chỉ lắng nghe 127.0.0.1

9.3 Secrets ​

Bí mậtNguồnGhi chú
admin.token, hub.token, redis.passwordTệp (*_file) hoặc biến môi trường AHC_ADMIN_TOKEN(_FILE), AHC_HUB_TOKEN(_FILE), AHC_REDIS_PASSWORD(_FILE)Không ghi vào YAML trong repo. Ở dev nằm trong thư mục cấu hình người dùng, quyền tệp do devctl.sh quản lý
Khóa TLS ingestingest.tls_cert_file, ingest.tls_key_file (đặt cùng nhau)Ở dev TLS kết thúc ở nginx
Token agentKhông lưu rõ, chỉ bămHiển thị đúng một lần lúc enroll

9.4 AppSec ​

Hạng mụcBiện pháp
Che dữ liệu nhạy cảmKhông log token, Authorization. X-Request-Id chỉ nhận theo mẫu ^[A-Za-z0-9._-]{1,64}$
Kiểm tra đầu vàoDanh mục chỉ số, nhãn cho phép, giới hạn kích thước, số điểm, số series, cửa sổ thời gian (mục 4 của L3 Ingest)
Chống lạm dụngGiới hạn tốc độ theo agent và theo IP, bus có giới hạn, giới hạn giải nén, MaxHeaderBytes 64 KiB
TLSTối thiểu 1.2 khi Collector tự kết thúc TLS
Lệnh RedisClient chặn FLUSHALL, FLUSHDB, KEYS, CONFIG, SHUTDOWN, DEBUG, SLAVEOF, REPLICAOF, MIGRATE, SCRIPT, EVAL, EVALSHA, ACL
Security loggingĐã có metric ahc_ingest_auth_failures_total, ahc_ingest_rate_limited_total, ahc_ingest_reserved_labels_total. Chưa có cảnh báo tự động (đề xuất)
Mã hóa lưu trữKhông do Collector cung cấp, phụ thuộc nền tảng lưu trữ (đề xuất: docs/07 mục 7)

10. Deployment ​

10.1 Environments ​

Môi trườngTopologyNguồn
DevNginx TLS, 2 ingest, 2 worker, 1 admin, Redis master và replica, vm-raw, vm-long, vmalert, mockhub, agent. Chạy bằng systemd user unitdeploy/dev, deploy/systemd, docs/09 mục 7
Production nhỏ (đề xuất theo docs/01)2 node collector sau LB, 1 Redis có replica, 1 VictoriaMetricsdocs/01, docs/09
Production lớnIngest, worker, admin tách riêng, Redis HA, VictoriaMetrics cụmdocs/08, chưa làm

Chi tiết dev (cổng, collector_id, tệp cấu hình):

Thành phầnDịch vụ systemdCổngGhi chú
Nginx TLSaccesshub-lb127.0.0.1:8443Upstream 2 ingest
Ingest 1 và 2accesshub-collector-ingest@{1,2}ingest 18443, 18444, ops 9111, 9112collector_id dev-ingest-1, dev-ingest-2, trusted_proxies 127.0.0.0/8
Worker 1 và 2accesshub-collector-worker@{1,2}ops 9121, 9122dev-worker-1, dev-worker-2
Adminaccesshub-collector-adminadmin 127.0.0.1:9101, ops 9110dev-admin
Redis master, replicaaccesshub-redis-master, accesshub-redis-replica6380, 6381Mật khẩu, AOF everysec, maxmemory 256mb, noeviction
vm-raw, vm-longaccesshub-vm-raw, accesshub-vm-long8428, 8429Retention 30 ngày và 400 ngày
vmalertaccesshub-vmalert8880Luật rollup sinh bởi collector -rollup-rules (dev: gen-vmalert-rules.sh)
Mockhubaccesshub-mockhub8090Chỉ dev. API monitoring thật của Access Hub (HUB-*) chưa xây
Agentaccesshub-agent(đi ra)Ghim CA dev

Các cổng và tên dịch vụ trên là trạng thái repo tại 2026-09-30. Thư mục deploy/ đang được luồng khác chỉnh sửa, cần đối chiếu lại khi chốt.

10.2 Deployment diagram ​

mermaid
flowchart TB
    classDef bc fill:#1f3a5f,stroke:#4a90d9,color:#fff;
    classDef entity fill:#3a3320,stroke:#d9b84a,color:#fff;
    classDef datastore fill:#3a2d4a,stroke:#a06fd9,color:#fff;
    classDef infra fill:#444,stroke:#aaa,color:#fff;

    AG(["Agent trên máy chủ"]):::entity
    OPS(["Vận hành qua bastion"]):::entity
    HUB(["Access Hub"]):::entity

    subgraph EDGE["Edge"]
        LB["Load balancer TLS"]:::infra
    end
    subgraph APP["Vùng ứng dụng"]
        ING["Ingest x N"]:::bc
        WRK["Worker x N"]:::bc
        ADM["Admin"]:::bc
    end
    subgraph DATA["Vùng dữ liệu"]
        RED[("Redis")]:::datastore
        VMR[("VM thô")]:::datastore
        VML[("VM dài hạn")]:::datastore
        VMA["vmalert"]:::infra
    end

    AG --> LB
    LB --> ING
    ING -.-> RED
    RED -.-> WRK
    WRK --> VMR
    VMR --> VMA
    VMA --> VML
    WRK ==> HUB
    ING ==> HUB
    HUB --> ADM
    ADM --> VMR
    ADM --> RED
    OPS --> ADM

Sơ đồ không ghi kích cỡ, phiên bản, IP. Ở dev không có firewall trên đường đi, mọi thành phần chạy trên một máy (cổng loopback).

10.3 Strategy ​

Deployment TypeDowntimeRollbackWindowApproval
Rolling (đề xuất, docs/09 mục 5): rút ingest khỏi LB khi /readyz trả 503, nâng, thêm lạiKhông có khi còn ít nhất một nodeCài lại binary trước đó (đề xuất, chưa có runbook)Chưa chỉ địnhChưa chỉ định
Worker: tắt êm, node khác nhận lô treo sau bus.claim_idle 30 giâyKhông (dữ liệu đệm trong Redis)Như trênChưa chỉ địnhChưa chỉ định
Dev: devctl.sh (khởi động lại từng dịch vụ systemd)Có ngắnCài lại binaryKhông áp dụngKhông áp dụng

Tương thích khi nâng cấp: nâng Collector trước, Agent sau (docs/09). Thay đổi cấu hình dùng kiểm tra collector -check trong ExecStartPre.

10.4 Network security ​

Hạng mụcGiải phápThông sốPhạm vi
Đường agentHTTPS đến LB, LB chuyển HTTP thuần đến ingest ở dev, trusted_proxies để lấy IP thậtTLS 1.2 trở lên, HTTP/2 ở LB, body tối đa 1 MiB, timeout đọc 30 giây (docs/09 mục 7)Internet đến LB
Đường adminChỉ lắng nghe loopback hoặc mạng nội bộ, Bearer admin token127.0.0.1:9101 mặc địnhNội bộ
Cổng opsChỉ lắng nghe loopback127.0.0.1:9100 mặc địnhNội bộ
Redis, TSDBMạng riêng, Redis có mật khẩu, tùy chọn TLSClient Redis hỗ trợ redis.tls và tls_ca_fileNội bộ
Cách ly tiến trìnhsystemd NoNewPrivileges, PrivateTmp, ProtectSystem=strict, ProtectHome=read-only, RestrictAddressFamilies, MemoryMaxXem deploy/systemdMáy chạy dịch vụ
Quản trị từ xaQua bastion (đề xuất, production)Chưa có tài liệu hạ tầngVận hành

10.5 Migration ​

Chưa có dữ liệu cũ cần di chuyển. Khi chuyển từ bus in-process sang Redis streams hoặc tách vai trò, cần redis.addr, bus Redis và outbox Redis (mã từ chối cấu hình tách vai trò thiếu điều kiện này lúc khởi động, internal/config). Guide triển khai production nằm ở docs/14-production-deployment-guide.md (do luồng khác viết, chưa có tại thời điểm này).


11. Cost and Capacity ​

11.1 Capacity ​

Mọi số dưới đây là ước tính thiết kế (docs/08), chưa kiểm chứng bằng đo thực tế.

MetricTargetRemarks
Số agent10.000 ở chu kỳ 30 giâyNFR-01, khoảng 333 request/giây
Mẫu ghikhoảng 23 nghìn mẫu/giây ở 10.000 máydocs/08 giả định 70 series mỗi máy
Dung lượng TSDB thôkhoảng 2 GB mỗi ngày ở 10.000 máyGiả định khoảng 1 byte mỗi mẫu sau nén
Series mỗi agent500 (giới hạn cứng, ingest.limits.max_series)Cửa sổ trượt 1 giờ
Điểm mỗi request20.000max_points
Body nén, giải nén1 MiB, 8 MiBmax_body_bytes, max_decoded_bytes
Shard logic64 (cố định)Tối đa 64 worker hữu ích
Trần bộ nhớ dev mỗi tiến trình512M ingest, worker, 256M adminMemoryMax trong unit dev
Redis devmaxmemory 256mb, noevictionĐầy Redis làm ghi lỗi, không bỏ dữ liệu ngầm

11.2 Cost ​

Chưa có mô hình chi phí hạ tầng (nợ thiết kế đã ghi ở docs/13 mục 4). Đề xuất: lập sau khi đo agentsim (spike S2, S3).


12. Scalability and Reliability ​

12.1 Scaling ​

Thành phầnCách scaleGhi chú
IngestNgang sau LB, không trạng tháiGiới hạn tốc độ theo agent là trong bộ nhớ từng node, không chia sẻ toàn cụm (TD-005)
WorkerNgang. Mỗi worker đọc min(bus.readers, shards) vòng lặp, Redis chia việc bằng consumer group, không có lease shardNhiều worker cùng đọc một shard là hợp lệ, thứ tự trong shard không được bảo đảm tuyệt đối khi có nhiều consumer (mẫu idempotent theo timestamp nên không hỏng dữ liệu)
AdminNgang, không trạng thái
RedisDọc, master và replica ở dev. Sentinel hoặc Cluster chưa làmĐiểm chung (AR-005)
VictoriaMetricsSingle hai instance. Cụm chưa làm

12.2 Reliability ​

Tình huốngHành vi (đã kiểm chứng trong mã hoặc kiểm thử)
Mất Access HubIngest dùng registry cache. Miss thì 503 Retry-After 30, không 401. Sự kiện nằm trong outbox 24 giờ
Mất RedisRegistry đọc lỗi thành ErrNotFound rồi hỏi Access Hub có giới hạn. Bus, outbox, presence ngưng (readiness "redis" đỏ). TestRedisRegistryDownFallsBackToNotFound
Mất TSDBWorker giữ lô và thử lại, dừng đọc bus khi đệm đầy, ingest trả 503. Tắt tiến trình lúc TSDB chết có thể mất mẫu (AR-002). Readiness "tsdb" đỏ
Một node ingest chếtLB chuyển sang node còn lại
Một worker chếtLô chưa xác nhận được worker khác nhận sau bus.claim_idle 30 giây (TestRedisBusClaimsEntriesOfDeadConsumer)
Sender chạy trên nhiều tiến trìnhLease Redis 15 giây bảo đảm một bên gửi, không có fencing (AR-003). Trùng lặp vô hại vì Access Hub khử trùng theo event_id

13. Observability ​

Hạng mụcNội dungNguồn
Endpoint ops/healthz, /readyz (kiểm tra "redis" và "tsdb", timeout 2 giây, 503 khi đang tắt êm), /metricsinternal/httpx, internal/app
Metric ingestahc_ingest_requests_total, ahc_ingest_request_duration_seconds, ahc_ingest_auth_failures_total, ahc_ingest_rate_limited_total, ahc_ingest_points_accepted_total, ahc_ingest_points_dropped_total{reason}, ahc_ingest_series_limit_dropped_total, ahc_ingest_reserved_labels_total, ahc_ingest_publish_failures_total, ahc_ingest_enroll_total{result}, ahc_ingest_bus_depth, ahc_ingest_inventory_pending, ahc_inventory_forwarded_total, ahc_inventory_dropped_totalinternal/ingest
Metric registry, worker, TSDBahc_registry_lookups_total{result}, ahc_tsdb_samples_written_total, ahc_tsdb_write_errors_total{kind}, ahc_tsdb_batches_dropped_total, ahc_worker_batches_total, ahc_tsdb_flush_seconds, ahc_worker_pending_samplesinternal/registry, internal/worker
Metric alerting, outboxahc_agents_down, ahc_events_lost_total, ahc_outbox_events_sent_total, ahc_outbox_send_failures_total{kind}, ahc_outbox_dead_letter_total{reason}, ahc_outbox_depth, ahc_outbox_oldest_age_secondsinternal/alerting, internal/outbox
LogJSON một dòng (log.format: json), request_id từ X-Request-Id hoặc sinh mớiinternal/app, internal/httpx
TraceChưa có (OpenTelemetry tùy chọn ở docs/10, chưa hiện thực)
Cảnh báo nội bộBộ luật mẫu ở docs/10 mục 5 (deploy/alerts/collector.rules.yaml chưa có trong repo tại thời điểm này)

Tên metric ở docs/10 khác tên trong mã ở nhiều chỗ, xem TD-004. Danh sách trên lấy từ mã. Mã còn có ahc_bus_depth, ahc_registry_agents, ahc_events_emitted_total{type}, ahc_build_info{version,commit}, ahc_uptime_seconds, ahc_goroutines.


14. Operational Readiness ​

Hạng mụcNội dung
Mức bảo mật dữ liệuSố liệu hệ thống của tenant và định danh máy chủ. Không có dữ liệu cá nhân. Đề xuất phân loại: nội bộ (Internal), chưa được bên bảo mật xác nhận
RTOChưa chỉ định. Đề xuất: theo cấp 3, vài giờ, cần xác nhận (OQ-4 của L1)
RPOChưa chỉ định. Thực tế kỹ thuật: outbox và bus Redis bền theo AOF everysec (mất tối đa khoảng 1 giây ghi khi Redis hỏng đột ngột, đề xuất xác nhận), sample chưa vào TSDB có thể mất khi TSDB hỏng lúc tắt tiến trình. Agent còn đệm WAL đĩa để gửi bù (phía Agent)
Blast radiusMất Collector không làm sập luồng nghiệp vụ Access Hub (ADR 0004). Tenant thấy trạng thái cũ hoặc không có dữ liệu. Một token admin bị lộ ảnh hưởng mọi tenant
DR modelRegistry tự nạp lại từ Access Hub khi Redis rỗng (đồng bộ theo since). TSDB khôi phục từ snapshot (chưa có lịch snapshot ở dev). Redis RDB, AOF. Runbook: docs/09 mục 5, 6 (rút gọn)
Runbookdocs/09 mục 6 (rút gọn, chi tiết chưa viết)
Sao lưuSnapshot VM và Redis theo lịch: chưa có ở dev

15. Testing and Quality ​

TầngHiện trạngBằng chứng
Đơn vịCó, mỗi gói có _test.goXem danh sách test ở từng L3
Tích hợp trong tiến trìnhCó, pipeline ingest đến TSDB bộ nhớ, tách tiến trình qua Redisinternal/app/pipeline_test.go, events_test.go (TestSplitProcessesShareStateThroughRedis)
Cô lập hai tenantCóinternal/app/tenant_test.go (TestTwoTenantIsolationThroughIngestAndAdminAPI), internal/ingest/ingest_test.go (TestTwoTenantsNeverMix), internal/admin/admin_test.go (TestDeleteDataIsTenantScoped)
Với VictoriaMetrics thậtCó, tùy chọn: bỏ qua nếu thiếu AHC_TEST_VM_URLdeploy/dev/vmcheck/vmcheck_test.go. Không chạy trong phiên viết tài liệu này
Hợp đồng với Access HubChỉ có mockhub, API thật (HUB-*) chưa xâycmd/mockhub (đề xuất kiểm tra lại khi HUB-* xong)
Fuzz, tải (agentsim), hỗn loạnChưa códocs/12 mô tả kế hoạch. Không có cmd/agentsim trong cây mã hiện tại
Redis thậtCó phần dùng Redis giả cho hợp đồng, phần dùng Redis thật tùy chọninternal/registry/redis_test.go (TestRedisRegistryContractLive)

Chất lượng mã (đề xuất theo docs/12 mục 7): gofmt, go vet, staticcheck, govulncheck, go test -race. CI: chưa xác minh trong phiên này.


16. Risks ​

16.1 Architecture Risks ​

Xác suất và mức độ dùng thang T (thấp), V (vừa), C (cao). Chủ sở hữu: chưa chỉ định cho mọi dòng. Tất cả trạng thái: Mở.

Risk IDCategoryDescriptionBusiness ImpactLikelihoodSeverityMitigationResidualOwnerStatus
AR-001ReliabilityDanh sách thử lại trong bộ nhớ của Detector mất nếu tiến trình chết giữa lúc đánh dấu agent down và Outbox.Append thành công (internal/alerting/alerting.go)Mất một sự kiện agent.down, Access Hub không biết máy mất tín hiệuTVOutbox bền, thử lại trong bộ nhớ. Đề xuất: ghi cờ bền trước khi đánh dấu downVChưa chỉ địnhMở
AR-002ReliabilityFlush cuối lúc tắt mất mẫu nếu TSDB đang chết (lost_on_shutdown)Khoảng trống số liệu ngắnVTworker.shutdown_flush 10 giây, agent đệm và gửi bùTChưa chỉ địnhMở
AR-003ConcurrencyLease gửi outbox không có fencing (internal/redisx/lease.go)Có thể gửi trùng, vô hại vì khử trùng theo event_idTTIdempotent sendTChưa chỉ địnhMở
AR-004CapacityĐệm bus Redis chỉ bị chặn mềm (XLEN lấy mẫu 200 ms), chưa có JetStream, NFR-07 (đệm 2 giờ) chưa đạtMất TSDB lâu thì ingest trả 503, agent phải đệmVVTăng bus.queue_per_shard, theo dõi ahc_ingest_bus_depth, JetStream (chưa làm)VChưa chỉ địnhMở
AR-005AvailabilityRedis là điểm chung của registry, presence, bus, outbox. Dev có master và replica nhưng chưa SentinelMất Redis: ngừng ghi mẫu và phát hiện mất tín hiệuVCRegistry hỏi lại Access Hub, AOF, replica. Sentinel hoặc Cluster (chưa làm)VChưa chỉ địnhMở
AR-006IntegrationAdapter VictoriaMetrics dùng /api/v1/import JSON, ADR 0005 nói remote-write. Có kiểm thử thật tùy chọn nhưng chưa chạy trong đợt nàyNếu định dạng sai, số liệu không vào TSDBTCdeploy/dev/vmcheck chạy khi có AHC_TEST_VM_URLTChưa chỉ địnhMở
AR-007Functional gapLuật ngưỡng đã có (COL-8), còn thiếu group_down, flapping, silence, bảo trì (COL-9)Chống nhiễu nâng cao chưa có (G3 của L1 đạt phần lớn)CVLàm COL-9 theo docs/11VChưa chỉ địnhMở
AR-008Functional gapPOST /credentials/renew là stub 503, chưa có xoay token (FR-04)Token dài hạn tăng rủi ro lộVVLàm ở giai đoạn 2, thu hồi thủ công khi cầnVChưa chỉ địnhMở
AR-009Data lifecycleRegistry và presence không TTL, dọn dẹp phụ thuộc đồng bộ và Admin APIBản ghi mồ côi nếu đồng bộ lỗiTTĐồng bộ since, DeleteServer, DeleteCompanyTChưa chỉ địnhMở
AR-010DependencyRollup phụ thuộc vmalert chạy đúng. Truy vấn 7 ngày trở lên đọc vm-longBiểu đồ dài hạn rỗng nếu vmalert dừngVVTheo dõi vmalert, sinh luật từ catalogTChưa chỉ địnhMở
AR-011IntegrationAPI monitoring thật của Access Hub (HUB-*) chưa có, dev dùng mockhubHợp đồng thật chưa được kiểm chứngCVKiểm thử hợp đồng khi có HUB-* (R-A của L1)VChưa chỉ địnhMở
AR-012SecurityMột token admin duy nhất, không phân quyền chi tiết, không xoay tự độngLộ token ảnh hưởng mọi tenantTCMạng nội bộ, so sánh hằng thời gian. Đề xuất: mTLS hoặc token theo vai tròVChưa chỉ địnhMở

16.2 Tech Debt ​

IDMô tảVị tríƯu tiên (đề xuất)
TD-001ADR 0005, docs/01, docs/08, docs/09 nói remote-write, mã dùng POST /api/v1/import JSON line. docs/04 đã ghi chú lệch. Cấu hình mẫu docs/09 dùng tsdb.write_url, mã dùng tsdb.urlinternal/tsdb/vm.goCao
TD-002ADR 0009 nói Redis Streams "không chọn", nhưng mã và docs/09 dùng Redis streams làm bus giai đoạn 1internal/bus/redis.goCao
TD-003docs/08 và ADR 0009 mô tả lease shard trong Redis (ah:collector:{id}), mã không có, dùng consumer groupinternal/bus/redis.goTrung bình
TD-004Tên metric trong docs/10 khác mã: ahc_ingest_duration_seconds so với ahc_ingest_request_duration_seconds; ahc_samples_accepted_total so với ahc_ingest_points_accepted_total; ahc_auth_failures_total so với ahc_ingest_auth_failures_total; ahc_bus_depth{shard} trong docs còn mã có ahc_bus_depth (không nhãn shard) và ahc_ingest_bus_depth; chưa có ahc_agents_online, ahc_alert_*, ahc_shard_owned, ahc_accesshub_*, ahc_agent_versions, ahc_active_series_totalinternal/ingest, internal/app/wiring.go, docs/10Trung bình
TD-005docs/08 nói giới hạn tốc độ có phạm vi cụm trên Redis, mã chỉ có token bucket trong bộ nhớ mỗi nodeinternal/ratelimitTrung bình
TD-006Cầu chì (circuit breaker) đề xuất ở docs/08 chưa hiện thựcToàn bộThấp
TD-007docs/03 nói Admin có /internal/v1/query/... và /internal/v1/tenants/{id}/data, mã dùng /servers/{id}/series, /servers/{id}/data, /companies/{id}/datainternal/admin/admin.goTrung bình
TD-008docs/04 mô tả TTL 1 giờ cho reg:tok, reg:agent và khóa ah:seen, ah:agent:{id}:st, ah:rl:*, ah:series:*; mã dùng pres:*, không TTL cho registry, giới hạn tốc độ và series trong bộ nhớinternal/registry/redis.go, internal/presence/redis.goTrung bình
TD-009proto/accesshub/agent/v1/agent.proto là bản nháp; nguồn sự thật là docs/03-protocol.md. Mã Go dùng struct thủ công cho một số phầnproto/, internal/ingestTrung bình
TD-010CLAUDE.md của repo Collector còn ghi "chưa có mã Go", nhưng mã đã cóCLAUDE.mdThấp
TD-011docs/09 mục 2 mô tả tệp cấu hình (listen.agent, accesshub.base_url, bus.kind, logging) khác cấu hình thật (ingest.listen, hub.base_url, bus.backend, log)internal/configCao
TD-012docs/12 nêu agentsim, testcontainers, buf breaking, golden protobuf; chưa có trong cây mãToàn bộTrung bình
TD-013Cờ CLI: docs/09 nêu collector check-config, mã dùng cờ -check và -configcmd/collector/main.goThấp

Appendix A. Glossary ​

Thuật ngữÝ nghĩa
AgentChương trình chạy trên máy chủ được giám sát, chỉ đẩy dữ liệu ra ngoài
CollectorHệ thống này, data plane nhận số liệu
Access HubControl plane, nguồn sự thật về công ty, máy chủ, agent, luật
RegistryBản sao đọc danh tính agent trong Redis, tra theo băm token
PresenceTrạng thái lần thấy cuối và up hoặc down của agent
BusHàng đợi giữa ingest và worker, chia 64 shard theo server_id
ShardPhân vùng logic, FNV-32a(server_id) mod 64
OutboxHàng đợi sự kiện bền vững chờ gửi Access Hub
Dead-letterKho sự kiện bị từ chối hoặc quá hạn
LeaseKhóa Redis có TTL để một tiến trình duy nhất gửi outbox
TenantMột công ty, đơn vị cô lập dữ liệu
TSDBCơ sở dữ liệu chuỗi thời gian (VictoriaMetrics)
RollupSố liệu tổng hợp 5 phút và 1 giờ (avg, min, max, last) trong vm-long
COL-xMã hạng mục lộ trình Collector (docs/11)
HUB-xMã hạng mục phía Access Hub
ETagBăm của cấu hình agent để agent hỏi có đổi không

Appendix B. References ​

Tài liệuVị trí
Thiết kế và yêu cầudocs/00 đến docs/13 (repo Collector)
Quyết địnhdocs/adr/0001 đến 0011
Hợp đồng giao thứcdocs/03-protocol.md, proto/accesshub/agent/v1/agent.proto (nháp)
Cấu hình agentdocs/03-protocol.md (phần cấu hình kéo về agent)
L1L1 - Collector
L3Năm tài liệu L3 cùng thư mục
Mãcmd/collector, cmd/mockhub, internal/**
Triển khaideploy/dev, deploy/systemd

Quyết định kiến trúc ​

ADR 0001 đến 0011 dùng định dạng cũ (bối cảnh, lựa chọn, quyết định, lý do). Từ 0012 dùng mẫu chín mục và đã có Product Owner duyệt.

SốQuyết địnhTrạng tháiNgày
0001Mô hình đẩy (push) từ agentChấp nhận30/09/2026
0002HTTPS + protobuf, không dùng gRPCChấp nhận30/09/2026
0003Ngôn ngữ Go cho agent và collectorChấp nhận30/09/2026
0004Tách control plane (Access Hub) và data plane (Collector)Chấp nhận30/09/2026
0005Chuỗi thời gian lưu trong TSDB (VictoriaMetrics) qua remote-write, không lưu trong MySQLĐiều chỉnh một phần bởi 0015Chấp nhận30/09/2026
0006Chỉ dùng gauge, agent tính sẵn tốc độChấp nhận30/09/2026
0007Token mờ cho agent và đồng bộ registryChấp nhận30/09/2026
0008Chỉ gửi sự kiện chuyển trạng thái về Access HubChấp nhận30/09/2026
0009Trừu tượng hóa Bus, phân shard theo máy chủThay một phần 0012Chấp nhận30/09/2026
0010Không thực thi mã từ xa, kiểm tra chỉ gồm kiểu cố địnhChấp nhận30/09/2026
0011Kiểm kê từ agent không tự ghi vào ServerChấp nhận30/09/2026
0012Bus Redis Streams, outbox dùng chung trong Redis và lease bộ gửiChấp nhận01/10/2026
0013Môi trường dev mô phỏng đầy đủ các thành phần như sản xuấtChấp nhận01/10/2026
0014Giữ VictoriaMetrics làm kho chuỗi thời gian ở giai đoạn hiện tạiBổ sung 0005Chấp nhận01/10/2026
0015Ghi vào VictoriaMetrics bằng API nhập JSON thay cho remote-writeĐiều chỉnh một phần 0005Chấp nhận01/10/2026
0016Retention theo gói bằng nhãn ngày và xóa theo ngày trên VictoriaMetrics OSSChấp nhận02/10/2026
0017Cụm VictoriaMetrics cho hệ thống CloudĐề xuất02/10/2026
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.