Sản phẩm
Databricks mã nguồn mở Metals v2: Trình hỗ trợ ngôn ngữ Java và Scala cho các hệ thống khổng lồ
(giờ Việt Nam)
Tóm tắt AI
Databricks vừa ra mắt Metals v2, trình hỗ trợ ngôn ngữ tối ưu cho các kho mã nguồn hàng triệu dòng. Công cụ này được thiết kế để tăng tốc độ điều hướng và chỉnh sửa, hỗ trợ đắc lực cho các kỹ sư trong quy trình phát triển phần mềm do AI điều khiển.
Bản dịch AI

Hầu hết mã nguồn tại Databricks hiện nay đều được viết bởi các tác nhân (agents). Trong những lúc các kỹ sư vẫn cần can thiệp thủ công, họ thường chọn các trình soạn thảo nhẹ, khởi động nhanh và cho phép điều hướng mã nguồn mà không cần thiết lập phức tạp. Tuy nhiên, đối với Scala và Java, IntelliJ đã thiết lập tiêu chuẩn trong nhiều năm qua. Với quy mô monorepo của chúng tôi, đây gần như là trình soạn thảo duy nhất có thể đáp ứng được. Bài viết này chia sẻ cách chúng tôi xây dựng một giải pháp thay thế bằng cách mở rộng Metals – máy chủ ngôn ngữ (language server) Scala được sử dụng rộng rãi – để hỗ trợ Java ở mức độ cao cấp và mở rộng quy mô cho monorepo của chúng tôi. Hợp tác cùng đội ngũ phát triển Metals, chúng tôi đã mã nguồn mở Metals v2 để bất kỳ ai sở hữu cơ sở mã Java và Scala lớn đều có thể kết hợp tác nhân lập trình của họ với một trình soạn thảo nhẹ.
Metals v2 hiện đã có sẵn trên Cursor, VS Code và Neovim với hướng dẫn cài đặt trên trang web của Metals.
Xây dựng bánh đà IDE
Vào tháng 5 năm 2025, chúng tôi bắt đầu tiêu chuẩn hóa quy trình làm việc hàng ngày tại Databricks xung quanh Cursor. Cursor và VS Code vốn đã được sử dụng rộng rãi tại Databricks cho frontend và các công việc không liên quan đến JVM, đồng thời cả hai đều hỗ trợ SSH từ xa mạnh mẽ cho môi trường phát triển dựa trên đám mây của chúng tôi. Tuy nhiên, hầu hết các dịch vụ của chúng tôi đều được viết bằng Scala và Java, và việc điều hướng chúng ở quy mô monorepo là trở ngại lớn nhất; đây chính là vấn đề chúng tôi đặt mục tiêu giải quyết.
Việc tiêu chuẩn hóa trên một trình soạn thảo duy nhất quan trọng hơn cả sở thích cá nhân. Một nền tảng IDE thống nhất tạo ra một "bánh đà": các nhóm chia sẻ chung một nền tảng để khám phá và phát triển mã nguồn, trong khi đội ngũ nền tảng có thể tập trung đầu tư vào một nơi. Cursor đã trở thành trình soạn thảo chính cho công việc JVM trong monorepo của chúng tôi, và chúng tôi đã hợp nhất đủ để không gia hạn phần lớn các giấy phép IntelliJ trong năm nay.

Ba tín hiệu cho thấy sự chuyển dịch sang Cursor đã đi xa đến mức nào: mức độ sử dụng IDE tổng thể, các sự kiện mở tệp Scala và Java nơi Metals đóng vai trò then chốt, và mức độ chấp nhận bên ngoài Databricks.
Mức độ sử dụng IDE
Tín hiệu rộng nhất là mức độ sử dụng IDE tổng thể. Việc áp dụng Cursor tự phát triển tại Databricks nhưng đã chững lại vào tháng 9 năm 2025 và duy trì trong nhiều tháng. Sự tăng trưởng tiếp tục trở lại với việc triển khai Metals v2 và đến tháng 7 năm 2026, 92% người dùng IDE hoạt động hàng tuần mở Cursor so với 12% của IntelliJ. Trong số các kỹ sư chỉ sử dụng một IDE duy nhất, 2,4 nghìn người hiện đang dùng Cursor so với 120 người dùng IntelliJ.

