Vũ Văn HảiFull-stack · AI-native
Hướng dẫnBlog
Trao đổi dự án

© 2026 Vũ Văn Hải · Viết từ kinh nghiệm triển khai thật.

Trang chủHướng dẫnBlogRSS
  1. Hướng dẫn
  2. /Database
  3. /Tối ưu hiệu suất VPS: swap, PostgreSQL và DB pool

Tối ưu hiệu suất VPS: swap, PostgreSQL và DB pool

Tối ưu VPS Ubuntu 16GB RAM chạy nhiều Docker container cùng PostgreSQL: thêm swap để tránh OOM Killer, chỉnh cấu hình PostgreSQL cho RAM lớn và SSD, rồi tăng connection pool trong ứng dụng.

Cập nhật: 21 thg 9, 20269 phút đọc
PostgreSQLVPSHiệu năngUbuntu
Mục lục
  • Tóm tắt thao tác nhanh
  • Kiểm tra hệ thống trước khi tối ưu
  • Tăng swap (không downtime)
  • Tối ưu PostgreSQL (cần restart khoảng 3-5 giây)
  • Phần 1: Tăng swap - chống OOM Killer
  • Tại sao cần tăng swap?
  • Bước 1.1 - Kiểm tra swap hiện tại
  • Bước 1.2 - Tạo thêm 4GB swap
  • Bước 1.3 - Đảm bảo swap tự mount khi reboot
  • Bước 1.4 - Xác nhận swap đã tăng
  • Phần 2: Tối ưu PostgreSQL - tăng hiệu suất 2-5 lần
  • Tại sao PostgreSQL mặc định chạy chậm?
  • Bảng chỉnh config (cho server 16GB RAM)
  • Bước 2.1 - Tìm đường dẫn file config
  • Bước 2.2 - Backup config cũ
  • Bước 2.3 - Chạy script tự động chỉnh config
  • Bước 2.4 - Kiểm tra config đã đúng chưa
  • Bước 2.5 - Restart PostgreSQL
  • Bước 2.6 - Xác nhận PostgreSQL hoạt động bình thường
  • Phần 3: Tăng DB connection pool trong ứng dụng
  • Tại sao cần tăng pool?
  • Thực hiện (trên máy local, không phải VPS)
  • Xử lý sự cố và lưu ý
  • Rollback cấu hình PostgreSQL
  • Xóa swap nếu cần
  • PostgreSQL không start sau khi chỉnh config
  • Kiểm tra slow query log
  • Công cụ hữu ích

Bài này tối ưu hiệu suất một VPS Ubuntu đang chạy nhiều Docker container và PostgreSQL, gồm ba phần: tăng swap để tránh OOM, chỉnh cấu hình PostgreSQL cho server 16GB RAM, và tăng DB connection pool trong ứng dụng. Dùng bài này khi:

  • VPS chạy chậm, swap gần cạn kiệt
  • PostgreSQL vẫn dùng cấu hình mặc định (chỉ 128MB shared_buffers)
  • Ứng dụng thường bị lỗi "too many connections" hoặc timeout

Các đường dẫn trong bài dùng PostgreSQL 16 - đổi 16 theo phiên bản của bạn. Các giá trị cấu hình được tính cho VPS 16GB RAM + SSD.

Tóm tắt thao tác nhanh

Nếu đã hiểu mình đang làm gì, ba khối lệnh dưới đây là đủ. Phần giải thích từng bước nằm ở các mục sau.

Kiểm tra hệ thống trước khi tối ưu

echo "===== SYSTEM INFO =====" && \
echo "--- RAM ---" && free -h && \
echo "--- DISK ---" && df -h / && \
echo "===== POSTGRESQL =====" && \
sudo -u postgres psql -c "SHOW shared_buffers;" && \
sudo -u postgres psql -c "SHOW effective_cache_size;" && \
sudo -u postgres psql -c "SHOW work_mem;" && \
sudo -u postgres psql -c "SHOW max_connections;" && \
sudo -u postgres psql -c "SELECT count(*) as active_connections FROM pg_stat_activity;"

Tăng swap (không downtime)

