Garbage Collection Optimization for High-Throughput and Low-Latency Java Applications

Bài tóm tắt LinkedIn 2014 3. Quy mô lớn Độ khó: Trung bình

LinkedIn · 2014 · 3. Quy mô lớn · Độ khó: Trung bình — bài gốc

Bối cảnh

  • Khi dựng thế hệ mới của feed data platform (index cập nhật từ member, company, group để phục vụ feed), team làm prototype gần đủ chức năng, chạy lại workload query của hệ đang chạy để đo GC trong thời gian dài. Java 7u51.
  • Theo bài, nên tune GC trên code gần hoàn chỉnh, nhưng cần đo sớm trên prototype với workload giống production để biết giới hạn latency/throughput và quyết định scale up hay scale out.

Thay đổi chính

  • Quy trình: xác định yêu cầu GC (độ dài và tần suất pause stop-the-world so với SLA, CPU mà GC đồng thời giành của ứng dụng, phân mảnh heap dẫn tới full GC, bộ nhớ GC cần), đọc GC log, rồi chỉnh kích thước các vùng heap theo vòng đời object.
  • ParNew/CMS thắng G1 với workload này: G1 tốn CPU hơn làm giảm throughput và latency, tốn bộ nhớ hơn, không đạt pause dự đoán được dù tune nhiều, và gặp một bug rò bộ nhớ.
  • Một số tuỳ chọn gán luồng GC vào CPU không có tác dụng trên Linux (theo đọc mã nguồn JDK 7/8).
  • Mức OS: pause có user time thấp nhưng wall time cao là dấu hiệu trang bị Linux lấy đi hoặc luồng GC kẹt chờ flush đĩa. Dùng -XX:+AlwaysPreTouch (chạm trang từ lúc khởi động) và vm.swappiness=0; không dùng mlock vì khi hết bộ nhớ OOM killer sẽ giết chính ứng dụng, mất khả năng xuống cấp từ từ.
  • Kết quả: young GC 40–60 ms mỗi khoảng ba giây, một chu kỳ CMS mỗi giờ; p99.9 còn 60 ms ở mức hàng nghìn request đọc/giây.

Vì sao

  • Với dịch vụ Java latency thấp, GC pause là thành phần chính của tail latency; tối ưu runtime đang có rẻ hơn đổi ngôn ngữ.

Bài học cho SWE

  • Tune GC bằng workload thật chạy đủ lâu để qua nhiều chu kỳ, không bằng benchmark ngắn.
  • Collector "mới hơn" không tự động tốt hơn; đo với workload của mình.
  • Ổn định pause cần cả cấu hình OS (swap, page cache), không chỉ cờ JVM.

Liên quan