Bản dựng phân phối

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

Khi bạn có một 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 thường có thể phụ thuộc vào hàng chục nghìn mục tiêu bản dựng. Ở quy mô lớn này, bạn không thể hoàn thành 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ể xử lý các nguyên tắc cơ bản của vật lý được áp dụng trê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 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 mà hệ thống thực hiện sẽ được mở rộng trên 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ỏ (xem thêm về vấn đề này sau), điều này sẽ cho phép chúng tôi hoàn thành bất kỳ công trình nào có kích thước bất kỳ nhanh chóng như chúng tôi sẵn sàng trả. Khả năng mở rộng này chính là giải pháp mà chúng tôi đã nỗ lực hướng đến 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.

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

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

Bản dựng phân tán với bộ nhớ đệm từ xa

Hình 1 Bản dựng phân tán cho thấy quá trình 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 dành cho nhà phát triển và hệ thống tích hợp liên tục, đều chia sẻ thông tin tham chiếu đến dịch vụ bộ nhớ đệm từ xa chung. Dịch vụ này có thể là một hệ thống lưu trữ ngắn hạn 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 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 bằng bộ nhớ đệm từ xa để xem cấu phần phần mềm đó đã tồn tại ở đó hay chưa. Nếu có, ứng dụng có thể tải cấu phần phần mềm xuống thay vì xây dựng. 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ẻ cho người dùng thay vì phải tạo lại từng phần. 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.

Để 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. Điều này nghĩa là đối với mọi mục tiêu bản dựng, bạn phải xác định được tập hợp dữ liệu đầu vào để nhắm mục tiêu sao cho cùng một tập hợp dữ liệu đầu vào sẽ tạo ra cùng một đầu ra trên mọi máy. Đâ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. Lưu ý: Theo cách này, 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 nhập. Bằng cách đó, các kỹ sư khác nhau có thể thực hiện nhiều sửa đổi cho 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ấu phần phần mềm thu được, phân phối các cấu phần phần mềm đó một cách phù hợp mà không bị xung đột.

Tất nhiên, để có thể hưởng lợi từ bộ nhớ đệm từ xa, việc tải cấu phần phần mềm xuống phải nhanh hơn so với việc tạo bộ nhớ đệm. Không phải lúc nào cũng xảy ra trường hợp này, đặc biệt 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ả bản 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 đượ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 thay đổi cấp thấp đòi hỏi mọi thứ phải được tạo lại, bạn vẫn cần phải thực hiện toàn bộ bản dựng 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ế để tạo bản dựng có thể được trải rộng 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ụ bản dựng chạy trên máy của từng người dùng (trong đó người dùng là kỹ sư hoặc con người là hệ thống xây dựng tự động) gửi yêu cầu đến một bản dựng chính của 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 đó cho một nhóm trình chạy có thể mở rộng. Mỗi trình chạy thực hiện các hành động được yêu cầu với thông tin đầu vào do người dùng chỉ định và ghi lại các cấu phần phần mềm thu được. 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 ra và gửi kết quả cuối cùng cho người dùng.

Điều khó khăn nhất trong việc triển khai hệ thống đó là quản lý hoạt động giao tiếp giữa trình chạy, thiết bị 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à kết quả đầu ra cuối cùng cần được gửi trở lại 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 trên bộ nhớ đệm được phân phối được mô tả trước đó bằng cách yêu cầu từng worker chạy kết quả và đọc các phần phụ thuộc của nó từ bộ nhớ đệm. Bậc thầy chính chặn nhân viên tiếp tục cho đến khi mọi thao tác họ phụ thuộc hoàn tất, trong trường hợp đó, họ 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 sản phẩm đó xuống. Hãy lưu ý rằng chúng tôi cũng cần một phương tiện riêng cho việc xuất các thay đổi cục bộ trong cây nguồn của người dùng để các nhân viên có thể áp dụng những thay đổi đó trước khi tạo.

Để chế độ này hoạt động, 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 phối hợp với nhau. Môi trường xây dựng phải hoàn toàn tự mô tả để chúng tôi có thể xoay vòng công nhân mà không cần có con người can thiệp. 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. Kết quả đầu ra phải hoàn toàn mang tính quyết định để mỗi trình chạy có thể tin tưởng vào kết quả mà trình chạy đó nhận được. Các bảo đảm như vậy là cực kỳ khó để một hệ thống dựa trên tác vụ cung cấp, khiến hệ thống không thể xây dựng một hệ thống thực thi từ xa đáng tin cậy hơn.

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

Từ năm 2008, Google đã sử dụng một hệ thống xây dựng phân tán sử dụng cả bộ nhớ đệm từ xa và việc thực thi từ xa, như minh họa trong Hình 3.

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

Hình 3. Hệ thống bản 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ữ các kết quả của bản dựng trong Bigtable được phân phối trong nhóm máy sản xuất và trình giao diện người dùng FUSE có tên là 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ể các tệp đó là các tệp thông thường được lưu trữ trên máy trạm, nhưng với nội dung tệp chỉ được tải xuống theo yêu cầu cho một vài tệp mà 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 sẽ 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 bản dựng nhanh gấp đôi so với khi chúng tôi lưu trữ toàn bộ đầu ra của 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 giả của Forge trong Blaze (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 từng thao tác đến một công việc đang chạy trong trung tâm dữ liệu, gọi là Trình lập lịch biểu. Trình lập lịch biểu duy trì một bộ nhớ đệm về kết quả hành động, cho phép nó 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, thao tác này sẽ đưa thao tác này vào hàng đợi. Một nhóm lớn các lệnh Executor liên tục đọc các hành động từ hàng đợi này, thực thi chú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 thao tác 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 mở rộng quy mô để hỗ trợ hiệu quả tất cả bản dựng được thực hiện tại Google. Quy mô 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 các petabyte đầu ra của bản dựng từ hàng tỷ dòng mã nguồn mỗi ngày. Hệ thống như vậy không chỉ giúp các kỹ sư của chúng tôi nhanh chóng xây dựng các cơ sở mã phức tạp, 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.