Thực thi động

Báo cáo vấn đề Xem nguồn Nightly · 8.3 · 8.2 · 8.1 · 8.0 · 7.6

Thực thi động là một tính năng trong Bazel, trong đó quá trình thực thi cục bộ và từ xa của cùng một thao tác được bắt đầu song song, sử dụng đầu ra từ nhánh đầu tiên hoàn tất, huỷ nhánh còn lại. Công cụ này kết hợp sức mạnh thực thi và/hoặc bộ nhớ đệm dùng chung lớn của một hệ thống tạo từ xa với độ trễ thấp của quá trình thực thi cục bộ, mang lại những lợi ích tốt nhất cho cả bản dựng sạch và bản dựng gia tăng.

Trang này mô tả cách bật, điều chỉnh và gỡ lỗi quá trình thực thi động. Nếu bạn đã thiết lập cả chế độ thực thi cục bộ và từ xa, đồng thời đang cố gắng điều chỉnh các chế độ cài đặt Bazel để cải thiện hiệu suất, thì trang này là dành cho bạn. Nếu bạn chưa thiết lập tính năng thực thi từ xa, trước tiên, hãy xem Tổng quan về tính năng thực thi từ xa của Bazel.

Bật tính năng thực thi động?

Mô-đun thực thi động là một phần của Bazel, nhưng để sử dụng tính năng thực thi động, bạn phải có thể biên dịch cả cục bộ và từ xa trong cùng một chế độ thiết lập Bazel.

Để bật mô-đun thực thi động, hãy chuyển cờ --internal_spawn_scheduler sang Bazel. Thao tác này sẽ thêm một chiến lược thực thi mới có tên là dynamic. Giờ đây, bạn có thể sử dụng chiến lược này cho những từ khoá gợi nhớ mà bạn muốn chạy một cách linh hoạt, chẳng hạn như --strategy=Javac=dynamic. Hãy xem phần tiếp theo để biết cách chọn những từ khoá cần bật tính năng thực thi động.

Đối với mọi mã nhớ sử dụng chiến lược linh hoạt, các chiến lược thực thi từ xa sẽ được lấy từ cờ --dynamic_remote_strategy và các chiến lược cục bộ từ cờ --dynamic_local_strategy. Truyền --dynamic_local_strategy=worker,sandboxed sẽ đặt giá trị mặc định cho nhánh cục bộ của quá trình thực thi động để thử với các worker hoặc quá trình thực thi trong hộp cát theo thứ tự đó. Việc truyền --dynamic_local_strategy=Javac=worker chỉ ghi đè giá trị mặc định cho từ khoá gợi nhớ Javac. Phiên bản từ xa cũng hoạt động theo cách tương tự. Bạn có thể chỉ định cả hai cờ nhiều lần. Nếu không thể thực hiện một thao tác cục bộ, thao tác đó sẽ được thực hiện từ xa như bình thường và ngược lại.

Nếu hệ thống từ xa của bạn có bộ nhớ đệm, thì cờ --dynamic_local_execution_delay sẽ thêm độ trễ tính bằng mili giây vào quá trình thực thi cục bộ sau khi hệ thống từ xa cho biết có lượt truy cập bộ nhớ đệm. Điều này giúp tránh chạy quá trình thực thi cục bộ khi có nhiều lượt truy cập vào bộ nhớ đệm hơn. Giá trị mặc định là 1000 mili giây, nhưng bạn nên điều chỉnh để thời gian này dài hơn một chút so với thời gian thường mất để đạt được lượt truy cập vào bộ nhớ đệm. Thời gian thực tế phụ thuộc vào cả hệ thống từ xa và thời gian cần thiết để thực hiện một chuyến khứ hồi. Thông thường, giá trị này sẽ giống nhau đối với tất cả người dùng của một hệ thống từ xa nhất định, trừ phi một số người dùng ở quá xa để thêm độ trễ khứ hồi. Bạn có thể sử dụng các tính năng lập hồ sơ Bazel để xem thời gian cần thiết cho các lượt truy cập bộ nhớ đệm thông thường.

Bạn có thể sử dụng tính năng thực thi động với chiến lược hộp cát cục bộ cũng như với worker liên tục. Các worker liên tục sẽ tự động chạy với tính năng hộp cát khi được dùng với tính năng thực thi động và không thể dùng các worker ghép kênh. Trên các hệ thống Darwin và Windows, chiến lược hộp cát có thể chậm; bạn có thể truyền --reuse_sandbox_directories để giảm chi phí tạo hộp cát trên các hệ thống này.

Hoạt động thực thi động cũng có thể chạy bằng chiến lược standalone, mặc dù chiến lược standalone phải lấy khoá đầu ra khi bắt đầu thực thi, nhưng chiến lược này sẽ chặn chiến lược từ xa hoàn thành trước. Cờ --experimental_local_lockfree_output cho phép giải quyết vấn đề này bằng cách cho phép quá trình thực thi cục bộ ghi trực tiếp vào đầu ra, nhưng bị quá trình thực thi từ xa huỷ bỏ nếu quá trình này hoàn tất trước.

Nếu một trong các nhánh thực thi động hoàn thành trước nhưng không thành công, thì toàn bộ thao tác sẽ không thành công. Đây là lựa chọn có chủ ý để ngăn chặn sự khác biệt giữa quá trình thực thi cục bộ và từ xa mà không được chú ý.

Để biết thêm thông tin cơ bản về cách hoạt động của tính năng thực thi động và khoá, hãy xem các bài đăng trên blog xuất sắc của Julio Merino

Khi nào tôi nên sử dụng tính năng thực thi linh động?

Việc thực thi linh hoạt đòi hỏi phải có một hình thức hệ thống thực thi từ xa. Hiện tại, bạn không thể sử dụng hệ thống từ xa chỉ có bộ nhớ đệm, vì lỗi bộ nhớ đệm sẽ được coi là một hành động không thành công.

Không phải loại hành động nào cũng phù hợp để thực thi từ xa. Các ứng cử viên tốt nhất là những ứng cử viên vốn có tốc độ nhanh hơn theo cách cục bộ, chẳng hạn như thông qua việc sử dụng các worker liên tục hoặc những ứng cử viên chạy đủ nhanh để chi phí thực thi từ xa chiếm phần lớn thời gian thực thi. Vì mỗi hành động được thực thi cục bộ sẽ khoá một lượng tài nguyên CPU và bộ nhớ nhất định, nên việc chạy các hành động không thuộc những danh mục đó chỉ đơn thuần là trì hoãn việc thực thi cho những hành động thuộc danh mục đó.

Kể từ bản phát hành 5.0.0-pre.20210708.4, phân tích tài nguyên hiệu suất chứa dữ liệu về quá trình thực thi của worker, bao gồm cả thời gian hoàn thành yêu cầu công việc sau khi mất một lượt thực thi động. Nếu thấy các luồng worker thực thi động dành nhiều thời gian đáng kể để thu thập tài nguyên hoặc dành nhiều thời gian trong async-worker-finish, thì có thể bạn có một số thao tác cục bộ chậm làm chậm các luồng worker.

Dữ liệu lập hồ sơ có hiệu suất thực thi động kém

Trong hồ sơ ở trên (sử dụng 8 worker Javac), chúng ta thấy nhiều worker Javac đã thua cuộc và hoàn thành công việc trên các luồng async-worker-finish. Nguyên nhân là do một câu ghi nhớ không phải của worker chiếm đủ tài nguyên để trì hoãn các worker.

Dữ liệu lập hồ sơ có hiệu suất thực thi động tốt hơn

Khi chỉ Javac chạy với tính năng thực thi động, chỉ khoảng một nửa số worker đã bắt đầu bị mất dữ liệu sau khi bắt đầu công việc.

Cờ --experimental_spawn_scheduler được đề xuất trước đây không còn được dùng nữa. Thao tác này sẽ bật tính năng thực thi động và đặt dynamic làm chiến lược mặc định cho tất cả các từ viết tắt, điều này thường dẫn đến những loại vấn đề này.

Hiệu suất

Phương pháp thực thi động giả định rằng có đủ tài nguyên ở cục bộ và từ xa để đáng bỏ ra thêm một số tài nguyên nhằm cải thiện hiệu suất tổng thể. Tuy nhiên, việc sử dụng quá nhiều tài nguyên có thể làm chậm chính Bazel hoặc máy mà Bazel chạy trên đó, hoặc gây áp lực ngoài dự kiến lên một hệ thống từ xa. Có một số lựa chọn để thay đổi hành vi của quá trình thực thi động:

