Cách khắc phục lỗi PostgreSQL 'FATAL: the database system is starting up'

beginner🐘 PostgreSQL2026-04-13| PostgreSQL (mọi phiên bản), Linux (Ubuntu, CentOS), Docker, Kubernetes

Error Message

FATAL: the database system is starting up
#postgresql#devops#phục hồi cơ sở dữ liệu#docker#khắc phục sự cố

Tóm tắt: Cách khắc phục nhanh

Gặp lỗi này có nghĩa là dịch vụ PostgreSQL của bạn đang chạy nhưng chưa sẵn sàng nhận lưu lượng truy cập. Thông thường, engine đang bận xử lý lại các Write-Ahead Logs (WAL) để đảm bảo dữ liệu nhất quán sau khi gặp sự cố hoặc khởi động lại đột ngột.

  • Hãy kiên nhẫn: Phần lớn thời gian, cơ sở dữ liệu chỉ cần một vài phút để hoàn thành các bước kiểm tra nội bộ.
  • Theo dõi log: Chạy lệnh tail -f /var/log/postgresql/postgresql-15-main.log để theo dõi tiến trình khôi phục trong thời gian thực.
  • Kiểm tra trạng thái sẵn sàng: Sử dụng tiện ích pg_isready để kiểm tra trạng thái mà không làm đầy log bằng các nỗ lực kết nối thất bại.

Tại sao lỗi này xảy ra

PostgreSQL sẽ chuyển sang chế độ khôi phục bảo vệ trong quá trình khởi động. Nó quét thư mục pg_wal (hoặc pg_xlog trong các phiên bản cũ) để tìm các giao dịch đã commit nhưng chưa được lưu vào các tệp dữ liệu chính. Biện pháp an toàn này được kích hoạt sau khi khởi động lại cứng, mất điện, hoặc khi tiến trình postmaster bị dừng đột ngột bằng lệnh kill -9.

Cơ sở dữ liệu sẽ bị khóa cho đến khi đạt đến "trạng thái nhất quán". Đối với một cơ sở dữ liệu 500GB với khối lượng ghi cao, quá trình này có thể mất vài phút. Nếu bạn đang chạy một bản sao Hot Standby, bạn cũng sẽ thấy thông báo này cho đến khi bản standby nhận đủ dữ liệu WAL từ bản primary để cho phép các truy vấn chỉ đọc (read-only).

Bước 1: Theo dõi tiến trình khởi động

Thay vì đoán xem sẽ mất bao lâu, hãy kiểm tra log. Log cung cấp các chi tiết cụ thể, chẳng hạn như vị trí WAL chính xác đang được xử lý lại hoặc khối lượng công việc còn lại.

# Hệ điều hành Debian/Ubuntu
sudo tail -f /var/log/postgresql/postgresql-main.log

# Hệ điều hành RHEL/CentOS
sudo tail -f /var/lib/pgsql/data/log/postgresql.log

# Các container Docker
docker logs -f <container_name>

Hãy chú ý đến các dấu hiệu log cụ thể sau:

LOG:  database system was shut down at 2023-10-27 10:00:00 UTC
LOG:  redo starts at 0/1A2B3C8
LOG:  consistent recovery state reached at 0/1A2B4D0
LOG:  database system is ready to accept connections

Bước 2: Sử dụng pg_isready để kiểm tra sức khỏe hệ thống

Tránh làm ứng dụng bị lỗi bằng cách sử dụng tiện ích pg_isready. Công cụ này trả về các mã thoát (exit code) tiêu chuẩn của shell, giúp nó trở nên hoàn hảo cho các luồng CI/CD hoặc các script khởi động. Nó cho phép bạn thăm dò trạng thái cơ sở dữ liệu một cách âm thầm.

pg_isready -h localhost -p 5432

Ý nghĩa của các mã thoát:

  • 0: Sẵn sàng. Máy chủ đang chấp nhận kết nối.
  • 1: Bận. Máy chủ đang từ chối kết nối (có khả năng vẫn đang khởi động).
  • 2: Không phản hồi. Máy chủ đang dừng hoặc có sự cố mạng.

Bước 3: Triển khai cơ chế thử lại thông minh

Trong môi trường Docker hoặc Kubernetes, các ứng dụng thường khởi động nhanh hơn cơ sở dữ liệu. Mã nguồn của bạn nên lường trước việc cơ sở dữ liệu có thể không khả dụng ngay tại thời điểm container bắt đầu chạy.

Ví dụ Python này sử dụng chiến lược backoff cơ bản để xử lý giai đoạn "đang khởi động" một cách mượt mà:

import psycopg2
import time

def connect_with_retry():
    retries = 15
    while retries > 0:
        try:
            conn = psycopg2.connect("dbname=test user=postgres password=secret host=db")
            return conn
        except psycopg2.OperationalError as e:
            if "starting up" in str(e):
                print("Postgres is still recovering. Retrying in 5 seconds...")
                time.sleep(5)
                retries -= 1
            else:
                raise e
    raise Exception("Timeout: Could not connect to PostgreSQL.")

Bước 4: Điều chỉnh cấu hình để tăng tốc độ khôi phục

Nếu cơ sở dữ liệu của bạn mất hơn 10 phút để khởi động mỗi lần, cấu hình của bạn có thể đang buộc phải xử lý lại quá nhiều WAL. Bạn có thể giảm bớt khoảng thời gian này bằng cách điều chỉnh tần suất PostgreSQL thực hiện "checkpoints".

Mở tệp postgresql.conf và tìm các cài đặt sau:

# Tăng tần suất checkpoint để rút ngắn thời gian khôi phục
checkpoint_timeout = 5min 
max_wal_size = 2GB
min_wal_size = 1GB

Bằng cách tăng max_wal_size, bạn cho phép cơ sở dữ liệu có thêm không gian để hoạt động. Tuy nhiên, nếu bạn muốn khởi động nhanh hơn, bạn nên đảm bảo checkpoint_timeout không được đặt quá dài như 30 phút, điều này sẽ để lại một lượng dữ liệu khổng lồ cần xử lý lại sau khi gặp sự cố.

Xử lý lỗi trong Docker/Kubernetes

Trong các thiết lập container, lỗi này thường kích hoạt các vòng lặp khởi động lại không cần thiết. Hãy sử dụng healthcheck trong tệp docker-compose.yml của bạn để đảm bảo các dịch vụ phụ thuộc sẽ đợi cho đến khi cơ sở dữ liệu hoạt động hoàn toàn.

services:
  db:
    image: postgres:15
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U postgres"]
      interval: 10s
      timeout: 5s
      retries: 5

  app:
    depends_on:
      db:
        condition: service_healthy

Kiểm tra cuối cùng

Sau khi bạn tin rằng cơ sở dữ liệu đã hoạt động, hãy xác minh bằng ba bước sau:

  • Kiểm tra pg_isready và xác nhận nó trả về mã thoát 0.
  • Chạy một truy vấn đơn giản qua psql: psql -U postgres -c "SELECT 1;".
  • Quét log để tìm thông báo: database system is ready to accept connections.

Nếu lỗi vẫn tiếp diễn trong hơn 20 phút mà không có hoạt động log nào, hãy kiểm tra dung lượng đĩa bằng lệnh df -h. Đĩa đầy sẽ khiến quá trình khôi phục bị đình trệ vô thời hạn, khiến cơ sở dữ liệu bị kẹt ở giai đoạn khởi động.

Related Error Notes