Stack Overflow: The Architecture - 2016 Edition
Stack Overflow · 2016 · 3. Quy mô lớn · Độ khó: Dễ — bài gốc
Bài 1 trong series của Nick Craver. Tiền thân: Stack Overflow 2013; các bài sau: Stack Overflow 2016, Stack Overflow 2016, Stack Overflow 2018, Stack Overflow 2019.
Bối cảnh
Số liệu một ngày (9/2/2016):
- 209 triệu HTTP request, trong đó 66 triệu page load;
- 504 triệu SQL query, 5,8 tỷ Redis hit;
- trang câu hỏi render trung bình 22,7ms, trang chủ 11,8ms.
So với 11/2013: thêm 61 triệu request/ngày mà thời gian xử lý ASP.Net giảm từ 757 xuống 447 giờ, nhờ nâng cấp phần cứng 2015 và tối ưu code ("performance is still a feature").
Thay đổi chính (kiến trúc 2016, gần như không đổi so với 2013)
- Phần cứng toàn bộ: 4 SQL Server, 11 web server IIS, 2 Redis, 3 tag engine, 3 Elasticsearch, 4 HAProxy. Thực tế chỉ cần 1 web server, và họ đã vô tình thử điều đó vài lần.
- Ứng dụng Q&A multi-tenant: một app phục vụ mọi site Stack Exchange; có thể chạy cả mạng lưới trên một app pool.
- Service tier: tag engine và API nội bộ chạy 3 bản thay vì 9, vì việc nặng (tải lại bài và tag mỗi 2 phút) không cần lặp trên mọi web server.
- Cache 2 tầng: L1 là HTTP cache trong process, L2 là Redis (dữ liệu dạng Protobuf). Miss cả hai thì lấy từ nguồn và ghi vào cả hai. Pub/sub của Redis dùng để xoá L1 trên các server khác. Redis ~160 tỷ op/tháng mà mỗi instance dưới 2% CPU.
- Websocket: ~500.000 kết nối đồng thời lúc cao điểm, chạy ngay trên web tier, thay polling. Vấn đề họ gặp: cạn ephemeral port và file handle ở load balancer.
- SQL Server là nguồn sự thật duy nhất: 2 cluster AlwaysOn, mỗi cluster 1 master (gánh gần hết tải) + 1 replica ở New York + 1 replica ở Colorado (DR), replicate bất đồng bộ. Máy 384–768GB RAM, SSD PCIe. Dùng SQL đơn giản qua Dapper (micro-ORM tự viết); chỉ còn 1 stored procedure.
- Elasticsearch cho tìm kiếm, vì CPU của SQL Server đắt; index tăng dần bằng
ROWVERSION.
Vì sao
Theo Stack Overflow: SQL đơn giản thì nhanh; máy mạnh + cache tốt + code được tối ưu (họ tự viết nhiều thư viện hiệu năng cao: Dapper, StackExchange.Redis, Jil, MiniProfiler) đủ cho quy mô của họ. Họ cố ý cấp dư web tier vì rolling build, headroom và dự phòng.
Dự phòng (trả lời câu hỏi "scale dọc thì một điểm hỏng?")
"Mọi thứ đều dư thừa":
- mỗi server có một cặp ở rack còn lại;
- 2 nguồn điện, 2 UPS, 2 máy phát;
- 4 ISP, 4 router edge;
- cả hệ thống được nhân đôi ở data center thứ hai (Colorado).
Scale dọc ở đây đi kèm dư thừa theo chiều ngang ở mức hạ tầng, không phải chạy trên một máy duy nhất.
Bài học cho SWE
- Monolith + DB quan hệ + cache vẫn phục vụ được hàng trăm triệu request/ngày nếu đo mọi request (MiniProfiler chạy trên mọi trang) và tối ưu liên tục.
- Phân biệt cần bao nhiêu máy với chạy bao nhiêu máy: phần dư là để deploy và chịu lỗi.
- Đưa việc nặng, lặp lại ra một tầng riêng ít bản (tag engine) thay vì làm trên mọi web server.
- Đây là bối cảnh workload đọc nhiều, cache được tốt. Không suy ra rằng mọi hệ thống đều không cần tách.