Memindahkan Ring ke p4
Tujuh perubahan kontrak antara sebuah mesin dan pemanggilnya. Masing-masing gagal dengan cara berbeda, dan hanya satu yang tampak seperti error.
Kami menggabungkan rilis baru mesin p4 dan ring berhenti melayani. Bukan dengan crash — pemuat melaporkan sukses, para agen melaporkan ready, dan tak terjadi apa-apa. Menelusuri balik dari kesunyian itu memakan satu hari dan menemukan tujuh tempat di mana pemanggil kami dan mesinnya sudah saling menyimpang. Yang membuatnya layak dicatat bukan jumlahnya. Melainkan bahwa enam dari tujuh tak menghasilkan error apa pun.
Peristiwa untuk node yang tak ada diteruskan, bukan ditolak
Pemuat kami mengalamatkan perintah LOAD ke node yang ingin diciptakannya. Tetapi sebuah node belum ada sampai LOAD menciptakannya, dan aturan broker untuk peristiwa yang menyebut node tak dikenal adalah meneruskannya keluar alih-alih menolaknya. Perintah itu meninggalkan agen sambil mencari tempat lain untuk dituju, tak menemukan apa pun, lalu dibuang. Tak ada satu baris log pun, karena dari sudut pandang broker tak ada yang salah.
Perbaikannya adalah mengalamatkan LOAD ke *agen*, dibungkus dalam amplop siklus-hidup mesin yang netral-backend, dengan perintah adapter sendiri sebagai isi yang buram. Jelas setelah tahu; tak terlihat dari luar.
Sebuah angka yang harus sama dengan angka lain
Sebuah model dimuat di bawah load generation, dan tiap node didaftarkan dengan node generation. Kami memperlakukan keduanya sebagai independen — timestamp untuk yang satu, 1 untuk yang lain — dan semuanya berjalan. Ring termuat. Ia menjawab satu permintaan dengan benar. Lalu node kepala mati.
Pemeriksaannya, di dalam akuntansi pelepasan milik adapter.
let Endpoint::Node { generation, .. } = &event.envelope.source;
if *generation != receipt.load_generation {
return Err("release owner census generation differs from source");
}Tanda terima yang menutup sebuah permintaan yang selesai membawa load generation, dan node yang mengirimnya membawa miliknya sendiri. Saat keduanya berbeda, node dihentikan. Jadi bentuk bug-nya adalah: pemuatan sukses, permintaan pertama sukses, kepala mati, dan setiap sesi sesudah itu menggantung setengah-termuat. Itu terbaca persis seperti crash di bawah beban dan sama sekali tak seperti ketidakcocokan. Pemuat kami kini menolak rencana yang kedua angkanya tak sepakat, sebelum apa pun dimuat.
Sebuah batas yang tak mungkin terpenuhi
Adapter membandingkan hasil terbesar yang boleh dikembalikan sebuah stage terhadap angka yang dilaporkan stage server saat ia menyala, untuk kesetaraan persis. Kami tak bisa tahu angka itu tanpa memuat modelnya — jadi kami memuat dengan tebakan, dan kegagalannya memberi tahu kami angka nyata keempat stage sekaligus:
Satu run, empat jawaban.
step37-s0: profile=33554432, READY=34419218444 step37-s1: profile=33554432, READY=34419218444 step37-s2: profile=33554432, READY=34419218444 step37-s3: profile=33554432, READY=59136012
34 GB. Retained store milik agen adalah 256 MiB, jadi ring itu tak akan pernah bisa diterima. Membaca penurunan rumusnya dari stage server menunjukkan sebabnya: batas itu menskala dengan n_batch × n_ubatch, dan kami mewarisi lebar batch 2048 dari sebuah konfigurasi yang mendahului pemeriksaan ini. Pada 128 baris — lebar yang dipakai tata letak produksi — batasnya 138 MB dan muat. Kini kami menurunkannya di dalam rencana dari rumus yang sama alih-alih membawa konstanta yang diingat, dan angka prediksi untuk stage ekor keluar persis sama dengan yang pernah dicatat deployment lain — jenis kesepakatan yang layak dimiliki sebelum menghabiskan dua puluh menit untuk satu pemuatan.
Ringkas saja
- Alamat loopback di ring dua-host. Sebuah stage menelepon agen stage berikutnya di alamat yang diiklankan agen itu. Iklankan
127.0.0.1dan host A menelepon dirinya sendiri. Konfigurasi ring yang tercatat ternyata loopback sejak awal — ia tak pernah bisa bekerja antar-host. - Jurnalnya wajib. Sebuah model tak akan dimuat tanpa jurnal operasional agen. Kami mematikannya saat mengejar error lain dan memperburuk gejalanya dengan cara yang tampak seperti kemajuan.
- Nama perangkat bersifat khusus-backend. Pembangun rencana acuan menargetkan CUDA dan memancarkan
--device CUDA0. Build HIP menamai perangkatnyaROCm0. Rencana itu memuat seluruh model *lalu* gagal menemukan perangkatnya. - Server native adalah bagian dari rilis. Agen yang dibangun dari pohon sumber lebih baru menginginkan kapabilitas yang tak dilaporkan stage server yang terpasang. Juga ditemukan setelah pemuatan model penuh.
Kesunyian adalah mode kegagalan yang mahal
Setiap satu dari semua ini murah untuk diperbaiki dan mahal untuk ditemukan, dan polanya konsisten: kegagalan yang mahal adalah yang membuat sistem tampak benar tetapi tak melakukan apa-apa, atau melakukan sesuatu sekali saja. Penjaga yang kami tambahkan semuanya berbentuk sama — menolak lebih awal, di tempat kesalahannya masih terbaca. Pemuat menuliskan load generation ke disk *sebelum* perintah pertama berangkat, karena tanpa itu ia tak terpulihkan. Ia menolak ketidakcocokan generation alih-alih menemukannya setelah permintaan pertama. Ia menurunkan batas hasil alih-alih mengingatnya.
Ring sedang melayani. Empat stage di dua mesin, 113 GiB bobot residen, token pertama dalam 1.4 dtk saat dingin dan ~0.3 dtk saat hangat, dan kontribusi per-node mengalir sampai ke buku besar penyelesaian untuk pertama kalinya.