Khôi phục thảm họa PostgreSQL: Tại sao bạn cần Barman khi cơ sở dữ liệu “chết” lúc 2 giờ sáng

Database tutorial - IT technology blog
Database tutorial - IT technology blog

Cảnh báo Pager lúc 2:14 sáng

Tiếng ‘Cảnh báo Nguy cấp’ từ điện thoại của tôi là một hồi còi chói tai, chát chúa mà tôi dành riêng cho các sự cố production nghiêm trọng nhất. Lúc 2:14 sáng thứ Ba tuần trước, tiếng còi đó đã vang lên. Tôi loạng choạng đi đến bàn làm việc, đôi mắt lờ đờ, và phát hiện node PostgreSQL chính hoàn toàn không phản hồi. Một lỗi phần cứng từ nhà cung cấp đám mây đã phá hỏng volume EBS bên dưới, kéo theo cả cơ sở dữ liệu của chúng tôi.

Suy nghĩ đầu tiên của tôi không phải là hoảng loạn; đó là một sự tính toán lạnh lùng. Công việc cron của chúng tôi chạy pg_dump vào mỗi đêm lúc nửa đêm. Bây giờ là 2:14 sáng. Khôi phục từ bản dump đó đồng nghĩa với việc mất 134 phút giao dịch của khách hàng. Trong thế giới của chúng tôi, con số đó tương đương với khoảng 8.500 đơn hàng và lượt đăng ký biến mất vĩnh viễn. Lúc đó tôi mới nhận ra rằng chiến lược sao lưu của mình thực chất chỉ là một chiến lược ‘hy vọng và cầu nguyện’.

Những khiếm khuyết chết người của Logical Backup

Tại sao pg_dump lại khiến chúng ta thất vọng? Để giải quyết vấn đề, chúng ta phải thừa nhận rằng logical backup không phải là giải pháp Khôi phục thảm họa (Disaster Recovery – DR) thực thụ. Một bản pg_dump chỉ là một ảnh chụp tĩnh. Nó hoạt động tốt cho môi trường phát triển cục bộ, nhưng sẽ vấp phải ba rào cản lớn trong môi trường production:

  • Khoảng cách RPO: Nếu bạn sao lưu mỗi ngày một lần, Mục tiêu điểm khôi phục (Recovery Point Objective) của bạn là 24 giờ. Về cơ bản, bạn đang chấp nhận rủi ro mất đi một ngày làm việc.
  • Tốc độ khôi phục chậm chạp: Việc nạp lại một tệp SQL dung lượng 500GB vào một cơ sở dữ liệu mới là một cực hình. Nó phải xây dựng lại mọi index và xác thực mọi ràng buộc từ đầu, thường với tốc độ chậm chỉ khoảng 20MB/s.
  • Thiếu độ chi tiết: Bạn không thể khôi phục về thời điểm 2:12 sáng—hai phút trước khi xảy ra sự cố. Bạn bị kẹt với bất kỳ dữ liệu nào hiện có vào lúc nửa đêm.

Giải pháp chính là WAL (Write Ahead Log) archiving. PostgreSQL ghi lại mọi thay đổi đơn lẻ vào một tệp WAL trước khi nó chạm đến các trang dữ liệu. Nếu bạn kết hợp một bản sao lưu cơ sở (base backup) với một luồng liên tục các tệp WAL này, bạn có thể tái hiện lại lịch sử đến bất kỳ mili giây nào.

pg_basebackup so với Barman: Chọn công cụ chuyên nghiệp

Sáng hôm sau, tôi tìm cách đạt được mục tiêu ‘không mất dữ liệu’. pg_basebackup là tùy chọn có sẵn của PostgreSQL. Nó ổn cho các thiết lập nhỏ, đơn node vì nó tạo ra một bản sao nhị phân của thư mục dữ liệu. Tuy nhiên, nó thiếu sự thông minh. Bạn phải tự quản lý các tệp WAL, xoay vòng các bản sao lưu cũ và viết các script tùy chỉnh để xóa dữ liệu cũ.

Và rồi có Barman (Backup and Recovery Manager). Hãy coi Barman như một hộp đen chuyên dụng cho toàn bộ hệ thống PostgreSQL của bạn. Nó tự động hóa việc truyền tải WAL, quản lý các danh mục sao lưu phức tạp và—quan trọng nhất—xác thực rằng các bản sao lưu của bạn thực sự khỏe mạnh trước khi hỏa hoạn xảy ra.

