Bản dựng phân tán

Báo cáo vấn đề Xem nguồn Nightly · 7.4 .

Khi bạn có cơ sở mã lớn, các chuỗi phần phụ thuộc có thể trở nên rất sâu. Ngay cả các tệp nhị phân đơn giản cũng có thể phụ thuộc vào hàng chục nghìn mục tiêu bản dựng. Ở quy mô này, bạn không thể hoàn tất một bản dựng trong một khoảng thời gian hợp lý trên một máy duy nhất: không có hệ thống xây dựng nào có thể vượt qua các quy luật vật lý cơ bản áp dụng cho phần cứng của máy. Cách duy nhất để thực hiện việc này là sử dụng một hệ thống xây dựng hỗ trợ các bản dựng phân tán, trong đó các đơn vị công việc do hệ thống thực hiện được phân bổ trên một số lượng máy tuỳ ý và có thể mở rộng. Giả sử chúng ta đã chia công việc của hệ thống thành các đơn vị đủ nhỏ (sẽ nói thêm về điều này sau), điều này sẽ cho phép chúng ta hoàn thành mọi bản dựng có kích thước bất kỳ nhanh chóng như chúng ta muốn. Khả năng mở rộng này là mục tiêu mà chúng tôi đã và đang hướng tới bằng cách xác định một hệ thống xây dựng dựa trên cấu phần phần mềm.

Lưu vào bộ nhớ đệm từ xa

Loại bản dựng được phân phối đơn giản nhất là loại chỉ tận dụng tính năng lưu vào bộ nhớ đệm từ xa, như minh hoạ trong Hình 1.

Bản dựng phân phối có lưu vào bộ nhớ đệm từ xa

Hình 1 Một bản dựng được phân phối cho thấy chức năng lưu vào bộ nhớ đệm từ xa

Mọi hệ thống thực hiện bản dựng, bao gồm cả máy trạm của nhà phát triển và hệ thống tích hợp liên tục, đều chia sẻ một tệp tham chiếu đến dịch vụ bộ nhớ đệm từ xa phổ biến. Dịch vụ này có thể là một hệ thống lưu trữ ngắn hạn nhanh và cục bộ như Redis hoặc một dịch vụ đám mây như Google Cloud Storage. Bất cứ khi nào người dùng cần tạo một cấu phần phần mềm, cho dù trực tiếp hay dưới dạng phần phụ thuộc, trước tiên hệ thống sẽ kiểm tra với bộ nhớ đệm từ xa để xem cấu phần phần mềm đó đã tồn tại hay chưa. Nếu có, thì hệ thống có thể tải cấu phần phần mềm xuống thay vì tạo cấu phần phần mềm. Nếu không, hệ thống sẽ tự tạo cấu phần phần mềm rồi tải kết quả trở lại bộ nhớ đệm. Điều này có nghĩa là các phần phụ thuộc cấp thấp không thường xuyên thay đổi có thể được tạo một lần và chia sẻ cho tất cả người dùng thay vì phải tạo lại cho từng người dùng. Tại Google, nhiều cấu phần phần mềm được phân phát từ bộ nhớ đệm thay vì được tạo từ đầu, giúp giảm đáng kể chi phí vận hành hệ thống xây dựng của chúng tôi.

Để hệ thống lưu vào bộ nhớ đệm từ xa hoạt động, hệ thống xây dựng phải đảm bảo rằng các bản dựng hoàn toàn có thể tái tạo. Tức là đối với bất kỳ mục tiêu bản dựng nào, bạn phải có thể xác định tập hợp dữ liệu đầu vào cho mục tiêu đó sao cho cùng một tập hợp dữ liệu đầu vào sẽ tạo ra chính xác cùng một kết quả trên bất kỳ máy nào. Đây là cách duy nhất để đảm bảo rằng kết quả tải cấu phần phần mềm xuống giống với kết quả của việc tự tạo cấu phần phần mềm. Xin lưu ý rằng điều này yêu cầu mỗi cấu phần phần mềm trong bộ nhớ đệm phải được khoá trên cả mục tiêu và hàm băm của dữ liệu đầu vào. Nhờ đó, các kỹ sư có thể thực hiện các sửa đổi khác nhau cho cùng một mục tiêu tại cùng một thời điểm và bộ nhớ đệm từ xa sẽ lưu trữ tất cả các cấu phần phần mềm thu được và phân phát các cấu phần phần mềm đó một cách thích hợp mà không xung đột.

