Hiểu rõ cấu trúc dữ liệu: Measurement, Tag và Field
Khái niệm cốt lõi của InfluxDB 2.x
Trong InfluxDB 2.x, dữ liệu không được tổ chức theo bảng quan hệ (Table) như SQL mà theo mô hình chuỗi thời gian (Time-Series). Ba thành phần chính tạo nên cấu trúc này là Measurement, Tag và Field.
Measurement đóng vai trò như một nhóm dữ liệu hoặc một "bảng" logic. Ví dụ: bạn có thể có một Measurement tên là cpu_usage để lưu tất cả dữ liệu CPU, và một Measurement khác là memory_usage cho RAM. Đây là cấp độ phân loại cao nhất.
Tag là các thuộc tính có giá trị không đổi hoặc thay đổi ít, được dùng để nhóm và lọc dữ liệu. InfluxDB tự động lập chỉ mục (index) cho Tag, giúp truy vấn cực nhanh. Ví dụ: host="server01", region="us-east", env="production". Quy tắc vàng: Chỉ đặt Tag cho các giá trị có số lượng hữu hạn (cardinality thấp).
Field là các giá trị số hoặc chuỗi (string) đại diện cho dữ liệu thực tế cần đo lường. Field không được index, do đó việc lọc theo Field sẽ chậm hơn Tag. Ví dụ: usage_user=45.2, value=1024, status="ok".
Thực hành viết dòng dữ liệu mẫu
Để hiểu rõ cách dữ liệu được lưu trữ, ta sẽ sử dụng dòng lệnh influx để viết một điểm dữ liệu (data point) mẫu vào Bucket. Dòng lệnh này sẽ giúp bạn hình dung vị trí của từng thành phần.
Trước khi chạy, hãy đảm bảo bạn đã có thông tin Token và Bucket ID từ Phần 3 (Cấu hình IAM). Nếu chưa có, bạn cần tạo một Bucket mới trước.
influx write \
--bucket "MySystemMetrics" \
--token "YOUR_ACCESS_TOKEN_HERE" \
--precision s \
--data "cpu,host=server01,region=us-west usage_idle=78.5,usage_user=12.3 1715000000"
Trong dòng lệnh trên:
cpu là Measurement.
host=server01 và region=us-west là Tags.
usage_idle=78.5 và usage_user=12.3 là Fields.
1715000000 là Timestamp (định dạng giây).
Kết quả mong đợi: InfluxDB sẽ trả về 201 Created hoặc không có lỗi, nghĩa là dữ liệu đã được ghi vào Bucket thành công.
Verify kết quả bằng Flux
Để kiểm tra cấu trúc dữ liệu vừa viết, ta sử dụng lệnh query với ngôn ngữ Flux để hiển thị dữ liệu dưới dạng bảng, giúp phân biệt rõ Tag và Field.
influx query \
--bucket "MySystemMetrics" \
--token "YOUR_ACCESS_TOKEN_HERE" \
--format table \
--org "MyOrg" \
-- "from(bucket: \"MySystemMetrics\") |> range(start: -1h) |> filter(fn: (r) => r._measurement == \"cpu\")"
Kết quả mong đợi: Bạn sẽ thấy một bảng dữ liệu. Các cột có tên bắt đầu bằng _ là metadata. Các cột khác như host, region là Tags, còn usage_idle, usage_user là Fields. Việc này xác nhận cấu trúc dữ liệu đã được InfluxDB phân tích đúng.
Chiến lược đặt tên Tag để tối ưu hiệu năng
Vấn đề về Cardinality (Độ đa dạng)
Yếu tố quan trọng nhất ảnh hưởng đến hiệu năng của InfluxDB là Cardinality của Tag. Cardinality là số lượng giá trị duy nhất của một Tag. Nếu bạn đặt một giá trị duy nhất cho mỗi điểm dữ liệu làm Tag (ví dụ: request_id, session_id, hoặc IP_address của người dùng), InfluxDB sẽ tạo ra hàng triệu chỉ mục (index), dẫn đến bộ nhớ RAM tăng vọt và tốc độ ghi/truy vấn giảm drastically.
Quy tắc thực tế: Chỉ sử dụng Tag cho các giá trị có số lượng giới hạn (ví dụ: 10, 100, 1000 giá trị). Nếu giá trị có thể là hàng triệu (như ID giao dịch, Email, IP), hãy chuyển nó sang Field.
Áp dụng chiến lược Tag vs Field
Chúng ta sẽ thực hiện một ví dụ so sánh. Giả sử bạn đang thu thập log lỗi. Một cách sai là đặt user_email làm Tag. Cách đúng là đặt user_email làm Field.
Đầu tiên, hãy viết dữ liệu theo cách sai (Cardinality cao) để bạn hình dung cấu trúc, sau đó sửa lại theo cách đúng.
influx write \
--bucket "MySystemMetrics" \
--token "YOUR_ACCESS_TOKEN_HERE" \
--precision s \
--data "error_log,user_email=user123@example.com,service=auth error_count=1 1715000100"
Trong dòng trên, user_email là Tag. Nếu có 1 triệu người dùng khác nhau, InfluxDB sẽ tạo 1 triệu chỉ mục. Đây là "bom" hiệu năng.
Bây giờ, hãy viết lại dữ liệu đúng chuẩn: chuyển user_email sang Field.
influx write \
--bucket "MySystemMetrics" \
--token "YOUR_ACCESS_TOKEN_HERE" \
--precision s \
--data "error_log,service=auth user_email=\"user123@example.com\",error_count=1 1715000100"
Trong dòng sửa đổi: user_email giờ là Field (có dấu ngoặc kép vì chứa ký tự đặc biệt). service vẫn là Tag vì số lượng service thường ít (dưới 100).
Kết quả mong đợi: Khi chạy lệnh query, bạn vẫn có thể lọc dữ liệu theo email, nhưng tốc độ sẽ chậm hơn so với lọc theo service. Tuy nhiên, bộ nhớ RAM của InfluxDB sẽ không bị bùng nổ, đảm bảo hệ thống ổn định khi dữ liệu lớn.
Verify kết quả về Cardinality
Sử dụng lệnh show tag values (trong CLI Flux) hoặc truy vấn Flux để đếm số lượng giá trị Tag duy nhất.
influx query \
--bucket "MySystemMetrics" \
--token "YOUR_ACCESS_TOKEN_HERE" \
--format table \
--org "MyOrg" \
-- "from(bucket: \"MySystemMetrics\") |> range(start: -1h) |> filter(fn: (r) => r._measurement == \"error_log\") |> distinct(column: \"service\")"
Kết quả mong đợi: Bạn sẽ thấy danh sách các service duy nhất (ví dụ: auth, api). Nếu bạn chạy lệnh tương tự cho user_email (nếu bạn đã lỡ đặt nó làm Tag), bạn sẽ thấy hàng trăm dòng, cảnh báo nguy hiểm về Cardinality cao.
Cấu hình chính sách lưu trữ (Retention Policy)
Khái niệm Bucket và Retention
Trong InfluxDB 2.x, khái niệm "Retention Policy" (RP) truyền thống của phiên bản 1.x đã được tích hợp trực tiếp vào định nghĩa của Bucket. Mỗi Bucket có một thời gian giữ dữ liệu (Retention Period) cố định. Khi thời gian này hết, dữ liệu cũ sẽ bị tự động xóa.
Chiến lược tối ưu là chia dữ liệu thành các Bucket khác nhau cho các mục đích khác nhau: một Bucket cho dữ liệu "Nóng" (gần đây, cần chi tiết) và một Bucket cho dữ liệu "Lạnh" (lịch sử, cần tổng hợp).
Tạo Bucket với Retention Policy cụ thể
Chúng ta sẽ tạo một Bucket mới tên là HotData_1h với chính sách giữ dữ liệu chỉ trong 1 giờ. Dữ liệu sau 1 giờ sẽ tự động bị xóa.
Sử dụng lệnh influx bucket create với tham số --retention-period. Đơn vị thời gian có thể là 1h (1 giờ), 1d (1 ngày), 1w (1 tuần), 1m (1 tháng), 1y (1 năm), hoặc infinite (vô hạn).
influx bucket create \
--name "HotData_1h" \
--org "MyOrg" \
--retention-period "1h"
Kết quả mong đợi: CLI sẽ trả về thông tin Bucket vừa tạo, bao gồm ID, Name, và Retention Period là 1h.
Tạo Bucket lưu trữ dài hạn (Cold Data)
Tiếp theo, tạo một Bucket để lưu dữ liệu lịch sử trong 1 năm. Dữ liệu này thường đã được tổng hợp (downsample) từ dữ liệu nóng, nhưng ở bước này chúng ta chỉ tập trung vào cấu hình Retention.
influx bucket create \
--name "ColdData_1y" \
--org "MyOrg" \
--retention-period "1y"
Kết quả mong đợi: Bucket ColdData_1y được tạo thành công với thời gian giữ dữ liệu là 1 năm.
Verify cấu hình Retention
Để kiểm tra xem chính sách Retention đã được áp dụng đúng chưa, hãy liệt kê tất cả Bucket và xem cột Retention Period.
influx bucket list --org "MyOrg"
Kết quả mong đợi: Bạn sẽ thấy bảng danh sách Bucket. Cột Retention Period sẽ hiển thị 1h cho Bucket HotData_1h và 1y cho Bucket ColdData_1y. Điều này xác nhận InfluxDB đã sẵn sàng tự động dọn dẹp dữ liệu theo lịch trình.
So sánh lưu trữ ngắn hạn (Hot) và dài hạn (Cold/Warm)
Chiến lược dữ liệu hai lớp
Trong môi trường sản xuất, việc lưu trữ mọi điểm dữ liệu gốc (raw data) với độ phân giải cao (ví dụ: 1 giây/lần) trong thời gian dài là không khả thi về chi phí lưu trữ và hiệu năng truy vấn.
Chiến lược Hot/Cold giải quyết vấn đề này:
- Hot Storage (Dữ liệu nóng): Lưu trữ dữ liệu gốc, độ phân giải cao (1s - 10s). Thời gian giữ ngắn (1 giờ - 1 ngày). Dùng cho giám sát thời gian thực, dashboard live, và cảnh báo tức thì.
- Cold/Warm Storage (Dữ liệu lạnh): Lưu trữ dữ liệu đã được tổng hợp (aggregated/downsampled). Độ phân giải thấp hơn (5 phút - 1 giờ). Thời gian giữ dài (1 năm - vĩnh viễn). Dùng cho báo cáo xu hướng (trending), phân tích lịch sử.
Minh họa luồng dữ liệu Hot -> Cold
Để minh họa, ta sẽ giả lập việc ghi dữ liệu vào Bucket "Nóng" và sau đó sử dụng tính năng Continuous Query (thông qua Task trong InfluxDB 2.x) để tổng hợp dữ liệu đó vào Bucket "Lạnh".
Đầu tiên, ghi dữ liệu chi tiết (1 điểm/giây) vào Bucket Hot.
influx write \
--bucket "HotData_1h" \
--token "YOUR_ACCESS_TOKEN_HERE" \
--precision s \
--data "cpu,host=server01 usage_idle=80.0 1715000200"
Kết quả mong đợi: Dữ liệu chi tiết được lưu vào Bucket Hot. Sau 1 giờ, dòng dữ liệu này sẽ tự động biến mất.
Thiết lập Task để Downsample (Tạo dữ liệu Cold)
Trong InfluxDB 2.x, chúng ta dùng Task để thực hiện việc tổng hợp dữ liệu định kỳ. Task này sẽ chạy mỗi 5 phút, lấy dữ liệu trung bình (mean) từ Bucket Hot trong 5 phút qua và ghi vào Bucket Cold.
Lưu ý: Để tạo Task, bạn cần biết ID của Bucket Hot và Bucket Cold. Bạn có thể lấy ID từ lệnh influx bucket list ở phần trước. Giả sử ID của Hot là HOT_ID và Cold là COLD_ID.
influx task create \
--name "Downsample_Cpu_5min" \
--org "MyOrg" \
--token "YOUR_ACCESS_TOKEN_HERE" \
--schedule "every 5m" \
--flux '
import "influxdata/influxdb/schema"
bucketID = "HOT_ID"
writeBucketID = "COLD_ID"
data = from(bucket: bucketID)
|> range(start: -5m)
|> filter(fn: (r) => r._measurement == "cpu")
|> aggregateWindow(every: 5m, fn: mean, createEmpty: false)
data
|> to(bucket: writeBucketID, org: "MyOrg")
Kết quả mong đợi: Task được tạo với trạng thái Enabled. Nhiệm vụ này sẽ tự động chạy mỗi 5 phút, lấy dữ liệu chi tiết từ Hot, tính trung bình, và ghi vào Cold. Khi Hot xóa dữ liệu cũ (sau 1h), Cold vẫn giữ lại bản tóm tắt của 5 phút đó trong 1 năm.
Verify luồng dữ liệu
Để kiểm tra xem Task đã hoạt động và dữ liệu đã được chuyển xuống Cold chưa, hãy truy vấn Bucket Cold sau khi Task chạy (chờ 5 phút hoặc chạy Task thủ công).
influx query \
--bucket "ColdData_1y" \
--token "YOUR_ACCESS_TOKEN_HERE" \
--format table \
--org "MyOrg" \
-- "from(bucket: \"ColdData_1y\") |> range(start: -1h) |> filter(fn: (r) => r._measurement == \"cpu\")"
Kết quả mong đợi: Bạn sẽ thấy dữ liệu trong Bucket Cold có timestamp cách nhau 5 phút (thay vì 1 giây như Bucket Hot) và giá trị usage_idle là giá trị trung bình. Điều này xác nhận chiến lược Hot/Cold đang hoạt động hiệu quả, giúp giảm dung lượng lưu trữ và tăng tốc độ truy vấn báo cáo lịch sử.
Điều hướng series:
Mục lục: Series: Triển khai Database Time-Series với InfluxDB trên Ubuntu 24.04
« Phần 3: Cấu hình bảo mật và quản lý truy cập (IAM)
Phần 5: Thu thập dữ liệu với Telegraf trên Ubuntu »