Kiến trúc hệ thống Khôi phục thảm họa Barman bền bỉ

Chúng tôi đã triển khai một máy chủ Barman riêng biệt nằm ngoài cụm cơ sở dữ liệu chính. Nó lấy các tệp WAL thông qua streaming replication và thực hiện sao lưu toàn bộ hàng tuần. Thiết lập này đảm bảo rằng một lỗi hoàn toàn ở node chính sẽ không dẫn đến một cơn đau tim cho người quản trị.

Bước 1: Chuẩn bị Node chính (Primary Node)

Cơ sở dữ liệu cần quyền để giao tiếp với Barman. Chúng tôi bắt đầu bằng cách tạo một người dùng sao lưu chuyên dụng.

-- Trên máy chủ PostgreSQL
CREATE USER barman WITH SUPERUSER PASSWORD 'your_secure_password';

Tiếp theo, chúng tôi sửa tệp postgresql.conf để kích hoạt tính năng lưu trữ (archiving). Điều này bật luồng dữ liệu thay đổi liên tục.

# postgresql.conf
wal_level = replica
archive_mode = on
archive_command = 'rsync -a %p barman@backup-server:/var/lib/barman/pg-server/incoming/%f'
max_wal_senders = 10
max_replication_slots = 10

Bước 2: Cấu hình máy chủ Barman

Trên máy chủ sao lưu, chúng tôi cấu hình hồ sơ cho máy chủ. Chúng tôi chọn phương thức streaming để đạt được mức độ mất dữ liệu gần như bằng không.

# /etc/barman.d/pg-server.conf
[pg-server]
description = "Cơ sở dữ liệu PostgreSQL Production"
conninfo = host=db-primary user=barman dbname=postgres
streaming_conninfo = host=db-primary user=barman dbname=postgres
backup_method = postgres
streaming_archiver = on
slot_name = barman_slot

Xác minh kết nối bằng lệnh kiểm tra nhanh:

barman check pg-server

Bước 3: Xử lý chuyển đổi dữ liệu

Trong khi đại tu quy trình DR, tôi phải nạp khoảng 150.000 dòng nhật ký kiểm tra cũ từ một tệp CSV. Để tránh việc phải viết một script dùng một lần, tôi đã sử dụng toolcraft.app/vi/tools/data/csv-to-json. Nó chạy hoàn toàn trong trình duyệt, giúp giữ dữ liệu nhạy cảm của khách hàng tránh khỏi môi trường internet công cộng.

Khôi phục: Biến hàng giờ thành hàng phút

Một bản sao lưu chưa được kiểm tra chỉ là dữ liệu kiểu ‘mèo của Schrödinger’; bạn không biết nó còn sống hay đã chết cho đến khi cố gắng mở nó ra. Với Barman, Point-in-Time Recovery chỉ bằng một câu lệnh duy nhất. Nếu sự cố lúc 2:14 sáng đó xảy ra hôm nay, tôi sẽ chạy lệnh này:

barman recover --target-time "2026-05-10 02:12:00" pg-server /var/lib/postgresql/15/main

Công cụ này sẽ xử lý các công việc nặng nhọc. Nó lấy bản sao lưu toàn bộ gần nhất và ‘phát lại’ các tệp WAL cho đến thời điểm 02:12:00. Cơ sở dữ liệu hoạt động trở lại với chỉ 120 giây mất dữ liệu thay vì 134 phút.

Kết luận cuối cùng

Nếu bạn dựa vào pg_dump cho một cơ sở dữ liệu có lưu lượng truy cập cao, bạn không phải đang vận hành hệ thống; bạn đang đánh bạc. Chúng tôi chỉ mất bốn giờ để triển khai và thử nghiệm Barman. Khoản đầu tư nhỏ đó đã biến rủi ro mất dữ liệu trong 2 giờ thành một tác vụ khôi phục trong 60 giây. Lần tới khi tiếng còi báo động vang lên lúc 2 giờ sáng, tôi sẽ không còn phải tính toán thiệt hại nữa. Tôi sẽ chỉ chạy lệnh khôi phục và tiếp tục đi ngủ.

Share: