Build Terdistribusi

Laporkan masalah Lihat sumber

Jika Anda memiliki codebase yang besar, rantai dependensi bisa menjadi sangat dalam. Bahkan biner sederhana pun sering kali dapat bergantung pada puluhan ribu target build. Pada skala ini, tidak mungkin menyelesaikan build dalam waktu yang wajar di satu mesin: tidak ada sistem build yang dapat mengakali hukum dasar fisika yang diberlakukan pada hardware mesin. Satu-satunya cara untuk melakukannya adalah dengan sistem build yang mendukung build terdistribusi di mana unit pekerjaan yang dilakukan oleh sistem tersebar di sejumlah mesin yang arbitrer dan skalabel. Dengan asumsi kita telah memecah pekerjaan sistem menjadi unit-unit yang cukup kecil (selengkapnya tentang hal ini akan dibahas nanti), hal ini akan memungkinkan kami menyelesaikan build apa pun dalam ukuran apa pun secepat yang kami mampu. Skalabilitas ini adalah hal utama yang sedang kita upayakan dengan menentukan sistem build berbasis artefak.

Penyimpanan cache jarak jauh

Jenis build terdistribusi yang paling sederhana adalah yang hanya memanfaatkan cache jarak jauh, yang ditunjukkan pada Gambar 1.

Build terdistribusi dengan cache jarak jauh

Gambar 1. Build terdistribusi yang menampilkan caching jarak jauh

Setiap sistem yang menjalankan build, termasuk workstation developer dan sistem continuous integration, berbagi referensi ke layanan cache jarak jauh yang umum. Layanan ini mungkin berupa sistem penyimpanan jangka pendek yang cepat dan lokal seperti Redis atau layanan cloud. Setiap kali pengguna perlu mem-build artefak, baik secara langsung maupun sebagai dependensi, sistem akan terlebih dahulu memeriksa dengan cache jarak jauh untuk melihat apakah artefak tersebut sudah ada di sana. Jika demikian, image tersebut dapat mendownload artefak, bukan membuatnya. Jika tidak, sistem akan mem-build artefak itu sendiri dan mengupload hasilnya kembali ke cache. Artinya, dependensi tingkat rendah yang tidak sering berubah dapat dibangun sekali dan dibagikan kepada seluruh pengguna, bukan harus dibangun ulang oleh setiap pengguna. Di Google, banyak artefak disajikan dari cache, bukan dibuat dari awal, sehingga sangat mengurangi biaya menjalankan sistem build.

Agar sistem caching jarak jauh dapat berfungsi, sistem build harus menjamin bahwa build sepenuhnya dapat direproduksi. 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 download artefak sama dengan hasil mem-build artefak itu sendiri. Perlu diperhatikan bahwa hal ini mengharuskan setiap artefak dalam cache dikunci pada target dan hash inputnya. Dengan begitu, engineer yang berbeda dapat membuat modifikasi yang berbeda pada target yang sama secara bersamaan, dan cache jarak jauh akan menyimpan semua artefak yang dihasilkan dan menyalurkannya dengan tepat tanpa konflik.

Tentu saja, agar ada manfaat dari cache jarak jauh, mendownload artefak harus lebih cepat daripada membangunnya. Tidak selalu demikian, terutama jika server cache jauh dari mesin yang melakukan proses 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 dibangun ulang, Anda masih harus menjalankan seluruh build secara lokal di mesin. Tujuan yang sebenarnya adalah mendukung eksekusi jarak jauh, yang memungkinkan pekerjaan aktual melakukan build dapat disebarkan ke sejumlah pekerja. Gambar 2 menunjukkan sistem eksekusi jarak jauh.

Sistem eksekusi jarak jauh

Gambar 2. Sistem eksekusi jarak jauh

Alat build yang berjalan di setiap mesin pengguna (dengan pengguna adalah manusia engineer atau sistem build otomatis) mengirimkan permintaan ke master build pusat. Master build memecah permintaan menjadi tindakan komponennya dan menjadwalkan eksekusi tindakan tersebut pada 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 mengeksekusi tindakan yang memerlukannya hingga output akhir dapat diproduksi dan dikirim ke pengguna.

Bagian tersulit dalam menerapkan sistem semacam itu adalah mengelola komunikasi antara pekerja, master, dan komputer lokal pengguna. Pekerja mungkin bergantung pada artefak perantara yang dihasilkan oleh pekerja lain, dan output akhir harus dikirim kembali ke mesin lokal pengguna. Untuk melakukannya, kita dapat mem-build di atas cache terdistribusi yang dijelaskan sebelumnya dengan meminta setiap pekerja menulis hasilnya dan membaca dependensinya dari cache. Master memblokir pekerja agar tidak melanjutkan hingga semua yang mereka andalkan telah selesai, yang dalam hal ini mereka akan dapat membaca input mereka 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 berfungsi, semua bagian dari sistem build berbasis artefak yang dijelaskan sebelumnya harus disatukan. Lingkungan build harus sepenuhnya mendeskripsikan diri agar kita dapat menjalankan pekerja tanpa campur tangan manusia. Proses build itu sendiri harus sepenuhnya mandiri karena setiap langkah mungkin dieksekusi di mesin yang berbeda. Output harus benar-benar determenistik agar setiap pekerja dapat memercayai hasil yang diterimanya dari pekerja lain. Jaminan tersebut sangat sulit untuk disediakan oleh sistem berbasis tugas, sehingga hampir tidak mungkin untuk membangun sistem eksekusi jarak jauh yang andal selain satu hal lainnya.

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.

Sistem build tingkat tinggi

Gambar 3. Sistem build terdistribusi dari Google

Cache jarak jauh Google disebut ObjFS. Solusi ini terdiri dari backend yang menyimpan output build di Bigtable yang didistribusikan ke seluruh fleet 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. Menyajikan konten file secara on-demand sangat mengurangi penggunaan jaringan dan disk, dan sistem mampu membangun dua kali lebih cepat dibandingkan saat kami 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 mengirim permintaan untuk setiap tindakan ke tugas yang berjalan di pusat data kami yang disebut Scheduler. Scheduler menyimpan cache hasil tindakan, sehingga dapat segera menampilkan respons jika tindakan telah dibuat oleh pengguna lain pada sistem. Jika tidak, tindakan akan ditempatkan dalam antrean. Kumpulan besar tugas Executor akan terus-menerus membaca tindakan dari antrean ini, menjalankannya, dan menyimpan hasilnya langsung di ObjFS Bigtable. Hasil ini tersedia bagi eksekutor untuk tindakan pada masa mendatang, atau untuk didownload oleh pengguna akhir melalui objfsd.

Hasil akhirnya adalah sistem yang melakukan penskalaan untuk mendukung semua build yang dijalankan di Google secara efisien. Dan skala build Google benar-benar masif: Google menjalankan jutaan build yang mengeksekusi jutaan kasus pengujian dan menghasilkan output build berukuran petabyte dari miliaran baris kode sumber setiap harinya. Sistem seperti itu tidak hanya memungkinkan engineer kami membangun codebase kompleks dengan cepat, tetapi juga memungkinkan kami menerapkan sejumlah besar alat dan sistem otomatis yang mengandalkan build kami.