Thiết lập môi trường phát triển và trích xuất dữ liệu từ Thanos Query API
Bước đầu tiên là xây dựng một script Python để kết nối với Thanos Query API, lấy dữ liệu lịch sử (historical metrics) và lưu trữ dưới dạng JSON thô. Chúng ta cần làm điều này vì LLM (Large Language Models) không thể đọc trực tiếp định dạng protobuf hay binary của Prometheus/Thanos, chúng cần dữ liệu dạng chuỗi văn bản có cấu trúc.
Trước tiên, cài đặt các thư viện Python cần thiết để xử lý HTTP request và dữ liệu chuỗi thời gian. Thư viện `requests` dùng để gọi API, `pandas` để xử lý dataframe, và `numpy` để tính toán thống kê.
pip install requests pandas numpy python-dotenv
Kết quả mong đợi: Các thư viện được cài đặt thành công trong environment Python của bạn mà không có lỗi version conflict.
Tạo file cấu hình biến môi trường để chứa URL của Thanos Query API và các tham số an toàn. Điều này giúp script không bị lộ thông tin cấu hình khi commit lên Git.
cat > /opt/aiopts/.env
Kết quả mong đợi: File `/opt/aiopts/.env` được tạo với nội dung chính xác, sẵn sàng để script đọc.
Viết script Python `extract_metrics.py` để gọi Thanos Query API. Script này sẽ thực hiện query range vector, giải mã response từ Thanos, và lưu kết quả thô vào file JSON. Logic quan trọng là chuyển đổi timestamp từ Unix timestamp sang ISO 8601 để LLM dễ hiểu hơn.
cat > /opt/aiopts/extract_metrics.py
Kết quả mong đợi: Script chạy thành công, tạo ra file JSON chứa danh sách các series metrics với timestamp đã được chuẩn hóa sang định dạng văn bản.
Verify kết quả trích xuất
Chạy script và kiểm tra nội dung file đầu ra để đảm bảo dữ liệu đã được lấy đúng định dạng.
cd /opt/aiopts && python extract_metrics.py && cat data/raw_node_cpu_seconds_total.json | head -n 50
Kết quả mong đợi: Xuất hiện log "Successfully extracted..." và nội dung file JSON hiển thị cấu trúc `{ "metric": {...}, "values": [...] }` với timestamp dạng `2023-01-01T...`.
Chuẩn hóa và làm sạch dữ liệu Metrics (Data Cleaning)
Dữ liệu thô từ Thanos thường chứa outliers (giá trị bất thường) và missing data (khoảng trống). Nếu đưa dữ liệu này trực tiếp vào LLM, mô hình có thể bị nhiễu hoặc đưa ra dự báo sai. Chúng ta cần viết module làm sạch dữ liệu trước khi chuyển đổi sang văn bản.
Tạo script `clean_metrics.py` để xử lý outliers bằng phương pháp IQR (Interquartile Range) và điền missing data bằng phương pháp interpolation. Đây là bước quan trọng để đảm bảo tính liên tục của chuỗi thời gian (time-series continuity).
cat > /opt/aiopts/clean_metrics.py upper_bound:
cleaned.append(None) # Mark as missing
else:
cleaned.append(v)
return cleaned
def interpolate_missing(values, timestamps):
# Tạo dataframe để dùng pandas interpolation
df = pd.DataFrame({
'timestamp': timestamps,
'value': values
})
# Chuyển timestamp sang datetime object
df['timestamp'] = pd.to_datetime(df['timestamp'])
# Sắp xếp theo thời gian
df = df.sort_values('timestamp')
# Interpolate linear cho các giá trị NaN
df['value'] = df['value'].interpolate(method='linear')
# Forward fill cho đầu và cuối nếu cần
df['value'] = df['value'].ffill().bfill()
return df.to_dict('records')
def clean_series(series):
# Bước 1: Xử lý outliers
values = [item['value'] for item in series['values']]
cleaned_values = remove_outliers_iqr(values)
# Bước 2: Tạo danh sách tạm thời để interpolate
temp_data = []
for i, ts in enumerate(series['values']):
temp_data.append({
'timestamp': ts['timestamp'],
'value': cleaned_values[i]
})
# Bước 3: Interpolate missing data
final_data = interpolate_missing(
[d['value'] for d in temp_data],
[d['timestamp'] for d in temp_data]
)
# Gán lại vào cấu trúc gốc
series['values'] = final_data
return series
if __name__ == "__main__":
import glob
input_files = glob.glob('/opt/aiopts/data/raw_*.json')
for filepath in input_files:
print(f"Cleaning: {filepath}")
data = load_data(filepath)
cleaned_data = [clean_series(s) for s in data]
output_filename = filepath.replace('raw_', 'clean_')
with open(output_filename, 'w') as f:
json.dump(cleaned_data, f, indent=2)
print(f"Done: {output_filename}")
EOF
Kết quả mong đợi: Script chạy và tạo ra file mới có đuôi `clean_` thay cho `raw_`, trong đó các giá trị NaN đã được lấp đầy và các outliers đã bị loại bỏ.
Verify kết quả làm sạch
So sánh file trước và sau khi làm sạch để xác nhận các giá trị bất thường đã được xử lý.
python /opt/aiopts/clean_metrics.py && diff /opt/aiopts/data/raw_node_cpu_seconds_total.json /opt/aiopts/data/clean_node_cpu_seconds_total.json | head -n 20
Kết quả mong đợi: Lệnh `diff` hiển thị sự khác biệt, cụ thể là các giá trị số đã thay đổi (được làm tròn hoặc nội suy) và không còn các giá trị `null` hoặc số quá lớn bất thường.
Biến đổi chuỗi thời gian thành mô tả văn bản ngữ nghĩa
Sau khi dữ liệu sạch, chúng ta cần chuyển đổi các con số khô khan thành câu văn mô tả hành vi của hệ thống (trends, patterns, anomalies). Đây là bước "Textualization" cốt lõi để LLM hiểu ngữ cảnh. Chúng ta sẽ sử dụng Python để phân tích xu hướng (tăng/giảm/ổn định) và tạo prompt template.
Tạo script `transform_to_text.py`. Script này sẽ phân tích slope (độ dốc) của chuỗi thời gian để xác định xu hướng, tính toán biến động (volatility), và tạo một đoạn văn bản mô tả ngắn gọn (summary) cho mỗi metric.
cat > /opt/aiopts/transform_to_text.py 0:
direction = "increasing" # Tăng
else:
direction = "decreasing" # Giảm
# Mức độ biến động
volatility = np.std(values) / (np.mean(values) + 1e-6)
if volatility > 0.5:
stability = "highly volatile"
elif volatility > 0.1:
stability = "moderately volatile"
else:
stability = "stable"
return {
"direction": direction,
"slope": slope,
"r_squared": r_squared,
"volatility": volatility,
"stability": stability
}
def generate_natural_language(series, analysis):
metric_name = series['metric'].get('__name__', 'unknown_metric')
instance = series['metric'].get('instance', 'unknown_instance')
# Template câu văn mô tả
trend_desc = {
"stable": "giữ mức ổn định",
"increasing": "có xu hướng tăng dần",
"decreasing": "có xu hướng giảm dần"
}
stability_desc = {
"stable": "biến động nhẹ",
"moderately volatile": "biến động ở mức trung bình",
"highly volatile": "biến động mạnh và không ổn định"
}
text = f"Metric '{metric_name}' trên instance '{instance}' {trend_desc[analysis['direction']]} với độ dốc {analysis['slope']:.4f}. "
text += f"Hành vi của hệ thống {stability_desc[analysis['stability']]}. "
text += f"Độ tin cậy của xu hướng là {analysis['r_squared']:.2f}."
return text
def process_file(input_path, output_path):
with open(input_path, 'r') as f:
data = json.load(f)
textual_data = []
for series in data:
values = [item['value'] for item in series['values']]
# Loại bỏ None nếu còn sót lại
values = [v for v in values if v is not None]
if not values:
continue
analysis = analyze_trend(values)
description = generate_natural_language(series, analysis)
textual_data.append({
"original_metric": series['metric'],
"time_range": f"{series['values'][0]['timestamp']} to {series['values'][-1]['timestamp']}",
"summary": description,
"stats": analysis
})
with open(output_path, 'w') as f:
json.dump(textual_data, f, indent=2, ensure_ascii=False)
print(f"Converted {len(textual_data)} series to text at {output_path}")
if __name__ == "__main__":
import glob
input_files = glob.glob('/opt/aiopts/data/clean_*.json')
for filepath in input_files:
output_path = filepath.replace('clean_', 'text_')
process_file(filepath, output_path)
EOF
Kết quả mong đợi: Script tạo ra file `text_*.json` chứa các đoạn văn bản mô tả bằng tiếng Việt (hoặc tiếng Anh tùy cấu hình) về hành vi của metric, thay vì chỉ là danh sách số liệu.
Verify kết quả chuyển đổi văn bản
Kiểm tra file đầu ra để đảm bảo mô tả văn bản đã phản ánh đúng dữ liệu số.
cat /opt/aiopts/data/text_node_cpu_seconds_total.json
Kết quả mong đợi: Hiển thị JSON chứa trường `summary` với nội dung dạng văn bản tự nhiên như "Metric 'node_cpu_seconds_total' trên instance 'web-01' có xu hướng tăng dần với độ dốc 0.0023. Hành vi của hệ thống biến động nhẹ...".
Tích hợp pipeline vào workflow CI/CD tự động
Để pipeline ETL hoạt động tự động, chúng ta cần đóng gói toàn bộ quy trình (Extract -> Clean -> Transform) vào một Docker container và định nghĩa nó trong pipeline CI/CD (ví dụ: GitHub Actions hoặc GitLab CI). Điều này đảm bảo mỗi khi có dữ liệu mới hoặc code thay đổi, pipeline sẽ tự động chạy và cập nhật dataset cho LLM.
Tạo file `Dockerfile` để đóng gói môi trường Python cùng với các script đã viết. Sử dụng image base `python:3.9-slim` để giảm kích thước container.
cat > /opt/aiopts/Dockerfile
Kết quả mong đợi: File Dockerfile được tạo sẵn sàng để build image.
Tạo file `requirements.txt` để liệt kê chính xác các thư viện cần thiết, đảm bảo môi trường build đồng nhất.
cat > /opt/aiopts/requirements.txt
Kết quả mong đợi: File yêu cầu thư viện được tạo chính xác.
Tạo script shell `run_pipeline.sh` để đóng gói logic chạy tuần tự 3 bước: Extract, Clean, Transform. Script này sẽ được gọi khi container khởi động.
cat > /opt/aiopts/run_pipeline.sh
Kết quả mong đợi: Script shell được tạo và có quyền thực thi.
Định nghĩa workflow CI/CD cho GitHub Actions. Workflow này sẽ kích hoạt khi có commit mới vào nhánh `main` hoặc chạy định kỳ (cron) mỗi ngày để thu thập dữ liệu mới nhất.
cat > .github/workflows/aiopts-etl.yaml
Kết quả mong đợi: File workflow YAML được tạo trong thư mục `.github/workflows`, sẵn sàng để push lên repository GitHub.
Verify tích hợp CI/CD
Build và test container Docker locally để đảm bảo pipeline chạy đúng trước khi đẩy lên CI/CD.
cd /opt/aiopts && docker build -t aiopts-etl:latest . && docker run --env-file .env aiopts-etl:latest
Kết quả mong đợi: Docker build thành công, container chạy và in ra log "Pipeline Completed Successfully", đồng thời tạo ra các file `text_*.json` trong volume hoặc thư mục data.
Điều hướng series:
Mục lục: Series: Xây dựng nền tảng AIOps với Prometheus, Thanos và LLM để dự báo sự cố
« Phần 2: Triển khai Prometheus và Thanos để thu thập dữ liệu lịch sử
Phần 4: Xây dựng mô hình dự báo sự cố với LLM (RAG hoặc Fine-tuning) »