Chuyển đến nội dung chính
DevOps

Hướng Dẫn Upgrade PostgreSQL 17.6 lên 18.1 (Chuẩn Production)

Hướng dẫn chi tiết upgrade PostgreSQL 17.6 lên 18.1 cho môi trường production với downtime tối thiểu. Bao gồm pg_upgrade, logical replication, rollback plan, và các best practices được cập nhật cho PostgreSQL 18 với Async I/O, Statistics Preservation, và pg_upgrade --swap mode mới.

Hướng Dẫn Upgrade PostgreSQL 17.6 lên 18.1 (Chuẩn Production)

PostgreSQL 18 chính thức ra mắt vào ngày 25/9/2025, đánh dấu một trong những bản release quan trọng nhất trong lịch sử PostgreSQL. Với việc giới thiệu Asynchronous I/O subsystem, hiệu năng đọc từ storage được cải thiện lên đến 3 lần, cùng nhiều tính năng mới như UUIDv7, Virtual Generated Columns, và OAuth 2.0 authentication.

Bài viết này sẽ hướng dẫn chi tiết cách upgrade từ PostgreSQL 17.6 lên 18.1 theo chuẩn production, đảm bảo downtime tối thiểu và rollback an toàn.


1. Tại Sao Nên Upgrade Lên PostgreSQL 18?

1.1. Các Tính Năng Nổi Bật

Tính năng Mô tả Lợi ích
Asynchronous I/O Hệ thống I/O bất đồng bộ mới Tăng tốc sequential scan, bitmap heap scan lên đến 3x
Statistics Preservation Giữ lại planner statistics khi upgrade Không cần chạy ANALYZE sau upgrade
Skip Scan Lookup trên multicolumn B-tree indexes Query nhanh hơn khi bỏ qua điều kiện = trên prefix columns
UUIDv7 Native uuidv7() function UUID có timestamp, tốt hơn cho indexing
Virtual Generated Columns Computed columns tại query time Linh hoạt hơn trong schema design
OAuth 2.0 Authentication với identity providers Tích hợp SSO dễ dàng
pg_upgrade --swap Chế độ swap mới Upgrade nhanh hơn, không cần copy files

1.2. Breaking Changes Cần Lưu Ý

⚠️ QUAN TRỌNG - Các thay đổi không tương thích ngược:
  1. Data Checksums mặc định BẬT (initdb)

    • Cần matching checksum settings khi pg_upgrade
  2. MD5 authentication DEPRECATED

    • Nên migrate sang SCRAM-SHA-256
  3. Time zone abbreviation handling thay đổi

    • Session timezone được ưu tiên trước timezone_abbreviations

2. Chuẩn Bị Trước Khi Upgrade

2.1. Checklist Pre-Upgrade

#!/bin/bash



pre-upgrade-checklist.sh

echo "=== PostgreSQL Upgrade Checklist ==="

1. Kiểm tra version hiện tại

echo "1. Current PostgreSQL Version:" psql -c "SELECT version();"

2. Kiểm tra disk space

echo "2. Disk Space (cần ít nhất 2x data directory size):" df -h /var/lib/postgresql

3. Kiểm tra data directory size

echo "3. Data Directory Size:" du -sh /var/lib/postgresql/17/main

4. Kiểm tra checksum status

echo "4. Data Checksum Status:" pg_controldata /var/lib/postgresql/17/main | grep "Data page checksum"

5. Kiểm tra extensions

echo "5. Installed Extensions:" psql -c "SELECT extname, extversion FROM pg_extension ORDER BY extname;"

6. Kiểm tra replication slots

echo "6. Replication Slots:" psql -c "SELECT slot_name, slot_type, active FROM pg_replication_slots;"

7. Kiểm tra prepared transactions

echo "7. Prepared Transactions (should be empty):" psql -c "SELECT * FROM pg_prepared_xacts;"

2.2. Backup Strategy

QUAN TRỌNG: Luôn backup trước khi upgrade!

# 1. Full backup với pg_dumpall (logical backup)
pg_dumpall -U postgres -h localhost -f /backup/full_backup_$(date +%Y%m%d).sql

