Trang này mô tả các worker ghép kênh, cách viết các quy tắc tương thích với việc ghép kênh và cách giải quyết một số hạn chế nhất định.
Multiplex worker cho phép Bazel xử lý nhiều yêu cầu bằng một quy trình worker duy nhất. Đối với các worker đa luồng, Bazel có thể sử dụng ít tài nguyên hơn để đạt được hiệu suất tương đương hoặc cao hơn. Ví dụ: thay vì có một quy trình worker cho mỗi worker, Bazel có thể có 4 worker được ghép kênh giao tiếp với cùng một quy trình worker, sau đó có thể xử lý các yêu cầu song song. Đối với các ngôn ngữ như Java và Scala, việc này giúp tiết kiệm thời gian khởi động JVM và thời gian biên dịch JIT, đồng thời cho phép sử dụng một bộ nhớ đệm dùng chung giữa tất cả các worker cùng loại.
Tổng quan
Có hai lớp giữa máy chủ Bazel và quy trình worker. Đối với một số từ khoá nhất định có thể chạy các quy trình song song, Bazel sẽ nhận được một WorkerProxy
từ nhóm worker. WorkerProxy
chuyển tiếp các yêu cầu đến quy trình worker theo trình tự cùng với request_id
, quy trình worker xử lý yêu cầu và gửi phản hồi đến WorkerMultiplexer
. Khi WorkerMultiplexer
nhận được phản hồi, nó sẽ phân tích cú pháp request_id
rồi chuyển tiếp các phản hồi trở lại WorkerProxy
chính xác. Giống như các worker không ghép kênh, mọi hoạt động giao tiếp đều được thực hiện qua đầu vào/đầu ra tiêu chuẩn, nhưng công cụ này không chỉ có thể sử dụng stderr
cho đầu ra mà người dùng nhìn thấy (xem bên dưới).
Mỗi worker đều có một khoá. Bazel sử dụng mã băm của khoá (bao gồm các biến môi trường, thư mục gốc thực thi và từ viết tắt) để xác định WorkerMultiplexer
nào sẽ sử dụng. Các WorkerProxy
giao tiếp với cùng một WorkerMultiplexer
nếu chúng có cùng mã băm. Do đó, giả sử các biến môi trường và thư mục gốc thực thi giống nhau trong một lệnh gọi Bazel duy nhất, thì mỗi từ khoá duy nhất chỉ có thể có một WorkerMultiplexer
và một quy trình worker. Tổng số nhân viên, bao gồm cả nhân viên chính thức và WorkerProxy
, vẫn bị giới hạn ở mức --worker_max_instances
.
Viết các quy tắc tương thích với tính năng ghép kênh
Quy trình thực thi của quy tắc phải là quy trình đa luồng để tận dụng các trình thực thi ghép kênh. Protobuf cho phép một bộ quy tắc phân tích cú pháp một yêu cầu duy nhất ngay cả khi có thể có nhiều yêu cầu tích luỹ trong luồng. Bất cứ khi nào quy trình worker phân tích cú pháp một yêu cầu từ luồng, quy trình đó sẽ xử lý yêu cầu trong một luồng mới. Vì các luồng khác nhau có thể hoàn thành và ghi vào luồng cùng một lúc, nên quy trình worker cần đảm bảo các phản hồi được ghi một cách nguyên tử (các thông báo không trùng lặp). Phản hồi phải chứa request_id
của yêu cầu mà chúng đang xử lý.
Xử lý đầu ra của tổ hợp
Nhân viên làm việc ở chế độ nhiều luồng cần cẩn thận hơn khi xử lý đầu ra so với nhân viên làm việc ở chế độ một luồng. Mọi nội dung được gửi đến stderr
sẽ được ghi vào một tệp nhật ký duy nhất được chia sẻ giữa tất cả các WorkerProxy
cùng loại, được xen kẽ ngẫu nhiên giữa các yêu cầu đồng thời. Mặc dù việc chuyển hướng stdout
vào stderr
là một ý tưởng hay, nhưng đừng thu thập đầu ra đó vào trường output
của WorkResponse
, vì điều đó có thể cho người dùng thấy các phần đầu ra bị hỏng.
Nếu công cụ của bạn chỉ gửi đầu ra hướng đến người dùng đến stdout
hoặc stderr
, bạn sẽ cần thay đổi hành vi đó trước khi có thể bật các worker ghép kênh.
Cho phép nhiều worker
Theo mặc định, các worker Multiplex không được bật. Một nhóm quy tắc có thể bật các worker ghép kênh bằng cách sử dụng thẻ supports-multiplex-workers
trong execution_requirements
của một thao tác (giống như thẻ supports-workers
cho phép các worker thông thường). Như khi sử dụng các worker thông thường, bạn cần chỉ định một chiến lược worker, ở cấp độ bộ quy tắc (ví dụ: --strategy=[some_mnemonic]=worker
) hoặc thường ở cấp độ chiến lược (ví dụ: --dynamic_local_strategy=worker,standalone
). Không cần thêm cờ nào khác và supports-multiplex-workers
sẽ được ưu tiên hơn supports-workers
nếu cả hai đều được đặt. Bạn có thể tắt các worker ghép kênh trên toàn cầu bằng cách truyền --noworker_multiplex
.
Bạn nên sử dụng nhóm quy tắc để dùng các worker ghép kênh nếu có thể, nhằm giảm áp lực bộ nhớ và cải thiện hiệu suất. Tuy nhiên, các worker ghép kênh hiện không tương thích với hoạt động thực thi động, trừ phi chúng triển khai hộp cát ghép kênh. Việc cố gắng chạy các worker đa luồng không được cách ly bằng hộp cát với quá trình thực thi động sẽ âm thầm sử dụng các worker đơn luồng được cách ly bằng hộp cát.
Chạy trong môi trường hộp cát Multiplex
Bạn có thể tạo hộp cát cho các worker ghép kênh bằng cách thêm tính năng hỗ trợ rõ ràng cho các worker đó trong quá trình triển khai worker. Mặc dù có thể thực hiện hộp cát cho trình chạy đơn bằng cách chạy từng quy trình trình chạy trong hộp cát riêng, nhưng các trình chạy đa luồng sẽ chia sẻ thư mục làm việc của quy trình giữa nhiều yêu cầu song song. Để cho phép hộp cát của các worker ghép kênh, worker phải hỗ trợ việc đọc và ghi vào một thư mục con được chỉ định trong mỗi yêu cầu, thay vì trực tiếp trong thư mục làm việc của worker.
Để hỗ trợ hộp cát ghép kênh, worker phải sử dụng trường sandbox_dir
từ WorkRequest
và dùng trường đó làm tiền tố cho mọi hoạt động đọc và ghi tệp.
Mặc dù các trường arguments
và inputs
vẫn không thay đổi so với yêu cầu chưa được cách ly, nhưng các dữ liệu đầu vào thực tế có liên quan đến sandbox_dir
. Worker phải dịch các đường dẫn tệp có trong arguments
và inputs
để đọc từ đường dẫn đã sửa đổi này, đồng thời phải ghi tất cả đầu ra liên quan đến sandbox_dir
.
Điều này bao gồm các đường dẫn như ".", cũng như các đường dẫn có trong các tệp được chỉ định trong đối số (chẳng hạn như đối số "argfile").
Sau khi một worker hỗ trợ hộp cát ghép kênh, bộ quy tắc có thể khai báo sự hỗ trợ này bằng cách thêm supports-multiplex-sandboxing
vào execution_requirements
của một thao tác. Sau đó, Bazel sẽ sử dụng hộp cát ghép kênh nếu cờ --experimental_worker_multiplex_sandboxing
được truyền hoặc nếu trình thực thi được dùng với tính năng thực thi động.
Các tệp worker của một worker ghép kênh được cách ly vẫn liên quan đến thư mục đang hoạt động của quy trình worker. Do đó, nếu một tệp được dùng cho cả việc chạy worker và làm đầu vào, thì bạn phải chỉ định tệp đó vừa làm đầu vào trong đối số flagfile vừa trong tools
, executable
hoặc runfiles
.