sudo fallocate -l 4G /swapfile2 && sudo chmod 600 /swapfile2 && \
sudo mkswap /swapfile2 && sudo swapon /swapfile2 && \
echo '/swapfile2 none swap sw 0 0' | sudo tee -a /etc/fstab

Tối ưu PostgreSQL (cần restart khoảng 3-5 giây)

PG_CONF="/etc/postgresql/16/main/postgresql.conf"
sudo cp $PG_CONF ${PG_CONF}.bak.$(date +%Y%m%d)
sudo sed -i "s/^#*shared_buffers\s*=.*/shared_buffers = 512MB/" $PG_CONF
sudo sed -i "s/^#*effective_cache_size\s*=.*/effective_cache_size = 6GB/" $PG_CONF
sudo sed -i "s/^#*work_mem\s*=.*/work_mem = 8MB/" $PG_CONF
sudo sed -i "s/^#*maintenance_work_mem\s*=.*/maintenance_work_mem = 128MB/" $PG_CONF
sudo sed -i "s/^#*wal_buffers\s*=.*/wal_buffers = 16MB/" $PG_CONF
sudo sed -i "s/^#*checkpoint_completion_target\s*=.*/checkpoint_completion_target = 0.9/" $PG_CONF
sudo sed -i "s/^#*random_page_cost\s*=.*/random_page_cost = 1.1/" $PG_CONF
sudo sed -i "s/^#*effective_io_concurrency\s*=.*/effective_io_concurrency = 200/" $PG_CONF
sudo sed -i "s/^#*log_min_duration_statement\s*=.*/log_min_duration_statement = 1000/" $PG_CONF
sudo systemctl restart postgresql

Phần 1: Tăng swap - chống OOM Killer

Tại sao cần tăng swap?

Swap là vùng ổ cứng được hệ thống dùng như RAM dự phòng. Khi RAM vật lý cạn kiệt, Linux chuyển các dữ liệu ít dùng từ RAM sang swap để giải phóng bộ nhớ.

Nếu cả RAM lẫn swap đều hết, Linux kích hoạt OOM Killer (Out of Memory Killer), tự động giết các process tiêu tốn RAM nhất - có thể chính là PostgreSQL hoặc Docker container của bạn.

VPS 16GB RAM chạy khoảng 30 Docker container thì swap mặc định 2GB là không đủ. Cần tăng lên ít nhất 6GB.

Bước 1.1 - Kiểm tra swap hiện tại

echo "=== SWAP HIỆN TẠI ===" && swapon --show && free -h | grep Swap

Kết quả cho thấy swap hiện tại là bao nhiêu và đã dùng bao nhiêu. Nếu used gần bằng total thì cần tăng gấp.

Bước 1.2 - Tạo thêm 4GB swap

# Tạo file 4GB làm swap
sudo fallocate -l 4G /swapfile2

# Chỉ cho phép root đọc/ghi (bảo mật)
sudo chmod 600 /swapfile2

# Format file thành swap
sudo mkswap /swapfile2

# Kích hoạt swap ngay lập tức (không cần restart)
sudo swapon /swapfile2

Giải thích từng lệnh:

LệnhTác dụng
fallocate -l 4GTạo file rỗng 4GB trên ổ cứng
chmod 600Chỉ root mới đọc/ghi được file này (tránh lỗ hổng bảo mật)
mkswapĐánh dấu file này là vùng swap (format)
swaponKích hoạt ngay, không cần reboot

Bước 1.3 - Đảm bảo swap tự mount khi reboot

echo '/swapfile2 none swap sw 0 0' | sudo tee -a /etc/fstab

File /etc/fstab chứa danh sách các phân vùng tự động mount khi khởi động. Nếu bỏ qua bước này, swap sẽ mất sau khi reboot VPS.

Bước 1.4 - Xác nhận swap đã tăng

echo "=== SWAP SAU KHI TĂNG ===" && swapon --show && free -h | grep Swap

Kết quả mong đợi: swap total khoảng 6GB (2GB cũ + 4GB mới).