Tất nhiên, để có được lợi ích từ bộ nhớ đệm từ xa, việc tải một cấu phần phần mềm xuống cần nhanh hơn so với việc tạo cấu phần phần mềm đó. Tuy nhiên, không phải lúc nào cũng vậy, đặc biệt là nếu máy chủ bộ nhớ đệm ở xa máy đang tạo bản dựng. Hệ thống xây dựng và mạng của Google được điều chỉnh cẩn thận để có thể nhanh chóng chia sẻ kết quả xây dựng.

Thực thi từ xa

Lưu vào bộ nhớ đệm từ xa không phải là bản dựng phân phối thực sự. Nếu bộ nhớ đệm bị mất hoặc nếu bạn thực hiện một thay đổi ở cấp độ thấp và yêu cầu phải tạo lại mọi thứ, bạn vẫn cần thực hiện toàn bộ bản dựng cục bộ trên máy của mình. Mục tiêu thực sự là hỗ trợ việc thực thi từ xa, trong đó công việc thực tế của việc tạo bản dựng có thể được phân bổ trên bất kỳ số lượng worker nào. Hình 2 mô tả một hệ thống thực thi từ xa.

Hệ thống thực thi từ xa

Hình 2. Hệ thống thực thi từ xa

Công cụ xây dựng chạy trên máy của từng người dùng (trong trường hợp người dùng là kỹ sư hoặc hệ thống xây dựng tự động) sẽ gửi yêu cầu đến một bản dựng chính trung tâm. Chủ bản dựng chia các yêu cầu thành các hành động thành phần và lên lịch thực thi các hành động đó trên một nhóm worker có thể mở rộng. Mỗi worker thực hiện các hành động được yêu cầu với dữ liệu đầu vào do người dùng chỉ định và ghi ra các cấu phần phần mềm kết quả. Các cấu phần phần mềm này được chia sẻ trên các máy khác thực thi các hành động yêu cầu chúng cho đến khi có thể tạo và gửi đầu ra cuối cùng cho người dùng.

Phần phức tạp nhất khi triển khai một hệ thống như vậy là quản lý hoạt động giao tiếp giữa worker (trình thực thi), chương trình chính và máy cục bộ của người dùng. Worker có thể phụ thuộc vào các cấu phần phần mềm trung gian do các worker khác tạo ra và đầu ra cuối cùng cần được gửi lại vào máy cục bộ của người dùng. Để làm việc này, chúng ta có thể xây dựng dựa trên bộ nhớ đệm phân tán được mô tả trước đó bằng cách yêu cầu mỗi worker ghi kết quả của nó vào và đọc các phần phụ thuộc của worker đó từ bộ nhớ đệm. Lệnh chặn chính ngăn các worker tiếp tục cho đến khi mọi thứ mà chúng phụ thuộc vào đã hoàn tất, trong trường hợp này, chúng sẽ có thể đọc dữ liệu đầu vào từ bộ nhớ đệm. Sản phẩm cuối cùng cũng được lưu vào bộ nhớ đệm, cho phép máy cục bộ tải xuống. Xin lưu ý rằng chúng ta cũng cần có một phương tiện riêng để xuất các thay đổi cục bộ trong cây nguồn của người dùng để các worker có thể áp dụng các thay đổi đó trước khi tạo.

