Cách khắc phục nhanh
Để xóa một slot hiện đang được sử dụng, bạn phải dừng tiến trình backend (PID) đang giữ nó. Chạy ba lệnh sau trong terminal hoặc bảng điều khiển SQL của bạn:
-- 1. Tìm PID đang sử dụng slot
SELECT active_pid
FROM pg_replication_slots
WHERE slot_name = 'my_subscription_slot';
-- 2. Chấm dứt tiến trình đó
-- Thay thế 1234 bằng PID từ bước 1
SELECT pg_terminate_backend(1234);
-- 3. Xóa slot ngay lập tức
SELECT pg_drop_replication_slot('my_subscription_slot');
Nguyên nhân gốc rễ
PostgreSQL khóa một replication slot bất cứ khi nào một tiến trình worker (Walsender) đang truyền dữ liệu. Khóa này ngăn chặn việc mất dữ liệu vô ý. Nếu bạn cố gắng xóa slot trong khi một subscriber đang kết nối, Postgres sẽ đưa ra lỗi bảo vệ để giữ cho luồng dữ liệu được nguyên vẹn.
Bạn thường sẽ thấy lỗi này trong các tình huống sau:
- Một instance subscriber vẫn đang chạy và cố gắng lấy dữ liệu.
- Các công cụ CDC như Debezium hoặc Airbyte đang có kết nối hoạt động.
- Sự cố mạng để lại một tiến trình "ma" trên máy chủ chưa hết thời gian chờ (timeout).
- Một pod Kubernetes bị kẹt trong vòng lặp crash (crash loop), liên tục kết nối lại mỗi 500ms.
Các bước giải quyết
1. Xác định tiến trình đang hoạt động
Kiểm tra xem tiến trình nào đang chiếm giữ slot. View pg_replication_slots hiển thị active_pid. Nếu cột này chứa một con số, slot đó đang bị khóa.
SELECT slot_name, active, active_pid
FROM pg_replication_slots
WHERE slot_name = 'my_subscription_slot';
2. Xác định Client
Đừng thao tác mù quáng. Tốt hơn là nên biết bạn sắp dừng tiến trình nào. Kết hợp (join) view slots với pg_stat_activity để xem tên ứng dụng và địa chỉ IP.
SELECT
s.slot_name,
a.application_name,
a.client_addr,
a.backend_start
FROM pg_replication_slots s
JOIN pg_stat_activity a ON s.active_pid = a.pid
WHERE s.slot_name = 'my_subscription_slot';
3. Chấm dứt và Xóa
Nếu một dịch vụ như Debezium đang chạy, nó có thể sẽ kết nối lại ngay lập tức khi bạn dừng PID. Hãy dừng ứng dụng tiêu thụ (consumer application) trước. Nếu bạn không thể dừng ứng dụng, bạn phải thực hiện lệnh chấm dứt và lệnh xóa liên tiếp thật nhanh.
-- Ngắt kết nối
SELECT pg_terminate_backend(active_pid)
FROM pg_replication_slots
WHERE slot_name = 'my_subscription_slot';
-- Xóa slot ngay lập tức
SELECT pg_drop_replication_slot('my_subscription_slot');
Xử lý tình huống kết nối lại liên tục
Các dịch vụ quản lý hoặc pod Kubernetes thường kết nối lại trong vòng vài mili giây. Nếu slot hoạt động trở lại trước khi bạn kịp nhập lệnh tiếp theo, hãy sử dụng các chiến lược sau.
Tùy chọn A: Vô hiệu hóa Subscriber (Cách tốt nhất)
Trên cơ sở dữ liệu đích, hãy dừng subscription. Đây là cách sạch nhất để giải phóng slot.
-- Chạy lệnh này trên cơ sở dữ liệu SUBSCRIBER/ĐÍCH
ALTER SUBSCRIPTION my_sub DISABLE;
ALTER SUBSCRIPTION my_sub SET (slot_name = NONE);
Bây giờ hãy quay lại publisher và xóa slot mà không gặp bất kỳ sự can thiệp nào.
Tùy chọn B: Phím tắt dấu chấm phẩy
Chạy cả hai lệnh trên một dòng duy nhất. Điều này giảm thiểu khoảng thời gian client có thể kết nối lại.
SELECT pg_terminate_backend(active_pid) FROM pg_replication_slots WHERE slot_name = 'my_subscription_slot'; SELECT pg_drop_replication_slot('my_subscription_slot');
Tại sao điều này quan trọng đối với dung lượng đĩa
Một replication slot đang hoạt động nhưng bị chậm trễ là "kẻ giết người thầm lặng" đối với bộ nhớ lưu trữ. Nó buộc PostgreSQL phải giữ các tệp WAL trên đĩa vô thời hạn. Chúng tôi đã thấy những trường hợp một slot bị bỏ quên tiêu tốn hơn 200GB không gian pg_wal chỉ trong vài giờ. Khi bạn xóa slot, Postgres sẽ tự động thu hồi không gian này trong lần checkpoint tiếp theo.
Các lỗi thường gặp
- Quyền hạn: Bạn cần quyền superuser hoặc role
REPLICATIONđể quản lý các slot. - Hạn chế trên Cloud: Trên AWS RDS,
pg_drop_replication_slothoạt động bình thường, nhưng hãy đảm bảo bạn không sử dụng tác vụ AWS DMS được quản lý vốn tự động tạo lại slot. - Primary vs Replica: Bạn chỉ có thể xóa một slot trên node nơi nó được tạo ra. Nếu bạn đang ở trên một Read Replica, lệnh sẽ thất bại; bạn phải chạy nó trên instance Primary.

