Incident review: API and Dashboard outage on 10 October 2017
Bài tóm tắt GoCardless 2017 2. Tăng trưởng Độ khó: Trung bình
GoCardless · 2017 · 2. Tăng trưởng · Độ khó: Trung bình — bài gốc
Bối cảnh
- Dữ liệu quan trọng nhất nằm trên Postgres 3 node: primary + 1 replica đồng bộ + 1 replica bất đồng bộ (mỗi lần ghi thành công đều có ít nhất 2 bản).
- Pacemaker tự promote replica khi primary hỏng và quản lý VIP (IP ảo) mà app Rails kết nối tới. Tự động hoá này đã chạy tốt suốt 2 năm.
Diễn biến
- 10/10/2017, 15:09–16:59 (BST): API và dashboard sập 1 giờ 50 phút. Nguyên nhân: mảng đĩa (RAID) của primary hỏng (3 đĩa mất cùng lúc), và Pacemaker không promote được replica, biến sự cố lẽ ra chỉ 1–2 phút thành gần 2 giờ.
- Mọi cách can thiệp vào Pacemaker đều thất bại (nó luôn đặt lại cấu hình replica). Cuối cùng họ tắt automation (maintenance mode), promote bằng tay, rồi trỏ app thẳng vào IP thật của primary mới.
- Sau đó: chạy với một VIP quản lý bằng tay, kiểm tra toàn vẹn dữ liệu (không thấy hỏng).
Điều tra
- Hai nhóm làm song song: một nhóm tái hiện lỗi, một nhóm chuẩn bị chuyển sang cluster mới.
- Dùng một cluster Postgres chạy trong Docker để viết script tái hiện lỗi và lặp thử nhanh.
- Manh mối giả: primary hỏng đã lưu trữ một file WAL lỗi, replica tải về rồi bỏ đi. Mất nhiều thời gian điều tra nhưng không liên quan.
- Cần đúng 3 điều kiện cùng lúc:
default-resource-stickinesskhác 0 (để tránh dời tài nguyên không cần thiết);- một Backup VIP với luật colocation
-INF"không bao giờ nằm cùng primary" (đang nằm ở đúng replica cần promote); - hai process crash gần như cùng lúc (Postgres trên primary và một tiến trình con trên replica đồng bộ).
- Cách sửa bất ngờ: viết luật ngược lại,
INF"luôn nằm cùng một replica". Về logic là tương đương, nhưng hành vi khi có lỗi hoàn toàn khác.
Thay đổi chính
- Không tin được cluster đã bị can thiệp tay nhiều, nên dựng cluster mới và chuyển traffic bằng cơ chế failover không downtime có sẵn: PgBouncer chạy sau một VIP riêng; tạm dừng query ở PgBouncer (xếp hàng) → promote → chuyển VIP Postgres → cho query chạy tiếp. Họ tập dượt vài tuần, vẫn thông báo cửa sổ bảo trì, chuyển trơn tru.
- Hướng tới: bỏ VIP, chạy proxy trên app server để route theo trạng thái cluster (ít tài nguyên do Pacemaker quản lý hơn).
Bài học (GoCardless tự nêu)
- Cấu hình trông đơn giản có thể có hành vi rất lạ khi lỗi: "không được ở cùng" khác "phải ở cùng".
- Có bug chỉ lộ ra qua fault injection (hai crash đồng thời). Họ muốn thêm game day khắc nghiệt hơn và chaos testing kiểu Chaos Monkey.
- Tự động hoá làm mai một kỹ năng: automation chạy tốt 2 năm thì kỹ năng thao tác tay teo đi, và runbook không dùng nhiều năm chắc chắn lỗi thời. Ý tưởng: game day có ràng buộc kiểu "automation hỏng rồi, phục hồi bằng cách khác".
- Vì sao không dùng Postgres managed (theo GoCardless): lúc đó ít nhà cung cấp hỗ trợ nâng cấp patch không downtime; hạ tầng của họ ở bare-metal, chuyển sang DB managed sẽ thêm latency (app đang giả định ≤1ms tới Postgres).
Bài học cho SWE
- Failover tự động là một hệ thống cũng phải được kiểm thử bằng lỗi thật. Cùng bài học với Netflix 2011: diễn tập chỉ chứng minh thứ nó mô phỏng (Netflix 2011).
- Lớp gián tiếp (PgBouncer + VIP) cho phép tạm dừng traffic trong lúc đổi primary, giống Figma (Figma 2023).
- Build vs buy cho DB phụ thuộc vào hạ tầng còn lại (latency từ bare-metal). Xem Chi phí hạ tầng và build vs buy.
Liên quan
Failover, replica và dự phòng dữ liệuMigration không downtimeChi phí hạ tầng và build vs buySự cố và postmortemTự động hoá vận hành và auto-remediation
Được nhắc tới trong
Chủ đề (5)
Công ty (1)