Build Terdistribusi

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 menyelesaikan build dalam waktu yang wajar di satu mesin: tidak ada sistem build yang dapat menghindari hukum fisika mendasar yang diterapkan pada hardware mesin. Satu-satunya cara untuk membuat sistem ini berfungsi adalah dengan sistem build yang mendukung build terdistribusi, yang unit kerjanya dilakukan oleh sistem yang tersebar di sejumlah mesin yang arbitrer dan skalabel. Dengan asumsi kita telah membagi pekerjaan sistem menjadi unit yang cukup kecil (akan dibahas lebih lanjut nanti), hal ini akan memungkinkan kita menyelesaikan build apa pun dengan ukuran apa pun secepat yang kita bersedia bayar. Skalabilitas ini adalah tujuan utama yang telah kami upayakan dengan menentukan sistem build berbasis artefak.

Penyimpanan cache jarak jauh

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

Build terdistribusi dengan caching jarak jauh

Gambar 1. Build terdistribusi yang menampilkan penyimpanan cache jarak jauh

Setiap sistem yang melakukan build, termasuk workstation developer dan sistem integrasi berkelanjutan, berbagi referensi ke layanan penyimpanan 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 membuat artefak, baik secara langsung maupun sebagai dependensi, sistem akan terlebih dahulu memeriksa penyimpanan cache jarak jauh untuk melihat apakah artefak tersebut sudah ada di sana. Jika ada, sistem dapat mendownload artefak tersebut, bukan membuatnya. Jika tidak ada, sistem akan membuat artefak itu sendiri dan mengupload hasilnya kembali ke penyimpanan cache. Artinya, dependensi tingkat rendah yang tidak terlalu sering berubah dapat dibuat satu kali dan dibagikan kepada pengguna, bukan harus dibuat ulang oleh setiap pengguna. Di Google, banyak artefak yang disediakan dari penyimpanan cache, bukan dibuat dari awal, sehingga mengurangi biaya menjalankan sistem build kami secara signifikan.

Agar sistem penyimpanan cache jarak jauh berfungsi, sistem build harus menjamin bahwa build dapat direproduksi sepenuhnya. Artinya, untuk target build apa pun, harus memungkinkan untuk 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 mendownload artefak sama dengan hasil membuat artefak itu sendiri. Perhatikan bahwa hal ini mengharuskan setiap artefak dalam penyimpanan cache diberi kunci pada targetnya dan hash inputnya—dengan begitu, engineer yang berbeda dapat membuat modifikasi yang berbeda ke target yang sama pada waktu yang sama, dan penyimpanan cache jarak jauh akan menyimpan semua artefak yang dihasilkan dan menyajikannya dengan tepat tanpa konflik.

Tentu saja, agar ada manfaat dari penyimpanan cache jarak jauh, mendownload artefak harus lebih cepat daripada membuatnya. Hal ini tidak selalu terjadi, terutama jika server penyimpanan cache jauh dari mesin yang melakukan build. Sistem build dan jaringan Google disetel dengan cermat agar dapat berbagi hasil build dengan cepat.

Eksekusi jarak jauh

Penyimpanan cache jarak jauh bukanlah build terdistribusi yang sebenarnya. Jika penyimpanan cache hilang atau jika Anda membuat perubahan tingkat rendah yang mengharuskan semuanya dibuat ulang, Anda tetap harus melakukan seluruh build secara lokal di mesin Anda. Tujuan sebenarnya adalah mendukung eksekusi jarak jauh, yang memungkinkan pekerjaan build yang sebenarnya 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 mesin setiap pengguna (dengan pengguna adalah engineer manusia atau sistem build otomatis) mengirimkan permintaan ke master build pusat. Master build membagi permintaan menjadi tindakan komponennya 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 dibuat dan dikirim ke pengguna.

Bagian tersulit dalam menerapkan 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 harus dikirim kembali ke mesin lokal pengguna. Untuk melakukannya, kita dapat membangun di atas penyimpanan cache terdistribusi yang dijelaskan sebelumnya dengan membuat setiap pekerja menulis hasilnya ke penyimpanan cache dan membaca dependensinya dari penyimpanan cache. Master memblokir pekerja agar tidak melanjutkan hingga semua yang mereka andalkan selesai, dan dalam hal ini mereka akan dapat membaca input dari penyimpanan cache. Produk akhir juga di-cache, sehingga mesin lokal dapat mendownloadnya. Perhatikan bahwa kita juga memerlukan cara terpisah untuk mengekspor perubahan lokal di pohon sumber pengguna sehingga pekerja dapat menerapkan perubahan tersebut sebelum membuat build.

Agar dapat berfungsi, semua bagian dari sistem build berbasis artefak yang dijelaskan sebelumnya harus digabungkan. Lingkungan build harus sepenuhnya mendeskripsikan 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 mempercayai hasil yang diterimanya dari pekerja lain. Jaminan seperti itu sangat sulit diberikan oleh sistem berbasis tugas, sehingga hampir tidak mungkin untuk membangun sistem eksekusi jarak jauh yang andal di atasnya.

Build terdistribusi di Google

Sejak tahun 2008, Google telah menggunakan sistem build terdistribusi yang menggunakan penyimpanan cache jarak jauh dan eksekusi jarak jauh, yang diilustrasikan pada Gambar 3.

Sistem build tingkat tinggi

Gambar 3. Sistem build terdistribusi Google

Penyimpanan cache jarak jauh Google disebut ObjFS. Penyimpanan cache ini terdiri dari backend yang menyimpan output build di Bigtable yang didistribusikan di seluruh armada mesin produksi kami dan daemon FUSE frontend bernama objfsd yang berjalan di mesin setiap 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 diminta langsung oleh pengguna. Menyajikan konten file sesuai permintaan sangat mengurangi penggunaan jaringan dan disk, dan sistem dapat membuat 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 pusat data kami yang disebut Scheduler. Scheduler mempertahankan penyimpanan cache hasil tindakan, sehingga dapat segera menampilkan respons jika tindakan telah dibuat oleh pengguna sistem lainnya. Jika tidak, Scheduler akan menempatkan tindakan 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 dapat diskalakan untuk mendukung semua build yang dilakukan di Google secara efisien. Skala build Google sangat besar: Google menjalankan jutaan build yang menjalankan jutaan kasus pengujian dan menghasilkan petabyte output build dari miliaran baris kode sumber setiap hari. Sistem ini 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.