Phần 2: Tối ưu PostgreSQL - tăng hiệu suất 2-5 lần

Tại sao PostgreSQL mặc định chạy chậm?

PostgreSQL được cấu hình mặc định rất bảo thủ (chỉ dùng 128MB RAM) để chạy được trên mọi server, kể cả máy chỉ có 512MB RAM. Trên VPS 16GB RAM, việc tối ưu config sẽ giúp:

  • Query nhanh hơn 2-5 lần nhờ cache nhiều dữ liệu hơn trong RAM
  • Sort/Join nhanh hơn nhờ tăng bộ nhớ cho mỗi truy vấn
  • VACUUM nhanh hơn, bảng không bị bloat

Bảng chỉnh config (cho server 16GB RAM)

Tham sốMặc địnhChỉnh thànhGiải thích
shared_buffers128 MB (quá thấp)512 MBCache dữ liệu trong RAM. Rule of thumb: 25-40% RAM dành cho PG
effective_cache_size4 GB6 GBGợi ý cho PG biết tổng RAM có thể dùng cho cache (OS + PG)
work_mem4 MB8 MBRAM cho mỗi thao tác sort/hash join. Cẩn thận: mỗi connection dùng riêng
maintenance_work_mem64 MB128 MBRAM cho VACUUM, CREATE INDEX. Chỉ chạy một lúc nên tăng được
wal_buffers-1 (auto)16 MBBuffer cho Write-Ahead Log. 16MB là best practice
checkpoint_completion_target0.50.9Dàn đều I/O khi checkpoint, tránh spike
random_page_cost4.01.1Cho SSD. Giúp PG ưu tiên Index Scan thay vì Seq Scan
effective_io_concurrency1200Cho SSD. Cho phép PG đọc nhiều trang đồng thời
log_min_duration_statement-1 (tắt)1000Log các query chạy hơn 1 giây. Giúp tìm query chậm

Các giá trị trên tối ưu cho VPS 16GB RAM + SSD. Nếu server khác cấu hình, dùng PGTune để tính lại.

Bước 2.1 - Tìm đường dẫn file config

sudo -u postgres psql -c "SHOW config_file;"

Thông thường sẽ là /etc/postgresql/16/main/postgresql.conf (đổi 16 theo phiên bản PG của bạn).

Bước 2.2 - Backup config cũ

# ĐỔI đường dẫn nếu phiên bản PG khác 16
sudo cp /etc/postgresql/16/main/postgresql.conf /etc/postgresql/16/main/postgresql.conf.bak.$(date +%Y%m%d)

Luôn backup trước khi chỉnh. Nếu có vấn đề, bạn có thể rollback ngay (xem mục "Rollback cấu hình PostgreSQL" ở cuối bài).

Bước 2.3 - Chạy script tự động chỉnh config

Copy toàn bộ khối dưới đây vào terminal:

# ĐỔI đường dẫn nếu phiên bản PG khác 16
PG_CONF="/etc/postgresql/16/main/postgresql.conf"

# Bộ nhớ chính
sudo sed -i "s/^#*shared_buffers\s*=.*/shared_buffers = 512MB/" $PG_CONF
sudo sed -i "s/^#*effective_cache_size\s*=.*/effective_cache_size = 6GB/" $PG_CONF
sudo sed -i "s/^#*work_mem\s*=.*/work_mem = 8MB/" $PG_CONF
sudo sed -i "s/^#*maintenance_work_mem\s*=.*/maintenance_work_mem = 128MB/" $PG_CONF

# Write-Ahead Log
sudo sed -i "s/^#*wal_buffers\s*=.*/wal_buffers = 16MB/" $PG_CONF
sudo sed -i "s/^#*checkpoint_completion_target\s*=.*/checkpoint_completion_target = 0.9/" $PG_CONF

# Tối ưu cho SSD
sudo sed -i "s/^#*random_page_cost\s*=.*/random_page_cost = 1.1/" $PG_CONF
sudo sed -i "s/^#*effective_io_concurrency\s*=.*/effective_io_concurrency = 200/" $PG_CONF

# Logging
sudo sed -i "s/^#*log_min_duration_statement\s*=.*/log_min_duration_statement = 1000/" $PG_CONF

echo "Config đã được cập nhật!"

sed -i là lệnh tìm và thay thế text ngay trong file. Pattern s/^#*param\s*=.*/param = value/ hoạt động như sau:

  • ^#* - bỏ dấu # nếu dòng đang bị comment
  • \s*=.* - tìm phần = giá_trị_cũ
  • Thay cả dòng bằng giá trị mới

Bước 2.4 - Kiểm tra config đã đúng chưa

PG_CONF="/etc/postgresql/16/main/postgresql.conf"
echo "=== CONFIG MỚI ===" && \
grep -E "^(shared_buffers|effective_cache_size|work_mem|maintenance_work_mem|wal_buffers|checkpoint_completion_target|random_page_cost|effective_io_concurrency|log_min_duration_statement)" $PG_CONF

Kết quả mong đợi:

shared_buffers = 512MB
effective_cache_size = 6GB
work_mem = 8MB
maintenance_work_mem = 128MB
wal_buffers = 16MB
checkpoint_completion_target = 0.9
random_page_cost = 1.1
effective_io_concurrency = 200
log_min_duration_statement = 1000

Bước 2.5 - Restart PostgreSQL

sudo systemctl restart postgresql

Restart sẽ ngắt tất cả kết nối DB trong khoảng 3-5 giây. Nên làm lúc ít người dùng nhất (ví dụ: 2-4 giờ sáng).

Bước 2.6 - Xác nhận PostgreSQL hoạt động bình thường

echo "=== PG STATUS ===" && \
sudo systemctl status postgresql --no-pager | head -5 && \
echo "" && \
echo "=== CONFIG VERIFY ===" && \
sudo -u postgres psql -c "SHOW shared_buffers;" && \
sudo -u postgres psql -c "SHOW effective_cache_size;" && \
sudo -u postgres psql -c "SHOW work_mem;" && \
sudo -u postgres psql -c "SHOW maintenance_work_mem;" && \
echo "" && \
echo "=== CONNECTIONS ===" && \
sudo -u postgres psql -c "SELECT count(*) as active_connections FROM pg_stat_activity;" && \
echo "" && \
echo "=== MEMORY SAU RESTART ===" && \
free -h

Kiểm tra: shared_buffers hiển thị 512MB, PG status là active (running).

Phần 3: Tăng DB connection pool trong ứng dụng

Tại sao cần tăng pool?

Mỗi request từ ứng dụng cần một kết nối đến PostgreSQL. Connection pool duy trì sẵn một số kết nối mở để tái sử dụng, tránh overhead tạo kết nối mới.

  • Pool quá nhỏ: request phải xếp hàng chờ, dẫn tới timeout
  • Pool quá lớn: lãng phí RAM (mỗi connection dùng khoảng 5-10MB)

Quy tắc: pool size <= max_connections * 0.8 để chừa headroom cho admin/monitoring.

Thực hiện (trên máy local, không phải VPS)

Sửa file cấu hình database pool trong source code, thay đổi giá trị max:

const pool = new pg.Pool({
  connectionString: env.DATABASE_URL,
  max: 30,                        // Tăng từ 20 -> 30
  idleTimeoutMillis: 30_000,      // Đóng connection idle sau 30s
  connectionTimeoutMillis: 10_000, // Timeout nếu không lấy được connection sau 10s
});

Sau khi sửa, rebuild và deploy lại backend.

Xử lý sự cố và lưu ý

Rollback cấu hình PostgreSQL

Nếu sau khi restart PostgreSQL mà có vấn đề (lỗi khởi động, out of memory):

# ĐỔI đường dẫn và ngày nếu cần
sudo cp /etc/postgresql/16/main/postgresql.conf.bak.$(date +%Y%m%d) /etc/postgresql/16/main/postgresql.conf
sudo systemctl restart postgresql

Xóa swap nếu cần

sudo swapoff /swapfile2
sudo rm /swapfile2
# Xóa dòng /swapfile2 trong /etc/fstab
sudo sed -i '/swapfile2/d' /etc/fstab

