- Trong quá trình di chuyển codebase từ Scala 2.13 sang Scala 3, đã phát sinh suy giảm hiệu năng ngoài dự kiến
- Ở các bài test ban đầu và môi trường triển khai, mọi chỉ số đều bình thường, nhưng sau vài giờ thì độ trễ (lag) Kafka tăng lên
- Kết quả kiểm thử tải cho thấy hiện tượng thông lượng giảm mạnh khi xử lý message được phân mảnh chi tiết
- Thông qua phân tích bằng async-profiler, nguyên nhân được xác định là bug kém hiệu quả trong đánh giá chuỗi của thư viện Quicklens
- Sau khi cập nhật thư viện, hiệu năng đã được khôi phục, đồng thời nhấn mạnh sự cần thiết phải lưu ý đến khác biệt trong cách thư viện hoạt động giữa các phiên bản Scala
Quá trình di chuyển dịch vụ
- Dịch vụ hiện có được chuyển từ Scala 2.13 sang Scala 3.7.3
- Đây là một dịch vụ tập trung vào thu thập dữ liệu, không dùng macro, và hiệu năng là yếu tố quan trọng
- Sau khi áp dụng thay đổi về dependency, tùy chọn compiler, kiểu và cú pháp, việc biên dịch đã thành công
- Trong môi trường thử nghiệm và triển khai từng bước, cả log lẫn metric đều bình thường
- Các chỉ số ở mức hạ tầng, JVM và ứng dụng đều được xác nhận là khỏe mạnh
Suy giảm hiệu năng chưa rõ nguyên nhân
- Khoảng 5~6 giờ sau khi triển khai, hiện tượng Kafka lag tăng bắt đầu xuất hiện
- Ngay cả khi không có spike dữ liệu, thông lượng trên mỗi instance vẫn giảm
- Sau khi rollback, thông lượng phục hồi ngay lập tức, xác nhận rằng thay đổi trong code là nguyên nhân
Phân tích hiệu năng và lần theo nguyên nhân
- Trong kiểm thử tải, ban đầu không tái hiện được hồi quy hiệu năng
- Chỉ khi message có payload phân mảnh nhỏ và không đồng nhất thì thông lượng mới giảm mạnh
- Các thư viện phụ thuộc (serialization, DB SDK, Docker image, thư viện cấu hình, v.v.) được hoàn nguyên và kiểm thử từng cái một nhưng không có thay đổi
- Kết quả profiling CPU bằng async-profiler cho thấy,
- Trên Scala 3, mức sử dụng CPU của JIT compiler và giai đoạn decoding tăng vọt
- Ở phần trên của flamegraph, các lời gọi Quicklens chiếm một nửa tổng thời gian CPU
- Trên Scala 2.13, cùng lời gọi đó chỉ ở mức khoảng 0.5%
Nguyên nhân gốc rễ của vấn đề
- Bug kém hiệu quả trong đánh giá chuỗi của thư viện Quicklens xuất hiện trên Scala 3
- Bản sửa liên quan đã được phản ánh trong GitHub PR #115
- Sau khi cập nhật thư viện, khác biệt hiệu năng giữa Scala 3 và 2.13 đã được loại bỏ
Bài học và khuyến nghị
- Sự phụ thuộc của thư viện vào metaprogramming có thể gây ra khác biệt hiệu năng giữa các phiên bản Scala
- Ngay cả khi migration hoàn tất bình thường, vẫn cần benchmark các hotspot và điểm nghẽn
- Với các dịch vụ nhạy cảm về hiệu năng, thay vì giả định “nó hoạt động tốt”, việc xác minh bằng đo đạc thực tế là bắt buộc
- Cần kiểm tra trước để tránh tình huống benchmark chứ không phải code mới là thứ làm lộ ra điểm nghẽn
1 bình luận
Ý kiến trên Hacker News
Blog kỹ thuật nên được viết theo kiểu này. AI khó có thể thay thế được mức độ tư duy như vậy
Câu hỏi đầu tiên rất đơn giản — “tại sao lại phải nâng cấp?”
inlinehoạt động như một phần của hệ thống macroKhi dùng
inlinecho tham số, trình biên dịch sẽ được chỉ thị inline biểu thức ngay tại vị trí gọiNhưng nếu phần này lớn, nó tạo gánh nặng lớn cho trình biên dịch JIT
Trong Scala 2,
@inlinechỉ là một gợi ý đơn giản, nhưng ở bản 3 thì được áp dụng bắt buộcVì vậy, việc chỉ đơn giản đổi
@inlinethànhinlinelà một sai lầm lớnregistertrong C/C++ từng trải quaBan đầu nó mang tính bắt buộc, nhưng khi tối ưu hóa phát triển hơn thì chỉ còn là một khuyến nghị và cuối cùng bị bỏ qua
inlinecủa C++ cũng đã đi theo con đường tương tựinlinerất tích cực ở gần như mọi nơiMục đích là để loại bỏ overhead của lambda trong các hàm như
mapHầu như không có vấn đề hiệu năng nào, nhưng khi kết hợp với hệ thống macro của Scala thì có thể tạo ra các biểu thức phức tạp và gây vấn đề
Tôi cũng từng có trải nghiệm tương tự khi nâng cấp Ruby 2→3
Không chỉ nâng ngôn ngữ, mà cần cập nhật toàn bộ dependency lên mới thì hệ thống mới ổn định
Các vấn đề suy luận kiểu của Scala 2 vẫn chưa được giải quyết, thay vào đó chỉ có ngôn ngữ bị thay đổi
Thành ra giống như đã làm ra một sản phẩm mà thị trường không cần, trong khi phớt lờ nhu cầu thực tế
PS: Cần xây dựng một bộ unit test đúng nghĩa cho trình biên dịch
Nhưng đợt viết lại Scala 3 đã không giải quyết được tốc độ biên dịch và vấn đề tooling, và khiến dự án mất hoàn toàn đà phát triển
Tôi tự hỏi liệu đến năm 2025 này còn ai bắt đầu dự án mới bằng Scala nữa không
Scala giống một ngôn ngữ do giới học thuật tạo ra, và việc nó từng thịnh hành trong công nghiệp mới là điều lạ
Giờ mọi công cụ đều phải thích ứng với Scala 3, và ngay cả IntelliJ cũng vẫn chưa hỗ trợ hoàn hảo
Giá mà Scala 2 được cải tiến dần dần thì tốt hơn, nhưng có vẻ họ chỉ tập trung vào thành công học thuật
Ví dụ như chuyện tranh cãi quanh
early returntrong bài viết của tpolecat, trong khi Kotlin hỗ trợ điều đó hoàn toàn bình thườngTrình biên dịch Scala có hàng nghìn, hàng chục nghìn test, và
thư mục test chính thức cùng với
hệ thống community build dùng để kiểm chứng hàng triệu LOC
Điều đó đặc biệt cần thiết với những thay đổi lớn như nâng phiên bản ngôn ngữ
Chúng tôi liên tục benchmark một công cụ viết bằng C++, nhưng vì nhiễu môi trường nên rất khó giữ kết quả nhất quán
Chúng tôi đang cân nhắc cách chạy nhiều lần trên cùng một máy để so sánh
Sai lầm là tạo ra cú pháp thứ hai rồi ép nó như là tương lai
Điều này cũng làm hệ sinh thái tooling chậm lại
Cũng có thể tự động chuyển đổi style bằng trình biên dịch hoặc scalafmt
Giờ thì cú pháp ngoặc nhọn và cú pháp thụt lề đều tồn tại, thành ra gấp đôi
Cú pháp
matchquá dài dòng và giống như đang bắt chước PythonKhi đó Scala được chú ý nhờ Spark, nhưng đã bỏ lỡ cơ hội phát triển thành một ngôn ngữ thương mại
Giờ thì Spark đi với Python, còn vị trí ngôn ngữ hiện đại trên JVM đã thuộc về Kotlin
Cuối cùng Scala lại có cảm giác trở về thành một ngôn ngữ học thuật
Có thể thấy điều đó qua Scala Adoption Tracker
Các tính năng mới của Scala 3 vẫn có tiềm năng đổi mới lại hệ sinh thái ngôn ngữ
Ví dụ: giải thích về Capture Checking
Khi Java bổ sung thêm các tính năng hàm, nó đã hấp thụ một phần sức hút của Scala
Theo kinh nghiệm của tôi, nhu cầu thị trường cũng rất nhỏ
Chỉ là vì Google hạn chế hỗ trợ Java nên mới thành ra như vậy
Trên toàn thị trường JVM, nó chỉ chiếm khoảng 10%
Nếu phải qua audit bảo mật (PCI-DSS v.v.) thì việc duy trì thư viện mới nhất là bắt buộc
Tôi thậm chí còn có xu hướng giữ dependency ở trạng thái cũ
Phiên bản mới đem theo bug mới, thay đổi maintainer hoặc cả rủi ro bảo mật
Có vẻ ban đầu họ chỉ nâng một phần. Chia nhỏ thành các bước nhỏ là cách làm phổ biến, nhưng có vẻ lần này đã kém may mắn
Vấn đề không nằm ở bản thân Scala 3 mà là ở sự tương tác giữa nhiều yếu tố
Tuy vậy, cần cẩn thận vì các thư viện riêng cho Scala thường có phiên bản Scala trong chính version của chúng
Chúng cho thấy rõ tính biểu đạt và độ an toàn kiểu của Scala
Như bài viết của Li Haoyi, nó cũng đủ hấp dẫn để làm ngôn ngữ thay thế Python
Điều này đặc biệt quan trọng khi có nhiều thư viện lạm dụng các tính năng ma thuật