2. Base backup (physical backup) - khuyến nghị

pg_basebackup -D /backup/basebackup_$(date +%Y%m%d)
-Ft -z -P
-U replication
-h localhost

3. Backup configuration files

cp /etc/postgresql/17/main/postgresql.conf /backup/ cp /etc/postgresql/17/main/pg_hba.conf /backup/ cp /etc/postgresql/17/main/pg_ident.conf /backup/

2.3. Cài Đặt PostgreSQL 18.1

# Ubuntu/Debian
sudo sh -c 'echo "deb http://apt.postgresql.org/pub/repos/apt $(lsb_release -cs)-pgdg main" > /etc/apt/sources.list.d/pgdg.list'
wget --quiet -O - https://www.postgresql.org/media/keys/ACCC4CF8.asc | sudo apt-key add -
sudo apt-get update
sudo apt-get install postgresql-18

RHEL/Rocky Linux

sudo dnf install -y https://download.postgresql.org/pub/repos/yum/reporpms/EL-9-x86_64/pgdg-redhat-repo-latest.noarch.rpm sudo dnf -qy module disable postgresql sudo dnf install -y postgresql18-server postgresql18-contrib


3. Các Phương Pháp Upgrade

3.1. So Sánh Các Phương Pháp

Phương pháp Downtime Use Case Độ phức tạp
pg_upgrade Phút Same host, brief pause Thấp
pg_upgrade --link Giây - Phút Same filesystem, nhanh nhất Thấp
pg_upgrade --swap (PG18 mới) Giây - Phút Swap directories Thấp
Logical Replication Giây 24x7 apps, zero-downtime Cao
pg_dump/restore Giờ - Ngày Small DBs, cross-platform Thấp

3.2. Khuyến Nghị Cho Production

┌─────────────────────────────────────────────────────────────┐
│                    DECISION FLOWCHART                        │
├─────────────────────────────────────────────────────────────┤
│                                                              │
│  Database size < 100GB?                                      │
│     YES → pg_upgrade --link hoặc --swap                     │
│     NO  ↓                                                   │
│                                                              │
│  Zero-downtime required?                                     │
│     YES → Logical Replication                                │
│     NO  → pg_upgrade --link với maintenance window           │
│                                                              │
│  Cross-platform migration?                                   │
│     YES → pg_dump/restore                                    │
│                                                              │
└─────────────────────────────────────────────────────────────┘

4.1. Khởi Tạo Cluster Mới

# Tạo data directory cho PostgreSQL 18
sudo mkdir -p /var/lib/postgresql/18/main
sudo chown postgres:postgres /var/lib/postgresql/18/main

Chuyển sang user postgres

sudo -i -u postgres

Kiểm tra checksum của cluster cũ

pg_controldata /var/lib/postgresql/17/main | grep "Data page checksum"

Output: Data page checksum version: 0 (disabled) hoặc 1 (enabled)

Init cluster mới với MATCHING checksum setting

Nếu cluster cũ KHÔNG có checksum:

/usr/lib/postgresql/18/bin/initdb
-D /var/lib/postgresql/18/main
--no-data-checksums
--encoding=UTF8
--locale=en_US.UTF-8

Nếu cluster cũ CÓ checksum (hoặc muốn enable):

/usr/lib/postgresql/18/bin/initdb
-D /var/lib/postgresql/18/main
--data-checksums
--encoding=UTF8
--locale=en_US.UTF-8

4.2. Pre-Upgrade Check

# Set environment variables
export PGBINOLD=/usr/lib/postgresql/17/bin
export PGBINNEW=/usr/lib/postgresql/18/bin
export PGDATAOLD=/var/lib/postgresql/17/main
export PGDATANEW=/var/lib/postgresql/18/main

Chạy check mode TRƯỚC

/usr/lib/postgresql/18/bin/pg_upgrade
--old-datadir=$PGDATAOLD
--new-datadir=$PGDATANEW
--old-bindir=$PGBINOLD
--new-bindir=$PGBINNEW
--check

Expected output:

