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

Báo cáo sự cố Xem nguồn

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, khó có thể hoàn thành 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 hệ thống xây dựng nào có thể vượt qua được các định luật cơ bản của vật lý áp dụng cho phần cứng của máy tính. 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 được phân phối, 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 tôi đã chia nhỏ công việc của hệ thống thành các đơn vị đủ nhỏ (sẽ tìm hiểu thêm về vấn đề này ở phần sau), điều này sẽ cho phép chúng tôi hoàn thành mọi bản dựng ở bất kỳ quy mô nào nhanh chóng theo số tiền mà chúng tôi sẵn sàng chi trả. Khả năng mở rộng này là mục tiêu chung mà chúng tôi đang nỗ lực 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 được phân phối có chức năng 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 các 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ẻ tệp tham chiếu đến một 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 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ù 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 bộ nhớ đệm từ xa để xem cấu phần phần mềm đó đã tồn tại ở đó hay chưa. Nếu có, trình tạo này 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ì 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 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 có thể tái tạo hoàn toàn. 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 đầ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ả 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 mỗi cấu phần phần mềm trong bộ nhớ đệm phải được khoá cả mục tiêu và hàm băm của dữ liệu đầu vào. Bằng cách đó, nhiều kỹ sư có thể thực hiện nhiều thao tác sửa đổi cho cùng một mục tiêu cùng một lúc, đồng thời bộ nhớ đệm từ xa sẽ lưu trữ tất cả cấu phần phần mềm thu được và phân phát chúng một cách phù hợp mà không có sự xung đột.

Tất nhiên, để có được lợi ích 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 so với 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 chủ đang tạo 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ả bản dựng.

Thực thi từ xa

Tính năng lưu vào bộ nhớ đệm từ xa không phải là bản dựng được 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ợ quá trình thực thi từ xa, trong đó công việc thực tế của bản dựng có thể được trải rộng cho 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 thao tác được yêu cầu với dữ liệu đầ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 thao tác yêu cầu chúng cho đến khi có thể tạo và gửi kết quả 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 điều này, chúng ta có thể xây dựng dựa trên bộ nhớ đệm được phân phối được mô tả trước đó bằng cách yêu cầu mỗi worker ghi kết quả vào và đọc các phần phụ thuộc của bộ nhớ đệm đó từ bộ nhớ đệm đó. Chính chặn không cho các trình thực thi tiếp tục cho đến khi mọi thứ chúng phụ thuộc vào đã hoàn tất. Trong trường hợp đó, trình thực thi sẽ có thể đọc dữ liệu đầu vào từ bộ nhớ đệm. Sản phẩm hoàn thiện cũng được lưu vào bộ nhớ đệm để máy cục bộ có thể tải sản phẩm 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 điều 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 tôi có thể kết hợp các worker mà không cần sự can thiệp của con người. Bản thân các 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 có tính xác định hoàn toàn để mỗi worker có thể tin tưởng kết quả 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 gần như không thể xây dựng một hệ thống thực thi từ xa đáng tin cậy hơn một hệ thống.

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 xây dựng được phân phối hỗ trợ 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 phối của Google

Bộ nhớ đệm từ xa của Google được gọi là ObjFS. Thư viện này bao gồm một phần phụ trợ lưu trữ đầu ra của bản dựng trong Bigtables được phân phối trên toàn bộ hệ thống 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 từng máy của 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 giúp giảm đáng kể mức sử dụng cả mạng và ổ đĩa, đồng thời hệ thống có thể tạo bản dựng 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ó tên là Forge. Một ứng dụng Forge trong Blaze (ứng dụng tương đương nội bộ của Bazel) có tên là Nhà phân phối gửi yêu cầu cho mỗi hành động đến một công việc đang chạy trong 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 lưu giữ bộ nhớ đệm của các kết quả của hành động, cho phép bộ nhớ đệm trả về một 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, thao tác này sẽ được đưa vào một hàng đợi. Một nhóm lớn các công việc 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 người thực thi để thực hiện các hành động trong tương lai hoặc đượ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 quy mô để 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. Một 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ông cụ và hệ thống tự động dựa vào bản dựng của chúng tôi.