Để làm được việc này, tất cả các phần của hệ thống xây dựng dựa trên cấu phần phần mềm được mô tả trước đó cần phải kết hợp với nhau. Môi trường xây dựng phải tự mô tả hoàn toàn để chúng ta có thể khởi động worker mà không cần sự can thiệp của con người. Bản thân quy trình xây dựng phải hoàn toàn độc lập vì mỗi bước có thể được thực thi trên một máy khác. Đầu ra phải hoàn toàn xác định để mỗi worker có thể tin tưởng kết quả mà worker đó nhận được từ các worker khác. Những đảm bảo như vậy là cực kỳ khó khăn đối với một hệ thống dựa trên nhiệm vụ, khiến cho việc xây dựng một hệ thống thực thi từ xa đáng tin cậy gần như không thể.

Bản dựng được phân phối tại Google

Kể từ năm 2008, Google đã sử dụng một hệ thống bản dựng phân tán sử dụng cả tính năng lưu vào bộ nhớ đệm từ xa và thực thi từ xa, như minh hoạ trong Hình 3.

Hệ thống xây dựng cấp cao

Hình 3. Hệ thống xây dựng phân tán của Google

Bộ nhớ đệm từ xa của Google có tên là ObjFS. Công cụ này bao gồm một phần phụ trợ lưu trữ kết quả bản dựng trong Bigtables được phân phối trên toàn bộ nhóm máy phát hành và một trình nền FUSE giao diện người dùng có tên objfsd chạy trên máy của từng nhà phát triển. Trình nền FUSE cho phép các kỹ sư duyệt qua các kết quả của bản dựng như thể chúng là các tệp bình thường được lưu trữ trên máy trạm, nhưng với nội dung tệp được tải xuống theo yêu cầu chỉ cho một vài tệp mà người dùng trực tiếp yêu cầu. Việc phân phát nội dung tệp theo yêu cầu làm giảm đáng kể mức sử dụng mạng và ổ đĩa, đồng thời hệ thống có thể tạo nhanh gấp đôi so với khi chúng ta lưu trữ tất cả đầu ra bản dựng trên ổ đĩa cục bộ của nhà phát triển.

Hệ thống thực thi từ xa của Google được gọi là Forge. Một ứng dụng Forge trong Blaze (tương đương nội bộ của Bazel) có tên là Trình phân phối sẽ gửi các yêu cầu cho từng hành động đến một công việc đang chạy trong các trung tâm dữ liệu của chúng tôi có tên là Trình lập lịch biểu. Trình lập lịch biểu duy trì bộ nhớ đệm của các kết quả hành động, cho phép trả về phản hồi ngay lập tức nếu hành động đã được bất kỳ người dùng nào khác của hệ thống tạo. Nếu không, thao tác này sẽ được đưa vào hàng đợi. Một nhóm lớn các công việc của Trình thực thi liên tục đọc các hành động từ hàng đợi này, thực thi các hành động đó và lưu trữ kết quả trực tiếp trong ObjFS Bigtables. Các kết quả này có sẵn cho trình thực thi cho các hành động trong tương lai hoặc để người dùng cuối tải xuống thông qua objfsd.

Kết quả cuối cùng là một hệ thống có thể mở rộng để hỗ trợ hiệu quả tất cả các bản dựng được thực hiện tại Google. Và quy mô các bản dựng của Google thực sự khổng lồ: Google chạy hàng triệu bản dựng thực thi hàng triệu trường hợp kiểm thử và tạo ra hàng petabyte bản dựng đầu ra từ hàng tỷ dòng mã nguồn mỗi ngày. Hệ thống như vậy không chỉ cho phép các kỹ sư của chúng tôi xây dựng cơ sở mã phức tạp một cách nhanh chóng mà còn cho phép chúng tôi triển khai một số lượng lớn các công cụ và hệ thống tự động dựa trên bản dựng của chúng tôi.