1. Cơ chế tự động phát hiện và loại bỏ Node bị lỗi (Fault Tolerance)
Trong môi trường phân tán, việc một node (nút mạng) treo hoặc mất kết nối là tình huống tất yếu. Chúng ta cần cơ chế "Heartbeat" để phát hiện sự cố và "Gossip Protocol" để lan truyền thông tin lỗi, từ đó loại bỏ node đó khỏi danh sách tham gia tính toán Shamir.
Chúng ta sẽ sử dụng một script Shell giám sát kết nối với các node láng giềng và một cơ chế "Watchdog" để tự động đánh dấu node là "Dead" nếu không nhận được phản hồi trong thời gian quy định (timeout).
Trước tiên, tạo file cấu hình tham số giám sát tại /etc/shamir-ds/monitor.conf.
HEARTBEAT_INTERVAL=2
TIMEOUT_THRESHOLD=5
PEER_LIST="192.168.1.10 192.168.1.11 192.168.1.12"
LOG_FILE="/var/log/shamir-ds/monitor.log"
LOCK_FILE="/var/lock/shamir-ds/monitor.lock"
File này định nghĩa thời gian gửi tín hiệu tim (2 giây), ngưỡng thời gian chờ (5 giây), và danh sách các node cần kiểm tra.
Tiếp theo, tạo script giám sát tự động /usr/local/bin/shamir-health-check.sh với nội dung hoàn chỉnh:
#!/bin/bash
# Load configuration
source /etc/shamir-ds/monitor.conf
# Prevent multiple instances
exec 200>"$LOCK_FILE"
flock -n 200 || exit 1
LOG_DATE=$(date '+%Y-%m-%d %H:%M:%S')
for PEER in $PEER_LIST; do
# Check connectivity using ping or specific port check
if ! ping -c 1 -W 1 $PEER > /dev/null 2>&1; then
echo "$LOG_DATE [CRITICAL] Node $PEER is unreachable. Marking as DEAD." >> $LOG_FILE
# Update local status file for the consensus layer
echo "$PEER:DEAD:$LOG_DATE" >> /var/lib/shamir-ds/node_status.txt
# Trigger immediate re-sharding if this node held a fragment
/usr/local/bin/shamir-recovery-trigger --node=$PEER
else
echo "$LOG_DATE [INFO] Node $PEER is healthy." >> $LOG_FILE
fi
done
# Cleanup old status entries (older than 1 hour) if node is back
if [ -f /var/lib/shamir-ds/node_status.txt ]; then
find /var/lib/shamir-ds/node_status.txt -mmin +60 -delete 2>/dev/null
fi
Script này thực hiện kiểm tra Ping đến từng node. Nếu không nhận được phản hồi, nó ghi log lỗi, cập nhật trạng thái node thành "DEAD" vào file trạng thái, và gọi hàm kích hoạt khôi phục.
Cấp quyền thực thi cho script:
chmod +x /usr/local/bin/shamir-health-check.sh
Thiết lập Cron job để chạy script liên tục theo chu kỳ HEARTBEAT_INTERVAL:
(crontab -l 2>/dev/null; echo "* * * * * /usr/local/bin/shamir-health-check.sh") | crontab -
Kết quả mong đợi: Khi bạn tắt máy hoặc ngắt mạng của một node (ví dụ 192.168.1.10), file /var/log/shamir-ds/monitor.log sẽ xuất hiện dòng báo lỗi [CRITICAL] và file /var/lib/shamir-ds/node_status.txt sẽ chứa trạng thái DEAD của node đó.
Để verify kết quả, kiểm tra file log và trạng thái:
tail -n 5 /var/log/shamir-ds/monitor.log && cat /var/lib/shamir-ds/node_status.txt
2. Quy trình khôi phục dữ liệu từ các fragment còn lại
Khi một node bị đánh dấu là DEAD, hệ thống Shamir Secret Sharing (SSS) cần thực hiện quá trình "Reconstruction". Với tham số k=3, n=5, ta cần ít nhất 3 fragments để khôi phục dữ liệu gốc. Nếu mất 1 node, ta còn 4 fragments, đủ để khôi phục.
Quy trình bao gồm: Thu thập các fragments từ các node còn sống -> Giải mã (Reconstruct) -> Mã hóa lại (Re-share) -> Phân phối lại các fragments mới cho các node còn lại và node mới.
Tạo script khôi phục /usr/local/bin/shamir-recovery-trigger để xử lý logic này:
#!/bin/bash
# Parse arguments
NODE_ID=""
while [[ $# -gt 0 ]]; do
case $1 in
--node)
NODE_ID="$2"
shift 2
;;
*)
echo "Usage: $0 --node "
exit 1
;;
esac
done
if [ -z "$NODE_ID" ]; then
echo "Error: Node ID is required."
exit 1
fi
# Define paths
FRAGMENTS_DIR="/var/lib/shamir-ds/fragments"
RECONSTRUCTED_FILE="/tmp/shamir-reconstructed.bin"
SHARED_SECRET_FILE="/var/lib/shamir-ds/secret.bin"
# Step 1: Identify healthy nodes and collect fragments
# Assume we need k=3 fragments. We skip the failed node.
echo "Starting recovery for missing node: $NODE_ID"
echo "Collecting fragments from healthy peers..."
# Simulate fetching fragments from remaining nodes (In production, use SSH/HTTP)
# Here we assume fragments are named fragment_1.bin, fragment_2.bin...
# We skip the fragment belonging to the failed node (mapped by ID logic)
# For demo, we assume fragment_3 is missing (Node 192.168.1.12)
# We collect fragment_1 and fragment_2 and fragment_4
HEALTHY_FRAGMENTS=()
for i in {1..5}; do
# Logic to check if node i is in the DEAD list
if grep -q "192.168.1.$((10 + i)):DEAD" /var/lib/shamir-ds/node_status.txt 2>/dev/null; then
echo "Skipping fragment $i (Node failed)"
continue
fi
if [ -f "$FRAGMENTS_DIR/fragment_$i.bin" ]; then
HEALTHY_FRAGMENTS+=("$FRAGMENTS_DIR/fragment_$i.bin")
fi
done
# Step 2: Verify if we have enough fragments (k=3)
COUNT=${#HEALTHY_FRAGMENTS[@]}
if [ $COUNT -lt 3 ]; then
echo "FATAL: Not enough fragments to reconstruct. Available: $COUNT, Required: 3"
exit 1
fi
echo "Sufficient fragments found ($COUNT). Reconstructing secret..."
# Step 3: Run the Kernel Module User-space tool to reconstruct
# The tool 'shamir-reconstruct' takes the list of fragments and outputs the original data
shamir-reconstruct -i "${HEALTHY_FRAGMENTS[@]}" -o $RECONSTRUCTED_FILE
if [ $? -ne 0 ]; then
echo "ERROR: Reconstruction failed."
rm -f $RECONSTRUCTED_FILE
exit 1
fi
# Step 4: Re-share the recovered secret to all healthy nodes
# Generate new shares for all nodes including a new slot for the failed node if needed
echo "Re-sharing secret to healthy nodes..."
shamir-reshare -i $RECONSTRUCTED_FILE -n 5 -k 3 -d $FRAGMENTS_DIR
# Step 5: Clean up temporary files
rm -f $RECONSTRUCTED_FILE
echo "Recovery completed successfully. Data integrity restored."
# Trigger a sync to the new/replica node if it rejoined
/usr/local/bin/shamir-sync --target=$NODE_ID
Script này kiểm tra số lượng fragments hiện có, gọi công cụ shamir-reconstruct (giả định đã được compile từ Phần 4 và 5) để khôi phục dữ liệu gốc, sau đó gọi shamir-reshare để tạo ra bộ fragments mới phân phối lại.
Để đảm bảo tính nhất quán (Consistency), chúng ta cần cơ chế xác thực checksum. Sau khi khôi phục, hãy chạy lệnh verify:
sha256sum /var/lib/shamir-ds/fragments/fragment_1.bin > /tmp/checksum_new.txt
sha256sum /var/lib/shamir-ds/fragments/fragment_2.bin >> /tmp/checksum_new.txt
# Compare with backup checksums if available
diff /tmp/checksum_new.txt /var/lib/shamir-ds/backup_checksums.txt
Kết quả mong đợi: Nếu quá trình thành công, lệnh diff sẽ không trả về kết quả (không có sự khác biệt so với checksum cũ) hoặc các fragments mới sẽ có checksum khác do việc re-share tạo ra các shares mới, nhưng dữ liệu gốc khôi phục ra phải giống hệt ban đầu.
Để verify toàn bộ quy trình khôi phục dữ liệu:
ls -lh /var/lib/shamir-ds/fragments/ && cat /var/log/shamir-ds/monitor.log | grep "Recovery completed"
3. Xử lý Deadlock và Race Condition trong môi trường phân tán
Trong quá trình khôi phục song song, có thể xảy ra tình trạng Deadlock (hai node chờ nhau để khóa tài nguyên) hoặc Race Condition (hai node cùng cố gắng ghi vào cùng một file fragment hoặc cùng một lúc thực hiện recovery cho cùng một node).
Chúng ta sẽ sử dụng cơ chế phân tán Lock (Distributed Lock) dựa trên file lock kết hợp với cơ chế "Lease" (thời hạn thuê) để tránh Deadlock, và sử dụng "Leader Election" để tránh Race Condition.
Tạo script quản lý khóa phân tán /usr/local/bin/distributed-lock.sh:
#!/bin/bash
LOCK_RESOURCE="$1"
ACTION="$2" # acquire or release
LEASE_TIME="${3:-60}" # Default 60 seconds
LOCK_DIR="/var/lock/shamir-ds"
LOCK_FILE="$LOCK_DIR/$LOCK_RESOURCE.lock"
PID_FILE="$LOCK_DIR/$LOCK_RESOURCE.pid"
mkdir -p $LOCK_DIR
if [ "$ACTION" == "acquire" ]; then
# Try to acquire lock with non-blocking mode
exec 9>"$LOCK_FILE"
if flock -n 9; then
echo $$ > $PID_FILE
echo "$(date '+%s')" > "$LOCK_FILE.timestamp"
echo "Lock acquired for $LOCK_RESOURCE by PID $$"
exit 0
else
# Check if existing lock is stale (Deadlock prevention)
if [ -f "$LOCK_FILE.timestamp" ]; then
CURRENT_TIME=$(date '+%s')
LOCK_TIME=$(cat "$LOCK_FILE.timestamp")
DIFF=$((CURRENT_TIME - LOCK_TIME))
if [ $DIFF -gt $LEASE_TIME ]; then
# Lock is stale, force acquire (Handle Deadlock)
rm -f $PID_FILE
echo "Stale lock detected ($DIFF seconds). Forcing acquisition for $LOCK_RESOURCE."
echo $$ > $PID_FILE
echo "$CURRENT_TIME" > "$LOCK_FILE.timestamp"
exit 0
fi
fi
echo "Lock $LOCK_RESOURCE is held by another process."
exit 1
fi
elif [ "$ACTION" == "release" ]; then
if [ -f $LOCK_FILE ]; then
# Close file descriptor 9 if open (simplified for script context)
exec 9
Script này sử dụng flock với chế độ non-blocking (-n). Nếu không thể lấy lock ngay lập tức, nó kiểm tra thời gian tạo lock. Nếu quá thời hạn (lease_time), nó coi đó là deadlock và ép buộc lấy lại lock (force acquire).
Để xử lý Race Condition trong quá trình Recovery, ta cần một Leader duy nhất thực hiện việc Re-share. Sử dụng cơ chế Leader Election đơn giản dựa trên IP thấp nhất hoặc một file leader.
Cập nhật script recovery /usr/local/bin/shamir-recovery-trigger (thêm đoạn đầu) để kiểm tra quyền Leader trước khi chạy:
#!/bin/bash
# ... (Giữ nguyên phần header và parse arguments của script cũ) ...
# Leader Election Logic
LEADER_LOCK="/var/lock/shamir-ds/recovery_leader.lock"
MY_IP=$(hostname -i | awk '{print $1}')
# Check if I am the leader or need to become one
# Simple rule: Only the node with lowest IP among healthy nodes can lead recovery
# Or use a distributed lock for the "recovery" resource
if ! /usr/local/bin/distributed-lock.sh "global_recovery" acquire 30; then
echo "Recovery is already in progress by another node. Exiting to avoid Race Condition."
exit 0
fi
# ... (Tiếp tục phần logic recovery như cũ) ...
# At the end of the script, release the lock
/usr/local/bin/distributed-lock.sh "global_recovery" release
echo "Recovery completed successfully. Data integrity restored."
Việc thêm distributed-lock.sh vào đầu script recovery đảm bảo chỉ có một node thực hiện khôi phục tại một thời điểm, tránh việc hai node cùng viết vào cùng một file fragments gây hỏng dữ liệu (Race Condition).
Để verify cơ chế xử lý Race Condition, hãy chạy hai instance của script recovery cùng lúc trên hai terminal khác nhau:
# Terminal 1
timeout 10 /usr/local/bin/shamir-recovery-trigger --node=192.168.1.12 &
# Terminal 2
timeout 10 /usr/local/bin/shamir-recovery-trigger --node=192.168.1.12 &
Kết quả mong đợi: Chỉ một trong hai terminal sẽ in dòng "Lock acquired" và thực hiện khôi phục. Terminal còn lại sẽ in dòng "Recovery is already in progress... Exiting" và thoát ngay lập tức, chứng tỏ Race Condition đã được xử lý.
Để kiểm tra file lock đang được giữ:
ls -l /var/lock/shamir-ds/global_recovery.lock && cat /var/lock/shamir-ds/global_recovery.pid
Điều hướng series:
Mục lục: Series: Triển khai Database phân tán với Shamir Secret Sharing và Linux Kernel Modules
« Phần 6: Quản lý bảo mật: Mã hóa, xác thực và kiểm soát truy cập
Phần 8: Tối ưu hiệu năng và gỡ lỗi nâng cao cho hệ thống »