PostgreSQL không start sau khi chỉnh config

Kiểm tra log lỗi:

sudo tail -50 /var/log/postgresql/postgresql-16-main.log

Lỗi thường gặp:

Triệu chứngCách xử lý
shared_buffers quá lớnGiảm xuống. Tối đa nên là 40% RAM
Sai cú pháp trong configKiểm tra lại file, chú ý không có space thừa

Kiểm tra slow query log

Sau khi bật log_min_duration_statement = 1000, các query chạy hơn 1 giây sẽ được log vào:

sudo tail -f /var/log/postgresql/postgresql-16-main.log | grep "duration"

Công cụ hữu ích

  • PGTune - tính config tối ưu cho server của bạn
  • pg_stat_statements - extension theo dõi query performance
  • htop - xem RAM/CPU realtime trên VPS
Bài trướcSửa lỗi Docker container không kết nối được PostgreSQL trên VPSBài tiếp theoKết nối PostgreSQL trên VPS qua SSH Tunnel từ máy local

Bài liên quan

  • Migrate database PostgreSQL giữa hai VPS bằng pg_dump và psql

    Di chuyển toàn bộ một database PostgreSQL (schema lẫn data) từ VPS nguồn sang VPS đích qua máy local: dump bằng pg_dump, restore trong một transaction, verify số dòng, cutover và rollback an toàn.

    Database

    Database
  • Cài đặt PostgreSQL trên VPS an toàn

    Cài và cấu hình PostgreSQL trên VPS Ubuntu/Debian cho production: tạo database và user, mở kết nối từ xa an toàn (SSL + pg_hba + UFW), và hiểu transaction isolation.

    Database

    Database
  • Đặt app ở đâu trên VPS? Cấu trúc thư mục chuẩn /opt/apps

    Quy ước đặt mỗi app trong một thư mục con của /opt/apps trên VPS: chown thư mục cha một lần duy nhất, từ đó git clone, git pull và sửa .env đều không cần sudo.

    VPS

    VPS

Viết bởi Vũ Văn Hải

Tôi là Hải, full-stack developer ở TP. Hồ Chí Minh. Các bài ở đây đúc kết từ những hệ thống tôi tự dựng và vận hành. Cần dựng hoặc gỡ rối một hệ thống tương tự? Cứ nhắn tôi.

Trao đổi dự ánXem thêm hướng dẫn

Thấy sai sót hoặc lệnh không còn chạy? Báo cho tôi

Mục lục

  • Tóm tắt thao tác nhanh
  • Kiểm tra hệ thống trước khi tối ưu
  • Tăng swap (không downtime)
  • Tối ưu PostgreSQL (cần restart khoảng 3-5 giây)
  • Phần 1: Tăng swap - chống OOM Killer
  • Tại sao cần tăng swap?
  • Bước 1.1 - Kiểm tra swap hiện tại
  • Bước 1.2 - Tạo thêm 4GB swap
  • Bước 1.3 - Đảm bảo swap tự mount khi reboot
  • Bước 1.4 - Xác nhận swap đã tăng
  • Phần 2: Tối ưu PostgreSQL - tăng hiệu suất 2-5 lần
  • Tại sao PostgreSQL mặc định chạy chậm?
  • Bảng chỉnh config (cho server 16GB RAM)
  • Bước 2.1 - Tìm đường dẫn file config
  • Bước 2.2 - Backup config cũ
  • Bước 2.3 - Chạy script tự động chỉnh config
  • Bước 2.4 - Kiểm tra config đã đúng chưa
  • Bước 2.5 - Restart PostgreSQL
  • Bước 2.6 - Xác nhận PostgreSQL hoạt động bình thường
  • Phần 3: Tăng DB connection pool trong ứng dụng
  • Tại sao cần tăng pool?
  • Thực hiện (trên máy local, không phải VPS)
  • Xử lý sự cố và lưu ý
  • Rollback cấu hình PostgreSQL
  • Xóa swap nếu cần
  • PostgreSQL không start sau khi chỉnh config
  • Kiểm tra slow query log
  • Công cụ hữu ích