How we migrated Dropbox from Nginx to Envoy
Bài tóm tắt Dropbox 2020 4. Điều chỉnh Độ khó: Trung bình
Dropbox · 2020 · 4. Điều chỉnh · Độ khó: Trung bình — bài gốc
Theo nhóm tác giả, nhiều so sánh gắn với cách làm riêng của Dropbox (Bazel, gRPC, C++/Go) và chỉ xét Nginx bản mã nguồn mở.
Bối cảnh
- Hạ tầng traffic dựa trên Nginx gần mười năm: hàng chục triệu kết nối mở, hàng triệu request/giây, hàng terabit băng thông. Cấu hình phần lớn tĩnh, sinh bằng Python 2 + Jinja2 + YAML (cả ba đều cho logic, không có mô hình dữ liệu sạch), mọi thay đổi phải deploy lại; phần động (quản lý upstream, xuất stats) viết bằng Lua; logic phức tạp đẩy xuống tầng proxy Go phía sau (Bandaid).
- Không còn hợp cách làm hiện tại: API chuyển từ REST sang gRPC (cần transcoding), protobuf là chuẩn mô tả, mọi thứ build bằng Bazel. Vận hành đắt: giám sát chắp vá (Lua, parse error.log, exporter riêng), module bên thứ ba làm nâng cấp khó, quy trình deploy khác mọi service.
- Không chọn Bandaid: Go tốn tài nguyên hơn (GC, parser HTTP, TLS kém BoringSSL; goroutine mỗi request tốn bộ nhớ khi kết nối nhiều) mà ở edge thì không autoscale dễ; TLS của Go không có FIPS; không có cộng đồng ngoài Dropbox.
Thay đổi chính
- Hiệu năng: đo bằng công cụ tải nội bộ trên nhiều workload, Nginx và Envoy tương đương, nhưng Nginx có đuôi latency cao hơn (event loop đứng khi I/O nặng như mở file, ghi log, nhất là với
SO_REUSEPORT) và stats bằng Lua làm Nginx chậm 3 lần ở bài RPS cao (lua_shared_dictkhoá mutex giữa worker). Sau khi chuyển, giải phóng tới 60% số server trước đây chỉ dành cho Nginx. - Quan sát: Nginx miễn phí có 7 chỉ số; Envoy có hàng nghìn (khoảng 14.800 dòng Prometheus), admin interface đổi mức log khi đang chạy, profiler CPU/heap, đổi runtime flag không cần đẩy cấu hình; tracing; access log stream qua gRPC thay cầu syslog→Hive.
- Tích hợp qua control plane xDS tự viết (một service gRPC thường, viết bằng Go): EDS nối service discovery, SDS nối hệ phân phối secret, RTDS trỏ vào kho cấu hình phân tán để cả cụm nhận cùng flag (bản Nginx dựa trên kiểm file bằng Lua, dễ lệch giữa máy), RDS sinh từ định nghĩa service. Không còn file, signal, cron, logrotate, syslog.
- Cấu hình bằng protobuf + Python 3 có type annotation (mypy-protobuf), ràng buộc giá trị bằng protoc-gen-validate; tài liệu nằm cạnh định nghĩa. Mở rộng bằng plugin C++ (tích hợp hệ metric Vortex2 khoảng 200 dòng).
- Chuyển: chạy song song Nginx và Envoy hơn nửa năm, chuyển traffic dần bằng DNS: dữ liệu file của desktop client (gRPC end-to-end), metadata RPS cao, notification (hàng triệu kết nối; có thể chuyển long-poll sang streaming gRPC), API, proxy egress ra S3; www.dropbox.com chuyển sau cùng. Không gây sự cố đáng kể.
- Khó nhất là public API: client (script curl/wget, thiết bị nhúng HTTP/1.0) phụ thuộc ngầm vào hành vi của Nginx: gộp dấu
/, Host có port,Transfer-Encoding: Chunkedviết hoa, request có cả Content-Length lẫn chunked; vá và đưa lên upstream Envoy. Lỗi cấu hình hay gặp: circuit breaker mặc định của Envoy quá chặt cho proxy inbound; Envoy không buffer request ra đĩa như Nginx.
Vì sao
- Đổi proxy không vì hiệu năng thô mà vì khả năng tích hợp, quan sát và cấu hình có kiểu khớp với phần còn lại của hạ tầng; tiết kiệm server là hệ quả của bỏ stats chắp vá.
Bài học cho SWE
- Cấu hình sinh bằng nhiều ngôn ngữ có logic mà không có mô hình dữ liệu sẽ thành code không kiểm được; một schema có kiểu cho cấu hình rẻ hơn về lâu dài.
- Thay một thành phần "chuẩn công nghiệp" ở rìa thì client đã phụ thuộc vào hành vi không theo RFC của nó; chạy song song và chuyển dần theo loại traffic.
Liên quan
- Đổi ngôn ngữ và runtime · Observability và monitoring · Migration không downtime
- Cùng công ty: Dropbox 2017 · Dropbox 2021 (dùng gRPC-HTTP transcoding của Envoy)
- Proxy và mesh khác: Slack 2017
#Nginx#Envoy#Bandaid#edge proxy#xDS control plane#protobuf config#Lua stats#event loop stall#tail latency#gRPC transcoding#admin interface#access log over gRPC#circuit breaking#DNS traffic shift
Được nhắc tới trong
Công ty (1)