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 berbagai ukuran 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 ditunjukkan 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 target build apa pun, Anda harus dapat menentukan kumpulan input ke target tersebut sehingga kumpulan input yang sama akan menghasilkan output yang sama persis di komputer mana 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. Sasaran sebenarnya adalah untuk mendukung eksekusi jarak jauh, tempat pekerjaan sebenarnya untuk melakukan build dapat tersebar di 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) mengirimkan 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 ke 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 menjelaskan dirinya sendiri sehingga kita dapat mengaktifkan pekerja tanpa intervensi manusia. Proses build itu sendiri harus sepenuhnya mandiri karena setiap langkah mungkin dijalankan 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 tahun 2008, Google telah menggunakan sistem build terdistribusi yang menggunakan caching jarak jauh dan eksekusi jarak jauh, yang diilustrasikan dalam Gambar 3.
Gambar 3. Sistem build terdistribusi 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 menjelajahi output build seolah-olah file normal yang disimpan di workstation, tetapi dengan konten file yang didownload sesuai permintaan hanya untuk beberapa file yang langsung diminta oleh pengguna. Menayangkan konten file secara on-demand sangat mengurangi penggunaan jaringan dan disk, dan sistem dapat mem-build 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 membaca tindakan dari antrean ini, menjalankannya, dan menyimpan hasilnya langsung di Bigtable ObjFS. 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.