Build yang Didistribusikan

Laporkan masalah Lihat sumber

Jika Anda memiliki codebase besar, rantai dependensi dapat menjadi sangat dalam. Bahkan biner sederhana sering kali dapat bergantung pada puluhan ribu target build. Pada skala ini, tidak mungkin untuk menyelesaikan build dalam jumlah waktu yang wajar di satu mesin: tidak ada sistem build yang dapat melanggar hukum fisik dasar yang diberlakukan pada hardware mesin. Satu-satunya cara untuk melakukan pekerjaan ini adalah dengan sistem build yang mendukung build terdistribusi di mana unit pekerjaan yang dilakukan oleh sistem tersebar di beberapa mesin yang arbitrer dan skalabel. Dengan asumsi bahwa kita telah membagi pekerjaan sistem menjadi unit yang cukup kecil (nanti akan dijelaskan lebih lanjut), hal ini akan memungkinkan kita menyelesaikan build dalam ukuran apa pun secepat yang bersedia kita bayar. Skalabilitas ini adalah tujuan utama yang kami perjuangkan dengan menentukan sistem build berbasis artefak.

Pembuatan cache dari jarak jauh

Jenis build terdistribusi yang paling sederhana adalah build 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, memiliki referensi yang sama ke layanan cache jarak jauh umum. Layanan ini mungkin merupakan 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, aplikasi tersebut dapat mendownload artefak, bukan mem-build-nya. Jika tidak, sistem akan mem-build artefak itu sendiri dan mengupload hasilnya kembali ke cache. Artinya, dependensi tingkat rendah yang tidak terlalu sering berubah dapat dibuat sekali dan dibagikan kepada seluruh pengguna, bukan harus dibuat ulang oleh setiap pengguna. Di Google, banyak artefak disajikan dari cache, bukan di-build dari awal, sehingga sangat mengurangi biaya pengoperasian sistem build.

Agar sistem caching jarak jauh berfungsi, sistem build harus menjamin bahwa build dapat direproduksi sepenuhnya. Artinya, untuk setiap target build, Anda harus menentukan kumpulan input ke target tersebut sehingga kumpulan input yang sama akan menghasilkan output yang sama persis di mesin mana pun. Ini adalah satu-satunya cara untuk memastikan bahwa hasil download artefak sama dengan hasil mem-build artefak sendiri. Perlu diperhatikan bahwa setiap artefak dalam cache dikunci pada targetnya 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 menayangkannya dengan tepat tanpa konflik.

Tentu saja, agar ada manfaat dari cache jarak jauh, mendownload artefak harus lebih cepat daripada membuatnya. 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

Pembuatan cache dari jarak jauh bukanlah build yang terdistribusi yang sebenarnya. Jika cache hilang atau jika Anda membuat perubahan tingkat rendah yang mengharuskan semuanya dibuat ulang, Anda masih perlu melakukan seluruh build secara lokal di mesin. Sasaran yang sebenarnya adalah mendukung eksekusi jarak jauh, dan pekerjaan sebenarnya yang dilakukan saat mem-build dapat disebarkan ke sejumlah pekerja. Gambar 2 menggambarkan sistem eksekusi jarak jauh.

Sistem eksekusi jarak jauh

Gambar 2. Sistem eksekusi jarak jauh

Alat build yang berjalan di setiap mesin pengguna (di mana pengguna adalah engineer manusia atau sistem build otomatis) mengirimkan permintaan ke master build pusat. Master build membagi permintaan ke dalam tindakan komponennya dan menjadwalkan eksekusi tindakan tersebut di atas kumpulan pekerja yang skalabel. Setiap pekerja melakukan tindakan yang diminta dengan input yang ditentukan oleh pengguna dan menulis artefak yang dihasilkan. Artefak ini digunakan bersama oleh mesin lain yang menjalankan tindakan yang memerlukannya hingga output akhir dapat diproduksi dan dikirim kepada pengguna.

Bagian tersulit dari mengimplementasikan sistem tersebut adalah mengelola komunikasi antara pekerja, master, dan mesin 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 membuat cache yang didistribusikan seperti yang dijelaskan sebelumnya dengan meminta setiap pekerja menulis hasilnya dan membaca dependensinya dari cache. Master memblokir pekerja agar tidak melanjutkan hingga semua yang mereka perlukan telah selesai, sehingga mereka dapat membaca input dari cache. Produk akhir juga disimpan dalam 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 dari sistem build berbasis artefak yang dijelaskan di awal harus digabungkan. Lingkungan build harus benar-benar mendeskripsikan sendiri sehingga kami dapat menyiapkan pekerja tanpa intervensi manusia. Proses build itu sendiri harus sepenuhnya mandiri karena setiap langkah mungkin dijalankan pada mesin yang berbeda. Output harus sepenuhnya deterministik sehingga setiap pekerja dapat memercayai hasil yang diterimanya dari pekerja lain. Jaminan tersebut sangat sulit untuk diberikan oleh sistem berbasis tugas, yang membuatnya sangat mustahil untuk membuat sistem eksekusi jarak jauh yang andal.

Build terdistribusi di Google

Sejak 2008, Google telah menggunakan sistem build terdistribusi yang menggunakan cache dari jarak jauh dan eksekusi jarak jauh, yang diilustrasikan dalam Gambar 3.

Sistem build tingkat tinggi

Gambar 3. Sistem build terdistribusi Google

Cache jarak jauh Google disebut ObjFS. Ini terdiri dari backend yang menyimpan output build di Bigtable yang didistribusikan ke seluruh armada mesin produksi kami dan daemon frontend FUSE bernama objfsd yang berjalan di setiap mesin developer. Daemon FUSE memungkinkan engineer menjelajahi output build seolah-olah file normal tersebut disimpan di workstation, tetapi dengan konten file yang didownload secara on demand hanya untuk beberapa file yang diminta langsung oleh pengguna. Menayangkan konten file on demand sangat mengurangi penggunaan jaringan dan disk, dan sistem dapat mem-build dua kali lebih cepat dibandingkan dengan 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 mengirimkan permintaan untuk setiap tindakan ke tugas yang berjalan di pusat data kami yang disebut Scheduler. Penjadwal mempertahankan cache hasil tindakan, sehingga memungkinkannya segera menampilkan respons jika tindakan sudah dibuat oleh pengguna sistem lainnya. Jika tidak, tindakan akan ditempatkan dalam antrean. Kumpulan besar tugas Executor terus-menerus membaca tindakan dari antrean ini, menjalankannya, dan menyimpan hasilnya langsung di ObjFS Bigtable. Hasil ini tersedia bagi eksekutor untuk tindakan mendatang, atau dapat didownload oleh pengguna akhir melalui objfsd.

Hasil akhirnya adalah sistem yang melakukan penskalaan untuk mendukung semua build yang dilakukan di Google secara efisien. Selain itu, skala build Google sangat besar: Google menjalankan jutaan build yang mengeksekusi jutaan kasus pengujian dan menghasilkan petabyte build output dari miliaran baris kode sumber setiap hari. Sistem ini tidak hanya memungkinkan engineer kami membuat codebase kompleks dengan cepat, tetapi juga memungkinkan kami menerapkan sejumlah besar alat dan sistem otomatis yang mengandalkan build kami.