Khi bạn có một cơ sở mã lớn, các chuỗi 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 thường có thể phụ thuộc vào hàng chục nghìn mục tiêu xây dựng. Ở quy mô này, bạn không thể hoàn tấ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 hệ thống xây dựng nào có thể vượt qua các định luật vật lý cơ bản áp đặt lên 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 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 trải rộng 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ề vấn đề này sau), thì điều này sẽ cho phép chúng ta hoàn tất mọi bản dựng ở mọi kích thước một cách nhanh nhất có thể nếu chúng ta sẵn sàng trả tiề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 hệ thống xây dựng dựa trên cấu phần phần mềm.
Bộ nhớ đệm từ xa
Loại bản dựng phân tán đơn giản nhất là loại chỉ tận dụng bộ nhớ đệm từ xa, như minh hoạ trong Hình 1.
Hình 1. Bản dựng phân tán cho thấy 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 tham chiếu đến dịch vụ bộ nhớ đệm từ xa chung. Dịch vụ này có thể là hệ thống lưu trữ ngắn hạn, nhanh và cục bộ như Redis hoặc 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, dù là trực tiếp hay dưới dạng phần phụ thuộc, hệ thống sẽ kiểm tra trước 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ó, 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 và tải kết quả lên bộ nhớ đệm. Điều này có nghĩa là các phần phụ thuộc cấp thấp không thay đổi thường xuyên có thể được tạo một lần và chia sẻ giữa những người dùng thay vì phải được tạo lại bởi 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í chạy hệ thống xây dựng của chúng tôi.
Để hệ thống 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 xây dựng nào, bạn phải có thể xác định tập hợp các đầu vào cho mục tiêu đó sao cho cùng một tập hợp đầu vào sẽ tạo ra chính xác cùng một đầu ra trên bất kỳ máy nào. Đây là cách duy nhất để đảm bảo rằng kết quả của việc tải cấu phần phần mềm xuống cũng giống như 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 đòi hỏi mỗi cấu phần phần mềm trong bộ nhớ đệm phải được khoá bằng cả mục tiêu và hàm băm của các đầu vào. Nhờ đó, các kỹ sư khác nhau có thể thực hiện các sửa đổi khác nhau đối với cùng một mục tiêu cùng một lúc và bộ nhớ đệm từ xa sẽ lưu trữ tất cả các cấu phần phần mềm kết quả và phân phát chúng một cách thích hợp mà không gây xung đột.
Tất nhiên, để có bất kỳ lợi ích nào từ bộ nhớ đệm từ xa, việc tải cấu phần phần mềm xuống cần phải nhanh hơn việc tạo cấu phần phần mềm đó. Điều này không phải lúc nào cũng đúng, đặc biệt là nếu máy chủ bộ nhớ đệm ở xa máy thực hiện bản dựng. Mạng và hệ thống xây dự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
Bộ nhớ đệm từ xa không phải là bản dựng phân tán thực sự. Nếu bộ nhớ đệm bị mất hoặc nếu bạn thực hiện thay đổi ở cấp thấp đòi hỏi 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ợ 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 trải rộng trên bất kỳ số lượng nhân viên nào. Hình 2 mô tả 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 mỗi người dùng (trong đó 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. Bản dựng chính 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 nhân viên có thể mở rộng. Mỗi nhân viên thực hiện các hành động được yêu cầu với các đầu vào do người dùng chỉ định và ghi 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 khó nhất của việc triển khai hệ thống như vậy là quản lý giao tiếp giữa nhân viên, bản dựng chính và máy cục bộ của người dùng. Nhân viên có thể phụ thuộc vào các cấu phần phần mềm trung gian do nhân viên khác tạo và đầu ra cuối cùng cần được gửi lại máy cục bộ của người dùng. Để thực hiện 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 nhân viên ghi kết quả vào bộ nhớ đệm và đọc các phần phụ thuộc từ bộ nhớ đệm. Bản dựng chính chặn nhân viên tiếp tục cho đến khi mọi thứ mà họ phụ thuộc vào đã hoàn tất. Trong trường hợp đó, họ sẽ có thể đọc các đầ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 sản phẩm đó xuống. Xin lưu ý rằng chúng ta cũng cần 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 để nhân viên có thể áp dụng những thay đổi đó trước khi tạo.
Để thực hiện 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 hoàn toàn tự mô tả để chúng ta có thể khởi động nhân viên 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 nhân viên có thể tin tưởng vào kết quả mà họ nhận được từ các nhân viên khác. Các đảm bảo như vậy cực kỳ khó cung cấp cho hệ thống dựa trên tác vụ, khiến việc xây dựng hệ thống thực thi từ xa đáng tin cậy dựa trên hệ thống đó gần như không thể.
Bản dựng phân tán tại Google
Kể từ năm 2008, Google đã sử dụng hệ thống xây dựng phân tán sử dụng cả bộ nhớ đệm từ xa và thực thi từ xa, như minh hoạ trong Hình 3.
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. Bộ nhớ đệm này bao gồm một phần phụ trợ lưu trữ đầu ra xây dựng trong Bigtable được phân phối trên toàn bộ nhóm máy sản xuất của chúng tôi và một trình nền FUSE giao diện người dùng có tên là objfsd chạy trên máy của mỗi nhà phát triển. Trình nền FUSE cho phép các kỹ sư duyệt đầu ra xây dựng như thể đó là các tệp thông thường được lưu trữ trên máy trạm, nhưng chỉ tải nội dung tệp xuống theo yêu cầu đối với một số ít tệp được người dùng yêu cầu trực tiếp. Việc phân phát nội dung tệp theo yêu cầu giúp giảm đáng kể cả 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 tôi lưu trữ tất cả đầu ra xây 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ó tên là Forge. Ứ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 yêu cầu cho từng hành động đến một công việc 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. Trình lập lịch duy trì bộ nhớ đệm 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 tạo bởi bất kỳ người dùng nào khác của hệ thống. Nếu không, trình lập lịch sẽ đặt hành động 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 Bigtable ObjFS. Các kết quả này có sẵn cho trình thực thi đối với các hành động trong tương lai hoặc để người dùng cuối tải xuố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ủa các bản dựng của Google thực sự rất lớn: 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 đầu ra xây dựng từ hàng tỷ dòng mã nguồn mỗi ngày. Không chỉ giúp các kỹ sư của chúng tôi nhanh chóng tạo các cơ sở mã phức tạp, hệ thống như vậy 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 vào bản dựng của chúng tôi.


