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.
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. Upgrade Với pg_upgrade (Recommended)
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
7.1. Rollback Từ pg_upgrade --link
# 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 --checktrước khi upgrade thực sự - [ ] Monitor disk space trong quá trình upgrade
- [ ] Giữ terminal session với
screenhoặctmux - [ ] 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! 👇