Phân tích log Pacemaker và SQL Server để tìm nguyên nhân lỗi
Trong môi trường Linux HA, khi sự cố xảy ra, bước đầu tiên là xác định xem lỗi nằm ở tầng Cluster (Pacemaker/Corosync) hay tầng Database (MSSQL).
Log của Pacemaker ghi lại các quyết định về việc khởi động, di chuyển (migrate), hoặc dừng (stop) các resource. Log của SQL Server ghi lại các lỗi nội bộ như I/O failure, deadlock, hoặc lỗi replication.
Bạn cần truy cập vào file log chính của Pacemaker và file log của MSSQL trên từng node để đối chiếu thời gian (timestamp).
1. Kiểm tra log Pacemaker và Corosync
File log của Pacemaker trên Ubuntu 24.04 thường nằm trong thư mục /var/log/pacemaker.log. Corosync (hệ thống giao tiếp giữa các node) có log riêng.
Thực hiện lệnh dưới đây để xem 50 dòng cuối cùng của log Pacemaker, lọc theo từ khóa lỗi hoặc cảnh báo.
grep -E "ERROR|WARN|CRITICAL" /var/log/pacemaker.log | tail -n 50
Kết quả mong đợi: Bạn sẽ thấy các dòng log mô tả trạng thái của resource (ví dụ: "Resource mssql-ag-1 failed to start", "Stonith device failed").
2. Kiểm tra log SQL Server (MSSQL)
Log của SQL Server trên Linux được lưu trong thư mục /var/opt/mssql/log. File quan trọng nhất là errorlog (chứa lỗi khởi động, lỗi hệ thống) và các file sqlagent.log nếu dùng Agent.
Để xem log lỗi mới nhất của SQL Server, sử dụng lệnh sau:
tail -n 100 /var/opt/mssql/log/errorlog
Kết quả mong đợi: Các dòng log bắt đầu bằng timestamp, chứa thông báo lỗi như "Database 'AdventureWorks' is not available" hoặc "Always On Availability Group 'AG1' failed to start".
3. Đồng bộ thời gian (Timestamp) để debug
Để xác định chính xác nguyên nhân, bạn cần đảm bảo thời gian trên tất cả các node đồng bộ. Nếu lệch, việc so sánh log là vô nghĩa.
Kiểm tra trạng thái đồng bộ thời gian của NTP/Chrony:
timedatectl status
Kết quả mong đợi: Dòng "System clock synchronized" phải hiển thị là "yes".
Xử lý các lỗi mất kết nối (Split-brain) trong cluster
Split-brain xảy ra khi mạng bị chia cắt, khiến hai hoặc nhiều node trong cluster đều nghĩ mình là master và tiếp tục hoạt động độc lập. Điều này dẫn đến dữ liệu bị phân mảnh (data corruption).
Pacemaker sử dụng cơ chế Fencing (STONITH - Secure Take-Over, Isolation, and Notification) để ngăn chặn Split-brain. Khi phát hiện mất kết nối, node bị cô lập sẽ bị "giết" (shutdown/reboot) để bảo vệ dữ liệu.
1. Kiểm tra trạng thái Fencing (STONITH)
Trước tiên, hãy kiểm tra xem resource STONITH có đang hoạt động và được cấu hình đúng trên cluster không.
crm_mon -1 -A
Kết quả mong đợi: Trong output, bạn phải thấy dòng "stonith" hoặc "fence" đang ở trạng thái "Started" trên ít nhất một node. Nếu không thấy, cluster không thể tự động xử lý Split-brain.
2. Xử lý sự cố khi STONITH bị lỗi hoặc không có
Nếu STONITH không được cấu hình (do thiếu phần cứng hoặc virtualization không hỗ trợ), Pacemaker sẽ không tự động kill node bị cô lập, dẫn đến Split-brain.
Để tạm thời cho phép cluster hoạt động mà không có STONITH (chỉ dùng để test hoặc môi trường không critical), bạn phải đặt biến stonith-enabled về false. WARNING: Chỉ làm điều này khi hiểu rõ rủi ro mất dữ liệu.
crm configure property stonith-enabled=false
Kết quả mong đợi: Cluster sẽ tiếp tục hoạt động ngay cả khi mạng bị chia cắt, nhưng rủi ro data corruption là rất cao.
Để quay lại chế độ bảo vệ an toàn (bắt buộc có STONITH):
crm configure property stonith-enabled=true
Kết quả mong đợi: Cluster sẽ yêu cầu resource STONITH phải online. Nếu không có, cluster sẽ không cho phép các resource quan trọng (như SQL Server) chạy.
3. Kiểm tra log khi xảy ra Split-brain
Nếu sự cố Split-brain đã xảy ra, kiểm tra log để xem node nào đã bị Fencing:
grep -i "fence\|stonith\|kill" /var/log/pacemaker.log
Kết quả mong đợi: Các dòng log mô tả hành động "stonith: fencing node node2" hoặc "stonith: failed to fence node2".
Cấu hình cảnh báo (Alerting) cho sự cố Availability Group
Việc chủ động cảnh báo khi Availability Group (AG) gặp sự cố là bắt buộc để giảm thời gian (downtime). SQL Server trên Linux không có SQL Server Agent như trên Windows để gửi email trực tiếp, nên chúng ta sẽ dùng cơ chế Log Monitor hoặc PowerShell Script kết hợp với hệ thống monitoring (như Prometheus, Zabbix) hoặc đơn giản là Cron job gửi log.
Ở đây, chúng ta sẽ tạo một script kiểm tra trạng thái AG và gửi cảnh báo qua email hoặc Slack (thông qua curl).
1. Tạo script kiểm tra trạng thái AG
Tạo một file script shell để kiểm tra xem AG có đang ở trạng thái "Synchronized" và "Primary" không.
Đường dẫn file: /usr/local/bin/check_sql_ag_status.sh
#!/bin/bash
# Script kiểm tra trạng thái Always On AG
AG_NAME="MyAlwaysOnAG"
DB_NAME="AdventureWorks"
REPLICA_NAME="Replica1"
# Kiểm tra trạng thái AG
STATUS=$(sudo /opt/mssql-tools/bin/sqlcmd -S localhost -U sa -P "YourStrongPassword" -Q "SELECT AG.STATE, AG.STATE_DESC FROM sys.dm_hadr_availability_group_states AS AG WHERE AG.name = '$AG_NAME';" -h -1 | grep -v "STATE")
if [ -z "$STATUS" ]; then
echo "ERROR: Cannot connect to SQL Server or AG not found."
exit 1
fi
# Kiểm tra trạng thái Database
DB_STATUS=$(sudo /opt/mssql-tools/bin/sqlcmd -S localhost -U sa -P "YourStrongPassword" -Q "SELECT DATABASE_NAME, SYNCHRONIZING_STATUS, FAILOVER_MODE FROM sys.dm_hadr_database_replica_states WHERE DATABASE_NAME = '$DB_NAME';" -h -1)
# Logic cảnh báo
if echo "$STATUS" | grep -q "SUSPENDED\|IN_RECOVERY"; then
echo "CRITICAL: AG $AG_NAME is in $STATUS state."
# Gửi cảnh báo (ví dụ qua curl đến Slack webhook)
# curl -X POST -H 'Content-type: application/json' --data "{\"text\":\"CRITICAL: SQL AG $AG_NAME is down\"}" YOUR_SLACK_WEBHOOK_URL
exit 2
elif echo "$DB_STATUS" | grep -q "NOT_SYNCHRONIZED"; then
echo "WARNING: Database $DB_NAME is NOT_SYNCHRONIZED."
# curl -X POST -H 'Content-type: application/json' --data "{\"text\":\"WARNING: SQL DB $DB_NAME is lagging\"}" YOUR_SLACK_WEBHOOK_URL
exit 1
else
echo "OK: AG $AG_NAME is healthy."
exit 0
fi
Kết quả mong đợi: Script chạy và trả về mã lỗi 0 nếu healthy, 1 nếu warning, 2 nếu critical.
2. Cấu hình Cron job để chạy script định kỳ
Thêm script vào crontab của user root để chạy mỗi 5 phút.
chmod +x /usr/local/bin/check_sql_ag_status.sh
crontab -e
Thêm dòng sau vào file crontab:
*/5 * * * * /usr/local/bin/check_sql_ag_status.sh >> /var/log/sql_ag_alert.log 2>&1
Kết quả mong đợi: Cron job được lưu và sẽ chạy script kiểm tra mỗi 5 phút.
3. Tích hợp với hệ thống Monitoring (Prometheus)
Nếu bạn dùng Prometheus, hãy dùng Exporter SQL Server (sql_exporter) để scrape metrics.
File cấu hình /etc/prometheus/prometheus.yml (thêm job):
scrape_configs:
- job_name: 'sql-server'
static_configs:
- targets: ['localhost:9182']
metrics_path: /metrics
Kết quả mong đợi: Prometheus có thể thu thập metric mssql_hadr_availability_group_state và mssql_hadr_database_replica_state để tạo alert rule.
Lịch trình backup và restore cho Availability Group trong môi trường Linux
Trong Always On AG, chỉ có Primary Replica mới có thể thực hiện Backup Full. Secondary Replica có thể thực hiện Backup Differential và Backup Log (nếu tính năng Backup Priority được cấu hình).
Mục tiêu là tạo lịch trình backup tự động trên Primary và lưu trữ backup file vào một thư mục chia sẻ (Shared Storage) hoặc thư mục local đồng bộ qua rsync/NFS.
1. Cấu hình thư mục Backup
Tạo thư mục backup trên cả Primary và Secondary (nếu dùng local storage) hoặc trên shared storage.
sudo mkdir -p /var/opt/mssql/backup
sudo chown mssql:mssql /var/opt/mssql/backup
Kết quả mong đợi: Thư mục được tạo và quyền sở hữu thuộc về user mssql.
2. Tạo Stored Procedure để Backup thông minh
Tạo một Stored Procedure trong SQL Server để tự động phát hiện nếu server đang là Primary thì mới thực hiện Backup Full. Nếu là Secondary, nó sẽ bỏ qua hoặc chỉ backup Log (tùy cấu hình).
File SQL script: /var/opt/mssql/scripts/backup_ag.sql
USE master;
GO
IF NOT EXISTS (SELECT name FROM sys.objects WHERE name = 'usp_BackupAlwaysOn' AND type = 'P')
BEGIN
EXEC('
CREATE PROCEDURE usp_BackupAlwaysOn
@DBName NVARCHAR(128),
@BackupPath NVARCHAR(260)
AS
BEGIN
SET NOCOUNT ON;
DECLARE @IsPrimary BIT = 0;
DECLARE @AGName NVARCHAR(128);
DECLARE @BackupType NVARCHAR(20);
-- Kiểm tra xem server này có phải là Primary Replica của AG không
SELECT @IsPrimary = 1, @AGName = ag.name
FROM sys.dm_hadr_availability_group_states AS ags
JOIN sys.availability_groups AS ag ON ags.group_id = ag.group_id
WHERE ags.role_desc = ''PRIMARY'';
IF @IsPrimary = 1
BEGIN
PRINT ''Running Full Backup on Primary Replica for AG: '' + @AGName;
BACKUP DATABASE ['' + @DBName + '']
TO DISK = @BackupPath + @DBName + ''_FULL_''+ CAST(GETDATE() AS VARCHAR(20)) + ''.bak''
WITH INIT, COMPRESSION, STATS = 10;
END
ELSE
BEGIN
PRINT ''Current node is NOT Primary. Skipping Full Backup.''
-- Có thể thêm logic backup Log ở đây nếu cần
END
END
');
END
GO
Kết quả mong đợi: Stored Procedure usp_BackupAlwaysOn được tạo trong database master.
3. Chạy script Backup và tạo lịch trình
Tạo file script shell để gọi Stored Procedure hàng ngày vào lúc 22:00.
File script: /usr/local/bin/sql_backup_daily.sh
#!/bin/bash
DB_NAME="AdventureWorks"
BACKUP_PATH="/var/opt/mssql/backup/"
# Chạy backup qua sqlcmd
sudo /opt/mssql-tools/bin/sqlcmd -S localhost -U sa -P "YourStrongPassword" -d master -Q "EXEC usp_BackupAlwaysOn '$DB_NAME', '$BACKUP_PATH'"
# Kiểm tra kết quả (exit code của sqlcmd)
if [ $? -eq 0 ]; then
echo "$(date): Backup completed successfully."
else
echo "$(date): Backup failed."
fi
Kết quả mong đợi: Script chạy và tạo file .bak trong thư mục backup.
chmod +x /usr/local/bin/sql_backup_daily.sh
crontab -e
Thêm dòng vào crontab:
0 22 * * * /usr/local/bin/sql_backup_daily.sh >> /var/log/sql_backup.log 2>&1
Kết quả mong đợi: Backup tự động chạy mỗi ngày lúc 22:00 trên Primary Replica.
4. Verify Backup và Restore Test
Sau khi backup, cần kiểm tra tính toàn vẹn của file backup.
sudo /opt/mssql-tools/bin/sqlcmd -S localhost -U sa -P "YourStrongPassword" -Q "RESTORE VERIFYONLY FROM DISK = '/var/opt/mssql/backup/AdventureWorks_FULL_20241025.bak'"
Kết quả mong đợi: Thông báo "RESTORE VERIFYONLY completed successfully" và không có lỗi.
Để test Restore (chỉ nên làm trên môi trường test hoặc node Secondary tạm dừng):
sudo /opt/mssql-tools/bin/sqlcmd -S localhost -U sa -P "YourStrongPassword" -Q "RESTORE DATABASE [AdventureWorks_Test] FROM DISK = '/var/opt/mssql/backup/AdventureWorks_FULL_20241025.bak' WITH MOVE 'AdventureWorks' TO '/var/opt/mssql/data/AdventureWorks_Test.mdf', MOVE 'AdventureWorks_log' TO '/var/opt/mssql/data/AdventureWorks_Test_log.ldf', RECOVERY"
Kết quả mong đợi: Database mới AdventureWorks_Test được tạo và ở trạng thái ONLINE.
Điều hướng series:
Mục lục: Series: Triển khai Database SQL Server Always On với Ubuntu 24.04
« Phần 5: Kiểm thử Failover và cân bằng tải cho Always On