Making the LinkedIn experimentation engine 20x faster

Bài tóm tắt LinkedIn 2020 4. Điều chỉnh Độ khó: Khó

LinkedIn · 2020 · 4. Điều chỉnh · Độ khó: Khó — bài gốc

Bối cảnh

  • Mọi release ở LinkedIn đều qua thí nghiệm. Năm 2020 nền tảng: tới 800.000 QPS, khoảng 35.000 thí nghiệm chạy cùng lúc, tới 23 nghìn tỷ lượt evaluate/ngày, latency trung bình 700 ns (p99 3 µs), dùng trong khoảng 500 service production.
  • Lix Engine là thư viện chạy trong service, hiểu một DSL kiểu Lisp để chia ngẫu nhiên, phân khúc và gán biến thể. DSL được giao tới service độc lập với deploy code (nên cũng dùng làm feature flag và cấu hình định tuyến), tất định (không cần lưu ai được gán gì), và cố ý hạn chế (không vòng lặp, không đệ quy).
  • Engine viết bằng Clojure khoảng 2012. Vấn đề: không kiểm kiểu trong lõi, không đa hình; lazy sequence tạo object tạm chiếm ít nhất 30% heap của service dùng nó; cấu trúc bất biến tốn bộ nhớ, GC pause khoảng 0,5 giây; reflection, tìm method động, ép kiểu, exception và lock làm chậm; và gần như không còn ai viết được Clojure.

Thay đổi chính

  • Viết lại bằng Java: proof-of-concept nhanh hơn 2–3 lần ngay chưa tối ưu. Thông dịch cây đánh giá (đủ nhanh, làm nhanh hơn sinh bytecode). Sinh code lúc compile cho phân giải overload thay vì reflection (15 ns so với 45 ns mỗi call), từ một file đặc tả hợp đồng kiểu của từng toán tử.
  • Cây đánh giá lưu bằng ba mảng phẳng (node, số con, vị trí bắt đầu danh sách con): 60 byte so với 208 byte cho cách cài thông thường và nhanh hơn 2,5 lần nhờ truy cập bộ nhớ tuần tự.
  • Tránh remote call: toán tử như is-student cần gọi mạng (p99 4 ms so với 50 ns cục bộ); với and/or, thử các nhánh tính cục bộ trước, nhánh nào trả false thì bỏ hẳn remote call.
  • Kiểm tương đương v1/v2: unit test 80–90% dòng; bộ sinh test case từ cấu trúc từng DSL production phủ 99,9% nhánh; rồi chạy 8 tỷ test case trên Hadoop (4.000 tổ hợp tham số × 2 triệu bộ thuộc tính member) so v1 với v2, phủ 99,9998% nhánh.
  • Rollout bằng chính A/B test: phát hành client chứa cả hai engine, một thí nghiệm nội bộ chọn engine; mất 37 vòng và 8 tháng; giữa chừng mới thấy tầm quan trọng của cache remote call và A/B test ba kiểu cache cùng lúc.
  • Kết quả: nhanh hơn 20 lần tuần tự (14,7 lần đồng thời), bộ nhớ giảm 10,2 lần, rác tạm giảm 6 lần, không còn GC pause trên 50 ms; trung bình mọi API endpoint nhanh hơn 0,5%, vài service quan trọng nhanh gấp đôi, giải phóng hơn 4 TB RAM toàn fleet.

Vì sao

  • Thư viện chạy trong mọi request của 500 service: tối ưu nhỏ ở đây nhân lên toàn fleet, và chi phí ngôn ngữ ít người biết là rủi ro bảo trì.

Bài học cho SWE

  • Với thư viện nằm trên đường nóng của cả công ty, bộ nhớ và rác tạm quan trọng như tốc độ.
  • Viết lại một bộ thông dịch thì chứng minh tương đương bằng test sinh tự động từ dữ liệu production, không chỉ test viết tay.
  • Hệ thí nghiệm có sẵn là công cụ rollout tốt nhất cho chính nó.

Liên quan