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.
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.
- Agent đẩy số liệu và enroll qua HTTPS 443, đường dẫn
/agent/v1/*. - Load balancer kết thúc TLS, chia tải, chỉ gửi tới node có
/readyzsẵn sàng. - Ingest xác thực token qua registry, đẩy lô mẫu theo shard lên Redis Streams.
- Worker đọc lô của các shard mình giữ, chia theo
server_id. - Worker ghi VictoriaMetrics bằng
/api/v1/import(ADR 0015). - Ingest chuyển tiếp enroll và tra ngược token lạ tới Access Hub.
- Worker gửi sự kiện đổi trạng thái và
last_seenqua outbox, khử trùng theoevent_id. - Access Hub đẩy registry, nạp lại luật, truy vấn và xóa dữ liệu qua admin.
- 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ái | BẢN NHÁP (chưa sẵn sàng trình thẩm định) |
| Phiên bản và nhật ký thay đổi | 0.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ệt | Chư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ếu | Khung 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ối | 2026-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 L2 | Mục tiêu L1 (mục 2) | Ghi chú |
|---|---|---|
| 1 Mục tiêu nghiệp vụ, 2 Tổng quan | G1 trạng thái gần thời gian thực, G4 scale ngang | Collector là data plane |
| 3 Yêu cầu chức năng | G1, G2, G3 | Cả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ăng | G4, G5 | Bám NFR-01 đến NFR-15 |
| 5 Công nghệ | G4 | Chọn TSDB, bus, giao thức |
| 6 Tích hợp | G1, G3 | Tích hợp với Agent và Access Hub |
| 7 Dữ liệu | G2, G5 | Mô hình dữ liệu, cô lập tenant |
| 8 Luồng nghiệp vụ | G1, G3 | Enroll, ingest, mất tín hiệu |
| 9 Bảo mật | G5 | Token, admin token, cô lập tenant |
| 10 Triển khai | G4, G6 | Topology dev và production |
| 11, 12 Sức chứa, mở rộng, độ tin cậy | G4 | 64 shard, vai trò tách rời |
| 13 Quan sát | G1, G4 | ahc_*, /readyz |
| 14 Sẵn sàng vận hành | G4 | RTO, RPO, DR |
| 15 Kiểm thử | G5 | Kiểm thử hai tenant |
| 16 Rủi ro | mục 10 của L1 | R1, 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óm | Phạm vi | Trạng thái |
|---|---|---|
| Ingest | ping, enroll (proxy sang Access Hub), metrics, config, inventory cho agent, giới hạn và kiểm tra đầu vào | Đã làm |
| Registry | Bả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à worker | 64 shard theo server_id, bus in-process hoặc Redis streams, worker ghi TSDB theo lô | Đã làm |
| TSDB | Ghi 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ệu | Phát hiện agent.down, agent.up, gửi last_seen, heartbeat | Đã làm |
| Outbox | Sự 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ưỡng | Ké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áy | Chỉ 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 token | Xoay token agent chồng lấn 24 giờ (FR-04) | Chỉ thiết kế (stub 503) |
1.2 Out of scope
| Nội dung | Thuộ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, audit | Access 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, cert | Agent (hệ thống ngoài) | Chạy trên máy được giám sát |
| Gửi email, webhook | Access Hub | Collector chỉ phát sự kiện |
| Thực thi lệnh từ xa | Khô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 agent | Giai đoạn 4 | Ngoài phạm vi giai đoạn 1 đến 3 |
| PromQL thô từ bên ngoài | Không cung cấp | Cô lập tenant (internal/admin) |
2. Architecture Overview and Principles
2.1 Nguyên tắc kiến trúc
| Mã | Nguyên tắc | Hiện thực và bằng chứng |
|---|---|---|
| P1 | Danh tính chỉ đến từ registry, không tin nội dung agent | internal/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 |
| P2 | Nhãn tenant do Collector gắn sau cùng và thắng mọi nhãn khác | internal/tsdb/vm.go đặt company_id, server_id cuối; CheckTenant kiểm tra định dạng id |
| P3 | Truy vấn và xóa luôn có company_id bắt buộc, không PromQL thô | internal/admin/admin.go, internal/tsdb |
| P4 | Ingest không trạng thái, scale ngang; trạng thái dùng chung nằm ở Redis | internal/registry/redis.go, internal/presence/redis.go, internal/bus/redis.go, internal/outbox/redis.go |
| P5 | Từ chối có kiểm soát thay vì nhận rồi mất | Bus đầ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 |
| P6 | Sự 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_id | internal/outbox, internal/events |
| P7 | Một binary, chọn vai trò khi chạy | cmd/collector, internal/app: ingest, worker, admin, all |
| P8 | Không thêm thư viện nặng khi tự viết được gọn | Client 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)
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, Admin | Ba vai trò của cùng một binary, scale độc lập (internal/app/wiring.go) |
| Redis | Registry, presence, bus, outbox, lease gửi (tiền tố ah:) |
| VictoriaMetrics | Hai 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ần | Vai trò | L3 chi tiết |
|---|---|---|
| Ingest API | Nhận HTTP từ agent, kiểm tra, xác thực, đẩy lên bus | L3 Ingest API |
| Registry, Resolver, Enroll proxy, Presence | Danh tính agent, tra ngược Access Hub, theo dõi lần thấy cuối | L3 Registry, Enroll |
| Bus, Worker, TSDB adapter | Đệm, ghi lô, chọn nguồn truy vấn | L3 Bus, Worker, TSDB |
| Detector, Emitter, Outbox, Sender | Mất tín hiệu, sự kiện, gửi bền vững | L3 Alerting, Outbox |
| Admin API | Cổng nội bộ cho Access Hub | L3 Admin API |
| Nền chung | internal/config, internal/app, internal/httpx, internal/ratelimit, internal/metrics, internal/catalog, internal/redisx | Mụ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ã.
| STT | Nhóm chức năng | Mô tả | Trạng thái |
|---|---|---|---|
| 1 | Enroll 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) |
| 2 | Thu 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) |
| 3 | Nhậ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 |
| 4 | Ghi TSDB (FR-14) | Gom lô 5000 mẫu hoặc 500 ms, thử lại, gắn nhãn tenant | Đã làm |
| 5 | Rollup (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/ |
| 6 | Kiể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) |
| 7 | Cấu hình agent | Trả 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) |
| 8 | Mấ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) |
| 9 | Gửi sự kiện (FR-24) | Outbox bền vững, gửi lô tối đa 200, dead-letter | Đã làm (internal/outbox) |
| 10 | last_seen và heartbeat | Gửi theo lô 500, heartbeat mỗi phút | Đã làm |
| 11 | Truy 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 |
| 12 | Xó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 |
| 13 | Luậ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ẫu | Luật ngưỡng và check đã làm (COL-8). Flapping, group_down, silence, bảo trì chưa làm (COL-9) |
| 14 | Cấ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).
| STT | Category | Requirement | Target | Hiện trạng |
|---|---|---|---|---|
| 1 | Performance | Sứ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ận | Chưa đo. Có histogram ahc_ingest_request_duration_seconds để đo |
| 2 | Availability | Sẵ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ận | Ingest không trạng thái, /readyz cho LB, chưa đo |
| 3 | Detectability | Phát hiện mất tín hiệu (NFR-03) | Không quá 3 x interval + 30 giây | Mã 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 |
| 4 | Latency | Độ 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ập | Chư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 |
| 5 | Query | Truy 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ây | Chưa đo |
| 6 | Resilience | Chị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) |
| 7 | Resilience | Chị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 |
| 8 | Security | Bảo mật truyền tải (NFR-11) | TLS 1.2 trở lên | Mã đặt MinVersion TLS 1.2 khi bật ingest.tls_*. Dev: TLS kết thúc ở nginx |
| 9 | Security | Cô 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ự động | Có internal/app/tenant_test.go, TestTwoTenantsNeverMix, TestDeleteDataIsTenantScoped |
| 10 | Recovery | Khô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 |
| 11 | Compatibility | Giao thức N và N-1 (NFR-14) | Hỗ trợ N và N-1 | Hiện chỉ phiên bản 1 (X-AH-Proto: 1, proto_min 1, proto_max 1) |
| 12 | Observability | Quan sát (NFR-15) | /metrics, /healthz, /readyz, log JSON có request_id | Đã làm trên cổng ops (internal/httpx) |
5. Technology Stack
| STT | Phương án | Approach | Ưu điểm | Nhược điểm | Kết luận |
|---|---|---|---|---|---|
| 1 | Go, 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ình | Binary tĩnh, dễ đóng gói, ít phụ thuộc | Đội cần quen Go (R12) | SELECTED (ADR 0003, ADR 0004) |
| 2 | HTTPS + protobuf, nén zstd hoặc gzip | Agent đẩy POST /agent/v1/* | Qua proxy, tường lửa dễ, gọn, dễ cân tải | Bảo trì .proto chung hai repo (R17) | SELECTED (ADR 0002) |
| 3 | gRPC | Luồng hai chiều | Sinh mã sẵn | Khó qua proxy doanh nghiệp | REJECTED (ADR 0002) |
| 4 | VictoriaMetrics (hai instance thô và dài hạn) | Ghi bằng import JSON line, truy vấn bằng HTTP query_range | Nén tốt, vận hành đơn giản | OSS không downsampling, retention toàn cụm (R11) | SELECTED (ADR 0005, lệch cách ghi so với ADR, xem TD-001) |
| 5 | MySQL, TimescaleDB, InfluxDB, Prometheus, ClickHouse | Lưu số liệu | Nhiề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) |
| 6 | Bus Redis streams, consumer group workers | Mỗi shard một stream, XREADGROUP, XAUTOCLAIM | Bề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ềm | SELECTED (mã, docs/09). ADR 0009 chưa cập nhật (TD-002) |
| 7 | Bus in-process (channel có giới hạn) | Một bộ chứa mỗi shard | Đơn giản, nhanh | Không bền, chỉ một tiến trình | SELECTED cho dev một tiến trình, tự chọn khi không có redis.addr |
| 8 | Bus NATS JetStream | Stream lưu file, nhân bản | Đệm 2 giờ, consumer bền | Thêm thành phần vận hành | Chưa làm, phương án mở rộng |
| 9 | Kafka | Bus | Sức chứa lớn | Nặng vận hành | REJECTED (ADR 0009) |
| 10 | Redis (Valkey tương thích) làm registry, presence, bus, outbox | Mộ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 |
| 11 | Client 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ểm | Tự bảo trì | SELECTED (docs/04 ghi chú COL-3) |
| 12 | Outbox Redis, file, bộ nhớ | outbox.backend: auto chọn redis rồi file rồi memory | Bền theo môi trường | File không dùng chung giữa tiến trình | SELECTED cả ba, Discard khi không có hub |
| 13 | Token mờ, tra registry | Băm SHA-256, tra Redis rồi Access Hub | Thu hồi nhanh, danh tính đáng tin | Cần đồng bộ registry | SELECTED (ADR 0007) |
| 14 | JWT tự chứa, mTLS bắt buộc | Xác thực không tra cứu | Không cần registry | Khó thu hồi, cần PKI | REJECTED (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.
| ID | Quyết định | Status |
|---|---|---|
| ADR 0001 | Agent đẩy (push), chỉ kết nối đi ra | Chấp nhận |
| ADR 0002 | HTTPS + protobuf, không gRPC | Chấp nhận |
| ADR 0003 | Ngôn ngữ Go | Chấp nhận |
| ADR 0004 | Tách control plane (Access Hub) và data plane (Collector) | Chấp nhận |
| ADR 0005 | VictoriaMetrics làm TSDB, gọi là remote-write | Chấp nhận, cần sửa: mã dùng /api/v1/import JSON (TD-001) |
| ADR 0006 | Chỉ số dạng gauge, tốc độ tính ở agent | Chấp nhận |
| ADR 0007 | Token mờ và đồng bộ registry | Chấp nhận |
| ADR 0008 | Chỉ gửi sự kiện đổi trạng thái về Access Hub | Chấp nhận |
| ADR 0009 | Trừ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 0010 | Không thực thi mã từ xa | Chấp nhận |
| ADR 0011 | Kiểm kê không bao giờ ghi vào Server | Chấ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
| Component | Responsibility | Data | Tech | Storage | External exposure |
|---|---|---|---|---|---|
| Ingest | Nhận và xác thực request agent, kiểm tra giới hạn, đẩy bus | Lô mẫu, enroll, kiểm kê | Go net/http, protobuf | Không (Redis dùng chung) | Cổng ingest :8443 mặc định, qua LB TLS. Không lộ trực tiếp ở dev |
| Registry, Resolver | Danh tính agent theo băm token | AgentRecord (agent, công ty, máy chủ, trạng thái, hạn) | Go, Redis | Redis reg:*, cache nút | Không |
| Presence | Lần thấy cuối, trạng thái up hoặc down | Hash và zset theo agent | Go, Redis | Redis pres:* | Không |
| Bus | Đệm lô mẫu theo shard | SampleBatch | Go, Redis streams hoặc channel | Redis bus:s:<n> | Không |
| Worker | Gom lô, ghi TSDB | tsdb.Batch | Go | Bộ nhớ (đệm ngắn) | Chỉ cổng ops |
| TSDB adapter | Ghi, truy vấn, xóa | Series ah_* | Go net/http | VictoriaMetrics | Không |
| Detector, Emitter | Phát hiện mất tín hiệu, tạo sự kiện | Event | Go | Presence trong Redis | Không |
| Outbox, Sender | Hàng đợi sự kiện bền vững, gửi lô | Entry (JSON) | Go, Redis | Redis ob:* hoặc tệp | Không |
| Admin | API nội bộ cho Access Hub | JSON | Go net/http | Không | Cổng admin 127.0.0.1:9101 mặc định, chỉ mạng nội bộ |
| Ops | /healthz, /readyz, /metrics | Text Prometheus | internal/httpx | Không | Cổng ops 127.0.0.1:9100 mặc định |
6.2 Integration table
| Interface | Protocol | Contract | Scope | Sync/Async |
|---|---|---|---|---|
| Agent đến Ingest | HTTPS, protobuf, /agent/v1 | docs/03-protocol.md, proto/accesshub/agent/v1/agent.proto (bản nháp), L3 Ingest | Bên ngoài (Agent) | Sync |
| Ingest đến Access Hub (enroll, tra token) | HTTPS, JSON, <hub>/api/v1/monitoring/collector | internal/hubclient, docs/06 | Bên ngoài (Access Hub) | Sync |
| Ingest đến Worker | Redis streams (hoặc channel) | internal/bus, L3 Bus | Nội bộ | Async |
| Worker đến VictoriaMetrics | HTTP POST /api/v1/import, NDJSON | internal/tsdb/vm.go | Nội bộ | Sync (theo lô) |
Worker đến Access Hub (sự kiện, last_seen, heartbeat, kiểm kê) | HTTPS, JSON | internal/hubclient, internal/outbox/sender.go | Bên ngoài | Async (qua outbox) |
| Access Hub đến Admin | HTTP, JSON, /internal/v1, Bearer | L3 Admin | Bê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ài | Sync (kéo định kỳ) |
| Admin đến VictoriaMetrics | HTTP, query_range, query, delete_series | internal/tsdb/vm.go | Nội bộ | Sync |
| Prometheus đến Ops | HTTP /metrics | internal/metrics | Nội bộ | Sync |
| LB đến Ops (kiểm tra) | HTTP /readyz | internal/httpx | Nộ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ặng | Timeout | Retry | Backoff | Circuit breaker |
|---|---|---|---|---|
| Ingest đến Access Hub (tra token) | hub.timeout 10 giây | Không thử lại trong request; cache âm 60 giây, giới hạn hub.lookup_rate 50/s, single-flight | Cache âm | Khô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 jitter | Không có |
| Worker đến VictoriaMetrics | tsdb.timeout 10 giây | Lỗi tạm (5xx, 408, 429, mạng) thử lại đến khi thành công | 200 ms nhân đôi đến tsdb.retry_max 30 giây | Không có, thay bằng chặn đọc bus khi đệm quá 4 lần cỡ lô |
| Registry đến Redis | 500 ms (mặc định) | Không; lỗi Redis đọc như ErrNotFound rồi hỏi Access Hub | Không | Không có |
| Publish bus Redis | Timeout client Redis | Không; đầy thì ErrFull rồi 503 | Agent | Không có |
| Sender đến Access Hub | hub.timeout | Lỗi tạm thử lại, lỗi 4xx vĩnh viễn tách lô rồi dead-letter | outbox.backoff_min 1 giây đến backoff_max 5 phút | Không có |
| Forwarder kiểm kê đến Access Hub | hub.timeout | 4xx vĩnh viễn thì bỏ lô | Đến 1 phút | Không có |
| Admin đến TSDB | tsdb.timeout | Không | Không | Khô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:
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| Aggregate | Kho | Khóa | Vòng đời | Nhạ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:all | Băm token, agent_id | Không TTL. Xóa qua đồng bộ, Admin API, DeleteServer, DeleteCompany. Băm thu hồi giữ làm tombstone để trả 403 | Có (băm token). Không lưu token rõ |
PresenceEntry | Redis pres:a:{agent}, pres:up, pres:up:{co}, pres:down, pres:down:{co}, pres:unrep | agent_id | Xóa khi thu hồi hoặc xóa máy chủ | Thấp |
SampleBatch | Redis stream bus:s:<0..63> | Shard | Xóa (XACK và XDEL) sau khi worker xử lý | Số liệu của tenant, tạm thời |
Series | VictoriaMetrics (ah_<metric>{company_id,server_id,...}) | Nhãn | Retention theo instance (thô 30 ngày, dài hạn 400 ngày trong dev, theo docs/04) | Số liệu của tenant |
OutboxEntry | Redis ob:q, ob:e, ob:dead hoặc tệp outbox.log, deadletter.jsonl | event_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ối | Trung 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
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"| D3Ghi 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ồng | Nội dung | Đường đọc kèm theo |
|---|---|---|
| 1 | Body protobuf nén, header xác thực | Ingest đọc Registry (D1) để tra danh tính, Access Hub khi miss |
| 3 | Presence.Touch sau khi publish bus | Detector đọc D2 khi quét |
| 5 | Lô mẫu đã gắn company_id, server_id | Admin đọc D3 |
| 7, 8 | Outbox.Append rồi Peek | Sender đọc D4 |
7.3 Privacy / PII
| Hạng mục | Có / Không | Ghi chú |
|---|---|---|
| Lưu thông tin định danh cá nhân (họ tên, email, số điện thoại) | Không | Khô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ông | Chỉ băm SHA-256 |
| Lưu log chứa token | Không | Bộ lọc che và tiêu chuẩn log (mục 9.4) |
| Số liệu chứa dữ liệu nhạy cảm | Không | Chỉ 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ống | Có | 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
| Actor | Vai trò |
|---|---|
| Agent | Đẩy số liệu, enroll, kiểm kê |
| Quản trị Access Hub | Tạ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ành | Chạy và giám sát Collector, Redis, TSDB |
8.1 Sequence
Luồng enroll
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
endLuồng nhận số liệu
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 msLuồng mất tín hiệu
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-letter8.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:
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 tystateDiagram-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ượng | Cơ chế | Nguồn sự thật |
|---|---|---|
| Agent | Token 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 |
| Enroll | License do Access Hub kiểm tra, Collector chỉ chuyển tiếp, giới hạn theo IP | Access Hub |
| Access Hub gọi Admin | Bearer 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ình | Cấu hình collector |
| Collector gọi Access Hub | Bearer hub.token (dịch vụ) | Access Hub cấp |
| Người dùng | Không bao giờ chạm Collector trực tiếp, đi qua Access Hub | Access Hub |
9.2 AuthZ
| Cơ chế | Mô tả |
|---|---|
| Danh tính từ registry | Mọi API agent (trừ ping, enroll) dùng danh tính tra được; nội dung body không ghi đè |
| Tenant trong Admin | company_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 API | Khô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 API | Không | Không |
| Access Hub (admin token) | Không | Cho phép | Không |
| Prometheus, LB | Không | Không | Cho phép, mạng nội bộ |
| Không xác thực | Chỉ ping và enroll | Không | Mặc định chỉ lắng nghe 127.0.0.1 |
9.3 Secrets
| Bí mật | Nguồn | Ghi chú |
|---|---|---|
admin.token, hub.token, redis.password | Tệ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 ingest | ingest.tls_cert_file, ingest.tls_key_file (đặt cùng nhau) | Ở dev TLS kết thúc ở nginx |
| Token agent | Không lưu rõ, chỉ băm | Hiển thị đúng một lần lúc enroll |
9.4 AppSec
| Hạng mục | Biện pháp |
|---|---|
| Che dữ liệu nhạy cảm | Không log token, Authorization. X-Request-Id chỉ nhận theo mẫu ^[A-Za-z0-9._-]{1,64}$ |
| Kiểm tra đầu vào | Danh 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ụng | Giớ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 |
| TLS | Tối thiểu 1.2 khi Collector tự kết thúc TLS |
| Lệnh Redis | Client 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ường | Topology | Nguồn |
|---|---|---|
| Dev | Nginx TLS, 2 ingest, 2 worker, 1 admin, Redis master và replica, vm-raw, vm-long, vmalert, mockhub, agent. Chạy bằng systemd user unit | deploy/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 VictoriaMetrics | docs/01, docs/09 |
| Production lớn | Ingest, worker, admin tách riêng, Redis HA, VictoriaMetrics cụm | docs/08, chưa làm |
Chi tiết dev (cổng, collector_id, tệp cấu hình):
| Thành phần | Dịch vụ systemd | Cổng | Ghi chú |
|---|---|---|---|
| Nginx TLS | accesshub-lb | 127.0.0.1:8443 | Upstream 2 ingest |
| Ingest 1 và 2 | accesshub-collector-ingest@{1,2} | ingest 18443, 18444, ops 9111, 9112 | collector_id dev-ingest-1, dev-ingest-2, trusted_proxies 127.0.0.0/8 |
| Worker 1 và 2 | accesshub-collector-worker@{1,2} | ops 9121, 9122 | dev-worker-1, dev-worker-2 |
| Admin | accesshub-collector-admin | admin 127.0.0.1:9101, ops 9110 | dev-admin |
| Redis master, replica | accesshub-redis-master, accesshub-redis-replica | 6380, 6381 | Mật khẩu, AOF everysec, maxmemory 256mb, noeviction |
vm-raw, vm-long | accesshub-vm-raw, accesshub-vm-long | 8428, 8429 | Retention 30 ngày và 400 ngày |
vmalert | accesshub-vmalert | 8880 | Luật rollup sinh bởi collector -rollup-rules (dev: gen-vmalert-rules.sh) |
| Mockhub | accesshub-mockhub | 8090 | Chỉ dev. API monitoring thật của Access Hub (HUB-*) chưa xây |
| Agent | accesshub-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
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 --> ADMSơ đồ 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 Type | Downtime | Rollback | Window | Approval |
|---|---|---|---|---|
Rolling (đề xuất, docs/09 mục 5): rút ingest khỏi LB khi /readyz trả 503, nâng, thêm lại | Không có khi còn ít nhất một node | Cài lại binary trước đó (đề xuất, chưa có runbook) | Chưa chỉ định | Chưa chỉ định |
Worker: tắt êm, node khác nhận lô treo sau bus.claim_idle 30 giây | Không (dữ liệu đệm trong Redis) | Như trên | Chưa chỉ định | Chưa chỉ định |
Dev: devctl.sh (khởi động lại từng dịch vụ systemd) | Có ngắn | Cài lại binary | Không áp dụng | Khô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ục | Giải pháp | Thông số | Phạm vi |
|---|---|---|---|
| Đường agent | HTTPS đến LB, LB chuyển HTTP thuần đến ingest ở dev, trusted_proxies để lấy IP thật | TLS 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 admin | Chỉ lắng nghe loopback hoặc mạng nội bộ, Bearer admin token | 127.0.0.1:9101 mặc định | Nội bộ |
| Cổng ops | Chỉ lắng nghe loopback | 127.0.0.1:9100 mặc định | Nội bộ |
| Redis, TSDB | Mạng riêng, Redis có mật khẩu, tùy chọn TLS | Client Redis hỗ trợ redis.tls và tls_ca_file | Nội bộ |
| Cách ly tiến trình | systemd NoNewPrivileges, PrivateTmp, ProtectSystem=strict, ProtectHome=read-only, RestrictAddressFamilies, MemoryMax | Xem deploy/systemd | Máy chạy dịch vụ |
| Quản trị từ xa | Qua bastion (đề xuất, production) | Chưa có tài liệu hạ tầng | Vậ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ế.
| Metric | Target | Remarks |
|---|---|---|
| Số agent | 10.000 ở chu kỳ 30 giây | NFR-01, khoảng 333 request/giây |
| Mẫu ghi | khoảng 23 nghìn mẫu/giây ở 10.000 máy | docs/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áy | Giả định khoảng 1 byte mỗi mẫu sau nén |
| Series mỗi agent | 500 (giới hạn cứng, ingest.limits.max_series) | Cửa sổ trượt 1 giờ |
| Điểm mỗi request | 20.000 | max_points |
| Body nén, giải nén | 1 MiB, 8 MiB | max_body_bytes, max_decoded_bytes |
| Shard logic | 64 (cố định) | Tối đa 64 worker hữu ích |
| Trần bộ nhớ dev mỗi tiến trình | 512M ingest, worker, 256M admin | MemoryMax trong unit dev |
| Redis dev | maxmemory 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ần | Cách scale | Ghi chú |
|---|---|---|
| Ingest | Ngang sau LB, không trạng thái | Giới hạn tốc độ theo agent là trong bộ nhớ từng node, không chia sẻ toàn cụm (TD-005) |
| Worker | Ngang. Mỗi worker đọc min(bus.readers, shards) vòng lặp, Redis chia việc bằng consumer group, không có lease shard | Nhiề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) |
| Admin | Ngang, không trạng thái | |
| Redis | Dọc, master và replica ở dev. Sentinel hoặc Cluster chưa làm | Điểm chung (AR-005) |
| VictoriaMetrics | Single hai instance. Cụm chưa làm |
12.2 Reliability
| Tình huống | Hành vi (đã kiểm chứng trong mã hoặc kiểm thử) |
|---|---|
| Mất Access Hub | Ingest dùng registry cache. Miss thì 503 Retry-After 30, không 401. Sự kiện nằm trong outbox 24 giờ |
| Mất Redis | Registry đọ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 TSDB | Worker 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ết | LB chuyển sang node còn lại |
| Một worker chết | Lô 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ình | Lease 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ục | Nội dung | Nguồn |
|---|---|---|
| Endpoint ops | /healthz, /readyz (kiểm tra "redis" và "tsdb", timeout 2 giây, 503 khi đang tắt êm), /metrics | internal/httpx, internal/app |
| Metric ingest | ahc_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_total | internal/ingest |
| Metric registry, worker, TSDB | ahc_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_samples | internal/registry, internal/worker |
| Metric alerting, outbox | ahc_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_seconds | internal/alerting, internal/outbox |
| Log | JSON một dòng (log.format: json), request_id từ X-Request-Id hoặc sinh mới | internal/app, internal/httpx |
| Trace | Chư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ục | Nội dung |
|---|---|
| Mức bảo mật dữ liệu | Số 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 |
| RTO | Chưa chỉ định. Đề xuất: theo cấp 3, vài giờ, cần xác nhận (OQ-4 của L1) |
| RPO | Chư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 radius | Mấ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 model | Registry 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) |
| Runbook | docs/09 mục 6 (rút gọn, chi tiết chưa viết) |
| Sao lưu | Snapshot VM và Redis theo lịch: chưa có ở dev |
15. Testing and Quality
| Tầng | Hiện trạng | Bằng chứng |
|---|---|---|
| Đơn vị | Có, mỗi gói có _test.go | Xem danh sách test ở từng L3 |
| Tích hợp trong tiến trình | Có, pipeline ingest đến TSDB bộ nhớ, tách tiến trình qua Redis | internal/app/pipeline_test.go, events_test.go (TestSplitProcessesShareStateThroughRedis) |
| Cô lập hai tenant | Có | internal/app/tenant_test.go (TestTwoTenantIsolationThroughIngestAndAdminAPI), internal/ingest/ingest_test.go (TestTwoTenantsNeverMix), internal/admin/admin_test.go (TestDeleteDataIsTenantScoped) |
| Với VictoriaMetrics thật | Có, tùy chọn: bỏ qua nếu thiếu AHC_TEST_VM_URL | deploy/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 Hub | Chỉ có mockhub, API thật (HUB-*) chưa xây | cmd/mockhub (đề xuất kiểm tra lại khi HUB-* xong) |
Fuzz, tải (agentsim), hỗn loạn | Chưa có | docs/12 mô tả kế hoạch. Không có cmd/agentsim trong cây mã hiện tại |
| Redis thật | Có phần dùng Redis giả cho hợp đồng, phần dùng Redis thật tùy chọn | internal/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 ID | Category | Description | Business Impact | Likelihood | Severity | Mitigation | Residual | Owner | Status |
|---|---|---|---|---|---|---|---|---|---|
| AR-001 | Reliability | Danh 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ệu | T | V | Outbox bền, thử lại trong bộ nhớ. Đề xuất: ghi cờ bền trước khi đánh dấu down | V | Chưa chỉ định | Mở |
| AR-002 | Reliability | Flush 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ắn | V | T | worker.shutdown_flush 10 giây, agent đệm và gửi bù | T | Chưa chỉ định | Mở |
| AR-003 | Concurrency | Lease 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_id | T | T | Idempotent send | T | Chưa chỉ định | Mở |
| AR-004 | Capacity | Đệ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 đạt | Mất TSDB lâu thì ingest trả 503, agent phải đệm | V | V | Tăng bus.queue_per_shard, theo dõi ahc_ingest_bus_depth, JetStream (chưa làm) | V | Chưa chỉ định | Mở |
| AR-005 | Availability | Redis là điểm chung của registry, presence, bus, outbox. Dev có master và replica nhưng chưa Sentinel | Mất Redis: ngừng ghi mẫu và phát hiện mất tín hiệu | V | C | Registry hỏi lại Access Hub, AOF, replica. Sentinel hoặc Cluster (chưa làm) | V | Chưa chỉ định | Mở |
| AR-006 | Integration | Adapter 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ày | Nếu định dạng sai, số liệu không vào TSDB | T | C | deploy/dev/vmcheck chạy khi có AHC_TEST_VM_URL | T | Chưa chỉ định | Mở |
| AR-007 | Functional gap | Luậ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) | C | V | Làm COL-9 theo docs/11 | V | Chưa chỉ định | Mở |
| AR-008 | Functional gap | POST /credentials/renew là stub 503, chưa có xoay token (FR-04) | Token dài hạn tăng rủi ro lộ | V | V | Làm ở giai đoạn 2, thu hồi thủ công khi cần | V | Chưa chỉ định | Mở |
| AR-009 | Data lifecycle | Registry và presence không TTL, dọn dẹp phụ thuộc đồng bộ và Admin API | Bản ghi mồ côi nếu đồng bộ lỗi | T | T | Đồng bộ since, DeleteServer, DeleteCompany | T | Chưa chỉ định | Mở |
| AR-010 | Dependency | Rollup phụ thuộc vmalert chạy đúng. Truy vấn 7 ngày trở lên đọc vm-long | Biểu đồ dài hạn rỗng nếu vmalert dừng | V | V | Theo dõi vmalert, sinh luật từ catalog | T | Chưa chỉ định | Mở |
| AR-011 | Integration | API monitoring thật của Access Hub (HUB-*) chưa có, dev dùng mockhub | Hợp đồng thật chưa được kiểm chứng | C | V | Kiểm thử hợp đồng khi có HUB-* (R-A của L1) | V | Chưa chỉ định | Mở |
| AR-012 | Security | Một token admin duy nhất, không phân quyền chi tiết, không xoay tự động | Lộ token ảnh hưởng mọi tenant | T | C | Mạng nội bộ, so sánh hằng thời gian. Đề xuất: mTLS hoặc token theo vai trò | V | Chưa chỉ định | Mở |
16.2 Tech Debt
| ID | Mô tả | Vị trí | Ưu tiên (đề xuất) |
|---|---|---|---|
| TD-001 | ADR 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.url | internal/tsdb/vm.go | Cao |
| TD-002 | ADR 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 1 | internal/bus/redis.go | Cao |
| TD-003 | docs/08 và ADR 0009 mô tả lease shard trong Redis (ah:collector:{id}), mã không có, dùng consumer group | internal/bus/redis.go | Trung bình |
| TD-004 | Tê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_total | internal/ingest, internal/app/wiring.go, docs/10 | Trung bình |
| TD-005 | docs/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 node | internal/ratelimit | Trung bình |
| TD-006 | Cầu chì (circuit breaker) đề xuất ở docs/08 chưa hiện thực | Toàn bộ | Thấp |
| TD-007 | docs/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}/data | internal/admin/admin.go | Trung bình |
| TD-008 | docs/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.go | Trung bình |
| TD-009 | proto/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ần | proto/, internal/ingest | Trung bình |
| TD-010 | CLAUDE.md của repo Collector còn ghi "chưa có mã Go", nhưng mã đã có | CLAUDE.md | Thấp |
| TD-011 | docs/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/config | Cao |
| TD-012 | docs/12 nêu agentsim, testcontainers, buf breaking, golden protobuf; chưa có trong cây mã | Toàn bộ | Trung bình |
| TD-013 | Cờ CLI: docs/09 nêu collector check-config, mã dùng cờ -check và -config | cmd/collector/main.go | Thấp |
Appendix A. Glossary
| Thuật ngữ | Ý nghĩa |
|---|---|
| Agent | Chương trình chạy trên máy chủ được giám sát, chỉ đẩy dữ liệu ra ngoài |
| Collector | Hệ thống này, data plane nhận số liệu |
| Access Hub | Control plane, nguồn sự thật về công ty, máy chủ, agent, luật |
| Registry | Bản sao đọc danh tính agent trong Redis, tra theo băm token |
| Presence | Trạng thái lần thấy cuối và up hoặc down của agent |
| Bus | Hàng đợi giữa ingest và worker, chia 64 shard theo server_id |
| Shard | Phân vùng logic, FNV-32a(server_id) mod 64 |
| Outbox | Hàng đợi sự kiện bền vững chờ gửi Access Hub |
| Dead-letter | Kho sự kiện bị từ chối hoặc quá hạn |
| Lease | Khóa Redis có TTL để một tiến trình duy nhất gửi outbox |
| Tenant | Một công ty, đơn vị cô lập dữ liệu |
| TSDB | Cơ sở dữ liệu chuỗi thời gian (VictoriaMetrics) |
| Rollup | Số liệu tổng hợp 5 phút và 1 giờ (avg, min, max, last) trong vm-long |
| COL-x | Mã hạng mục lộ trình Collector (docs/11) |
| HUB-x | Mã hạng mục phía Access Hub |
| ETag | Băm của cấu hình agent để agent hỏi có đổi không |
Appendix B. References
| Tài liệu | Vị trí |
|---|---|
| Thiết kế và yêu cầu | docs/00 đến docs/13 (repo Collector) |
| Quyết định | docs/adr/0001 đến 0011 |
| Hợp đồng giao thức | docs/03-protocol.md, proto/accesshub/agent/v1/agent.proto (nháp) |
| Cấu hình agent | docs/03-protocol.md (phần cấu hình kéo về agent) |
| L1 | L1 - Collector |
| L3 | Năm tài liệu L3 cùng thư mục |
| Mã | cmd/collector, cmd/mockhub, internal/** |
| Triển khai | deploy/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.