L3 - Monitoring Platform - Agent - Collectors (Bộ thu số liệu)
Thông tin tài liệu đầy đủ
| Trường | Giá trị |
|---|---|
| Tên trang | L3 - Monitoring Platform - Agent - Collectors |
| Trạng thái | BẢN NHÁP (tài liệu chưa sẵn sàng trình thẩm định) |
| Phiên bản | v0.1, 2026-09-30: bản nháp đầu tiên, dựng từ mã tại commit a23f929 (internal/collector/**, internal/stats, internal/cli/collectonce.go) và docs/03-metrics-catalog.md |
| Tên dự án | Monitoring Platform (Access Hub Monitoring) |
| Bên thẩm định / Phê duyệt | chưa chỉ định. Chưa ai sign-off |
| Tài liệu tầng trên (Parent) | L2 - Monitoring Platform - Agent - SAD, thành phần CMP-2 Collector Engine (mục 2.3), FR-04 đến FR-07, FR-22 đến FR-24, L2-NFR-01, 02, 09, 16. Truy vết tiếp lên L1: L1 HLD mục 2 (Mục tiêu 2, 3), mục 3 (T1, T2), mục 4 |
| Tài liệu anh em | L3 WAL và Sender, L3 Enroll, Credentials, Config, L3 Service và Packaging |
| Mục lục | 0 Governance, 1 Phạm vi, 2 Yêu cầu, 3 Kiến trúc, 4 Domain model, 5 Hợp đồng API, 6 Dữ liệu vật lý, 7 Thuật toán, 8 Xử lý lỗi, 9 Suy thoái, 10 Đồng thời, 11 Bảo mật, 12 Cấu hình, 13 Telemetry, 14 Kiểm thử, 15 Trình tự xây dựng, Phụ lục A, B, C |
Quy ước nhãn trạng thái (giống L2): ĐÃ HIỆN THỰC (đã xác minh trong mã), THIẾT KẾ, CHƯA XÂY (chỉ có trong tài liệu thiết kế), MỘT PHẦN, ĐỀ XUẤT. Khi mã và tài liệu khác nhau, mã thắng và sai lệch được nêu trong tài liệu này và gom về L2 mục 16.2.
0. Front Matter & Approvals
Governance metadata
| Trường | Giá trị |
|---|---|
| Component | CMP-2 Collector Engine (L2 mục 2.3). Package internal/collector, internal/collector/linux, internal/collector/host |
| Truy vết L2 | L2-SAD-agent.md mục 2.3, 3 (FR-04, FR-05, FR-06, FR-07), 4 (L2-NFR-01, 02, 09, 16), 7.3 |
| Phân loại rủi ro | Đề xuất, chưa xác nhận: Tier 3, kế thừa System Tier của L2 mục 14. Thành phần này không giữ bí mật và không nhận đầu vào từ mạng |
| Data classification | Nội bộ (số liệu vận hành máy chủ, không PII). Nhãn mount và iface có thể tiết lộ cấu trúc máy nhưng không chứa dữ liệu người dùng (L2 mục 7.3) |
| Blast radius | Một máy chủ. Bộ thu lỗi chỉ làm mất số liệu của chính nó (bulkhead theo bộ thu). Lỗi nặng nhất theo mã: một cuộc gọi statfs treo (ví dụ NFS hỏng, chỉ khi bật include_network_fs) có thể chặn cả vòng thu, xem mục 8.3 và OQ-C1 |
Sign-off gate
| Vai trò | Tên | Trách nhiệm duyệt | Trạng thái | Ngày |
|---|---|---|---|---|
| Tech lead thành phần | chưa chỉ định | Đúng đắn của thuật toán thu, giới hạn cardinality | Chưa duyệt | chưa có |
| SA hệ thống Agent | chưa chỉ định | Nhất quán với L2 và giao thức | Chưa duyệt | chưa có |
| Bảo mật | chưa chỉ định | Danh sách trắng nhãn, đọc /proc | Chưa duyệt | chưa có |
1. Component Scope & Non-Goals
Vai trò: Collector Engine là bộ gom số liệu theo mẫu pipeline nhiều bộ thu cắm được (plugin collectors) với một bộ chuẩn hóa chặn ở cổng (catalog-guarded normalizer). Mỗi bộ thu là một đối tượng độc lập cài đặt interface Collector, đọc một nguồn của hệ điều hành và trả về các mẫu gauge. Engine chạy tuần tự các bộ thu, cách ly lỗi từng bộ thu, rồi ép mọi mẫu qua danh sách trắng tên chỉ số và nhãn, loại NaN, Inf, trùng, và cắt theo giới hạn series trước khi giao cho Sender.
Sơ đồ ngữ cảnh
flowchart LR
classDef bc fill:#1f3a5f,stroke:#4a90d9,color:#fff
classDef owned fill:#2d4a3e,stroke:#5fb37a,color:#fff
classDef infra fill:#444,stroke:#aaa,color:#fff
OS(["Hệ điều hành: /proc và statfs"]):::infra
CLI(["CLI collect-once"]):::infra
subgraph BC["Collector Engine"]
ENG["Engine: gom và chuẩn hóa"]:::owned
COLS["Bộ thu Linux"]:::owned
end
RT["Runtime Core: vòng chu kỳ"]:::bc
SND["Sender: đóng lô và gửi"]:::bc
CFGL["Config Loader"]:::bc
RT -->|"yêu cầu thu một chu kỳ"| ENG
CLI -->|"thu hai lần in JSON"| ENG
ENG -->|"gọi từng bộ thu"| COLS
COLS -->|"đọc số liệu thô"| OS
ENG -->|"trả mẫu đã chuẩn hóa"| RT
RT -->|"chuyển mẫu để gửi"| SND
CFGL -.->|"cấp cờ bật tắt và bộ lọc"| ENGMô tả quan hệ
| Chiều | Bên | Nội dung |
|---|---|---|
| Vào | Runtime Core (internal/agent/agent.go) | Gọi Engine.Collect(ctx, now) mỗi chu kỳ, một lần khởi động để mồi các bộ thu dạng tốc độ (kết quả bị bỏ) |
| Vào | CLI collect-once (internal/cli/collectonce.go) | Gọi Collect hai lần cách nhau -gap (mặc định 1 s, 100 ms đến 1 phút) rồi in mẫu lần hai dưới dạng JSON, không gửi |
| Ra | Hệ điều hành | Đọc /proc/stat, /proc/loadavg, /proc/meminfo, /proc/self/mountinfo, /proc/net/dev, /proc/uptime, thư mục số của /proc, /proc/self/statm, /proc/self/stat, và statfs(2) cho từng mount. Chỉ đọc |
| Ra | Runtime Core | Result{Samples, Dropped, Errors, Duration}. Runtime tự chuyển mẫu cho Sender (BuildBatch thuộc L3 WAL và Sender) |
| Vào (lúc dựng) | Config Loader | Cờ metrics.*, limits.max_series, collect_timeout, labels. Cấu hình được đọc một lần khi dựng engine. Đổi cấu hình bằng SIGHUP không dựng lại engine (xem mục 12.1) |
| Ra | Thống kê dùng chung (internal/stats) | Ghi số bộ thu lỗi, thời lượng thu, số mẫu bị loại. Bộ thu tự thân đọc lại để phát agent_* |
Trong phạm vi (bao phủ)
| Trong phạm vi | Ghi chú |
|---|---|
Interface Collector, kiểu Sample, SeriesKey | internal/collector/collector.go. ĐÃ HIỆN THỰC |
| Engine: chạy tuần tự, timeout chung, cách ly panic, chuẩn hóa, giới hạn series, dự trữ cho tự thân | internal/collector/engine.go. ĐÃ HIỆN THỰC |
Danh mục chỉ số (nguồn sự thật) và danh sách trắng Allowed | Danh mục nằm ở internal/catalog/catalog.go (nhóm, đơn vị, nhãn, bộ thu, nền tảng, mặc định, bắt buộc, mô tả vi và en), Allowed trong internal/collector/catalog.go sinh từ đó. ĐÃ HIỆN THỰC (có các chỉ số planned chưa phát, xem 5.2) |
Chọn chỉ số (metrics.include, metrics.exclude, glob theo tên) | internal/catalog/select.go, áp trong Engine.selected. Chỉ số bị loại không tạo ra, không tính là bỏ. Bộ thu có mọi chỉ số bị loại thì không chạy (host.go). ĐÃ HIỆN THỰC, xem ADR 0006 |
| Bộ thu Linux: cpu, memory (gồm swap và chi tiết bộ nhớ), disk, net, uptime (gồm boot time, số tiến trình), pressure (PSI) | internal/collector/linux/*.go. ĐÃ HIỆN THỰC |
Bộ thu tự thân agent_* | internal/collector/linux/self.go. ĐÃ HIỆN THỰC. Đọc /proc/self, nên chỉ có trên Linux |
| Bộ lọc mount và giao diện mạng mặc định và theo cấu hình | internal/collector/linux/filter.go. ĐÃ HIỆN THỰC |
| Dựng engine từ cấu hình hiệu lực | internal/collector/host/host.go. ĐÃ HIỆN THỰC |
| Hành vi trên nền tảng không phải Linux | Chỉ trả chỉ số agent (thực tế engine rỗng, không có bộ thu tự thân). ĐÃ HIỆN THỰC ở mức khung, xem 8.2 |
Dịch vụ Windows (internal/winsvc, ADR 0008) | ĐÃ XÂY (SCM, ACL, mã thoát), chưa chạy trên Windows thật |
| Bộ thu Windows (API trực tiếp, ADR 0007) | ĐÃ XÂY MỘT PHẦN (AGT-7, internal/collector/windows), chưa chạy trên Windows thật. PDH (ADR 0004) chỉ còn cho I/O đĩa, chưa làm |
Ngoài phạm vi
| Không thuộc BC | Thuộc về |
|---|---|
Đóng lô protobuf, gán seq, AgentStats, gửi, backoff | L3 WAL và Sender |
| Đọc, kiểm tra cấu hình YAML, cờ, env, SIGHUP | L3 Enroll, Credentials, Config |
| Quyền tệp, tài khoản, unit systemd | L3 Service và Packaging |
Checks service, port, tcp, http, cert (service_up, port_up, tcp_connect_*, http_*, cert_days_left) | ĐÃ XÂY (AGT-8): internal/collector/checks, chạy nền, trả kết quả lần chạy gần nhất |
| Kiểm kê phần cứng và hệ điều hành | ĐÃ XÂY (AGT-9): ReadHostFacts trong inventory.go dùng lại bộ phân tích /proc và bộ lọc mount, interface của bộ thu. Phần mềm cài đặt không thu |
Tốc độ I/O đĩa, open_fds_percent (disk_read_bytes_per_sec, disk_write_bytes_per_sec, disk_io_util_percent, open_fds_percent) | Chưa có bộ thu (L2 D-03). docs/03 xếp vào giai đoạn 2 |
| Container, cgroup v2 | Ngoài phạm vi giai đoạn này theo docs/03 |
| Lưu, đánh giá, cảnh báo trên số liệu | Collector (L2 Collector) |
2. Detailed Requirements & Acceptance Criteria
Functional Requirements
| # | Trách nhiệm | Giải thích | Hiện thực ở |
|---|---|---|---|
| FR-C01 | Định nghĩa hợp đồng bộ thu | Mỗi bộ thu có Name() và Collect(ctx, now). Bộ thu dạng tốc độ giữ trạng thái giữa các lần gọi và không trả mẫu tốc độ ở lần đầu | collector.go. ĐÃ HIỆN THỰC |
| FR-C02 | Thu CPU | cpu_usage_percent, cpu_mode_percent{mode} (đủ 8 chế độ: user, nice, system, idle, iowait, irq, softirq, steal), cpu_load1/5/15, load_per_core_5m, cpu_cores | linux/cpu.go. ĐÃ HIỆN THỰC |
| FR-C03 | Thu bộ nhớ và swap | mem_total/used/available_bytes, mem_used_percent, mem_free/cached/buffers/slab/page_tables_bytes, swap_total/used/cached_bytes, swap_used_percent. Dự phòng MemAvailable cho kernel cũ | linux/memory.go. ĐÃ HIỆN THỰC |
| FR-C04 | Thu đĩa | disk_total_bytes, disk_used_bytes, disk_used_percent, disk_inodes_used_percent theo {mount, fstype}. Loại pseudo fs, network fs mặc định, mount trùng thiết bị. Tối đa 40 mount | linux/disk.go, filter.go. ĐÃ HIỆN THỰC |
| FR-C05 | Thu mạng | 6 chỉ số tốc độ theo {iface} (bytes, errors, drops, chiều rx và tx). Tối đa 20 giao diện. Xử lý tràn bộ đếm 32 bit | linux/net.go, helpers.go. ĐÃ HIỆN THỰC |
| FR-C06 | Thu uptime | uptime_seconds, boot_time_seconds, procs_total (chỉ đếm thư mục số, không đọc cmdline) | linux/uptime.go. ĐÃ HIỆN THỰC |
| FR-C07 | Thu tự thân | agent_* (11 tên, xem 13.1). Bộ thu tự thân chạy sau cùng và được miễn cắt series | linux/self.go, engine.go. ĐÃ HIỆN THỰC |
| FR-C08 | Cách ly lỗi | Lỗi hoặc panic ở một bộ thu được ghi vào Result.Errors, không dừng các bộ thu khác | engine.go (safeCollect). ĐÃ HIỆN THỰC |
| FR-C09 | Chuẩn hóa mẫu | Loại mẫu có tên ngoài danh sách trắng, nhãn ngoài danh sách của chỉ số đó, nhãn dành riêng, NaN, Inf, series trùng. Cắt giá trị nhãn 128 byte theo ranh giới UTF-8. Gắn nhãn tĩnh labels | engine.go (sanitize). ĐÃ HIỆN THỰC |
| FR-C10 | Giới hạn series | Cắt phần dư quá max_series trừ dự trữ tự thân (tối đa 16), cảnh báo một lần cho tới khi trở lại dưới ngưỡng | engine.go. ĐÃ HIỆN THỰC |
| FR-C11 | Bật tắt và lọc theo cấu hình | Bật tắt từng bộ thu, include_iowait_in_usage, bộ lọc fstype, mount, giao diện bằng RE2. Regex sai làm dựng engine thất bại | host/host.go, linux/filter.go. ĐÃ HIỆN THỰC |
| FR-C12 | Thu một lần để chẩn đoán | collect-once thu hai lần rồi in JSON đã sắp xếp | cli/collectonce.go. ĐÃ HIỆN THỰC (thuộc CLI, ghi ở đây vì dùng engine) |
| FR-C13 | Checks, kiểm kê, Windows | Xem mục 1 Ngoài phạm vi | THIẾT KẾ, CHƯA XÂY |
Non-Functional Requirements
| NFR | Target (Ý nghĩa) | Parent L2-NFR (Kiểu) | Satisfied-by (Tactic → Mục) |
|---|---|---|---|
| NFR-C01 | CPU và RAM của agent nằm trong ngân sách: đọc tệp /proc nhỏ, không đọc theo tiến trình, không thư viện bên thứ ba | L2-NFR-01, L2-NFR-02 (Allocated một phần) | Cắt cardinality (7.4.1), đọc chỉ /proc tổng (7.4.5). Số đo thật chưa có (L2 D-16) |
| NFR-C02 | Số series không vượt max_series (cứng 500), tự thân luôn được dự trữ | L2-NFR-16 (Allocated) | Cắt series và dự trữ (7.4.1), giới hạn MaxMounts 40 và MaxInterfaces 20 (7.4.3, 7.4.4), tham số ở 12.1 |
| NFR-C03 | Một bộ thu lỗi hoặc panic không làm mất số liệu của bộ thu khác và không dừng agent | L2-NFR-09 (Allocated) | Bulkhead theo bộ thu (7.2, luồng 3), recover trong safeCollect |
| NFR-C04 | Một chu kỳ thu hoàn tất trong collect_timeout (mặc định 5 s, nhỏ hơn interval) | Không có tương ứng trực tiếp trong L2. Kế thừa ANFR (khởi động và chu kỳ) (Owned) | Timeout chung qua ngữ cảnh (7.2.2). Chỉ số agent_collect_duration_seconds (13.1). Tham số collect_timeout (12.1). Giới hạn: xem 8.3 |
| NFR-C05 | Chỉ số và nhãn phát ra luôn khớp catalog và giao thức (không nhãn dành riêng) | L2-NFR-18 (Inherited, tương thích giao thức) | Danh sách trắng (7.4.1), TestCatalogConformance |
| NFR-C06 | Đọc không để lại dấu vết và không tăng đặc quyền: chỉ đọc /proc, statfs | L2-NFR-12 (Inherited) | Không ghi tệp, không exec. Xem 11 |
| NFR-C07 | Tốc độ không sinh giá trị vô lý khi tràn hoặc đặt lại bộ đếm | Không có tương ứng trong L2 (Owned) | counterDelta, maxRatePerSec (7.4.2). Đo bằng TestCounterDelta |
Acceptance Criteria
| AC | Kịch bản đặc tả (Given / When / Then) | Truy vết → Test ID |
|---|---|---|
| AC-C01 | Given bộ thu CPU vừa dựng, When gọi Collect lần đầu, Then không có mẫu tốc độ (chỉ cpu_cores và tải) | TestCPUFirstSampleHasNoRates |
| AC-C02 | Given hai lần đọc /proc/stat có delta, When gọi Collect lần hai, Then cpu_usage_percent và cpu_mode_percent tính đúng theo delta | TestCPURatesFromDeltas |
| AC-C03 | Given bộ đếm CPU đi lùi (hotplug), When thu, Then bỏ mẫu tốc độ chu kỳ đó, không lỗi | TestCPUCounterGoingBackwardsSkipsSample |
| AC-C04 | Given kernel cũ thiếu cột hoặc thiếu MemAvailable, When thu, Then vẫn ra số liệu hợp lệ | TestCPULegacyStatColumns, TestMemoryLegacyWithoutMemAvailable |
| AC-C05 | Given tệp /proc thiếu hoặc sai, When thu, Then trả lỗi mô tả, không panic | TestCPUMissingFilesReportError, TestMemoryNoSwapAndBadData |
| AC-C06 | Given bộ đếm mạng 32 bit tràn, When thu, Then tốc độ đúng. Given bộ đếm 64 bit đi lùi, Then bỏ mẫu | TestNetCounterWrapAndReset, TestCounterDelta |
| AC-C07 | Given hơn 20 giao diện, When thu, Then chỉ 20 giao diện x 8 series | TestNetInterfaceLimit |
| AC-C08 | Given danh sách mount có tmpfs, overlay, bind mount, When thu, Then chỉ mount thật, mỗi thiết bị một lần | TestDiskDefaultFilters, TestDiskRealHostFixture |
| AC-C09 | Given statfs lỗi ở một mount, When thu, Then các mount khác vẫn có số liệu | TestDiskStatfsErrorIsReportedButOthersSurvive |
| AC-C10 | Given hơn 40 mount, When thu, Then dừng ở 40 và báo lỗi | TestDiskMountLimit |
| AC-C11 | Given ngữ cảnh đã hủy, When thu đĩa, Then dừng sớm | TestDiskContextCancelled |
| AC-C12 | Given mẫu có tên lạ, nhãn lạ, NaN, nhãn dành riêng, When chuẩn hóa, Then bị loại và đếm | TestSanitizeDropsInvalidSamples, TestStaticLabelCannotOverrideReserved |
| AC-C13 | Given một bộ thu lỗi và một bộ thu panic, When Collect, Then bộ thu còn lại vẫn ra mẫu, lỗi ghi theo tên | TestEngineIsolatesFailingAndPanickingCollectors |
| AC-C14 | Given số mẫu vượt giới hạn, When Collect, Then cắt phần thường nhưng giữ mẫu tự thân | TestSeriesLimitTrimsMainButKeepsSelf |
| AC-C15 | Given collect_timeout, When Collect, Then ngữ cảnh truyền cho bộ thu có hạn | TestEngineTimeoutIsAppliedToContext |
| AC-C16 | Given mọi bộ thu chạy hai lần, When kiểm, Then mọi tên và nhãn phát ra đều trong Allowed | TestCatalogConformance |
| AC-C17 | Given cờ tắt một bộ thu, When dựng engine, Then không có bộ thu đó. Given regex sai, Then dựng thất bại | TestEngineHonorsCollectorToggles, TestBadRegexFailsEngineBuild |
| AC-C18 | Given /proc thật của máy chạy kiểm thử, When thu, Then không lỗi và có mẫu | TestRealProcSmoke |
| AC-C19 | Given collect-once, When chạy, Then in JSON và không chứa URL giữ chỗ, -gap ngoài khoảng bị từ chối | TestCollectOncePrintsJSON, TestCollectOnceRejectsBadGapAndConfig |
Quality Attribute Scenarios
| Mã kịch bản / NFR | Nguồn & Kích thích | Môi trường | Phản hồi của hệ thống (Tactic) | Thước đo chất lượng (Measure) |
|---|---|---|---|---|
| QAS-C01 / NFR-C03 | Một bộ thu gặp lỗi phân tích (/proc/meminfo hỏng) hoặc panic | Chạy bình thường | Engine ghi lỗi theo tên bộ thu, tiếp tục các bộ thu khác, Sender vẫn nhận số liệu còn lại và tự thân | agent_collector_errors{collector} bằng 1 ở chu kỳ đó, các chỉ số khác vẫn hiện diện |
| QAS-C02 / NFR-C02 | Máy có rất nhiều mount hoặc giao diện | Chạy bình thường | Giới hạn 40 mount, 20 giao diện, cắt theo max_series, cảnh báo một lần | Số series khi gửi không vượt max_series. Số mẫu bị loại thấy ở agent_dropped_samples_total |
| QAS-C03 / NFR-C07 | Bộ đếm mạng bị đặt lại (bơm lại driver) | Chạy bình thường | Bỏ mẫu tốc độ nếu bộ đếm 64 bit giảm, loại tốc độ trên 1e12 mỗi giây | Không có điểm tốc độ vô lý trong lô. Giới hạn của cách làm: xem 7.4.2 |
| QAS-C04 / NFR-C04 | Đọc /proc chậm hoặc statfs chậm | Tải cao, đĩa chậm | Ngữ cảnh có hạn collect_timeout. Bộ thu đĩa kiểm ngữ cảnh giữa các mount | agent_collect_duration_seconds dưới collect_timeout. Ngoại lệ ở 8.3 |
3. Kiến trúc ứng dụng
3.1. Kiến trúc runtime
Engine chạy trong cùng tiến trình và cùng goroutine với vòng chu kỳ của Runtime Core (không có goroutine riêng cho bộ thu). Đây là quyết định ngầm của mã (xem D-06 ở L2 và ADR-C02 ở Phụ lục B).
flowchart LR
classDef bc fill:#1f3a5f,stroke:#4a90d9,color:#fff
classDef owned fill:#2d4a3e,stroke:#5fb37a,color:#fff
classDef datastore fill:#3a2d4a,stroke:#a06fd9,color:#fff
RT["Runtime Core · vòng chu kỳ"]:::bc
ENG["Engine · gom, chuẩn hóa, cắt"]:::bc
CPU["Bộ thu CPU · tải và tốc độ"]:::bc
MEM["Bộ thu bộ nhớ · RAM và swap"]:::bc
DSK["Bộ thu đĩa · mount và statfs"]:::bc
NET["Bộ thu mạng · tốc độ"]:::bc
UPT["Bộ thu uptime · tiến trình"]:::bc
SELF["Bộ thu tự thân · agent_*"]:::bc
ST[("Thống kê · bộ đếm chung")]:::datastore
OS(["Hệ điều hành · /proc, statfs"]):::owned
RT -->|"yêu cầu thu một chu kỳ"| ENG
ENG -->|"gọi tuần tự"| CPU & MEM & DSK & NET & UPT
CPU & MEM & DSK & NET & UPT -->|"đọc số liệu thô"| OS
ENG -->|"gọi sau cùng"| SELF
SELF -->|"đọc RSS và CPU tiến trình"| OS
ENG -.->|"ghi lỗi, thời lượng, số loại"| ST
SELF -.->|"đọc bộ đếm chung"| STChú giải: nét liền là lời gọi đồng bộ trong cùng tiến trình, nét đứt là truy cập trạng thái dùng chung trong bộ nhớ.
Bảng connector
| Connector | Từ | Tới | Cơ chế | Đồng bộ | Ghi chú |
|---|---|---|---|---|---|
| CN-1 | Runtime Core | Engine | Gọi hàm Collect(ctx, now) | Đồng bộ, chặn vòng chu kỳ | Không có goroutine riêng. Thời gian thu cộng vào chu kỳ |
| CN-2 | Engine | Bộ thu | Interface Collector | Đồng bộ, tuần tự theo thứ tự cấu hình: cpu, memory, disk, net, uptime | safeCollect bọc recover |
| CN-3 | Bộ thu | Hệ điều hành | Đọc tệp qua fs.FS (os.DirFS("/proc")) và syscall.Statfs | Đồng bộ | Chỉ đọc. Có thể thay bằng fstest.MapFS khi kiểm thử |
| CN-4 | Engine | Bộ thu tự thân | Giống CN-2 | Đồng bộ, chạy sau cắt series | Miễn cắt series |
| CN-5 | Engine, Bộ thu tự thân | Thống kê | atomic và sync.Mutex | Đồng bộ | Cùng goroutine với Sender nên không tranh chấp thực tế, nhưng an toàn cho gọi đồng thời (Sender đọc Stats cùng luồng) |
3.2. Kiến trúc module
flowchart TB
classDef pub fill:#1f3a5f,stroke:#4a90d9,color:#fff
classDef intn fill:#3a3a3a,stroke:#888,color:#fff
classDef ext fill:#3a3a3a,stroke:#888,color:#fff
subgraph L1["Lớp lắp ráp: host"]
HOST["NewEngine, NewEngineFS"]:::pub
end
subgraph L2["Lớp hiện thực: linux"]
CTOR["Hàm dựng NewCPU, NewMemory, NewDisk, NewNet, NewUptime, NewSelf"]:::pub
PARSE["procfs: bộ phân tích tệp /proc"]:::intn
FILT["filter: lọc mount và giao diện"]:::intn
HELP["helpers: tốc độ, chặn phần trăm"]:::intn
end
subgraph L3["Lớp hợp đồng: collector"]
ENGN["Engine, EngineConfig, Result"]:::pub
CONTRACT["Collector, Sample, SeriesKey"]:::pub
CAT["Allowed: danh sách trắng"]:::pub
end
STATS(["stats, config, version"]):::ext
HOST --> ENGN
HOST --> CTOR
HOST -.-> STATS
CTOR --> PARSE & FILT & HELP
CTOR --> CONTRACT
ENGN --> CONTRACT
ENGN --> CAT
CTOR -.-> STATSChú giải: xanh dương là bề mặt công khai của gói, xám là nội bộ hoặc bên ngoài. Mũi tên liền là phụ thuộc biên dịch. Mũi tên đứt là phụ thuộc vào gói dùng chung. Không có phụ thuộc ngược từ collector sang linux (gói hợp đồng không biết gói hiện thực).
3.2.1. Cấu trúc: gói collector (Engine và hợp đồng)
| Giao diện | Người dùng | Hợp đồng |
|---|---|---|
Collector (Name() string, Collect(ctx, now) ([]Sample, error)) | Engine, kiểm thử | Bộ thu trả mẫu gauge. Bộ thu tốc độ giữ trạng thái và không trả mẫu tốc độ lần đầu. Có thể trả cả mẫu lẫn lỗi (errors.Join), Engine giữ cả hai |
Sample{Name, Labels, Value} | Mọi bên | Một giá trị gauge kèm nhãn |
Engine.Collect(ctx, now) Result | Runtime Core, collect-once | Không trả lỗi. Lỗi nằm trong Result.Errors[tên bộ thu] |
EngineConfig{Collectors, Self, MaxSeries, Selection, StaticLabels, Timeout, Stats, Log} | host | Selection (có thể nil) lọc chỉ số theo include, exclude. Self chạy cuối và được miễn cắt. Timeout bằng 0 nghĩa là không giới hạn |
Allowed (map tên chỉ số tới danh sách nhãn) | Engine, kiểm thử | Sinh từ internal/catalog, nguồn sự thật tên và nhãn phía Agent. Kiểm thử docs_sync_test.go giữ đồng bộ với docs/03, cần đồng bộ thêm với catalog của Collector |
SeriesKey(name, labels), SortSamples | Engine, collect-once | Khóa ổn định theo tên và nhãn đã sắp xếp. Phân cách bằng byte 0xff |
3.2.2. Cấu trúc: gói collector/linux (bộ thu Linux)
| Thành phần | Tệp | Nguồn dữ liệu | Trạng thái giữa các lần gọi |
|---|---|---|---|
cpuCollector | cpu.go | /proc/stat, /proc/loadavg | Giữ prev cpuTimes và cờ havePrev |
memCollector | memory.go | /proc/meminfo | Không |
diskCollector | disk.go, filter.go | /proc/self/mountinfo, statfs(2) | Không (bộ lọc dựng sẵn) |
netCollector | net.go | /proc/net/dev | Giữ prev map[iface]counters và prevTime |
uptimeCollector | uptime.go | /proc/uptime, đếm thư mục số trong /proc | Không |
selfCollector | self.go | Stats, runtime.NumGoroutine, /proc/self/statm, /proc/self/stat | Giữ prevCPU, prevAt |
| Bộ phân tích | procfs.go | Phân tích stat, meminfo, mountinfo, net/dev, loadavg | Không |
| Bộ lọc | filter.go | Bộ lọc mount, fstype, giao diện | Không |
| Tiện ích | helpers.go | clampPercent, counterDelta, ratePerSec | Không |
statfs_linux.go, statfs_other.go | syscall.Statfs. Ngoài Linux trả lỗi "statfs is only available on Linux" | Không |
Bộ thu Windows (ĐÃ XÂY MỘT PHẦN, AGT-7, ADR 0007): gói internal/collector/windows gồm cpu.go (GetSystemTimes), memory.go (GlobalMemoryStatusEx), disk.go (ổ có ký tự), net.go (GetIfTable2), uptime.go (GetTickCount64), self.go, ports.go (phân tích bảng TCP/UDP owner có giới hạn đọc). Logic chỉ thấy cấu trúc API (hàm thay được), lớp gọi hệ thống ở api_windows.go (thư viện chuẩn syscall, không x/sys), api_other.go trả lỗi ngoài Windows. host.NewEngineFS gọi NewEngineWindows khi chạy trên Windows, kiểm tra service và port nhận hàm từ API qua checks.Options.ServiceUp, PortListening. Không có tải trung bình trên Windows. Chưa chạy trên Windows thật.
3.2.3. Cấu trúc thành phần dùng chung: stats, config
| Thành phần | Vai trò với thành phần này | Ghi chú |
|---|---|---|
internal/stats.Stats | Bộ đếm nguyên tử chia sẻ giữa Engine, Sender, WAL: SendFailures, DroppedSamples, WALBytes, WALBatches, RSSBytes và các giá trị ghi bằng setter (collectNanos, clockSkew, cpuPercent, collectorErrors theo sync.Mutex) | Engine ghi ba giá trị của nó ở cuối phần chính, trước khi chạy bộ thu tự thân |
internal/config.Config | Cấp Metrics, Limits.MaxSeries, CollectTimeout, Labels cho host.NewEngine. Cờ checks được phân tích nhưng không có bộ thu (L2 D-02) | Đọc một lần khi dựng |
internal/version | Version, ProtoVersion cho agent_info |
4. Domain model
classDiagram
namespace Vung_Thu_So_Lieu {
class Engine {
<<Aggregate Root>>
+MaxSeries int
+Timeout duration
+StaticLabels map
}
class Collector {
<<Entity>>
+Name string
}
class RateBaseline {
<<Entity>>
+PrevCounters map
+PrevTime time
}
class Sample {
<<ValueObject>>
+Name string
+Labels map
+Value float
}
class Result {
<<ValueObject>>
+Dropped int
+Errors map
+Duration duration
}
class MetricDef {
<<ValueObject>>
+Name string
+AllowedLabels list
}
}
Engine "1" *-- "1..*" Collector : chạy tuần tự
Collector "1" o-- "0..1" RateBaseline : giữ
Collector ..> Sample : tạo
Engine ..> MetricDef : kiểm theo
Engine ..> Result : trả về
Result "1" *-- "0..*" Sample : chứaBất biến (invariants) của Aggregate Engine
| Mã | Bất biến | Nơi bảo đảm |
|---|---|---|
| INV-1 | Mọi Sample trong Result.Samples có Name thuộc Allowed và mọi khóa nhãn thuộc danh sách của tên đó | sanitize |
| INV-2 | Không có nhãn company_id, server_id, agent_id trong mẫu phát ra (nhãn tĩnh cũng không thể đặt chúng) | sanitize (reserved) |
| INV-3 | Giá trị mẫu là số hữu hạn (không NaN, không Inf) | sanitize |
| INV-4 | Không có hai mẫu cùng SeriesKey trong một chu kỳ | sanitize (seen) |
| INV-5 | Giá trị nhãn không dài quá 128 byte và luôn là UTF-8 hợp lệ | truncate |
| INV-6 | Số mẫu chính không vượt MaxSeries trừ min(16, MaxSeries/2) khi có bộ thu tự thân. Mẫu tự thân được nối sau khi cắt, nên tổng có thể tới MaxSeries cộng số mẫu tự thân dư (xem lưu ý dưới) | Collect |
| INV-7 | Bộ thu tốc độ không phát mẫu tốc độ ở lần gọi đầu và khi bộ đếm đi lùi không hợp lệ | Từng bộ thu (cpu, net, self) |
Lưu ý INV-6: các bộ thu chính bị cắt về MaxSeries - min(16, MaxSeries/2), bộ thu tự thân được nối sau. Bộ thu tự thân phát 8 series cố định (agent_goroutines, agent_wal_bytes, agent_wal_batches, agent_send_failures_total, agent_dropped_samples_total, agent_collect_duration_seconds, agent_clock_skew_seconds, agent_info), cộng agent_rss_bytes và agent_cpu_percent khi đọc được, cộng một series agent_collector_errors cho mỗi bộ thu chính đang lỗi (tối đa 5). Tối đa 15 series, nằm trong dự trữ 16. Đây là suy luận từ mã, TestSeriesLimitTrimsMainButKeepsSelf dùng bộ thu tự thân giả nên không khẳng định trực tiếp con số 15.
5. API Contract Specification
Thành phần này không có API mạng. Hợp đồng công khai của nó là interface Go trong tiến trình và lệnh CLI collect-once. Các mục 5.1 đến 5.5 được điền theo hình thức này (xem Phụ lục C).
5.1. Operations (Public API)
| # | Operation / Kênh Event | Loại hình | Hướng gọi (Caller → BC) | Ngữ nghĩa nghiệp vụ |
|---|---|---|---|---|
| 1 | Engine.Collect(ctx, now) Result | Lời gọi hàm đồng bộ | Runtime Core, CLI collect-once → Engine | Thu một chu kỳ, trả mẫu đã chuẩn hóa và cắt, số mẫu bị loại, lỗi theo bộ thu |
| 2 | Collector.Collect(ctx, now) ([]Sample, error) | Lời gọi hàm đồng bộ | Engine → Bộ thu | Đọc một nguồn, trả mẫu thô. Engine chịu trách nhiệm chuẩn hóa |
| 3 | Collector.Name() string | Lời gọi hàm | Engine → Bộ thu | Tên trong cấu hình (cpu, memory, disk, net, uptime, self), dùng làm khóa lỗi |
| 4 | host.NewEngine(cfg, stats, log), host.NewEngineFS(..., proc fs.FS) | Lời gọi hàm | Runtime Core, CLI → host | Dựng engine từ cấu hình hiệu lực. NewEngineFS cho phép tiêm /proc giả |
| 5 | accesshub-agent collect-once [-gap d] [-config f] [-collector u] [-state-dir d] [-log-level l] | CLI, in JSON ra stdout | Quản trị viên → CLI | Thu hai lần cách nhau -gap, in mẫu lần hai. Không gửi, không cần enroll |
| 6 | Kênh sự kiện ra | Không có | Thành phần không phát sự kiện |
5.2. Request / Response Schema
[Engine.Collect]
| Field | Kiểu | Ghi chú | ||
|---|---|---|---|---|
| Req | ctx | context.Context | ! | Hủy hoặc quá hạn collect_timeout (Engine tự bọc) |
| Req | now | time.Time | ! | Thời điểm của chu kỳ, dùng tính tốc độ và boot_time_seconds |
| Resp | Samples | []Sample | ! | Đã chuẩn hóa. Có thể rỗng. Chưa sắp xếp (dùng SortSamples khi cần) |
| Resp | Dropped | int | ! | Mẫu bị loại bởi chuẩn hóa, trùng, cắt series (không tính mẫu tự thân bị loại nếu có, xem lưu ý dưới bảng) |
| Resp | Errors | map[string]error | ! | Khóa là tên bộ thu. Kể cả self |
| Resp | Duration | time.Duration | ! | Từ đầu đến khi xong các bộ thu chính (không gồm bộ thu tự thân) |
| Errors có thể | Không trả lỗi ra ngoài. Xem 5.3 cho lỗi trong Errors |
Lưu ý: Duration và agent_collect_duration_seconds được đo trước khi chạy bộ thu tự thân. Errors["self"] được thêm sau khi ghi SetCollectorErrors, nên lỗi của bộ thu tự thân không xuất hiện ở agent_collector_errors (chỉ ở Result.Errors và log không có). Mẫu tự thân bị loại sau đó được cộng vào Result.Dropped nhưng không vào Stats.DroppedSamples. Đây là sai lệch nhỏ của mã (OQ-C4).
[Sample]
| Field | Kiểu | Ghi chú | ||
|---|---|---|---|---|
| Req | Name | string | ! | Thuộc Allowed. Không tiền tố ah_ |
| Req | Value | float64 | ! | Hữu hạn |
| Req | Labels | map[string]string | ? | Khóa thuộc danh sách của chỉ số, giá trị tối đa 128 byte |
[collect-once output]
| Field | Kiểu | Ghi chú | ||
|---|---|---|---|---|
| Resp | time | RFC 3339 UTC | ! | Thời điểm in |
| Resp | samples[] | {name, labels?, value} | ! | Sắp xếp theo tên rồi khóa series |
| Resp | dropped | int | ! | |
| Resp | errors | map[string]string | ? | Có khi có bộ thu lỗi |
| Resp | duration | string | ! | Ví dụ 1.2ms |
| Errors có thể | Mã thoát 2 (-gap ngoài khoảng), 3 (cấu hình sai), 1 (dựng bộ thu lỗi, hoặc bị hủy) |
Header và định danh người dùng cuối: không áp dụng (không có yêu cầu mạng, không có người dùng cuối).
Danh sách chỉ số đã phát (ĐÃ HIỆN THỰC) và chỉ đăng ký trong danh sách trắng (CHƯA PHÁT)
| Trạng thái | Tên chỉ số |
|---|---|
| Đã phát (Linux) | cpu_usage_percent, cpu_mode_percent{mode}, cpu_load1, cpu_load5, cpu_load15, load_per_core_5m, cpu_cores, mem_total_bytes, mem_used_bytes, mem_available_bytes, mem_used_percent, mem_free_bytes, mem_cached_bytes, mem_buffers_bytes, mem_slab_bytes, mem_page_tables_bytes, swap_total_bytes, swap_used_bytes, swap_used_percent, swap_cached_bytes, disk_total_bytes{mount,fstype}, disk_used_bytes, disk_used_percent, disk_inodes_used_percent, net_rx_bytes_per_sec{iface}, net_tx_bytes_per_sec, net_rx_packets_per_sec, net_tx_packets_per_sec, net_rx_errors_per_sec, net_tx_errors_per_sec, net_rx_drops_per_sec, net_tx_drops_per_sec, uptime_seconds, boot_time_seconds, procs_total, psi_cpu_some_percent, psi_memory_some_percent, psi_io_some_percent, và 11 chỉ số agent_* |
| Chỉ có trong danh sách trắng, CHƯA XÂY | disk_read_bytes_per_sec, disk_write_bytes_per_sec, disk_io_util_percent (giai đoạn 2), open_fds_percent (giai đoạn 2), service_up, port_up, tcp_connect_up, tcp_connect_seconds, http_up, http_duration_seconds, http_status_code, cert_days_left (AGT-8) |
5.3. Error Codes
Không có mã lỗi HTTP. Lỗi trả về trong Result.Errors là chuỗi Go, không có mã ổn định. Bảng dưới liệt kê các lỗi đặc thù để runbook nhận diện.
| Mã lỗi (chuỗi) | HTTP/gRPC | Điều kiện phát sinh |
|---|---|---|
collector panic: <giá trị> | Không áp dụng | Bộ thu panic, safeCollect bắt |
meminfo: missing MemTotal | Không áp dụng | /proc/meminfo không có MemTotal hợp lệ |
stat: no aggregate cpu line, stat: cpu line has N columns, need at least 4, stat: bad cpu counter "..." | Không áp dụng | /proc/stat hỏng |
uptime: bad value "...", uptime: empty file | Không áp dụng | /proc/uptime hỏng |
self/statm: unexpected format, self/stat: no command field, self/stat: too few fields, self/stat: bad cpu fields | Không áp dụng | /proc/self/* hỏng |
disk: mount limit reached, extra mounts ignored | Không áp dụng | Có mount thứ 41 đủ điều kiện |
statfs is only available on Linux | Không áp dụng | Bộ thu đĩa chạy ngoài Linux (không đến được vì NewEngineFS không dựng bộ thu ngoài Linux) |
Lỗi context deadline exceeded hoặc context canceled | Không áp dụng | Hết collect_timeout hoặc dừng agent giữa chừng khi thu đĩa |
exclude_mounts "<biểu thức>": ..., net.include "...", net.exclude "..." | Không áp dụng | Regex không biên dịch được lúc dựng engine, host.NewEngine trả lỗi và agent không khởi động (build collectors: ...) |
Lỗi từ statfs cho từng mount | Không áp dụng | Mount không đọc được. Các mount khác vẫn được thu |
5.4. Versioning
Không có API mạng nên không có phiên bản API riêng. Điểm hợp đồng có phiên bản là danh mục chỉ số: Allowed phản ánh docs/03-metrics-catalog.md và catalog máy đọc được của Collector (internal/catalog/metrics.yaml theo docs/03, chưa được đối chiếu trong bản nháp này). Thêm chỉ số mới chỉ cần thêm vào Allowed và bộ thu, nhưng phải cập nhật catalog phía Collector trước, nếu không Collector sẽ loại mẫu (hành vi chính xác của Collector xem L2 Collector).
Sai lệch đã biết: docs/03 mô tả nhãn catalog_version của agent_info nhưng mã chỉ có version, proto, os (L2 D-03). Không có cơ chế dò lệch catalog lúc chạy. Gợi ý: kiểm bằng scripts/check-proto-drift.sh chỉ áp dụng cho proto, không cho catalog (ĐỀ XUẤT: thêm kiểm tra tương tự cho catalog).
5.5. Authz - shared responsibility & permission matrix
Không có lớp phân quyền ứng dụng: thành phần không nhận yêu cầu từ bên ngoài, chỉ được gọi từ trong tiến trình. Quyền truy cập dữ liệu là quyền hệ điều hành của tài khoản accesshub-agent.
Phân định trách nhiệm Auth
| Lớp | Ai sở hữu | Gồm |
|---|---|---|
| Nhận diện tiến trình | Hệ điều hành và systemd | Chạy dưới tài khoản accesshub-agent, không capability (L3 Service và Packaging) |
Quyền đọc /proc, statfs | Hệ điều hành | Mọi tiến trình đọc được /proc/stat, meminfo, net/dev, self/*. statfs cần quyền duyệt tới điểm mount. Unit có ProtectSystem=strict và ProtectProc (theo L2 mục 10.4, xem L3 Service và Packaging để biết thông số chính xác) |
| Kiểm soát nội dung thu | Thành phần này | Danh sách trắng tên và nhãn, không đọc cmdline, không đọc nội dung tệp |
Permission matrix
| Public API (5.1) | service-principal | user-role |
|---|---|---|
| Mọi thao tác 1 đến 4 | Chỉ mã trong cùng tiến trình | Không áp dụng |
CLI collect-once | Người dùng chạy lệnh (không cần root, không cần enroll) | Không áp dụng, không có vai trò ứng dụng |
6. Data Schema (Physical)
Thành phần không có cơ sở dữ liệu và không ghi đĩa. Trạng thái duy nhất là các biến trong bộ nhớ của từng bộ thu. Mục này được điền ở dạng thu gọn (Phụ lục C).
6.1. Cài đặt vật lý
Bảng ánh xạ
| Phân hệ (3.2) | Aggregate (4) | CSDL (Store) | Cấu trúc vật lý cốt lõi |
|---|---|---|---|
collector | Engine | Không (bộ nhớ tiến trình) | Struct Engine với cờ warnedTrim. Không có trạng thái giữa các chu kỳ ngoài cờ cảnh báo |
collector/linux (cpu) | RateBaseline | Bộ nhớ tiến trình | prev cpuTimes, havePrev bool |
collector/linux (net) | RateBaseline | Bộ nhớ tiến trình | prev map[string]netCounters, prevTime time.Time |
collector/linux (self) | RateBaseline | Bộ nhớ tiến trình | prevCPU float64, prevAt time.Time, havePrev bool |
Lược đồ (trạng thái trong bộ nhớ)
classDiagram
namespace Trang_Thai_Bo_Nho {
class engineState {
warnedTrim bool
}
class cpuState {
prev cpuTimes
havePrev bool
}
class cpuTimes {
user uint64
nice uint64
system uint64
idle uint64
iowait uint64
irq uint64
softirq uint64
steal uint64
}
class netState {
prev map_iface_netCounters
prevTime time
}
class netCounters {
rxBytes uint64
rxErrs uint64
rxDrop uint64
txBytes uint64
txErrs uint64
txDrop uint64
}
class selfState {
prevCPU float64
prevAt time
havePrev bool
}
}
cpuState *-- cpuTimes : giữ mẫu trước
netState *-- netCounters : giữ mỗi giao diệnGhi chú lược đồ: engineState và selfState không có quan hệ chứa. Không có khóa ngoại và không có tham chiếu chéo aggregate.
6.2. Phân loại dữ liệu & retention
| Phần tử / Trường dữ liệu | Phân lớp dữ liệu | Thời hạn lưu trữ (Retention) | Cơ chế bảo vệ kỹ thuật |
|---|---|---|---|
| Bộ đếm mẫu trước (cpu, net, self) | Nội bộ | Chỉ trong đời tiến trình, mất khi khởi động lại (mẫu tốc độ đầu tiên bị bỏ sau mỗi lần khởi động, do đó có một chu kỳ khuyết) | Chỉ ở RAM, không ghi đĩa |
Mẫu trong Result | Nội bộ | Một chu kỳ, sau đó chuyển cho Sender và vào WAL (xem L3 WAL và Sender) | Không lưu ở thành phần này |
Nhãn mount, iface | Nội bộ | Như mẫu | Cắt 128 byte, danh sách trắng khóa nhãn |
7. Thuật toán & Luồng nghiệp vụ
7.1. Luồng nghiệp vụ chính (Happy paths)
Luồng 1: Một chu kỳ thu (từ lần thứ hai trở đi)
sequenceDiagram
participant RT as Runtime Core
participant EN as Engine
participant BT as Bộ thu chính
participant OS as Hệ điều hành
participant ST as Thống kê
participant SF as Bộ thu tự thân
RT->>EN: Collect(ctx, now)
loop mỗi bộ thu theo thứ tự
EN->>BT: Collect(ctx, now)
BT->>OS: đọc /proc hoặc statfs
BT-->>EN: mẫu thô
end
EN->>EN: chuẩn hóa, loại trùng, cắt series
EN->>ST: ghi lỗi, thời lượng, số mẫu loại
EN->>SF: Collect(ctx, now)
SF->>ST: đọc bộ đếm chung
SF-->>EN: mẫu agent_*
EN-->>RT: ResultLuồng 2: Lệnh collect-once
sequenceDiagram
participant OP as Quản trị viên
participant CLI as collect-once
participant EN as Engine
OP->>CLI: collect-once -gap 1s
CLI->>CLI: nạp cấu hình, URL giả nếu thiếu
CLI->>EN: dựng engine, Stats rỗng, log bỏ
CLI->>EN: Collect lần 1, bỏ kết quả
CLI->>CLI: chờ -gap
CLI->>EN: Collect lần 2
EN-->>CLI: Result
CLI-->>OP: JSON đã sắp xếp ra stdout7.2. Luồng thay thế / lỗi (Alt / Error paths)
Luồng 3: Bộ thu lỗi hoặc panic
sequenceDiagram
participant EN as Engine
participant BT as Bộ thu A
participant BU as Bộ thu B
participant ST as Thống kê
EN->>BT: safeCollect
BT--xEN: lỗi hoặc panic đã bắt
EN->>EN: ghi Errors, log Warn "collector failed"
EN->>BU: safeCollect (vẫn chạy)
BU-->>EN: mẫu
EN->>ST: agent_collector_errors A = 1Bộ thu có thể trả cả mẫu lẫn lỗi (ví dụ đĩa có một mount lỗi), Engine giữ phần mẫu đã có.
Luồng 4: Hết hạn collect_timeout
sequenceDiagram
participant EN as Engine
participant DK as Bộ thu đĩa
participant NE as Bộ thu mạng
EN->>EN: ctx có hạn collect_timeout chung
EN->>DK: Collect(ctx)
DK->>DK: kiểm ctx giữa các mount
DK--xEN: mẫu đã có và lỗi ctx
EN->>NE: Collect(ctx đã quá hạn)
NE-->>EN: đọc /proc vẫn xong, không kiểm ctx
EN->>EN: Result kèm lỗi, không hủy các bộ thu sauHạn là một hạn chung cho cả chu kỳ, không phải theo từng bộ thu. Bộ thu đọc tệp nhỏ trong /proc không kiểm ctx, nên chỉ bộ thu đĩa thực sự dừng sớm (xem 8.3 về statfs treo).
Luồng 5: Vượt giới hạn series
sequenceDiagram
participant EN as Engine
participant LG as Log
participant ST as Thống kê
participant SF as Bộ thu tự thân
EN->>EN: sau chuẩn hóa còn N mẫu chính
EN->>EN: N lớn hơn giới hạn chính
EN->>EN: cắt đuôi, cộng vào Dropped
EN->>LG: Warn một lần, cờ warnedTrim
EN->>ST: DroppedSamples cộng Dropped
EN->>SF: chạy sau cắt, không bị cắt
EN->>EN: N về dưới giới hạn thì xóa cờ warnedTrimThứ tự cắt là thứ tự bộ thu cấu hình rồi thứ tự phát của từng bộ thu, nên các bộ thu đứng sau (uptime) bị cắt trước. Không có ưu tiên theo mức quan trọng của chỉ số (OQ-C3).
7.3. State machines
Thực thể có vòng đời trạng thái đáng kể là đường cơ sở tốc độ (RateBaseline) của bộ thu CPU. Bộ thu mạng có trạng thái tương tự theo từng giao diện.
stateDiagram-v2
[*] --> KhongCoNen
KhongCoNen --> CoNen : Collect [đọc được] / lưu bộ đếm, chỉ phát tải và số lõi
CoNen --> CoNen : Collect [bộ đếm đi tiến, tổng khác 0] / phát tốc độ, cập nhật nền
CoNen --> CoNen : Collect [bộ đếm đi lùi hoặc tổng bằng 0] / bỏ tốc độ, cập nhật nền, không báo lỗi
CoNen --> CoNen : Collect [đọc lỗi] / giữ nền cũ, báo lỗi| Path | Đường trên máy trạng thái |
|---|---|
| Khởi động, lần thu đầu | KhongCoNen sang CoNen (Runtime Core chạy một lần thu mồi và bỏ kết quả, nên lần gửi đầu đã có tốc độ, xem L3 WAL và Sender) |
| Chu kỳ thường | CoNen sang CoNen phát tốc độ |
| Bộ đếm đi lùi (đặt lại, khởi động lại hạt nhân) | CoNen sang CoNen không phát mẫu tốc độ và không trả lỗi (im lặng), nền vẫn được cập nhật |
/proc/stat không đọc được | Giữ nguyên, không đổi nền |
| Khởi động lại agent | Về KhongCoNen, mất nền |
Ghi chú: nền CPU được gán ngay sau khi đọc và phân tích thành công, trước cả khi tính hiệu (cpu.go, hàm rates), nên bộ đếm đi lùi chỉ làm khuyết đúng một chu kỳ. Khi /proc/stat đọc lỗi thì rates không được gọi và nền cũ được giữ. Chưa có kiểm thử riêng cho nhánh đọc lỗi liên tiếp (TestCPUMissingFilesReportError chỉ kiểm lỗi được báo). Với net, nhánh trạng thái thêm mức từng giao diện: giao diện mới xuất hiện vào lúc now không có nền nên bị bỏ qua đúng một chu kỳ, còn giao diện biến mất bị xóa khỏi nền.
7.4. Thuật toán cốt lõi
7.4.1. Chuẩn hóa mẫu và chặn cardinality
Vấn đề: bộ thu là mã hiện thực nhiều, dễ sai. Không được để một bộ thu lỗi làm tăng cardinality không giới hạn hoặc rò rỉ nhãn định danh đa tenant lên đường truyền.
Giải pháp: hàm sanitize chạy trên mọi mẫu, thứ tự kiểm cho từng mẫu: (1) tên phải thuộc Allowed, (2) giá trị không NaN và không Inf, (3) mỗi khóa nhãn phải hợp lệ theo regex ^[a-zA-Z_][a-zA-Z0-9_]*$, không thuộc tập dành riêng (company_id, server_id, agent_id) và thuộc danh sách nhãn cho phép của tên đó, (4) giá trị nhãn cắt 128 byte ở ranh giới UTF-8, (5) thêm nhãn tĩnh cấu hình trừ khi trùng khóa dành riêng hoặc mẫu đã có khóa đó, (6) loại mẫu có SeriesKey trùng mẫu đã giữ. Mẫu vi phạm (1) đến (3) bị loại cả mẫu, (4) chỉ cắt. Sau đó cắt đuôi về giới hạn (7.2 luồng 5).
Trade-off: loại cả mẫu thay vì bỏ nhãn sai giữ cho chuỗi thời gian nhất quán, nhưng che giấu lỗi ở bộ thu (chỉ thấy qua agent_dropped_samples_total). Regex khóa nhãn phía Agent rộng hơn quy tắc giao thức ^[a-z][a-z0-9_]{0,31}$, nhưng danh sách trắng là hàng rào thực sự nên không gây hại (OQ-C5). Cắt theo thứ tự xuất hiện đơn giản và xác định, nhưng không ưu tiên chỉ số quan trọng.
7.4.2. Tốc độ từ bộ đếm tích lũy
Vấn đề: /proc/net/dev và /proc/stat là bộ đếm tích lũy, cần tốc độ theo giây. Bộ đếm có thể quay vòng (32 bit ở nhân cũ) hoặc đặt lại (giao diện khởi tạo lại), và hai lần đọc có thể cách nhau bất thường.
Giải pháp: giữ nền là lần đọc trước và thời điểm. Tốc độ mạng dùng counterDelta(cur, prev): nếu cur >= prev thì hiệu thường, nếu không và prev <= MaxUint32 thì hiểu là quay vòng 32 bit và tính 2^32 - prev + cur, còn lại là đặt lại nên bỏ mẫu. ratePerSec trả không hợp lệ khi thời gian trôi bằng hoặc nhỏ hơn 0, hoặc tốc độ vượt 1e12 (ngưỡng chống số vô lý). CPU dùng diffCPU: bất kỳ bộ đếm đi lùi hoặc tổng bằng 0 thì bỏ mẫu, không báo lỗi (không phân biệt quay vòng vì bộ đếm CPU là 64 bit trên hạt nhân hiện đại).
Trade-off: giả định quay vòng khi prev nhỏ hơn hoặc bằng 2^32 có thể tính sai thành tốc độ lớn hơn thực tế nếu thực chất là đặt lại với prev nhỏ. Giới hạn 1e12 chỉ chặn trường hợp cực đoan. Tần suất thu dài (vài chục giây) làm tốc độ tức thời bị trung bình hóa, spike ngắn hơn chu kỳ không thấy được.
7.4.3. Chọn mount đĩa
Vấn đề: máy chủ hiện đại có rất nhiều mount ảo (tmpfs, overlay, /snap, container) không có giá trị giám sát, và cùng một thiết bị có thể được gắn nhiều lần (bind mount) gây trùng số liệu.
Giải pháp: phân tích /proc/self/mountinfo rồi lọc: bỏ mount trùng điểm gắn hoặc trùng majMin cộng fstype (giữ mount đầu tiên), áp bộ lọc fstype (mặc định bỏ nhóm ảo, chỉ thêm fs mạng khi include_network_fs), bỏ tiền tố /var/lib/docker, /var/lib/containers, /snap, /run, /sys, /proc, /dev. Nếu include_fstypes không rỗng thì thay bộ lọc mặc định. exclude_fstypes và exclude_mounts luôn áp dụng. Gọi statfs cho từng mount còn lại, bỏ mount có tổng bằng 0, dừng ở MaxMounts = 40. used = total - min(free, total) và used_percent = used / (used + avail) (cùng ngữ nghĩa df, không tính phần dành cho root). Phần trăm inode chỉ phát khi inodes > 0.
Trade-off: giới hạn 40 mount chọn theo thứ tự mountinfo nên mount thật đứng sau có thể bị bỏ sót nếu có nhiều mount hợp lệ, đổi lại chặn cardinality (mỗi mount 4 series). statfs là lời gọi hệ thống chặn, không hủy được bằng ctx, một NFS treo sẽ chặn cả vòng chu kỳ (8.3, OQ-C1).
7.4.4. Giới hạn giao diện mạng
Vấn đề: máy chủ container có hàng trăm cặp veth làm cardinality nổ.
Giải pháp: lọc bằng regex loại mặc định ^(lo|veth.*|docker.*|br-.*|virbr.*|cali.*|flannel.*|tunl.*|vxlan.*)$. net.include khác rỗng thì ghi đè mặc định, net.exclude luôn áp dụng. Sắp xếp tên tăng dần, giữ tối đa MaxInterfaces = 20, mỗi giao diện 8 series. Giao diện chưa có nền thì bỏ ở lần này.
Trade-off: cắt theo thứ tự chữ cái không phản ánh mức dùng thực tế, và giới hạn 20 giao diện không thông báo cho người vận hành khi có giao diện bị bỏ (không có log hay chỉ số cho việc cắt này).
7.4.5. Công thức CPU, bộ nhớ, uptime
Vấn đề: cần quy ước nhất quán, so sánh được với công cụ quen thuộc (top, free, df).
Giải pháp: cpu_usage_percent = 100 * (total - idle') / total, với idle' = idle + iowait khi include_iowait_in_usage là sai (mặc định), và idle' = idle khi đặt đúng. Các mode: user = user + nice, system = system + irq + softirq, iowait, steal (không phát idle và guest vì guest đã nằm trong user). load_per_core_5m = load5 / cores. Mọi phần trăm bị chặn về khoảng 0 đến 100. Bộ nhớ: used = total - available, nếu thiếu MemAvailable (nhân cũ) thì available = MemFree + Buffers + Cached. Swap: 0% khi không có swap. Uptime: boot_time_seconds = now.Unix() - uptime, procs_total đếm thư mục số trong /proc.
Mặc định iowait được xem là nhàn rỗi, đặt include_iowait_in_usage: true thì iowait tính vào mức dùng (cpu.go, biến iowaitAsBusy).
Trade-off: xem iowait là nhàn rỗi khớp top nhưng làm CPU trông thấp khi đĩa nghẽn, mà nghẽn này lại có chỉ số riêng (cpu_mode_percent{mode=iowait}).
8. Xử lý lỗi
8.1. Các nhánh lỗi
| Bước lỗi | Nguyên nhân | Cơ chế | Trạng thái cuối |
|---|---|---|---|
Đọc tệp /proc | Tệp thiếu hoặc quyền | Bộ thu trả lỗi, không mẫu | Chỉ số nhóm đó khuyết trong chu kỳ, agent_collector_errors{collector} bằng 1 |
| Phân tích định dạng | Nhân lạ, tệp hỏng | Trả lỗi có mô tả (5.3) | Như trên |
| Panic trong bộ thu | Lỗi lập trình | safeCollect bắt, thành lỗi collector panic | Như trên, các bộ thu khác vẫn chạy |
| Bộ đếm đi lùi | Khởi động lại nhân, đặt lại giao diện | Bỏ mẫu tốc độ chu kỳ đó, cập nhật nền. CPU không báo lỗi, mạng chỉ bỏ mẫu của giao diện đó | Khuyết đúng một chu kỳ, không có dấu vết trong chỉ số lỗi |
statfs lỗi một mount | Mount chết, quyền | Ghi lỗi, các mount còn lại vẫn thu | Khuyết chỉ mount đó |
Vượt MaxMounts | Nhiều mount hợp lệ | Lỗi mount limit reached và bỏ phần dư | Chỉ số đĩa không đủ mount |
Vượt max_series | Cấu hình hoặc nhãn nổ | Cắt đuôi, log một lần | agent_dropped_samples_total tăng |
Hết collect_timeout | Đĩa chậm | ctx quá hạn, bộ thu đĩa dừng sớm | Mẫu đĩa thiếu, lỗi ghi nhận |
| Mẫu vi phạm danh mục | Lỗi bộ thu | sanitize loại | Dropped tăng |
8.2. Fail-fast
| Tình huống | Hành vi | Nơi kiểm |
|---|---|---|
Regex exclude_mounts, net.include, net.exclude không biên dịch | host.NewEngine trả lỗi, agent thoát khi khởi động (build collectors: ...), collect-once thoát mã 1 | TestBadRegexFailsEngineBuild |
collect_timeout ngoài 1 s đến 30 s hoặc không nhỏ hơn interval | Nạp cấu hình thất bại (L3 Enroll, Credentials, Config) | config.Validate |
limits.max_series ngoài 1 đến 500 | Nạp cấu hình thất bại | config.Validate |
| Nền tảng không phải Linux | Không thất bại: host.NewEngineFS ghi cảnh báo và dựng engine không có bộ thu và không có bộ thu tự thân | host.go |
Sai lệch cần lưu ý: chú thích mã và L2 nói ngoài Linux agent "chỉ gửi chỉ số agent", nhưng engine ngoài Linux không có Self, nên chu kỳ không phát agent_* mà chỉ có AgentStats do Sender đính kèm vào gói (L2 D-13 và OQ-C7). Điều này không gây lỗi vì mã Windows chưa hỗ trợ.
8.3. Race conditions
| Rủi ro | Mô tả | Xử lý |
|---|---|---|
statfs treo trên NFS hoặc thiết bị chết | Lời gọi chặn trong nhân, ctx chỉ được kiểm giữa các mount, nên cả vòng chu kỳ và Sender đứng theo (cùng goroutine) | Bảo vệ một phần: mặc định loại fs mạng, nên rủi ro chỉ khi bật include_network_fs hoặc đĩa cục bộ chết. Chưa có bulkhead theo bộ thu (OQ-C1, ADR-C02) |
Đọc Stats từ Sender | Giá trị bộ đếm nguyên tử và có mutex, không đọc rách | Bảo đảm bởi stats |
| Hai engine cùng lúc | Không xảy ra, engine dựng một lần, gọi từ một goroutine | Không cần |
9. Suy thoái dịch vụ & Khả năng phục hồi
9.1. Ma trận suy thoái
| Dependency lỗi | Hành vi thành phần | Kiểu suy thoái | Hệ quả vận hành |
|---|---|---|---|
Một tệp /proc không đọc được | Bộ thu tương ứng lỗi, còn lại chạy | Suy giảm từng phần (graceful degradation) | Nhóm chỉ số khuyết, cảnh báo phía Collector qua agent_collector_errors |
statfs chậm hoặc treo | Chặn vòng chu kỳ tới khi trả về, hoặc mãi mãi | Đứng nghẽn (không suy giảm được) | Thiếu gói dữ liệu, WAL không tăng, Collector coi là mất kết nối, cần restart agent |
Hạt nhân thiếu MemAvailable | Dùng công thức thay thế | Suy giảm chính xác | Số bộ nhớ khả dụng ước lượng |
| Bộ thu Windows chưa kiểm trên máy thật | Cấu trúc nhị phân sai bố cục đọc ra số rác | Cấu trúc có kiểm tra kích thước lúc biên dịch, cần chạy thử trên Windows 10, 11, Server | AGT-7 còn mở |
| Bộ nhớ agent cạn | Ngoài phạm vi thành phần này | Không xác định | Xem L2 mục 12 |
9.2. Backup, DR
Không áp dụng: thành phần không giữ dữ liệu bền. Mất trạng thái nền chỉ làm khuyết một chu kỳ tốc độ. RTO: một chu kỳ sau khi khởi động (giá trị đề xuất, vì Runtime Core thu mồi trước vòng lặp nên thực tế là tức thời cho chu kỳ gửi đầu). RPO: không áp dụng.
10. Đồng thời & Toàn vẹn dữ liệu
10.1. Ranh giới giao dịch
Không có giao dịch. Một lần Engine.Collect là một đơn vị nhất quán về phía bộ nhớ: kết quả gồm mẫu của một chu kỳ, và trạng thái nền chỉ được cập nhật bên trong lần gọi của từng bộ thu.
10.2. Cơ chế đồng thời
| Cơ chế | Mô tả | Mối nguy |
|---|---|---|
| Thu tuần tự, một goroutine | Các bộ thu chạy lần lượt trong vòng chu kỳ. Thời gian thu cộng thẳng vào chu kỳ nên chu kỳ thực là interval cộng thời gian thu | Một bộ thu chậm làm trễ tất cả (8.3) |
| Không khóa trong bộ thu | Trạng thái nền chỉ được một goroutine truy cập | Sai nếu sau này song song hóa bộ thu (ĐỀ XUẤT: nếu thêm bulkhead thì phải thêm khóa) |
Stats nguyên tử và mutex | Ghi từ Engine, Sender, WAL | Không |
| Engine dựng một lần | Không dựng lại khi SIGHUP | Đổi metrics.*, max_series, collect_timeout, labels cần khởi động lại (L3 Enroll, Credentials, Config) |
11. Bảo mật
11.1. Ba lớp bảo mật
| Lớp | Biện pháp |
|---|---|
| Ranh giới tiến trình | Chỉ đọc /proc và statfs, không chạy lệnh ngoài, không mở cổng, không ghi đĩa |
| Nội dung thu | Danh sách trắng tên và nhãn, không đọc cmdline, không đọc tên người dùng hay nội dung tệp |
| Ranh giới dữ liệu | Nhãn định danh đa tenant bị chặn ở gốc, nên tenant do Collector gắn từ khóa, không phải do agent khai |
11.2. Pipeline authz
Không áp dụng năm bước authz ứng dụng vì không có yêu cầu từ ngoài. Các bước tương đương ở tầng tiến trình: xác thực hệ điều hành (chạy với tài khoản riêng), giới hạn hệ thống tệp của unit systemd, danh sách trắng nội dung. Chi tiết cách ly ở L3 Service và Packaging.
11.3. Neo zero-trust
| Nguyên tắc (L2 mục 6) | Biện pháp |
|---|---|
| Không tin nhãn từ agent | company_id, server_id, agent_id bị loại ở sanitize, kể cả từ nhãn tĩnh |
| Tối thiểu đặc quyền | Không cần root, không cần capability để đọc /proc và statfs |
| Không rò rỉ bí mật | Không thu biến môi trường, đối số dòng lệnh, hay tên tiến trình. logx che bí mật trong log lỗi bộ thu |
| Giảm bề mặt tấn công | Không phụ thuộc thư viện ngoài để phân tích /proc, đầu vào phân tích được kiểm bằng bảng kiểm thử (TestParsers) và fixture thật. Gói linux chưa có fuzz test (ĐỀ XUẤT, OQ-C8) |
12. Cấu hình & Tinh chỉnh
12.1. Tunables
Tất cả tham số dưới đây chỉ được đọc khi dựng engine lúc khởi động (agent.Run gọi newEngine một lần). SIGHUP nạp lại tệp cấu hình cục bộ nhưng không dựng lại engine, nên mọi thay đổi ở bảng này cần khởi động lại dịch vụ.
| Tham số | Mặc định | Ý nghĩa | Mục liên quan |
|---|---|---|---|
collect_timeout | 5 s (1 s đến 30 s, phải nhỏ hơn interval) | Hạn chung cho một chu kỳ thu | 7.2 luồng 4, NFR-C04 |
limits.max_series | 500 (1 đến 500, trần cứng HardMaxSeries) | Trần số series mỗi gói. Trừ dự trữ tự thân min(16, max_series/2) khi cắt | 7.4.1, NFR-C02 |
labels | rỗng (tối đa 20 nhãn, giá trị tối đa 128 byte) | Nhãn tĩnh đính vào mọi mẫu. Không thể đặt nhãn dành riêng | 7.4.1 |
metrics.cpu.enabled | true | Bật bộ thu CPU | FR-C02 |
metrics.cpu.include_iowait_in_usage | false | Tính iowait vào cpu_usage_percent | 7.4.5 |
metrics.memory.enabled | true | Bật bộ thu bộ nhớ | FR-C03 |
metrics.uptime.enabled | true | Bật bộ thu uptime | FR-C06 |
metrics.pressure.enabled | true | Bật bộ thu áp lực PSI (Linux, bỏ qua lặng lẽ nếu kernel không có /proc/pressure) | FR-C07 |
metrics.include | rỗng | Tên hoặc glob, khác rỗng thì chỉ lấy chỉ số khớp (cộng chỉ số bắt buộc). Mẫu không khớp gì là lỗi cấu hình | ADR 0006 |
metrics.exclude | rỗng | Tên hoặc glob loại chỉ số, thắng include. Không loại được chỉ số bắt buộc (nhóm agent), chỉ cảnh báo | ADR 0006 |
metrics.disk.enabled | true | Bật bộ thu đĩa | FR-C04 |
metrics.disk.include_fstypes | rỗng | Khác rỗng thì thay bộ lọc fstype mặc định | 7.4.3 |
metrics.disk.exclude_fstypes | rỗng | Loại thêm fstype (luôn áp dụng) | 7.4.3 |
metrics.disk.exclude_mounts | rỗng | Regex RE2 loại điểm gắn (luôn áp dụng) | 7.4.3 |
metrics.disk.include_network_fs | false | Cho phép nfs, cifs, ceph... (kéo theo rủi ro statfs treo) | 7.4.3, 8.3 |
metrics.net.enabled | true | Bật bộ thu mạng | FR-C05 |
metrics.net.include | rỗng | Regex, khác rỗng thì ghi đè bộ loại mặc định | 7.4.4 |
metrics.net.exclude | rỗng | Regex loại giao diện (luôn áp dụng) | 7.4.4 |
Hằng số biên dịch (không cấu hình được)
| Hằng | Giá trị | Vai trò |
|---|---|---|
MaxMounts | 40 | Số mount tối đa mỗi chu kỳ |
MaxInterfaces | 20 | Số giao diện tối đa mỗi chu kỳ |
SelfReserve | 16 | Chỗ dự trữ cho chỉ số tự thân |
MaxLabelValueBytes | 128 | Độ dài tối đa giá trị nhãn |
maxRatePerSec | 1e12 | Ngưỡng chống tốc độ vô lý |
Các giá trị metrics.* được nạp từ tệp agent.yaml theo thứ tự ưu tiên của cấu hình (L3 Enroll, Credentials, Config, nơi ghi rõ khóa nào có biến môi trường AH_* tương ứng). Cấu hình từ xa (AGT-10) chưa có nên không có tham số nào đổi được lúc chạy.
12.2. Feature flags
Không có cờ tính năng. Tương đương duy nhất là các cờ enabled theo từng bộ thu ở 12.1. Cờ checks.* được phân tích nhưng chưa có bộ thu tương ứng (L2 D-02), bật cờ này không có hiệu ứng.
13. Telemetry & Vận hành
13.1. Metrics
Tất cả chỉ số của thành phần này là gauge do bộ thu tự thân phát vào chính luồng dữ liệu gửi đi, không có endpoint /metrics riêng. Các giá trị dạng _total được phát dưới dạng gauge chứa tổng tích lũy, phía Collector xử lý như bộ đếm.
| Tên | Kiểu | Nhãn | Ngữ nghĩa |
|---|---|---|---|
agent_goroutines | gauge | không | Số goroutine của tiến trình |
agent_rss_bytes | gauge | không | RSS của tiến trình (self/statm nhân kích thước trang). Chỉ phát khi đọc được |
agent_cpu_percent | gauge | không | CPU tiến trình (utime cộng stime chia thời gian thực, clockTicks 100). Không có ở lần đầu |
agent_wal_bytes | gauge | không | Byte WAL trên đĩa (do WAL cập nhật) |
agent_wal_batches | gauge | không | Số gói trong WAL |
agent_send_failures_total | gauge | không | Tổng số lần gửi thất bại từ khi khởi động |
agent_dropped_samples_total | gauge | không | Tổng mẫu bị Engine loại và điểm của gói bị bỏ. Không đếm việc WAL đầy loại gói cũ (L2 D-10) |
agent_collect_duration_seconds | gauge | không | Thời lượng thu chính của chu kỳ gần nhất (không gồm bộ thu tự thân). Chỉ số của NFR-C04 |
agent_collector_errors | gauge | collector | 1 cho mỗi bộ thu lỗi ở chu kỳ gần nhất. Không gồm lỗi của chính self |
agent_clock_skew_seconds | gauge | không | Lệch đồng hồ so với Collector (do Sender cập nhật) |
agent_info | gauge | version, proto, os | Luôn bằng 1. Chưa có nhãn catalog_version (L2 D-03) |
13.2. Log schema (JSON)
Log dùng slog qua logx (định dạng json hoặc text, bộ che bí mật maskingHandler, xoay tệp 10 MB giữ 1 bản sao). Trường chung: time, level, msg. Các sự kiện của thành phần này:
Sự kiện (msg) | Mức | Trường thêm | Khi nào |
|---|---|---|---|
collector failed | Warn | collector, err | Mỗi lần một bộ thu trả lỗi hoặc panic |
series limit reached, dropping the rest | Warn | max_series | Lần đầu vượt trần, im lặng tới khi trở lại dưới ngưỡng |
| Cảnh báo nền tảng không hỗ trợ | Warn | (theo mã host.go) | Dựng engine ngoài Linux |
| (không có log) | Giao diện bị cắt ở 20, mount bị cắt ở 40 (chỉ lỗi trong Result.Errors, không log), lỗi của self |
Trong collect-once, log của engine bị bỏ (slog.DiscardHandler), nên các cảnh báo trên không hiện. Người vận hành chỉ thấy trường errors trong JSON.
13.3. Alert to runbook
Thành phần không tự phát cảnh báo. Các điều kiện dưới đây do Collector đánh giá trên chỉ số tự thân (ĐỀ XUẤT, phụ thuộc bộ luật cảnh báo của Collector).
| Điều kiện (đề xuất) | Runbook |
|---|---|
agent_collector_errors{collector} bằng 1 kéo dài nhiều chu kỳ | Xem log collector failed, kiểm tra /proc và quyền. Chạy accesshub-agent collect-once để xem trường errors |
agent_dropped_samples_total tăng liên tục | Chạy collect-once, xem mẫu bị loại. Kiểm max_series, nhãn tĩnh, bộ lọc |
agent_collect_duration_seconds gần collect_timeout | Kiểm đĩa và mount (NFS?), xem 8.3. Cân nhắc tắt include_network_fs |
| Không có gói dữ liệu từ máy | Nghi statfs treo hoặc tiến trình đứng. Xem L3 WAL và Sender và L3 Service và Packaging |
13.4. Probes
Không có probe riêng. Tính sống của vòng thu được suy ra ở phía Collector từ việc gói dữ liệu đến đều đặn. Không có health endpoint cục bộ trong phạm vi hiện tại (lệnh status thuộc AGT-10, chưa xây).
13.5. Trace propagation
Không áp dụng. Không có trace. Mã tương quan duy nhất là agent_id do Sender gắn ở tầng truyền tải.
14. Kế hoạch kiểm thử
| Loại Test & Phạm vi | Ánh xạ mục tiêu | Mục tiêu kỹ thuật | Ví dụ kịch bản (Test ID) |
|---|---|---|---|
| Unit: bộ phân tích và công thức, fixture thật | AC-C01 đến C10, NFR-C07 | Đúng số học trên /proc mẫu của Ubuntu 24.04 và kernel 2.6.32 | TestCPURatesFromDeltas, TestMemory, TestDiskRealHostFixture, TestParsers, TestCounterDelta |
| Unit: Engine | AC-C12 đến C15, NFR-C02, NFR-C03, NFR-C05 | Chuẩn hóa, cắt, cách ly lỗi, hạn thời gian | TestSanitizeDropsInvalidSamples, TestEngineIsolatesFailingAndPanickingCollectors, TestSeriesLimitTrimsMainButKeepsSelf, TestEngineTimeoutIsAppliedToContext, TestSeriesKeyIsStableAndDistinct |
| Unit: hợp đồng danh mục | AC-C16, NFR-C05 | Mọi chỉ số phát ra nằm trong Allowed | TestCatalogConformance |
| Tích hợp cục bộ | AC-C17, AC-C18 | Lắp ráp engine từ cấu hình, chạy trên /proc thật | TestEngineHonorsCollectorToggles, TestBadRegexFailsEngineBuild, TestRealProcSmoke |
| CLI | AC-C19 | Đầu ra JSON, từ chối tham số sai | TestCollectOncePrintsJSON, TestCollectOnceRejectsBadGapAndConfig |
| Bảo mật log | NFR-C06 | Bí mật không lọt vào log của bộ thu | TestLoggerNeverLeaksSecrets, TestMaskFreeText |
Chưa có: fuzz bộ phân tích /proc | NFR-C01, NFR-C03 | Không panic với tệp /proc méo | ĐỀ XUẤT: FuzzParseNetDev, FuzzParseMountinfo (OQ-C8) |
| Chưa có: đo CPU và RAM của vòng thu | NFR-C01 | Kiểm chứng ngân sách (L2 D-16) | ĐỀ XUẤT: benchmark một chu kỳ trên máy có 40 mount |
Chưa có: statfs treo | NFR-C04 | Mô phỏng bộ thu chặn để đo tác động lên chu kỳ | ĐỀ XUẤT, phụ thuộc quyết định OQ-C1 |
| Chưa có: dò lệch danh mục với Collector | NFR-C05 | Allowed khớp catalog phía Collector | ĐỀ XUẤT: kiểm tra chéo trong CI |
15. Trình tự triển khai
15.1. Ma trận milestone
| Milestone | Nội dung | Phụ thuộc | Đóng góp nghiệm thu |
|---|---|---|---|
| M1 | Hợp đồng Collector, Engine, danh sách trắng, bộ thu Linux (cpu, memory, disk, net, uptime, self), collect-once, host (AGT-3). ĐÃ HIỆN THỰC | Không | AC-C01 đến C19 |
| M2 | Khép các nợ sai lệch: catalog_version trong agent_info (D-03), đếm lỗi của self, đếm việc cắt giao diện và mount, ưu tiên khi cắt series. ĐỀ XUẤT | M1 và quyết định catalog phía Collector | AC mới (chưa có) |
| M3 | Chỉ số đĩa I/O, open_fds_percent (giai đoạn 2 của catalog). THIẾT KẾ CHƯA XÂY | M1 | Chưa có AC |
| M4 | Bộ thu kiểm tra dịch vụ, cổng, TCP, HTTP, hạn chứng chỉ (AGT-8). ĐÃ XÂY 2026-10-02 | M1 | internal/collector/checks/checks_test.go, TestChecksRunThroughTheEngine, TestMergeCentralChecks |
| M5 | Bộ thu Windows bằng API trực tiếp theo ADR 0007 (AGT-7). ĐÃ XÂY, chưa chạy trên Windows thật. PDH cho I/O đĩa còn lại | M1 | Chưa có AC |
| M6 | Kiểm kê phần cứng và hệ điều hành (AGT-9). ĐÃ XÂY 2026-10-01 | M1 | TestReadHostFactsFromFixture, TestParseCPUInfoVariants, internal/inventory |
Ghi chú: M4 cần trước đó có cơ chế cô lập theo bộ thu (chạy song song có hạn riêng), vì các phép kiểm tra mạng có thể chặn. Đây là quyết định thiết kế ở OQ-C1 và ADR-C02.
15.2. Sơ đồ phụ thuộc milestone
flowchart LR
M1["M1 · Engine và bộ thu Linux"]
M2["M2 · Khép nợ sai lệch"]
M3["M3 · Đĩa I/O, fds"]
M4["M4 · Checks AGT-8"]
M5["M5 · Windows AGT-7"]
M6["M6 · Kiểm kê AGT-9"]
M1 --> M2 --> M4
M1 --> M3
M1 --> M5
M1 --> M6
style M1 fill:#2d4a3e,stroke:#5fb37a,color:#fff
style M2 fill:#3a3320,stroke:#d9b84a,color:#fff
style M3 fill:#444,stroke:#aaa,color:#fff
style M4 fill:#444,stroke:#aaa,color:#fff
style M5 fill:#444,stroke:#aaa,color:#fff
style M6 fill:#444,stroke:#aaa,color:#fffChú giải: xanh lá là đã hiện thực, vàng là đề xuất, xám là thiết kế chưa xây. Đường găng tới checks: M1, M2, M4.
Phụ lục A: Open Questions
| # | Câu hỏi | Hành vi tạm thời | Owner | Mã theo dõi |
|---|---|---|---|---|
| OQ-C1 | statfs treo (NFS, đĩa chết) chặn cả vòng chu kỳ. Có cần chạy bộ thu đĩa trong goroutine riêng có hạn riêng, hay chấp nhận và chỉ khuyến cáo không bật include_network_fs? | Chấp nhận, mặc định loại fs mạng | chưa chỉ định | L3-COL-OQ1 |
| OQ-C2 | Trong container, /proc phản ánh máy chủ hay cgroup? Agent có cần biết giới hạn cgroup không? | Agent thu theo /proc của môi trường chạy, chưa xử lý cgroup. Mô hình triển khai chính là máy ảo hoặc máy vật lý | chưa chỉ định | L3-COL-OQ2 |
| OQ-C3 | Thứ tự cắt series hiện theo thứ tự bộ thu, uptime bị cắt trước. Có cần ưu tiên chỉ số quan trọng (cpu, mem, disk used) không? | Cắt đuôi theo thứ tự cấu hình. Thực tế ít xảy ra vì trần 500 lớn hơn mức dùng thông thường | chưa chỉ định | L3-COL-OQ3 |
| OQ-C4 | Lỗi của bộ thu tự thân và mẫu tự thân bị loại không vào agent_collector_errors và agent_dropped_samples_total. Có sửa không? | Không sửa. Chỉ thấy trong Result.Errors | chưa chỉ định | L3-COL-OQ4 |
| OQ-C5 | Regex khóa nhãn của Agent (^[a-zA-Z_]...) rộng hơn giao thức (^[a-z][a-z0-9_]{0,31}$). Có siết cho khớp không? | Giữ nguyên. Danh sách trắng nhãn là hàng rào thực sự | chưa chỉ định | L3-COL-OQ5 |
| OQ-C6 | Cấu hình bộ thu không đổi lúc chạy (SIGHUP không dựng lại engine). Có cần dựng lại engine an toàn khi SIGHUP không? | Cần khởi động lại để đổi metrics.*, max_series, collect_timeout, labels | chưa chỉ định | L3-COL-OQ6 |
| OQ-C7 | Ngoài Linux, engine không có Self nên không phát agent_* trong chu kỳ, mâu thuẫn với chú thích mã ("chỉ gửi chỉ số agent"). Sửa mã hay sửa chú thích? | Chưa ảnh hưởng vì Windows chưa hỗ trợ | chưa chỉ định | L3-COL-OQ7 |
| OQ-C8 | Có thêm fuzz test cho bộ phân tích /proc (giống FuzzWALScanRecords, FuzzLoadNeverPanics) không? | Chỉ có bảng kiểm thử và fixture | chưa chỉ định | L3-COL-OQ8 |
| OQ-C9 | Giả định bộ đếm mạng dưới 2^32 là quay vòng 32 bit có thể sinh tốc độ lớn giả khi thực ra là đặt lại. Chấp nhận hay bỏ hẳn? | Chấp nhận, có chặn 1e12 | chưa chỉ định | L3-COL-OQ9 |
Phụ lục B: ADR nội bộ
| Mã ADR | Quyết định | Trạng thái | Động lực |
|---|---|---|---|
| ADR-C01 | Danh sách trắng tên chỉ số và nhãn đặt trong Agent (Allowed), không chỉ ở Collector | Đã hiện thực | Chặn cardinality và nhãn định danh tenant ngay từ nguồn. Đánh đổi: hai nơi phải đồng bộ (OQ-C5, mục 5.4) |
| ADR-C02 | Thu tuần tự trong goroutine của vòng chu kỳ, dưới một hạn collect_timeout chung, không có bulkhead theo bộ thu | Đã hiện thực | Đơn giản, xác định, ít tài nguyên. Đánh đổi: statfs treo chặn tất cả (OQ-C1). Sẽ xem lại trước khi làm AGT-8 |
| ADR-C03 | Chỉ phát gauge. Tốc độ được tính ở Agent từ hai lần đọc bộ đếm | Đã hiện thực | Giao thức chỉ có gauge, Collector không cần trạng thái bộ đếm. Đánh đổi: mất một chu kỳ sau mỗi lần khởi động |
| ADR-C04 | Loại cả mẫu khi vi phạm danh mục thay vì bỏ nhãn vi phạm | Đã hiện thực | Giữ chuỗi thời gian nhất quán, tránh tạo series mới ngầm. Đánh đổi: che khuất lỗi bộ thu, chỉ thấy qua bộ đếm loại |
| ADR-C05 | Chỉ số tự thân chạy sau cắt và có dự trữ 16 series | Đã hiện thực | Bảo đảm quan sát được sức khỏe agent khi cardinality vượt trần |
| ADR-C06 | Windows dùng PDH với PdhAddEnglishCounter, hai mẫu cho tốc độ | Đã chấp nhận, cần xác nhận ở spike S1 (ADR 0004 của repo) | Không CGO, tên bộ đếm độc lập ngôn ngữ. Chưa xây |
Phụ lục C: Section Profile
| Phân mục | Hồ sơ quy chuẩn | Trạng thái điền | Giải trình |
|---|---|---|---|
| §0 Metadata & Sign-off | Bắt buộc | Đã điền | Người ký để "chưa chỉ định" |
| §1 Scope | Bắt buộc | Đã điền | |
| §2 Yêu cầu | Bắt buộc | Đã điền | |
| §3 Kiến trúc | Bắt buộc | Đã điền | |
| §4 Domain model | Bắt buộc | Đã điền | |
| §5 API contract | Bắt buộc | Điền thu gọn | Không có API mạng. Hợp đồng là interface Go và CLI |
| §6 Data schema | Tùy chọn | Điền thu gọn | Không có CSDL. Chỉ trạng thái trong bộ nhớ |
| §7 Thuật toán | Bắt buộc | Đã điền | |
| §8 Xử lý lỗi | Bắt buộc | Đã điền | |
| §9 Suy thoái | Bắt buộc | Điền thu gọn | 9.2 không áp dụng (không dữ liệu bền) |
| §10 Đồng thời | Bắt buộc | Điền thu gọn | Không có giao dịch |
| §11 Bảo mật | Bắt buộc | Điền thu gọn | 11.2 không áp dụng (không có yêu cầu ngoài) |
| §12 Cấu hình | Bắt buộc | Đã điền | Không có feature flag |
| §13 Telemetry | Bắt buộc | Điền thu gọn | Không có probe, không có trace |
| §14 Kiểm thử | Bắt buộc | Đã điền | Có 4 khoảng trống đề xuất |
| §15 Triển khai | Bổ sung | Đã điền |