Performing Consistency Checks

-----------------------------

Checking cluster versions ok

Checking database connection settings ok

Checking database user is the install user ok

Checking for prepared transactions ok

...

Clusters are compatible

4.3. Stop Services & Upgrade

# 1. Stop ứng dụng kết nối đến database

(tùy thuộc vào setup của bạn)

2. Stop PostgreSQL 17

sudo systemctl stop postgresql@17-main

3. Verify PostgreSQL 17 đã stop

pg_isready -p 5432

Output: no response

4. Thực hiện upgrade với --link mode (nhanh nhất)

cd /var/lib/postgresql /usr/lib/postgresql/18/bin/pg_upgrade
--old-datadir=$PGDATAOLD
--new-datadir=$PGDATANEW
--old-bindir=$PGBINOLD
--new-bindir=$PGBINNEW
--link
--jobs=$(nproc)

Hoặc với --swap mode (PostgreSQL 18 mới)

/usr/lib/postgresql/18/bin/pg_upgrade
--old-datadir=$PGDATAOLD
--new-datadir=$PGDATANEW
--old-bindir=$PGBINOLD
--new-bindir=$PGBINNEW
--swap
--jobs=$(nproc)

4.4. Copy Configuration Files

# Copy các config files từ cluster cũ
cp /etc/postgresql/17/main/postgresql.conf /etc/postgresql/18/main/
cp /etc/postgresql/17/main/pg_hba.conf /etc/postgresql/18/main/
cp /etc/postgresql/17/main/pg_ident.conf /etc/postgresql/18/main/

Hoặc nếu dùng data directory cho config

cp $PGDATAOLD/postgresql.conf $PGDATANEW/ cp $PGDATAOLD/pg_hba.conf $PGDATANEW/

Cập nhật port trong postgresql.conf nếu cần

(nếu muốn chạy song song cả 2 version)

sed -i 's/port = 5432/port = 5433/' /etc/postgresql/18/main/postgresql.conf

4.5. Start PostgreSQL 18 & Verify

# Start PostgreSQL 18
sudo systemctl start postgresql@18-main

Verify connection

psql -p 5432 -c "SELECT version();"

Output: PostgreSQL 18.1 on x86_64-pc-linux-gnu...

Verify databases

psql -c "\l"

Verify table counts (sample)

psql -d your_database -c "SELECT schemaname, COUNT(*) FROM pg_tables GROUP BY schemaname;"


5. Post-Upgrade Tasks

5.1. Statistics Handling (PostgreSQL 18 tự động preserve)

# PostgreSQL 18 tự động preserve statistics!

Chỉ cần chạy cho extended statistics nếu có:

/usr/lib/postgresql/18/bin/vacuumdb
--all
--analyze-in-stages
--missing-stats-only

Hoặc chạy đầy đủ nếu muốn

vacuumdb --all --analyze

5.2. Extension Updates

# Kiểm tra extensions cần update
psql -c "SELECT * FROM pg_extension WHERE extversion != (SELECT default_version FROM pg_available_extensions WHERE name = extname);"

Update tất cả extensions

psql -c "SELECT format('ALTER EXTENSION %I UPDATE;', extname) FROM pg_extension;" | psql

Hoặc update từng extension

psql -c "ALTER EXTENSION pg_stat_statements UPDATE;" psql -c "ALTER EXTENSION postgis UPDATE;"

5.3. Cleanup

# Xóa cluster cũ (CHỈ SAU KHI VERIFY HOÀN TẤT!)

pg_upgrade tạo script delete_old_cluster.sh

./delete_old_cluster.sh

Hoặc thủ công

rm -rf /var/lib/postgresql/17/main

Disable PostgreSQL 17 service

sudo systemctl disable postgresql@17-main

5.4. Performance Validation

-- Kiểm tra query plan của các query quan trọng
EXPLAIN (ANALYZE, BUFFERS, VERBOSE)
SELECT * FROM your_critical_table WHERE your_condition;

-- So sánh với baseline trước upgrade -- Lưu ý: PostgreSQL 18 EXPLAIN ANALYZE tự động include BUFFERS

