Cảnh báo
Phân vai: Access Hub sở hữu luật, định tuyến thông báo, vòng đời alert và giao diện. Collector đánh giá luật trên luồng mẫu và phát sự kiện. Collector không gửi email hay webhook, việc đó do hệ thống thông báo có sẵn của Access Hub làm.
1. Mô hình luật
Luật lưu trong Access Hub (monitoring_rules), collector kéo về theo since và biên dịch.
{
"id": "0d6b...",
"version": 7,
"company_id": "c1...",
"name": "Đĩa gần đầy",
"kind": "threshold",
"scope": {
"all": false,
"server_ids": [],
"tags": ["prod"],
"environments": ["prod"],
"roles": [],
"datacenters": []
},
"metric": "disk_used_percent",
"matchers": { "mount": "/var" },
"operator": ">",
"threshold": 90,
"for_seconds": 300,
"recover_threshold": 85,
"recover_for_seconds": 120,
"severity": "critical",
"no_data": "ignore",
"renotify_seconds": 3600,
"enabled": true
}| Trường | Ý nghĩa |
|---|---|
kind | threshold (GĐ 2), check (kết quả kiểm tra port, dịch vụ, cert, GĐ 2), agent_down (dựng sẵn, GĐ 1) |
scope | Tập máy chủ áp dụng, hợp của các điều kiện. Thuộc tính lấy từ kiểm kê Server (tags, environment, role, datacenter) và Access Hub gửi kèm trong bản đồng bộ để collector không phải tra ngược |
matchers | Khớp nhãn của series (ví dụ chỉ /var). Giá trị đơn hoặc danh sách, cho phép regex đã kiểm chứng an toàn |
for_seconds | Điều kiện phải đúng liên tục chừng này thời gian mới mở alert |
recover_threshold, recover_for_seconds | Trễ phục hồi (hysteresis): phải xuống dưới ngưỡng này liên tục mới đóng, tránh nhấp nháy quanh ngưỡng |
no_data | Khi máy vẫn online nhưng series biến mất: ignore, alert, resolve |
renotify_seconds | Nhắc lại tối thiểu bao lâu một lần khi alert còn mở, 0 là không nhắc |
version tăng mỗi lần sửa. Sự kiện luôn mang rule_version để truy vết luật lúc phát sự kiện.
Bộ luật mặc định (mỗi công ty, bật tắt được)
| Luật | Điều kiện | Mức |
|---|---|---|
| Mất tín hiệu | agent_down sau max(3 x interval, 90 s) | critical |
| CPU cao | cpu_usage_percent > 90 trong 10 phút, phục hồi dưới 80 | warning |
| RAM cao | mem_used_percent > 90 trong 10 phút, phục hồi dưới 85 | warning |
| Đĩa đầy dần | disk_used_percent > 85 trong 5 phút | warning |
| Đĩa gần đầy | disk_used_percent > 95 trong 5 phút | critical |
| Tải cao | load_per_core_5m > 2 trong 15 phút | warning |
| Chứng chỉ sắp hết hạn | cert_days_left < 14 warning, < 3 critical | warning, critical |
2. Trạng thái và đánh giá
Mỗi cặp (rule_id, server_id, series) có máy trạng thái:
vi phạm vi phạm liên tục >= for
OK -----------------> PENDING --------------------------> FIRING
^ hết vi phạm | |
'-----------------------' thỏa recover liên tục >= |
^ recover_for |
'----------------------------------------------------------'- Đánh giá diễn ra mỗi khi mẫu của series đến, không theo đồng hồ riêng, nên độ trễ cảnh báo bám sát chu kỳ thu thập. Thời gian
fortính theo timestamp của mẫu, không theo giờ nhận, để bù lại khi agent gửi bù dữ liệu tồn. - Mẫu quá cũ (cũ hơn
max(for_seconds, 2 phút)so với mẫu mới nhất của cùng series, xem mục 2.1) không kích hoạt alert mới, chỉ dùng để lấp lịch sử. - Trạng thái nằm trong bộ nhớ worker theo shard, snapshot mỗi 30 giây (
alerting.rules_state_interval) và khi tắt êm, vào Redis, hoặc tệp (alerting.rules_dir), hoặc bộ nhớ khi không cấu hình gì. Khởi động lại nạp snapshot, alert đang mở không bị mất hay mở trùng (NFR-13), riêng vụ sập cứng trong cửa sổ 30 giây có thể phát lại mộtalert.opened(Access Hub khử trùng theoseq, xem mục 5). - Khi luật đổi
version: trạng thái đang FIRING của luật cũ được đóng với lý dorule_changednếu metric, matchers hoặc cờallcủa scope thay đổi, giữ nguyên nếu chỉ đổi thuộc tính không ảnh hưởng đánh giá (ví dụrenotify_seconds). Thêm hoặc bớt máy chủ khỏi scope không đổi chữ ký: máy chủ bị bớt đóng alert với lý doout_of_scope, các máy chủ còn lại giữ nguyên, không phát sự kiện nào.
2.1 Hiện thực COL-8
Bộ đánh giá nằm trong tiến trình worker, gắn vào worker.Options.OnBatch (internal/rules). Trạng thái chia 64 shard theo bus.ShardFor(server_id), mỗi shard một mutex.
Kéo luật. Syncer gọi GET /rules?since=&limit=500 của Access Hub ngay khi khởi động, rồi mỗi alerting.rules_sync_interval (mặc định 1 phút), và khi có POST /internal/v1/reload/rules. Con trỏ since là sync_version toàn cục của Access Hub (không phải version của từng luật), đọc tiếp theo next_since và more cho đến hết. Luật tắt hoặc xóa đến dưới dạng bia mộ (enabled=false hoặc deleted=true) và bị gỡ khỏi bộ đang chạy. Cả lần đồng bộ được áp dụng nguyên khối: lỗi giữa chừng giữ nguyên bộ cũ. Bộ luật thô và since được lưu snapshot, nên khởi động lại khi Access Hub sập vẫn chạy với bộ luật cuối.
Biên dịch. Mỗi luật được kiểm tra riêng: kind (threshold, check; agent_down là luật dựng sẵn nên bỏ qua), metric thuộc catalog, nhãn của matchers được phép với metric đó, operator, threshold hữu hạn, recover_threshold đúng phía của ngưỡng, severity, no_data, các khoảng thời gian, scope. Regex chạy RE2 (thời gian tuyến tính), neo hai đầu, tối đa 128 ký tự, danh sách tối đa 64 giá trị. Luật sai bị bỏ qua: log cảnh báo, ahc_rules_rejected_total{reason}, ahc_rules_invalid, GET /status mục rules.invalid_rules. Luật sai không bao giờ làm sập collector, và không có sự kiện rule.invalid vì phong bì sự kiện bắt buộc có server_id. Nếu luật đang FIRING bị sửa thành sai, alert đóng với lý do rule_removed.
Phạm vi. Đánh giá khi company_id của luật bằng company_id của lô (cách ly tenant, sự kiện luôn mang company_id của lô) và máy nằm trong scope: scope.all, hoặc hợp của resolved_server_ids (Access Hub đã giải tag, môi trường, vai trò, trung tâm dữ liệu) và scope.server_ids.
Máy trạng thái. Khóa (rule_id, server_id, series_key), series_key dạng metric{label="value"} nhãn sắp xếp, dài quá 255 byte (giới hạn cột của Access Hub) thì cắt còn phần đầu đọc được cộng hậu tố ~ và 12 ký tự hash của khóa đầy đủ. Vi phạm lần đầu vào PENDING. Đủ for_seconds (đo bằng timestamp mẫu) thì FIRING và phát alert.opened. Với for_seconds = 0, vi phạm đầu tiên mở alert ngay. PENDING chịu được khoảng trống dữ liệu tối đa alerting.no_data_after. Trong FIRING, mẫu thỏa điều kiện phục hồi (hết vi phạm và, nếu có recover_threshold, vượt qua nó) liên tục recover_for_seconds thì phát alert.resolved (reason=recovered). Đến hạn renotify_seconds phát alert.reminder. Giá trị ở giữa ngưỡng và recover_threshold giữ nguyên trạng thái (hysteresis).
Mẫu cũ. stale = max(for_seconds, 2 phút): mẫu có newest - ts > stale (newest là mẫu mới nhất của series trong lô) không mở alert mới, để agent gửi bù dữ liệu tồn không gây báo giả.
no_data. Sweep chạy định kỳ. Series im lặng quá alerting.no_data_after (mặc định 5 phút, giờ thật) trong khi máy vẫn gửi các lô khác thì áp no_data: ignore (giữ nguyên trạng thái), alert (nếu chưa FIRING thì mở alert alert.opened với nhãn no_data="true", không có threshold, còn đang FIRING vì vi phạm thì giữ nguyên), resolve (đóng alert đang mở với reason=no_data). Alert do no_data mở sẽ đóng với reason=data_returned khi mẫu đầu tiên quay lại, rồi đánh giá bình thường. Máy mất hoàn toàn tín hiệu do agent_down lo, không tính vào no_data.
Đổi luật. Chữ ký (công ty, metric, matchers, cờ all của scope) đổi thì alert FIRING đóng với reason=rule_changed rồi đánh giá lại từ đầu. Danh sách máy chủ của scope (resolved_server_ids) không nằm trong chữ ký: một máy chủ rời scope đóng alert của riêng nó với reason=out_of_scope, máy chủ khác không bị ảnh hưởng. Sau lần nâng cấp collector đầu tiên, snapshot cũ mang chữ ký có danh sách máy chủ nên các alert đang mở của luật theo nhóm máy chủ có thể đóng một lần với rule_changed rồi mở lại (Access Hub khử trùng theo seq). Luật bị tắt, xóa hoặc thành không hợp lệ đóng với reason=rule_removed. Sửa các trường khác (threshold, for, renotify, tên, mức) giữ nguyên trạng thái. Việc đóng làm lười, ở lần đánh giá hoặc quét kế tiếp.
Hook. Engine.Suppress nhận (company, server, at) và trả (suppressed, reason). COL-9 nối nó vào suppress.Suppressor (mục 4.1), nên mọi sự kiện luật mang suppressed và suppress_reason đúng.
Mất tín hiệu (agent_down)
- Bộ quét chạy mỗi 10 giây trên
ah:seen, tìm agent cólast_seen < now - max(3 x interval, 90 s). - Ra khỏi trạng thái up: ghi
agent:{id}:st, phátagent.downmột lần. - Nhận lại gói
metricshợp lệ: phátagent.up, đóng alert. - Máy có
Server.status = maintenancehoặcdecommissioned: vẫn đổi trạng thái nhưng đánh dấusuppressed: true(xem mục 4).
Kiểm tra (check)
Kết quả kiểm tra là series như mọi chỉ số (service_up, port_up, http_up, cert_days_left), luật kind=check đánh giá cùng cơ chế với ngưỡng.
3. Chống nhiễu
| Cơ chế | Mô tả |
|---|---|
| Hysteresis | recover_threshold và recover_for_seconds (COL-8) |
| Flapping | Alert chuyển FIRING <-> OK từ 4 lần trở lên trong 30 phút bị đánh dấu flapping, ngừng gửi thông báo chuyển trạng thái, gửi một thông báo tóm tắt, alert giữ FIRING cho đến khi ổn định 30 phút. Cấu hình được (mục 3.1) |
| Gom sự cố diện rộng | Nếu từ 5 máy trở lên và từ 30% số máy cùng subnet_id hoặc datacenter của một công ty mất tín hiệu trong cửa sổ 60 giây, collector phát một sự kiện group_down (group_key, member_server_ids) thay vì hàng trăm agent.down. Access Hub tạo một alert nhóm và gắn các alert con ở trạng thái grouped. Khi thành viên phục hồi lần lượt thì cập nhật nhóm (mục 3.2) |
| Nhắc lại | renotify_seconds. Không nhắc khi đang flapping |
| Khởi động thác | Sau khi collector khởi động hoặc bus tràn, giai đoạn ân hạn 2 x interval không phát agent.down để tránh báo giả do chưa kịp nhận gói |
3.1 Flapping (COL-9)
Khóa theo (rule_id, server_id, series_key). Mỗi lần alert mở hoặc đóng (đo bằng timestamp mẫu) được ghi vào lịch sử, chỉ giữ những lần trong alerting.flap_window.
- Dưới
alerting.flap_transitions(mặc định 4) lần: phátalert.openedvàalert.resolvednhư thường. - Lần chuyển thứ 4 đẩy series vào flapping: phát
alert.flappingvớireason=entered,transitions=<số lần>. Nếu chính lần chuyển đó là lần mở thìalert.openedvẫn đi trước, để Access Hub luôn có alert mở. Access Hub coi alert là FIRING cho đến khi ổn định. - Khi đang flapping: mọi
alert.opened,alert.resolvedtiếp theo bị giữ lại (không phát),alert.reminderbị bỏ qua. Số sự kiện bị giữ đếm ởahc_alert_flap_events_dropped_total. - Ổn định: sau
alerting.flap_stable(mặc định 30 phút, giờ thật) không có chuyển đổi nào, phátalert.flappingvớireason=exited. Nếu lúc đó điều kiện đã hết vi phạm thì phát thêmalert.resolved(reason=recovered). Nếu vẫn vi phạm thì alert tiếp tục mở bình thường. - Luật đổi chữ ký, bị gỡ hoặc máy rời scope khi đang flapping: alert đóng bằng
alert.resolvedvới lý do tương ứng, không phátexited. alerting.flap_transitions: 0tắt flapping. Trạng thái flapping nằm trong snapshot của bộ luật (khởi động lại vẫn giữ).- Metric:
ahc_alert_flaps_total{to=entered|exited},ahc_alerts_flapping,GET /statusmụcrules.flapping.
3.2 Gom sự cố diện rộng group_down (COL-9)
Chạy trong tiến trình worker, chỉ khi alerting.group_down.enabled (mặc định true). GroupIndex được cập nhật bởi hook của registry và phân nhóm máy theo subnet:<subnet_id> và datacenter:<datacenter> của từng công ty. Hai chiều là hai nhóm độc lập, nên máy có cả hai thuộc tính có thể sinh hai group_down (mỗi chiều một).
- Mở. Mỗi lần quét, các agent mới bị tuyên bố mất tín hiệu được ghi vào nhóm của chúng. Một nhóm mở khi số máy mất tín hiệu trong
window(mặc định 60 giây) đạtmin(mặc định 5) và chiếm ít nhấtratio(mặc định 0.30) số máy của nhóm. Phát mộtgroup_down. Cácagent.downriêng lẻ vẫn được phát (để Access Hub gắn chúng làm alert con, trạng tháigrouped). - Cập nhật. Khi có thành viên hồi phục rời nhóm hoặc máy im lặng mới gia nhập, phát
group_updatevới danh sách thành viên hiện tại. - Đóng. Khi không còn thành viên nào, phát
group_resolved(reason=recovered,duration_seconds). - Hồi phục được xác định bằng cách đọc presence của agent, nên đúng cả khi ingest và worker chạy tách tiến trình.
agent.upcủa từng thành viên vẫn phát riêng. - Định danh.
rule_id=group_down,series_key=group_key,server_idlà máy neo (thành viên cóserver_idnhỏ nhất lúc mở, giữ nguyên đến hết đời nhóm).seqtăng theo(server neo, group_key)nên Access Hub khử trùng như mọi sự kiện.group_totallà số máy của nhóm lúc phát. - Tham số theo công ty, từng trường, thứ tự ưu tiên:
GET /settings/{company_id}của Access Hub (trườngnullnghĩa là không đặt) > ghi đè trong cấu hìnhalerting.group_down.companies.<company_id>> mặc định. Cài đặt được cache 5 phút (30 giây sau lỗi gọi Access Hub),POST /internal/v1/reload/settingsxóa cache. - Chặn thông báo. Nhóm
suppressedkhi mọi thành viên lúc mở đều bị chặn,suppress_reasonlấy của thành viên đầu tiên.group_updatevàgroup_resolvedthừa hưởng quyết định lúc mở. - Ân hạn khởi động áp dụng như
agent.down: hết2 x intervalsau khi khởi động mới có nhóm. - Trạng thái nhóm đang mở được snapshot (Redis, tệp hoặc bộ nhớ) nên khởi động lại không mở trùng. Giới hạn: việc tuyên bố mất tín hiệu là race free giữa các worker (worker thắng
SADDphátagent.down), nhưng mỗi worker chỉ thấy những máy do chính nó tuyên bố nên nhóm không được chia sẻ. Khi chạy nhiều worker, chỉ một worker nên bậtalerting.group_down.enabled(các worker khác đặtfalse), nếu không ngưỡngmincó thể không bao giờ đạt. - Metric:
ahc_groups_open,ahc_events_emitted_total{type=group_*}.
4. Chặn thông báo
Collector vẫn đánh giá và phát sự kiện, kèm cờ suppressed và suppress_reason (maintenance, silence, decommissioned). Access Hub lưu alert nhưng không thông báo. Cách này giữ đủ lịch sử và cho phép gỡ chặn mà không mất dữ liệu. Cờ áp dụng cho mọi sự kiện: alert.*, agent.down, agent.up, group_*.
decommissionedvàmaintenance:Server.statuscủa máy, đồng bộ qua bản ghi agent (server_status, xem06mục 4.2). Đây là trạng thái hiện tại (collector không giữ lịch sử), lấy từ agent chưa bị thu hồi mới nhất của máy, cache 5 giây.silence: khoảng thời gian tắt tiếng theo phạm vi do người dùng tạo trong Access Hub, đồng bộ như luật (mục 4.1).- Thứ tự ưu tiên khi nhiều lý do cùng đúng:
decommissioned>maintenance>silence.
4.1 Silence (COL-9)
suppress.Syncer kéo GET /silences?since=&limit= theo đúng mẫu của Syncer luật: chạy lúc khởi động, mỗi alerting.silences_sync_interval (mặc định 1 phút) và khi có POST /internal/v1/reload/silences (tách tiến trình thì qua bộ đếm Redis <prefix>silences:reload). Con trỏ là sync_version toàn cục, bia mộ (deleted=true) gỡ silence, cả lần đồng bộ áp nguyên khối, lỗi giữa chừng giữ bộ cũ. Bộ thô và since được snapshot nên Access Hub sập lúc khởi động vẫn dùng bộ cuối.
- Cách ly tenant. Silence chỉ áp cho sự kiện cùng
company_id. Silence của công ty khác, dùscope.all, không bao giờ khớp. - Phạm vi.
scope.all, hoặc máy thuộcscope.server_idshoặcresolved_server_ids(ở trongscopehoặc ở cấp trên cùng). - Thời điểm. Silence được so với timestamp của sự kiện, không phải giờ phát, theo khoảng
[starts_at, ends_at). Ví dụalert.resolvedcủa một alert mở trước khi silence bắt đầu mà đóng trong silence thìsuppressed=true, còn sự kiện trướcstarts_atphát muộn thì không. Silence đã hết hạn không còn khớp sự kiện mới. Collector giữ bản thô thêm 24 giờ sau khi hết hạn (để khớp sự kiện trễ) rồi dọn. - Metric:
ahc_events_suppressed_total{reason},ahc_silences_sync_total{result},ahc_silences_last_sync_timestamp_seconds,ahc_silences_since,ahc_silences_active.GET /statusmụcsilences(active,loaded,since,last_sync_at,last_sync_error).
5. Sự kiện gửi về Access Hub
{
"event_id": "018f2c1e-7b6a-7d3e-8b8e-2f2f6d1e9c11",
"type": "alert.opened",
"seq": 42,
"occurred_at": "2026-09-30T02:15:30Z",
"company_id": "c1...",
"server_id": "s1...",
"rule_id": "0d6b...",
"rule_version": 7,
"series_key": "disk_used_percent{mount=\"/var\"}",
"severity": "critical",
"value": 93.4,
"threshold": 90,
"suppressed": false,
"suppress_reason": null,
"group_key": null,
"labels": { "mount": "/var" }
}type | Khi nào |
|---|---|
alert.opened | Chuyển PENDING -> FIRING |
alert.resolved | Chuyển FIRING -> OK, có duration_seconds, peak_value, reason (recovered, no_data, data_returned, rule_changed, out_of_scope, rule_removed) |
alert.reminder | Đến hạn renotify_seconds |
alert.flapping | Vào (reason=entered, transitions) hoặc ra (reason=exited) trạng thái flapping |
agent.down, agent.up | Mất và có lại tín hiệu |
group_down, group_update, group_resolved | Sự cố diện rộng: mang group_key, member_server_ids, group_total. group_resolved có duration_seconds và reason=recovered |
agent.seen_snapshot | Không phải sự kiện cảnh báo, xem endpoint seen |
Access Hub xử lý theo quy tắc: bỏ nếu event_id đã thấy, bỏ nếu seq không lớn hơn seq đã xử lý của cặp (server_id, rule_id, series_key), còn lại áp dụng vào bảng monitoring_alerts và kích hoạt thông báo (trừ khi suppressed).
6. Kiểm thử cảnh báo (tóm tắt)
- Bảng quyết định đơn vị cho máy trạng thái (vào PENDING, đủ
for, hysteresis, no_data). - Mô phỏng tái phát: phát lại chuỗi mẫu đã ghi để đảm bảo cùng chuỗi mẫu cho ra cùng chuỗi sự kiện (xác định).
- Kiểm thử khởi động lại giữa PENDING và FIRING: không mở trùng, không mất.
- Kiểm thử gom sự cố với 500 agent mất đồng loạt: đúng một sự kiện nhóm. Chi tiết ở 12-testing.