Why Uber Engineering Switched from Postgres to MySQL
Bài tóm tắt Uber 2016 2. Tăng trưởng Độ khó: Nâng cao
Uber · 2016 · 2. Tăng trưởng · Độ khó: Nâng cao — bài gốc
Bối cảnh
- Kiến trúc ban đầu: monolith Python + Postgres. 2016: microservices, và phần lớn chỗ trước đây dùng Postgres giờ dùng Schemaless, một lớp sharding tự xây trên MySQL. Một số trường hợp đặc biệt dùng Cassandra.
- Phân tích dựa trên Postgres 9.2, bản khá cũ. Uber cho rằng kiến trúc lưu trữ này không đổi nhiều ở các bản sau.
- Hạ tầng lúc đó: colocation ở bờ Tây (master + replica), thêm bờ Đông cho disaster recovery.
Thay đổi chính (năm hạn chế Uber nêu về Postgres)
- Write amplification: tuple bất biến, index trỏ thẳng tới vị trí vật lý (ctid). Cập nhật một cột thì mọi index phải thêm bản ghi mới, dù cột đó không được index. Bảng có 12 index thì một update chạm cả 12.
- Replication tốn băng thông: WAL chứa thay đổi vật lý ở mức đĩa, nên khuếch đại ghi thành khuếch đại replication. Băng thông xuyên lục địa đắt và có giới hạn. Lúc cao điểm, lưu trữ WAL lên dịch vụ file không theo kịp.
- Hỏng dữ liệu: một bug của 9.2 khi promote master làm replica áp sai WAL. Có hàng xuất hiện hai lần, mỗi replica hỏng một kiểu. Họ phải dựng lại toàn bộ replica từ snapshot. Theo Uber, replication vật lý làm loại bug này có thể lan ra cả cây replication.
- Replica không có MVCC thật: transaction dài trên replica chặn việc áp WAL, nên Postgres phải kill transaction. Code dùng ORM dễ vô tình giữ transaction mở (ví dụ trong lúc gửi email).
- Nâng cấp khó: không replicate được giữa các bản GA khác nhau;
pg_upgrade+ snapshot mất nhiều giờ. Lên 9.2 xong là không dám nâng nữa (khi đó đã có 9.5). pglogical (9.4+) có thể giúp nhưng chưa vào mainline.
Vì sao MySQL/InnoDB (theo Uber)
- Index phụ trỏ tới khoá chính thay vì vị trí vật lý, nên update chỉ chạm index có liên quan; bản cũ được đưa vào rollback segment. Đánh đổi: tra index phụ phải tra hai lần.
- Replication logic gọn hơn, replica có MVCC thật, bug khó làm hỏng index; nâng cấp lần lượt từng replica rồi promote, gần như không downtime.
- Buffer pool tự quản ở userspace (ít context switch hơn page cache của kernel). Ví dụ của Uber: replica Postgres 768GB RAM nhưng chỉ ~25GB là RSS của Postgres.
- Thread-per-connection rẻ hơn process-per-connection. Uber gặp khó khi Postgres vượt vài trăm kết nối hoạt động; PgBouncer giúp được, nhưng bug app mở quá nhiều kết nối "idle in transaction" từng gây downtime kéo dài.
Bài học cho SWE
- Hiểu cách DB biểu diễn dữ liệu trên đĩa để đoán được chi phí của update, replication, nâng cấp.
- Lý do đổi DB gắn với workload cụ thể: nhiều index, nhiều update, replication xuyên vùng, khó nâng cấp. Đây là đánh đổi theo Uber, không phải phán quyết chung về Postgres. Bài này gây tranh cãi, và nhiều điểm dựa trên bản 9.2 cũ.
- Đối chiếu: Instagram và Figma vẫn chọn Postgres ở quy mô lớn (Instagram 2011, Figma 2024).
Liên quan
Được nhắc tới trong
Công ty (1)
Bài tóm tắt (3)