-- Kiểm tra AIO settings (PostgreSQL 18) SHOW io_method; -- Output: io_uring (Linux) hoặc worker

-- Monitor với pg_stat_io (mới trong PG16, cải thiện PG18) SELECT * FROM pg_stat_io WHERE reads > 0;


6. Upgrade Với Logical Replication (Zero-Downtime)

6.1. Tổng Quan Architecture

┌──────────────────────┐         ┌──────────────────────┐
│   PostgreSQL 17.6    │         │   PostgreSQL 18.1    │
│     (Publisher)      │  ─────► │    (Subscriber)      │
│   Primary/Source     │   WAL   │   Target/Replica     │
│     Port: 5432       │         │     Port: 5433       │
└──────────────────────┘         └──────────────────────┘
│
▼
Cutover (DNS/HAProxy)

6.2. Setup Publisher (PostgreSQL 17)

-- 1. Enable logical replication trong postgresql.conf
-- wal_level = logical
-- max_replication_slots = 10
-- max_wal_senders = 10

-- 2. Tạo publication CREATE PUBLICATION pg18_migration FOR ALL TABLES;

-- 3. Tạo replication user CREATE USER repl_user WITH REPLICATION PASSWORD 'secure_password'; GRANT SELECT ON ALL TABLES IN SCHEMA public TO repl_user;

-- 4. Cập nhật pg_hba.conf -- host all repl_user subscriber_ip/32 scram-sha-256 -- host replication repl_user subscriber_ip/32 scram-sha-256

6.3. Setup Subscriber (PostgreSQL 18)

# 1. Dump schema only (không data)
pg_dump -h old_server -U postgres -s -d your_db > schema.sql

2. Restore schema vào PostgreSQL 18

psql -d your_db -f schema.sql

-- 3. Tạo subscription
CREATE SUBSCRIPTION pg18_sub
CONNECTION 'host=old_server port=5432 dbname=your_db user=repl_user password=secure_password'
PUBLICATION pg18_migration;

-- 4. Monitor sync progress SELECT * FROM pg_stat_subscription; SELECT * FROM pg_subscription_rel;

-- 5. Kiểm tra lag SELECT slot_name, pg_size_pretty(pg_wal_lsn_diff(pg_current_wal_lsn(), confirmed_flush_lsn)) as lag FROM pg_replication_slots;

6.4. Cutover Process

#!/bin/bash

cutover.sh - Zero-downtime cutover script

echo "=== Starting Cutover Process ==="

1. Stop writes to old server (application level)

echo "1. Stopping application writes..."

kubectl scale deployment/app --replicas=0

hoặc update HAProxy/PgBouncer

2. Wait for replication to catch up

echo "2. Waiting for replication lag to be 0..." while true; do LAG=$(psql -h new_server -p 5433 -t -c
"SELECT pg_wal_lsn_diff(pg_current_wal_lsn(), confirmed_flush_lsn) FROM pg_replication_slots WHERE slot_name='pg18_sub'") if [ "$LAG" -eq 0 ]; then break fi sleep 1 done

3. Disable subscription

echo "3. Disabling subscription..." psql -h new_server -p 5433 -c "ALTER SUBSCRIPTION pg18_sub DISABLE;" psql -h new_server -p 5433 -c "DROP SUBSCRIPTION pg18_sub;"

4. Reset sequences (quan trọng!)

echo "4. Resetting sequences..." psql -h new_server -p 5433 -c "SELECT setval(c.oid, s.last_value) FROM pg_class c JOIN pg_sequences s ON c.relname = s.sequencename WHERE s.last_value IS NOT NULL;"

5. Switch traffic to new server

echo "5. Switching traffic..."

Update DNS, HAProxy, PgBouncer, etc.

echo "=== Cutover Complete ==="


7. Rollback Plan

# QUAN TRỌNG: Với --link mode, bạn KHÔNG THỂ rollback sau khi start cluster mới!

Do đó, LUÔN test kỹ trước khi start

Nếu chưa start PostgreSQL 18:

Chỉ cần start lại PostgreSQL 17