Các sự kiện mở tệp Scala và Java
Một tín hiệu sát sao hơn mức độ sử dụng IDE tổng thể là tỷ lệ các tệp được mở trong mỗi IDE đối với Scala và Java, những ngôn ngữ mà Metals v2 đóng vai trò then chốt. Kể từ khi những cải tiến lớn đầu tiên của Metals v2 xuất hiện trên Cursor vào tháng 10 năm 2025, thị phần của Cursor trong các sự kiện mở tệp Scala và Java đã tăng từ 40% lên 78%. Tốc độ tăng trưởng này chậm hơn so với mức độ áp dụng IDE tổng thể vì Scala và Java là nơi IntelliJ bám rễ sâu nhất, nhưng thị phần của Cursor vẫn tiếp tục xu hướng tăng theo từng tháng.

Sự chấp nhận sớm từ bên ngoài
Metals v2 khởi đầu là một bản fork của Databricks, nhưng mục tiêu luôn là đưa công việc này trở lại cộng đồng mã nguồn mở. Cùng với đội ngũ Cursor và các nhà bảo trì cốt lõi của Metals tại VirtusLab, chúng tôi đang chuẩn bị một bản phát hành ổn định Metals v2 để thay thế cho bản v1 hiện tại.
Các cuộc thảo luận với những cơ sở mã JVM lớn khác đã củng cố mô hình tương tự mà chúng tôi thấy tại Databricks: nhu cầu về Cursor, VS Code và Neovim với hỗ trợ SSH từ xa mạnh mẽ, áp lực từ phía nền tảng hướng tới công cụ thống nhất, và không có lộ trình khả thi nào thông qua các máy chủ ngôn ngữ JVM hiện có ở quy mô monorepo.
Đây là mô hình chúng tôi muốn cho Metals v2: cơ sở hạ tầng dùng chung cho các cơ sở mã JVM lớn, được duy trì công khai và định hình bởi các công ty cần nó hoạt động ở quy mô lớn. Quá trình phát triển liên tục được dẫn dắt bởi VirtusLab, hãy liên hệ với họ nếu có câu hỏi, phản hồi hoặc đóng góp thông qua trình theo dõi vấn đề trên GitHub hoặc địa chỉ [email protected].
Tìm hiểu sâu: cách Metals v2 mở rộng quy mô
Tất cả những điều trên là lý do cho sự tồn tại của Metals v2. Phần còn lại dành cho những độc giả muốn hiểu rõ hơn về kỹ thuật đằng sau trí tuệ mã nguồn có độ trễ thấp trên một monorepo 26 triệu dòng.
Vì các tác nhân viết phần lớn mã nguồn, việc định hướng nhanh trong cơ sở mã quan trọng hơn so với độ bao phủ của việc hoàn thiện mã và tái cấu trúc theo Giao thức Máy chủ Ngôn ngữ (LSP). Điều đó thu hẹp vấn đề, nhưng không làm cho giải pháp trở nên hiển nhiên: chúng tôi vẫn phải cung cấp khả năng điều hướng độ trễ thấp, dễ thiết lập cho một monorepo Scala và Java Bazel lớn như vậy, và các LSP có sẵn không được thiết kế để hỗ trợ quy mô đó. Chúng tôi phải xây dựng trí tuệ mã nguồn ở quy mô kho lưu trữ từ những nguyên lý cơ bản, và coi tính hữu dụng khi khởi động là một chỉ số chính mà chúng tôi có thể đo lường và cải thiện.
Định nghĩa thời gian đạt đến trí tuệ ban đầu (TTII)
Thời gian đạt đến trí tuệ ban đầu (TTII) đo lường tốc độ trình soạn thảo trở nên hữu ích sau khi mở kho lưu trữ. Chúng tôi bắt đầu tính giờ khi máy chủ ngôn ngữ kích hoạt và dừng lại khi các tính năng quan trọng nhất khả dụng mà không cần người dùng can thiệp. Các tính năng quan trọng này bao gồm tìm kiếm mờ (fuzzy search) các biểu tượng trong không gian làm việc, nhảy đến định nghĩa (jump-to-definition) và tìm kiếm cách sử dụng biểu tượng trên toàn bộ kho lưu trữ.
Ba lớp của Metals v2
Metals v2 là một máy chủ ngôn ngữ cho Scala và Java. Chúng tôi bắt đầu từ Metals v1, máy chủ ngôn ngữ Scala chính thức, nhưng để đạt được mục tiêu TTII, cần nhiều hơn là chỉ tinh chỉnh sơ bộ. Chúng tôi đã fork nó và làm lại ba lớp trung tâm: chỉ mục kho lưu trữ (repo index), các đường ống trình biên dịch (compiler pipelines) Scala và Java, và ranh giới tích hợp bản dựng (build integration boundary).
Các phần dưới đây sẽ đi qua từng lớp một.
Chỉ mục mbt: trí tuệ toàn kho lưu trữ trước khi đồng bộ bản dựng
mbt là viết tắt của Metals Build Tool, và chỉ mục mbt là yếu tố chính cho phép đạt được TTII hay hợp đồng "hữu ích ngay lập tức". Đây là một chỉ mục dựa trên nội dung của các nguồn không gian làm việc: Metals sử dụng lệnh git ls-files --stage để khám phá các tệp và OID Git blob để quyết định mục chỉ mục nào có thể được tái sử dụng. Với thông tin toàn kho lưu trữ khả dụng trước khi đồng bộ bản dựng, Metals có thể trả lời các câu hỏi "dặm đầu tiên":
Chỉ mục mbt thực chất là một bảng băm từ tệp nguồn đến tóm tắt cục bộ của tệp đó. Một mục ghi lại các khai báo gói của tệp, các định nghĩa kèm vị trí nguồn và các bộ lọc bloom nhỏ gọn cho các định danh được tham chiếu trong tệp. Các định nghĩa hỗ trợ tìm kiếm biểu tượng không gian làm việc và nhảy đến định nghĩa, trong khi các bộ lọc bloom cho phép Metals nhanh chóng loại bỏ các tệp không thể chứa tham chiếu trước khi thực hiện các kiểm tra chính xác hơn. Vì mỗi mục chỉ được rút ra từ một tệp, các cập nhật gia tăng vẫn rất đơn giản: khi một tệp thay đổi, Metals tính toán lại mục của tệp đó và thay thế nó.
Trong monorepo của chúng tôi, chỉ mục mbt đã lưu trữ nặng 936MB khi chưa nén và chứa thông tin về 2,9 triệu biểu tượng trên hơn 142 nghìn tệp Scala, Java và Protobuf. Một bản dựng benchmark sạch mất 22 giây với mức sử dụng CPU tối đa trên 32 nhân, trong khi việc phân tích cú pháp một chỉ mục được xây dựng sẵn từ đĩa mất 5 giây. Trong môi trường sản xuất, chúng tôi đo TTII là thời gian để khởi động máy chủ, tải chỉ mục mbt cũ, cập nhật nó theo trạng thái git ls-files --stage mới nhất và khởi động lại các trình biên dịch trình bày Scala và Java: p50 là 8,7 giây, p90 là 36,7 giây. Tìm kiếm biểu tượng mờ trên 2,9 triệu biểu tượng không gian làm việc có p50 là 10ms, p90 là 95ms. Vẫn còn dư địa để giảm TTII hơn nữa, nhưng ở những con số này, nó không phải là nút thắt cổ chai mà chúng tôi cần giải quyết tiếp theo.
Đường ống Scala: xử lý 24 triệu dòng mã trên một phiên bản trình biên dịch duy nhất
Đường ống Scala được xây dựng xung quanh trình biên dịch trình bày (presentation compiler), một chế độ của trình kiểm tra kiểu Scala giúp lưu trữ và tái sử dụng thông tin bảng biểu tượng qua các lần biên dịch. Việc tái sử dụng này, kết hợp với khả năng phân giải biểu tượng lười biếng (lazy symbol resolution) của trình biên dịch, cho phép một phiên bản duy nhất giữ toàn bộ cơ sở mã Scala 24 triệu dòng trong phạm vi, đồng thời xuất ra các chẩn đoán ở mức p50 0,9 giây, p90 8,9 giây.
Phiên bản trình biên dịch Scala duy nhất đó chạy ở một trong hai chế độ, tùy thuộc vào lượng thông tin Metals có từ máy chủ bản dựng về tệp đang được chỉnh sửa. Trước khi đồng bộ bản dựng, một trình biên dịch dự phòng (fallback compiler) sẽ có cái nhìn cởi mở, coi mọi tệp nguồn trong kho lưu trữ là một ứng viên phụ thuộc hợp lệ, giúp việc điều hướng trở nên hữu ích ngay lập tức, ngay cả trên mã nguồn chưa biên dịch được trong Bazel. Sau khi đồng bộ bản dựng, một trình biên dịch chính xác (precise compiler) sẽ tự giới hạn trong các ranh giới classpath và sourcepath mà máy chủ bản dựng báo cáo, điều này làm cho các chẩn đoán và thông tin phụ thuộc của nó chính xác theo bản dựng. Cả hai chế độ chính xác và dự phòng đều dựa vào hai kỹ thuật giống nhau để giữ cho sourcepath lớn như vậy có thể quản lý được:
Chế độ chính xác bổ sung kỹ thuật thứ ba: nó giữ các nguồn phụ thuộc bắc cầu trên sourcepath, vì vậy các chỉnh sửa trên các tệp từ các mục tiêu Bazel khác nhau được phản ánh ngay lập tức trong trình soạn thảo mà không cần chờ Bazel tạo classpath mới, một hạn chế đã kìm hãm Metals v1.
Việc giữ một cơ sở mã 24 triệu dòng trong một phiên bản trình biên dịch trình bày duy nhất nằm ngoài phạm vi mà trình biên dịch Scala ban đầu được xây dựng. Metals v2 đạt được điều đó thông qua hai chế độ trình biên dịch được xây dựng trên một tập hợp các kỹ thuật dùng chung để mở rộng sourcepath. Nhảy đến định nghĩa, tính năng được sử dụng nhiều nhất của trình soạn thảo, chạy trên toàn bộ kho lưu trữ ở mức p50 7ms, p90 575ms. Scala là ngôn ngữ mà hầu hết các kỹ sư của chúng tôi làm việc, vì vậy đường ống này là phần bắt buộc phải hoạt động để Cursor trở thành một giải pháp thay thế thực sự cho IntelliJ trong monorepo của chúng tôi.
Đường ống Java: xử lý một triệu dòng mã Java mỗi giây với Turbine
Metals v2 triển khai bề mặt Java LSP trực tiếp trên các API của javac. Chúng tôi đã đánh giá việc tái sử dụng một máy chủ ngôn ngữ Java hiện có (các triển khai dựa trên JDT và NetBeans), nhưng cả hai đều tập trung vào bản dựng theo cách tương tự như Metals v1, chính là sự ràng buộc mà v2 đặt mục tiêu loại bỏ. Việc xây dựng trên javac cho phép Java chia sẻ sourcepath và mô hình đồng bộ bản dựng của Metals v2 với Scala, vốn vẫn chiếm phần lớn monorepo của chúng tôi, và bề mặt Java mà chúng tôi cần đủ nhỏ để tự duy trì.
Các API của javac cung cấp đủ quyền truy cập trình biên dịch để triển khai chẩn đoán, điều hướng, làm nổi bật ngữ nghĩa và các phương thức LSP chính khác, và chúng hoạt động tốt trên mã nguồn bị hỏng một phần, điều này rất quan trọng đối với quy trình làm việc của trình soạn thảo tương tác. Như với Scala, chúng tôi cố tình giữ các tính năng chỉnh sửa tích cực như tái cấu trúc và hoàn thiện mã ở phạm vi hẹp hơn.
Vấn đề khả năng mở rộng chính với kiến trúc này xuất hiện trong các tệp kích hoạt hiệu suất bệnh lý trong giai đoạn "enter" của javac bằng cách nhập bắc cầu hàng triệu dòng mã ở lớp phác thảo biểu tượng. Metals v2 giải quyết vấn đề này với chế độ javaSymbolLoader: "turbine-classpath", được bật theo mặc định, sử dụng phiên bản sửa đổi của trình biên dịch tiêu đề Turbine để tạo ra một classpath kho lưu trữ hoạt động trong môi trường IDE, bao gồm cả việc xử lý lỗi phân giải tên một cách linh hoạt. Turbine xử lý gần một triệu dòng mã Java mỗi giây trên một luồng duy nhất, nghĩa là Metals có thể biên dịch lại toàn bộ cơ sở mã Java theo định kỳ. Điều này giữ cho gần như tất cả các biểu tượng liên tệp trên classpath thay vì sourcepath, vì vậy giai đoạn "analyze" của javac có thể chạy gần giới hạn thực tế của nó cho việc sử dụng tương tác: gần 100 nghìn dòng mã mỗi giây theo các benchmark của chúng tôi.
Tích hợp bản dựng: truy vấn 285 nghìn mục tiêu Bazel ở độ trễ của trình soạn thảo
Bài viết được AI dịch và tổng hợp tự động từ Databricks: Blog. Liên kết bài gốc ở phía trên. Dữ liệu đồng bộ qua API công khai được ghi nguồn tại AI HOT (canonical) ↗. AIHOT.vn luôn dẫn nguồn đầy đủ — nếu bạn thấy điểm cần chỉnh sửa, hãy gửi ý kiến tại trang phản hồi.