mirror of
https://github.com/Rain-kl/OpenFlare.git
synced 2026-09-28 05:46:36 +08:00
454542c1d0
- README 默认英文:README.en.md → README.md(英文为默认),中文移至 README.zh-CN.md,语言切换链接同步 - 恢复被删除的 docs/en/ 英文文档(git 历史 cc5e53c5^),删除 4 篇已废弃文件 - 英文导航 config.ts 对齐中文结构(新增 Deployment/Changelog 侧栏,同步 Guide/Design 条目) - 翻译 15 篇中文新增文档:guide 5 篇(certificates/pages-usage/proxy-config/uptime-kuma/zone-domain-migration)+ design 10 篇(zone-design/cloudflare-pointing/waf-orchestration/origin-error-page/edge-cache-design/pages-design/logstore/kuma-design/login-captcha/observability 三篇) - en 首页更新(新增 Pages 特性、tagline 同步);changelog 英文入口指向中文版 - vitepress 构建验证:43 个英文页面全部渲染 注意:29 篇旧英文文档为恢复版,部分内容(如 deployment/server、reference/configuration)可能落后于中文,需后续逐篇同步
553 lines
22 KiB
Markdown
553 lines
22 KiB
Markdown
# Edge Observability and Business Traffic Statistics Refactor
|
||
|
||
You will learn: the problems this refactor solves (dashboard "OpenResty outbound" vs "Zone data provided" inconsistency, field and aggregation redundancy), and how the target architecture makes **the Agent report only facts and the Server interpret facts**, with access logs as the single source of truth for business traffic.
|
||
|
||
---
|
||
|
||
## 1. Goals
|
||
|
||
### 1.1 Problems to Solve
|
||
|
||
1. **Dual sources of truth**: business throughput comes from both access-log aggregation and OpenResty observability deltas, and the numbers never match long-term.
|
||
2. **Agent over-computes**: the edge pre-aggregates `TrafficReport`, throughput accumulation, and the control plane aggregates again — semantics are hard to evolve and reconcile.
|
||
3. **Field semantic overlap**: "OpenResty outbound" and "data provided" are the same business problem for users, but the system uses two field sets and two pipelines.
|
||
4. **Instant vs cumulative mixed**: 60-second window counts are treated as process cumulative values for 24h deltas, causing severe underestimation.
|
||
5. **UI induces wrong comparisons**: the dashboard and Zone page use similar "traffic/data" wording without declaring scope and caliber differences.
|
||
|
||
### 1.2 Refactor Goals
|
||
|
||
| Goal | Description |
|
||
| --- | --- |
|
||
| **Single business truth** | request count, data provided, UV, status distribution, Top domains etc. **only** derived from access logs (and Server-side rollups) |
|
||
| **Agent reports only facts** | detail logs + machine readings + health snapshots; **business UV/TopN/24h totals pre-aggregation is forbidden** |
|
||
| **Field convergence** | one business concept maps to one authoritative field; machine NIC and business delivery strictly separated by name |
|
||
| **Reconcilable** | global "data provided" ≈ sum of per-Zone "data provided" (difference only from unbound/unknown Hosts) |
|
||
| **Evolvable** | changing time windows, TopN, ownership rules only changes the Server, not the Agent |
|
||
|
||
### 1.3 Non-Goals (outside this design)
|
||
|
||
* Building a general log platform, full-log long-term archive, or search product.
|
||
* Replacing ClickHouse / removing the analytics DB dependency.
|
||
* Reworking Relay / OpenFlared host metric collection (principles align, but not in this round's protocol main path).
|
||
* Real-time streaming alert engine, APM tracing (the OpenTelemetry server side already exists and is orthogonal to this business traffic model).
|
||
|
||
---
|
||
|
||
## 2. Scope and Constraints
|
||
|
||
### 2.1 Product Constraints (inherited)
|
||
|
||
* Single-tenant, single globally active config; observability introduces no multi-tenant billing isolation.
|
||
* Access logs and time-series observability use the switchable log primary DB (ClickHouse by default; switchable to PostgreSQL/SQLite), see [Log Store Decoupling](./logstore.md).
|
||
* Agent has no inbound control, Pull model; during offline periods local OpenResty keeps serving, and observability can buffer locally and backfill.
|
||
|
||
### 2.2 Engineering Constraints
|
||
|
||
* Agent stays lightweight: parse log lines, read `/proc`, health checks; no business analysis.
|
||
* Control-plane API errors still use the unified envelope and `response.Abort*`.
|
||
* Access log field changes must update both the OpenResty `log_format` and the Agent parser simultaneously; Agent and control plane ship at the same version, no legacy protocol parsing.
|
||
|
||
---
|
||
|
||
## 3. Design Principles
|
||
|
||
### Principle P1: Agent Reports Facts, Server Interprets Facts
|
||
|
||
```text
|
||
Agent = collection + reliable delivery (raw / near-raw)
|
||
Server = storage + aggregation + ownership + trends + reconciliation
|
||
```
|
||
|
||
**Allowed edge processing (collection)**
|
||
|
||
* Parsing JSON access.log lines into structured fields
|
||
* path length caps, dropping invalid lines, skipping observability-port's own requests
|
||
* Reading NIC/CPU/memory counters as **raw values**
|
||
* Batching, compression, offline buffering and retries
|
||
|
||
**Forbidden edge processing (business computation)**
|
||
|
||
* UV / Top domains / status histograms / window request_count as authoritative metrics
|
||
* Maintaining "business in/out cumulative" for the dashboard
|
||
* Zone / domain ownership stats, country distribution (country can be resolved at Server insert time)
|
||
|
||
### Principle P2: Single Truth for Business Traffic = Access Logs
|
||
|
||
| Business Question | Single Answer |
|
||
| --- | --- |
|
||
| How much data was provided | `sum(bytes_sent)` |
|
||
| How many requests | `count()` |
|
||
| How many unique visitors | `uniqExact(remote_addr)` (or product-defined hashing) |
|
||
| Status codes / Top domains | `group by` on logs |
|
||
|
||
### Principle P3: Three Metric Layers Never Mixed
|
||
|
||
| Layer | Name | Purpose | Typical Fields |
|
||
| --- | --- | --- | --- |
|
||
| L1 Business delivery | Business Traffic | user & Zone reconciliation, dashboard business trends | access log |
|
||
| L2 Edge health | Edge Health | is OpenResty alive, current connections | status, connections |
|
||
| L3 Host capacity | Host Capacity | capacity planning, is the machine saturated | CPU, memory, disk, **NIC** |
|
||
|
||
Never name L3 NIC or L2 instant counts as "data provided"; never draw L1 and L3 on the same summary card without labeling semantics.
|
||
|
||
### Principle P4: One Business Concept, One Field
|
||
|
||
* **Data provided** ≡ response body delivered ≡ "OpenResty outbound (business meaning)" in legacy copy → **keep only `bytes_sent` aggregation**
|
||
* **Data received** (optional) ≡ request-side volume → log `request_length` aggregation
|
||
* **Host outbound** ≡ `network_tx` delta, copy must include "host/NIC"
|
||
|
||
---
|
||
|
||
## 4. Pre-Refactor Problems (Baseline)
|
||
|
||
### 4.1 Pre-Refactor Data Flow (redundant)
|
||
|
||
```text
|
||
One HTTP request
|
||
│
|
||
├─ access.log line
|
||
│ → Agent tail → AccessLogs[]
|
||
│ → CH of_node_access_logs
|
||
│ → Zone "data provided" ✅
|
||
│
|
||
├─ Lua shared dict window/cumulative counts
|
||
│ → /openflare/observability
|
||
│ → TrafficReport + OpenrestyObservation(rx/tx)
|
||
│ → CH request_reports / obs_openresty
|
||
│ → dashboard "OpenResty in/outbound" ❌ easily inconsistent with Zone
|
||
│
|
||
├─ second access.log aggregation (fallback when observability endpoint fails)
|
||
│ → yet another TrafficReport / throughput
|
||
│
|
||
└─ host network_rx/tx
|
||
→ Snapshot → "host" curve in network trends
|
||
```
|
||
|
||
### 4.2 Field Overlap
|
||
|
||
| User Perception | System Field A | System Field B | Problem |
|
||
| --- | --- | --- | --- |
|
||
| Outbound / provided | `openresty_tx_bytes` | `bytes_sent` | duplicate business semantics |
|
||
| Inbound | `openresty_rx_bytes` | `request_length` (log) | duplicate business semantics |
|
||
| Request count | `TrafficReport.request_count` | `count(access_logs)` | duplicate aggregation, window easily double-counted |
|
||
| Outbound (machine) | `network_tx_bytes` | (no business equivalent) | should be named separately, never reconciled with business |
|
||
|
||
### 4.3 Typical Failure Modes
|
||
|
||
1. Window counts treated as cumulative deltas → 24h business throughput severely underestimated.
|
||
2. Hourly rollup `max−min` broken for resetting counters.
|
||
3. Zone uses logs, dashboard uses observability → users think the system is wrong.
|
||
4. Changing caliber requires syncing Lua, Agent state accumulation, Server deltas, and frontend copy.
|
||
|
||
---
|
||
|
||
## 5. Target Architecture
|
||
|
||
### 5.1 Target Data Flow
|
||
|
||
```mermaid
|
||
flowchart TB
|
||
subgraph edge [Edge Node]
|
||
OR[OpenResty]
|
||
LOG[access.log]
|
||
PROC[host /proc and disk]
|
||
STUB[stub_status connections]
|
||
AG[Agent]
|
||
OR -->|log_format writes line| LOG
|
||
LOG -->|tail incremental details only| AG
|
||
PROC -->|reading snapshots| AG
|
||
STUB -->|instant connections| AG
|
||
OR -->|health probe| AG
|
||
end
|
||
|
||
subgraph server [Control-Plane Server]
|
||
HB[Heartbeat / WS receive]
|
||
CH[(ClickHouse)]
|
||
AGG[Aggregation query layer]
|
||
API[Admin API]
|
||
HB --> CH
|
||
CH --> AGG
|
||
AGG --> API
|
||
end
|
||
|
||
subgraph ui [Admin Panel]
|
||
DASH[Dashboard: global business trends]
|
||
ZONE[Zone: filter by domain]
|
||
NODE[Node: host resources + health]
|
||
end
|
||
|
||
AG -->|AccessLogs + HostSnapshot + Health| HB
|
||
API --> DASH
|
||
API --> ZONE
|
||
API --> NODE
|
||
```
|
||
|
||
### 5.2 Responsibility Matrix
|
||
|
||
| Capability | Agent | Server | Frontend |
|
||
| --- | --- | --- | --- |
|
||
| Write access.log | OpenResty | — | — |
|
||
| Read and report details | ✅ | store | — |
|
||
| sum/count/uniq/TopN | ❌ | ✅ | display |
|
||
| Zone domain filtering | ❌ | ✅ | select Zone |
|
||
| Host CPU/memory/NIC | read raw values and report | delta/average | node/dashboard resource area |
|
||
| OpenResty connections | read instant and report | latest value | node health |
|
||
| Business 24h in/outbound | ❌ | log aggregation | uniformly called "data provided/received" |
|
||
|
||
---
|
||
|
||
## 6. Metrics and Field Model
|
||
|
||
### 6.1 Authoritative Field Table (target)
|
||
|
||
#### L1 Business Delivery (from access logs)
|
||
|
||
| Concept | Storage Field | Aggregation | Display Name |
|
||
| --- | --- | --- | --- |
|
||
| Request time | `logged_at` | window filter | — |
|
||
| Node | `node_id` | group | — |
|
||
| Client IP | `remote_addr` | `uniq` → UV | Unique visitors |
|
||
| Host | `host` | group / Zone mapping | Domain |
|
||
| Path | `path` | optional | — |
|
||
| Status code | `status_code` | group | Status distribution |
|
||
| **Data provided** | **`bytes_sent`** | **`sum`** | **Data provided** |
|
||
| **Data received** | **`request_length`** | **`sum`** | **Data received** (optional display) |
|
||
| Region | `region` (resolved & written by Server) | group | Source region |
|
||
|
||
> Note: the JSON key in the OpenResty `log_format` may keep the name `bytes_sent`; the value must come from **`$body_bytes_sent`** (consistent with production), representing response body delivered, i.e. "data provided".
|
||
|
||
#### L2 Edge Health (instant; no 24h business totals)
|
||
|
||
| Concept | Field | Description |
|
||
| --- | --- | --- |
|
||
| OpenResty health | `openresty_status` / message | existing |
|
||
| Current connections | `openresty_connections` | stub_status |
|
||
| (optional) rough recent-window QPS | node detail "right now" only, **never** authoritative 24h totals | if implemented must be labeled "instant" |
|
||
|
||
#### L3 Host Capacity
|
||
|
||
| Concept | Field | Display Name |
|
||
| --- | --- | --- |
|
||
| CPU / memory / disk usage | `host_metrics` | keep |
|
||
| NIC cumulative bytes | `network_rx_bytes` / `network_tx_bytes` | **Host NIC in/outbound** |
|
||
| Disk IO cumulative | `disk_read_bytes` / `disk_write_bytes` | Disk read/write |
|
||
|
||
### 6.2 Removed Fields (no compatibility layer)
|
||
|
||
| Original Field | Disposition | Reason |
|
||
| --- | --- | --- |
|
||
| `openresty_tx_bytes` / `openresty_rx_bytes` | **removed** | business bytes follow access logs |
|
||
| `TrafficReport` and TopN/window UV | **removed** | edge pre-aggregation |
|
||
| Agent state business lifetime accumulators | removed | violates P1 |
|
||
| Lua shared dict business throughput/window request counts | removed | not the delivery main path |
|
||
|
||
### 6.3 Naming Reference (frontend copy enforced)
|
||
|
||
| Forbidden Copy | Correct Copy | Data Source |
|
||
| --- | --- | --- |
|
||
| OpenResty outbound (business volume) | **Data provided** | `sum(bytes_sent)` |
|
||
| OpenResty inbound (business volume) | **Data received** | `sum(request_length)` |
|
||
| Network outbound (unspecified) | **Host NIC outbound** | `network_tx` delta |
|
||
| Two cards: data provided vs outbound | **keep only one business card** | logs |
|
||
|
||
---
|
||
|
||
## 7. Agent Design
|
||
|
||
### 7.1 Heartbeat Payload (target protocol)
|
||
|
||
Keep and strengthen:
|
||
|
||
```text
|
||
NodePayload
|
||
identity / version / openresty_status / openresty_message # latest state → PG
|
||
profile # host overview (low frequency)
|
||
host_metrics # L3 resource readings (incl. NIC cumulative raw values)
|
||
edge_health # L2: status + connections (CH time series; message not in CH)
|
||
access_logs[] # L1 details (main path)
|
||
health_events[]
|
||
buffered[] # buffered facts above, not reports
|
||
waf_ip_group_checksums
|
||
```
|
||
|
||
Removed from the protocol (no compatibility layer):
|
||
|
||
```text
|
||
traffic_report
|
||
openresty_observation
|
||
snapshot / buffered_observability aliases
|
||
```
|
||
|
||
### 7.2 Access Log Reporting Requirements
|
||
|
||
Each detail at minimum contains:
|
||
|
||
| Field | Required | Note |
|
||
| --- | --- | --- |
|
||
| `logged_at_unix` | ✅ | request completion time |
|
||
| `remote_addr` | ✅ | UV |
|
||
| `host` | ✅ | Zone mapping |
|
||
| `path` | ✅ | may be truncated |
|
||
| `status_code` | ✅ | |
|
||
| `bytes_sent` | ✅ | body bytes, data provided |
|
||
| `request_length` | ✅ | data received |
|
||
|
||
Agent responsibilities:
|
||
|
||
1. Tail `access.log` by offset (reset offset on truncation/rotation, **only report new lines still present in the file**).
|
||
2. Parse into structured form, batch into heartbeat / WS.
|
||
3. Offline writes to local buffer, backfill by window once connected.
|
||
4. **No sum/count/uniq on details.**
|
||
|
||
### 7.3 Host Snapshot
|
||
|
||
* Keep reporting NIC/disk **cumulative counter raw values** (not business pre-aggregation).
|
||
* Server does non-negative deltas between adjacent samples → host trends.
|
||
* This is unrelated to "data provided"; the UI must display it in a separate section.
|
||
|
||
### 7.4 OpenResty Local Observability
|
||
|
||
Converged state:
|
||
|
||
* Keep: health checks, `stub_status` current connections.
|
||
* The main path no longer relies on `log.lua` shared dict business counts; `/openflare/observability` only returns health and connection snapshots, not business report sources.
|
||
|
||
### 7.5 Relationship with the Agent Design Doc
|
||
|
||
This design strengthens "pure data landing" in [Agent & Publish Model](./agent-design.md):
|
||
|
||
* Config and certificates: land and report applied state.
|
||
* Observability: only carry facts, not business conclusions.
|
||
|
||
---
|
||
|
||
## 8. Server Design
|
||
|
||
### 8.1 Storage
|
||
|
||
| Input | Table | Description |
|
||
| --- | --- | --- |
|
||
| `access_logs[]` | `of_node_access_logs` | authoritative business details |
|
||
| `host_metrics` | `of_node_metric_snapshots` | L3; NIC/disk cumulative |
|
||
| `openresty_status` / `openresty_message` | **PG node table** | L2 **latest-state authority** (message only here) |
|
||
| `edge_health` | `of_node_edge_health` | L2 time series: status + connections (**no message**) |
|
||
|
||
GeoIP: continue resolving `remote_addr` → `region` in the Server insert path, not in the Agent.
|
||
|
||
### 8.2 Aggregation Layer (unified)
|
||
|
||
All business trends and Zone stats share the same query semantics:
|
||
|
||
```text
|
||
filter: logged_at ∈ [since, until]
|
||
optional: node_id / host IN (...)
|
||
metrics:
|
||
request_count = count()
|
||
unique_visitors = uniqExact(remote_addr)
|
||
bytes_provided = sum(bytes_sent) -- data provided
|
||
bytes_received = sum(request_length) -- data received
|
||
series folded by hour/bucket
|
||
distributions by status_code / host / region
|
||
```
|
||
|
||
Implementation locations:
|
||
|
||
* Zone: `GET .../zones/:id/stats` (existing, align field naming)
|
||
* Dashboard: overview traffic / business network trends **switch to the same aggregation** (global, no host filter or Top filter)
|
||
* Node detail: business volume = the same aggregation filtered by that `node_id`; host NIC still uses metric deltas
|
||
|
||
### 8.3 Derived Rollups (optional performance path)
|
||
|
||
When detail queries over all nodes for 24h are too heavy, allow **Server-side** materialized views:
|
||
|
||
```text
|
||
of_access_log_hourly
|
||
(hour, node_id, host, request_count, bytes_sent, bytes_received, ...)
|
||
```
|
||
|
||
Constraints:
|
||
|
||
* Derived only by CH from `of_node_access_logs`; **Agent is forbidden from writing this table directly**.
|
||
* Zone / dashboard prefer reading the rollup, falling back to details (similar to the existing metric hourly policy).
|
||
|
||
### 8.4 Decommissioned Analytics Paths
|
||
|
||
| Path | After Migration |
|
||
| --- | --- |
|
||
| `BuildNetworkTrendPoints` delta on openresty_rx/tx | deleted, or keep only `network_*` host curves |
|
||
| `of_node_obs_openresty` throughput fields | stop writing; drop table or shrink columns after TTL expiry |
|
||
| `of_node_request_reports` + traffic hourly | business trends no longer depend on it; table can be deprecated wholesale |
|
||
| Dashboard compact openresty_tx series | change to bytes_provided series |
|
||
|
||
---
|
||
|
||
## 9. API and Frontend
|
||
|
||
### 9.1 Semantically Unified Response Fields
|
||
|
||
Business stats APIs should uniformly use:
|
||
|
||
```json
|
||
{
|
||
"request_count": 0,
|
||
"unique_visitors": 0,
|
||
"bytes_provided": 0,
|
||
"bytes_received": 0,
|
||
"series": [
|
||
{
|
||
"bucket_started_at": "...",
|
||
"request_count": 0,
|
||
"unique_visitors": 0,
|
||
"bytes_provided": 0,
|
||
"bytes_received": 0
|
||
}
|
||
]
|
||
}
|
||
```
|
||
|
||
API business byte fields use `bytes_provided` / `bytes_received` (access-log aggregation); no more openresty throughput aliases.
|
||
|
||
### 9.2 Dashboard
|
||
|
||
* **Business area**: request trend, data provided, data received (optional), status codes, Top domains, source regions — all L1.
|
||
* **Resource area**: CPU/memory, **host NIC**, disk IO — all L3.
|
||
* **Forbidden**: showing "OpenResty in/outbound" in the business area as a metric reconciled with Zone.
|
||
|
||
Suggest splitting or retitling "24-hour network and disk trends":
|
||
|
||
* "24-hour business traffic" → `bytes_provided` / `bytes_received` / requests
|
||
* "24-hour host network and disk" → `network_*` / `disk_*`
|
||
|
||
### 9.3 Zone `/websites/:id`
|
||
|
||
* Keep cards like "total data provided".
|
||
* Data and the dashboard business area use **the same aggregation function**, only `hosts = zone domain list`.
|
||
* Docs and UI may note: the global dashboard includes all Hosts; this page is only this Zone.
|
||
|
||
### 9.4 Node Detail
|
||
|
||
* Business throughput: that node's `sum(bytes_sent)` etc.
|
||
* OpenResty: health + current connections.
|
||
* NIC: clearly "host".
|
||
|
||
---
|
||
|
||
## 10. OpenResty and Log Format
|
||
|
||
### 10.1 Keep
|
||
|
||
Existing JSON `log_format` core fields:
|
||
|
||
```text
|
||
ts, host, path, remote_addr, status, request_time,
|
||
bytes_sent (= $body_bytes_sent), request_length
|
||
```
|
||
|
||
### 10.2 Changes
|
||
|
||
* No longer rely on log-phase writes of business shared dict counts as control-plane input.
|
||
* Observability-port requests continue not writing business stats (or `access_log off`).
|
||
|
||
### 10.3 Agent Parsing
|
||
|
||
* Protocol `NodeAccessLog` adds `request_length`.
|
||
* Legacy log lines missing fields default to 0, not blocking the whole batch.
|
||
|
||
---
|
||
|
||
## 11. Upgrade and Migration (no compatibility layer)
|
||
|
||
### 11.1 Phase Review (shipped)
|
||
|
||
| Phase | Content |
|
||
| --- | --- |
|
||
| **M1–M5** | read path switches to access logs; protocol v2; stop pre-aggregation; edge_health + access_log_hourly; drop old tables and API compat fields |
|
||
|
||
### 11.2 Upgrade Strategy
|
||
|
||
* **Agent: destroy-and-recreate preferred**; binary replacement allowed.
|
||
* On binary replacement: the local old observability buffer (including `snapshot` / `openresty_observation` / `traffic_report`) is **deleted wholesale**, rebuilt after running.
|
||
* Server **does not** parse v1 fields, **does not** dual-read request_reports / openresty throughput.
|
||
* Detail-missing periods: business charts are empty or partial; **never** impersonate data provided with NIC or removed openresty throughput.
|
||
|
||
### 11.3 Data Backfill
|
||
|
||
* Historical "data provided" follows access logs.
|
||
* Before `of_access_log_hourly` is created, history is backfilled with goose SQL (ANTI JOIN to prevent duplicates).
|
||
|
||
### 11.4 Health-State Authority
|
||
|
||
* **Current state**: PG `openresty_status` / `openresty_message`.
|
||
* **Time series**: log primary DB `of_node_edge_health` (status + connections; no message).
|
||
|
||
### 11.5 UV
|
||
|
||
* **Whole-window unique visitors**: `uniqExact(remote_addr)` (dashboard totals, Zone totals).
|
||
* **Bucketed UV** (Zone curves): per-bucket uniq, **not summable across buckets**; UI must note it.
|
||
* **Hourly trend path**: don't plot / fill per-hour UV (hourly table has no UV).
|
||
|
||
---
|
||
|
||
## 12. Storage and Capacity
|
||
|
||
* Business trends rely on details or hourly rollups; watch `of_node_access_logs` TTL and sampling.
|
||
* If details are too large: prefer **Server-side rollup** rather than restoring Agent pre-aggregation.
|
||
* For high-cardinality path scenarios, limit detail path length (existing); aggregation doesn't do global Top over full paths by default.
|
||
|
||
---
|
||
|
||
## 13. Risks and Trade-offs
|
||
|
||
| Risk | Mitigation |
|
||
| --- | --- |
|
||
| Large detail volume makes CH and heartbeat heavy | batching, compression, sampling policy evaluation; Server rollup; limit per-batch count |
|
||
| Brief log loss lowers business volume | local buffer and rotation handling; monitor access log collection lag |
|
||
| Users still compare "NIC outbound" with "data provided" | UI sections and copy enforce the "host" prefix |
|
||
| Old Agents stay online long-term | **no compatibility layer**; Agents must be upgraded/rebuilt |
|
||
|
||
**Why not keep Agent pre-aggregation as an optimization?**
|
||
|
||
* Saving bandwidth re-splits the truth, drifts calibers, and repeats this problem.
|
||
* Optimization belongs in Server derived tables and queries, not edge business computation.
|
||
|
||
---
|
||
|
||
## 14. Key Decision Summary
|
||
|
||
| Decision | Choice | Rejected Alternative |
|
||
| --- | --- | --- |
|
||
| Business traffic truth | access logs | OpenResty dict / TrafficReport |
|
||
| Agent role | report only facts | edge UV/TopN/throughput accumulation |
|
||
| "Outbound" vs "provided" | merged into data provided | dual fields and dual pipelines long-term |
|
||
| NIC traffic | independent L3, separate copy | reconciled side-by-side with business outbound |
|
||
| Performance | CH rollup | Agent pre-aggregation |
|
||
| Migration | switch read path first, then slim Agent | drop details first, rely on pre-aggregation |
|
||
|
||
---
|
||
|
||
## 15. Doc and Code Mapping
|
||
|
||
| Area | Main Paths |
|
||
| --- | --- |
|
||
| Protocol | `pkg/protocol/agent.go` |
|
||
| Agent collection | `internal/apps/agent/observability/`, `heartbeat/` |
|
||
| OpenResty logging and Lua | `pkg/render/openresty/`, `internal/apps/agent/nginx/observability_assets.go` |
|
||
| Server storage | `internal/apps/openflare/agent/observability.go` |
|
||
| Log aggregation | `internal/repository/analytics/node_access_log*.go`, `internal/apps/openflare/zone/stats.go` |
|
||
| Dashboard | `internal/apps/openflare/dashboard/`, `internal/apps/openflare/observability/analytics.go` |
|
||
| Frontend | `frontend/app/(main)/page.tsx`, `components/dashboard/*`, `websites/.../zone-overview.tsx` |
|
||
|
||
**Recommended reading order:**
|
||
|
||
1. **[Observability Transport Model](./observability-transport-model.md)** (latest: what to send, where collected from, frequency, sample JSON)
|
||
2. [Agent Reporting Protocol and Observability Data Model](./observability-data-model.md) (protocol fields and DDL)
|
||
|
||
---
|
||
|
||
## 16. Revision History
|
||
|
||
| Date | Notes |
|
||
| --- | --- |
|
||
| 2026-07-17 | initial draft: target architecture and migration phases for dual truth, Agent pre-aggregation, field redundancy |
|
||
| 2026-07-17 | added protocol/table-structure chapter links `observability-data-model.md` |
|