sudo systemctl start postgresql@17-main

7.2. Rollback Từ pg_upgrade --copy

# Nếu dùng --copy mode, cluster cũ vẫn còn nguyên

Chỉ cần switch về cluster cũ

sudo systemctl stop postgresql@18-main sudo systemctl start postgresql@17-main

7.3. Rollback Từ Logical Replication

-- Trên subscriber (PostgreSQL 18)
ALTER SUBSCRIPTION pg18_sub DISABLE;
DROP SUBSCRIPTION pg18_sub;

-- Switch traffic về PostgreSQL 17 -- Update DNS/HAProxy/PgBouncer


8. Monitoring & Troubleshooting

8.1. Monitoring Script

#!/bin/bash

monitor-upgrade.sh

echo "=== PostgreSQL 18 Health Check ==="

1. Version

psql -c "SELECT version();"

2. Uptime

psql -c "SELECT pg_postmaster_start_time(), now() - pg_postmaster_start_time() as uptime;"

3. Active connections

psql -c "SELECT count(*) as active_connections FROM pg_stat_activity WHERE state = 'active';"

4. Database sizes

psql -c "SELECT datname, pg_size_pretty(pg_database_size(datname)) FROM pg_database ORDER BY pg_database_size(datname) DESC;"

5. Long running queries

psql -c "SELECT pid, now() - pg_stat_activity.query_start AS duration, query FROM pg_stat_activity WHERE state = 'active' AND now() - pg_stat_activity.query_start > interval '5 minutes';"

6. Replication status (if applicable)

psql -c "SELECT * FROM pg_stat_replication;"

7. I/O statistics (PostgreSQL 18)

psql -c "SELECT backend_type, reads, writes, extends FROM pg_stat_io WHERE reads > 0 OR writes > 0;"

9. Best Practices Summary

9.1. Pre-Upgrade

  • [ ] Đọc kỹ Release Notes PostgreSQL 18
  • [ ] Test upgrade trên staging/development environment
  • [ ] Backup đầy đủ (logical + physical)
  • [ ] Document rollback plan
  • [ ] Notify stakeholders về maintenance window
  • [ ] Kiểm tra compatibility của tất cả extensions

9.2. During Upgrade

  • [ ] Sử dụng pg_upgrade --check trước khi upgrade thực sự
  • [ ] Monitor disk space trong quá trình upgrade
  • [ ] Giữ terminal session với screen hoặc tmux
  • [ ] Log tất cả output để troubleshoot

9.3. Post-Upgrade

  • [ ] Verify data integrity
  • [ ] Test critical queries và so sánh với baseline
  • [ ] Update extensions
  • [ ] Monitor performance 24-48 giờ
  • [ ] Cleanup old cluster sau khi verify hoàn tất
  • [ ] Update documentation và runbooks

10. Kết Luận

PostgreSQL 18 mang đến nhiều cải tiến đáng giá, đặc biệt là Asynchronous I/O và Statistics Preservation giúp upgrade mượt mà hơn bao giờ hết. Với việc lập kế hoạch kỹ càng và follow đúng quy trình, bạn có thể upgrade production database với downtime tối thiểu và risk thấp.

Tài liệu tham khảo:


Nếu bài viết hữu ích, hãy chia sẻ và để lại comment bên dưới! 👇

DUY TRAN
Tác giả

DUY TRAN

Pursuing an AI-first mindset and intelligent system architecture. I build solutions by combining technology, creativity, and the ability to see structure in chaos — the foundation for becoming a Solution Architect.

Bình luận

Bài viết liên quan

Circuit Breaker Pattern trong Spring Boot
DevOps

Circuit Breaker Pattern trong Spring Boot

Tìm hiểu Circuit Breaker Pattern trong Spring Boot với Resilience4j - từ nguyên lý hoạt động, cấu hình chi tiết, ví dụ thực tế đến best practices. Hướng dẫn đầy đủ giúp bạn xây dựng hệ thống microservices resilient, ngăn chặn cascading failures và tự động recovery khi service gặp sự cố.

Duy TranDuy Tran35 phút