Jika Anda memiliki codebase yang besar, rantai dependensi dapat menjadi sangat dalam. Bahkan biner sederhana sering kali bergantung pada puluhan ribu target build. Pada skala ini, tidak mungkin untuk menyelesaikan build dalam waktu yang wajar di satu mesin: tidak ada sistem build yang dapat mengakali hukum fisik dasar yang diterapkan pada hardware mesin. Satu-satunya cara untuk melakukannya adalah dengan sistem build yang mendukung build terdistribusi, dengan unit pekerjaan yang dilakukan oleh sistem tersebar di sejumlah mesin arbitrer dan skalabel. Dengan asumsi bahwa kita telah membagi pekerjaan sistem menjadi unit yang cukup kecil (selengkapnya nanti), hal ini akan memungkinkan kita menyelesaikan build dari ukuran apa pun secepat yang kita inginkan. Skalabilitas ini adalah tujuan utama yang telah kita perjuangkan dengan menentukan sistem build berbasis artefak.
Penyimpanan cache jarak jauh
Jenis build terdistribusi yang paling sederhana adalah build yang hanya memanfaatkan caching jarak jauh, yang ditampilkan pada Gambar 1.
Gambar 1. Build terdistribusi yang menampilkan penyimpanan dalam cache jarak jauh
Setiap sistem yang melakukan build, termasuk workstation developer dan sistem integrasi berkelanjutan, berbagi referensi ke layanan cache jarak jauh umum. Layanan ini mungkin berupa sistem penyimpanan jangka pendek yang cepat dan lokal seperti Redis atau layanan cloud seperti Google Cloud Storage. Setiap kali pengguna perlu mem-build artefak, baik secara langsung maupun sebagai dependensi, sistem akan terlebih dahulu memeriksa cache jarak jauh untuk melihat apakah artefak tersebut sudah ada di sana. Jika demikian, artifact dapat didownload, bukan di-build. Jika tidak, sistem akan mem-build artefak itu sendiri dan mengupload hasilnya kembali ke cache. Artinya, dependensi tingkat rendah yang tidak sering berubah dapat di-build satu kali dan dibagikan ke seluruh pengguna, bukan harus di-build ulang oleh setiap pengguna. Di Google, banyak artefak ditayangkan dari cache, bukan di-build dari awal, sehingga sangat mengurangi biaya untuk menjalankan sistem build kami.
Agar sistem penyimpanan dalam cache jarak jauh berfungsi, sistem build harus menjamin bahwa build dapat direproduksi sepenuhnya. Artinya, untuk setiap target build, kumpulan input ke target tersebut harus dapat ditentukan sehingga set input yang sama akan menghasilkan output yang sama persis di mesin apa pun. Ini adalah satu-satunya cara untuk memastikan bahwa hasil mendownload artefak sama dengan hasil mem-build-nya sendiri. Perhatikan bahwa hal ini mengharuskan setiap artefak dalam cache di-keying pada target dan hash inputnya—dengan begitu, engineer yang berbeda dapat melakukan modifikasi yang berbeda pada target yang sama pada waktu yang sama, dan cache jarak jauh akan menyimpan semua artefak yang dihasilkan dan menayangkannya dengan tepat tanpa konflik.
Tentu saja, agar ada manfaat dari cache jarak jauh, mendownload artefak harus lebih cepat daripada mem-build-nya. Hal ini tidak selalu terjadi, terutama jika server cache jauh dari mesin yang melakukan build. Jaringan dan sistem build Google disesuaikan dengan cermat agar dapat membagikan hasil build dengan cepat.
Eksekusi jarak jauh
Cache jarak jauh bukanlah build terdistribusi yang sebenarnya. Jika cache hilang atau jika Anda membuat perubahan tingkat rendah yang mengharuskan semuanya di-build ulang, Anda tetap perlu melakukan seluruh build secara lokal di komputer. Tujuan yang sebenarnya adalah mendukung eksekusi jarak jauh, yang memungkinkan pekerjaan aktual melakukan build dapat disebarkan ke sejumlah pekerja. Gambar 2 menggambarkan sistem eksekusi jarak jauh.
Gambar 2. Sistem eksekusi jarak jauh
Alat build yang berjalan di setiap komputer pengguna (dengan pengguna adalah engineer manusia atau sistem build otomatis) mengirim permintaan ke master build pusat. Build master membagi permintaan menjadi tindakan komponen dan menjadwalkan eksekusi tindakan tersebut melalui kumpulan pekerja yang skalabel. Setiap pekerja melakukan tindakan yang diminta dengan input yang ditentukan oleh pengguna dan menulis artefak yang dihasilkan. Artefak ini dibagikan di seluruh mesin lain yang menjalankan tindakan yang memerlukannya hingga output akhir dapat diproduksi dan dikirim ke pengguna.
Bagian tersulit dalam menerapkan sistem tersebut adalah mengelola komunikasi antara pekerja, master, dan komputer lokal pengguna. Pekerja mungkin bergantung pada artefak perantara yang dihasilkan oleh pekerja lain, dan output akhir perlu dikirim kembali ke mesin lokal pengguna. Untuk melakukannya, kita dapat mem-build di atas cache terdistribusi yang dijelaskan sebelumnya dengan meminta setiap pekerja menulis hasil dan membaca dependensinya dari cache. Master memblokir pekerja agar tidak melanjutkan hingga semua hal yang menjadi dependensinya selesai, sehingga pekerja dapat membaca input dari cache. Produk akhir juga di-cache, sehingga mesin lokal dapat mendownloadnya. Perhatikan bahwa kita juga memerlukan cara terpisah untuk mengekspor perubahan lokal di hierarki sumber pengguna sehingga pekerja dapat menerapkan perubahan tersebut sebelum mem-build.
Agar dapat berfungsi, semua bagian sistem build berbasis artefak yang dijelaskan sebelumnya harus digabungkan. Lingkungan build harus sepenuhnya mendeskripsikan diri agar kita dapat menjalankan pekerja tanpa intervensi manusia. Proses build itu sendiri harus sepenuhnya mandiri karena setiap langkah mungkin dieksekusi di mesin yang berbeda. Output harus sepenuhnya deterministik sehingga setiap pekerja dapat memercayai hasil yang diterima dari pekerja lain. Jaminan tersebut sangat sulit diberikan oleh sistem berbasis tugas, yang membuat hampir tidak mungkin untuk membuat sistem eksekusi jarak jauh yang andal di atas sistem tersebut.
Build terdistribusi di Google
Sejak 2008, Google telah menggunakan sistem build terdistribusi yang menggunakan cache jarak jauh dan eksekusi jarak jauh, seperti yang diilustrasikan pada Gambar 3.
Gambar 3. Sistem build terdistribusi dari Google
Cache jarak jauh Google disebut ObjFS. Sistem ini terdiri dari backend yang menyimpan output build di Bigtable yang didistribusikan di seluruh kumpulan mesin produksi kami dan daemon FUSE frontend bernama objfsd yang berjalan di setiap mesin developer. Daemon FUSE memungkinkan engineer untuk menelusuri output build seolah-olah adalah file normal yang disimpan di workstation, tetapi dengan konten file yang didownload secara on-demand hanya untuk beberapa file yang diminta langsung oleh pengguna. Penayangan konten file secara on-demand sangat mengurangi penggunaan jaringan dan disk, dan sistem mampu membangun dua kali lebih cepat dibandingkan saat kita menyimpan semua output build di disk lokal developer.
Sistem eksekusi jarak jauh Google disebut Forge. Klien Forge di Blaze (setara internal Bazel) yang disebut Distributor mengirimkan permintaan untuk setiap tindakan ke tugas yang berjalan di datacenter kami yang disebut Penjadwal. Penjadwal mempertahankan cache hasil tindakan, sehingga dapat segera menampilkan respons jika tindakan telah dibuat oleh pengguna lain sistem. Jika tidak, tindakan akan ditempatkan ke dalam antrean. Kumpulan besar tugas Executor terus-menerus membaca tindakan dari antrean ini, menjalankannya, dan menyimpan hasilnya langsung di ObjFS Bigtable. Hasil ini tersedia untuk eksekutor untuk tindakan mendatang, atau untuk didownload oleh pengguna akhir melalui objfsd.
Hasil akhirnya adalah sistem yang diskalakan untuk mendukung semua build yang dilakukan di Google secara efisien. Selain itu, skala build Google benar-benar besar: Google menjalankan jutaan build yang mengeksekusi jutaan kasus pengujian dan menghasilkan petabyte output build dari miliaran baris kode sumber setiap hari. Sistem tersebut tidak hanya memungkinkan engineer kami membuat codebase yang kompleks dengan cepat, tetapi juga memungkinkan kami menerapkan sejumlah besar alat dan sistem otomatis yang mengandalkan build kami.