--dynamic_local_execution_delay trì hoãn việc bắt đầu một nhánh cục bộ theo số mili giây sau khi nhánh từ xa bắt đầu, nhưng chỉ khi có một lượt truy cập bộ nhớ đệm từ xa trong bản dựng hiện tại. Điều này giúp các bản dựng tận dụng bộ nhớ đệm từ xa không lãng phí tài nguyên cục bộ khi có khả năng hầu hết các đầu ra đều có thể tìm thấy trong bộ nhớ đệm. Tuỳ thuộc vào chất lượng của bộ nhớ đệm, việc giảm kích thước này có thể cải thiện tốc độ xây dựng, nhưng phải trả giá bằng việc sử dụng nhiều tài nguyên cục bộ hơn.

--experimental_dynamic_local_load_factor là một lựa chọn quản lý tài nguyên nâng cao ở giai đoạn thử nghiệm. Giá trị này có thể từ 0 đến 1, trong đó 0 là tắt tính năng này. Khi được đặt thành một giá trị lớn hơn 0, Bazel sẽ điều chỉnh số lượng thao tác được lên lịch cục bộ khi có nhiều thao tác đang chờ được lên lịch. Việc đặt giá trị này thành 1 cho phép lên lịch nhiều hành động nhất có thể (theo --local_cpu_resources). Các giá trị thấp hơn sẽ đặt số lượng hành động được lên lịch thành số lượng tương ứng ít hơn khi có nhiều hành động hơn để chạy. Điều này có vẻ không hợp lý, nhưng với một hệ thống từ xa hiệu quả, việc thực thi cục bộ không giúp ích nhiều khi có nhiều hành động đang được chạy và CPU cục bộ sẽ được sử dụng hiệu quả hơn để quản lý các hành động từ xa.

--experimental_dynamic_slow_remote_time ưu tiên bắt đầu các nhánh cục bộ khi nhánh từ xa đã chạy ít nhất khoảng thời gian này. Thông thường, hành động được lên lịch gần đây nhất sẽ được ưu tiên vì có nhiều khả năng giành chiến thắng nhất, nhưng nếu hệ thống từ xa đôi khi bị treo hoặc mất quá nhiều thời gian, thì điều này có thể khiến bản dựng tiếp tục. Tính năng này không được bật theo mặc định, vì nó có thể ẩn các vấn đề với hệ thống từ xa mà bạn nên khắc phục. Hãy nhớ theo dõi hiệu suất của hệ thống từ xa nếu bạn bật lựa chọn này.

Bạn có thể dùng --experimental_dynamic_ignore_local_signals để cho phép nhánh từ xa tiếp quản khi một nhánh cục bộ thoát do một tín hiệu nhất định. Điều này chủ yếu hữu ích cùng với giới hạn tài nguyên của worker (xem --experimental_worker_memory_limit_mb, --experimental_worker_sandbox_hardening--experimental_sandbox_memory_limit_mb)), trong đó các quy trình worker có thể bị huỷ khi sử dụng quá nhiều tài nguyên.

Hồ sơ dấu vết JSON chứa một số biểu đồ liên quan đến hiệu suất có thể giúp xác định những cách cải thiện sự cân bằng giữa hiệu suất và mức sử dụng tài nguyên.

Khắc phục sự cố

Các vấn đề về việc thực thi động có thể rất tinh vi và khó gỡ lỗi, vì chúng chỉ có thể biểu hiện trong một số tổ hợp cụ thể giữa việc thực thi cục bộ và từ xa. --debug_spawn_scheduler sẽ thêm đầu ra bổ sung từ hệ thống thực thi động, có thể giúp gỡ lỗi những vấn đề này. Bạn cũng có thể điều chỉnh cờ --dynamic_local_execution_delay và số lượng công việc từ xa so với công việc cục bộ để dễ dàng tái hiện các vấn đề.

Nếu bạn gặp vấn đề với việc thực thi động bằng chiến lược standalone, hãy thử chạy mà không có --experimental_local_lockfree_output hoặc chạy các thao tác cục bộ trong hộp cát. Điều này có thể làm chậm quá trình tạo bản dựng một chút (xem ở trên nếu bạn đang dùng Mac hoặc Windows), nhưng sẽ loại bỏ một số nguyên nhân có thể gây ra lỗi.