Topik ini menjalankan eksperimen terpandu atas hot code upgrade, kemampuan Erlang memuat versi baru modul tanpa menghentikan proses yang berjalan. Eksperimennya dilakukan di laboratorium kecil: dua versi modul, satu proses yang memegang kode lama, dan pemeriksaan langsung atas co-existence dua versi itu. Tujuan topik ini adalah memahami mekanismenya sekali dengan benar, bukan mengangkatnya sebagai kebiasaan sehari-hari.
Dua versi kode di satu VM#
VM menyimpan paling banyak dua versi setiap modul: versi current yang dipakai pemanggilan baru dan versi old yang masih dipegang proses yang sedang mengeksekusinya. Proses yang masuk ke sebuah fungsi menempel pada versi kode yang ada saat itu dan tetap mengeksekusi versi itu sampai selesai, sekalipun versi baru dimuat. Pemanggilan berikutnya dari proses mana pun memakai versi current. Prinsip inilah yang membuat pembaruan tanpa henti mungkin: pemulihan dilakukan proses demi proses, dan setiap proses berpindah versi pada titik yang aman.
Eksperimen dua versi#
Siapkan dua folder berisi modul bernama sama dengan isi berbeda. Versi 1 dan versi 2 hanya berbeda pada fungsi versi/0, dan keduanya memiliki fungsi tunda/0 yang tidur lima detik untuk menahan eksekusi:
%% v1/kalkulator.erl
-module(kalkulator).
-export([versi/0, tunda/0]).
versi() -> 1.
tunda() -> timer:sleep(5000), ok.%% v2/kalkulator.erl
-module(kalkulator).
-export([versi/0, tunda/0]).
versi() -> 2.
tunda() -> timer:sleep(5000), ok.Kompilasi masing-masing ke foldernya, lalu jalankan eksperimen di satu sesi: muat versi 1, mulai proses yang mengeksekusi kode lama sambil tidur, muat versi 2, dan periksa semuanya:
Erlang/OTP 29 [erts-17.1.1] [source] [64-bit] [smp:2:2] [ds:2:2:10] [async-threads:1] [jit:ns]
Eshell V17.1.1 (press Ctrl+G to abort, type help(). for help)
1> code:add_pathz("v1").
true
2> kalkulator:versi().
1
3> P = spawn(kalkulator, tunda, []).
<0.89.0>
4> code:load_abs("v2/kalkulator").
{module,kalkulator}
5> kalkulator:versi().
2
6> erlang:check_process_code(P, kalkulator).
true
7> code:soft_purge(kalkulator).
falseUrutannya terbaca sendiri: versi 1 dijalankan, proses P masuk ke tunda/0 versi lama, versi 2 dimuat dan seketika dipakai pemanggilan versi/0 berikutnya, dan pemeriksaan check_process_code/2 menegaskan P masih menempel versi lama. Percobaan soft_purge/1 mengembalikan false karena kode lama masih dibutuhkan. VM menolak membuangnya alih-alih membunuh prosesnya.
Pelepasan kode lama#
Setelah proses selesai mengeksekusi kode lamanya, versi lama tidak lagi dibutuhkan dan dapat dilepas dengan aman:
8> timer:sleep(5200).
ok
9> erlang:check_process_code(P, kalkulator).
false
10> code:soft_purge(kalkulator).
truesoft_purge/1 menolak membuang saat masih dibutuhkan, sedangkan code:purge/1 membuang kode lama secara paksa dan mengakhiri proses yang masih menempelnya, sehingga dua fungsi itu berbeda konsekuensinya dan pemilihannya perlu dipertimbangkan. Pada sistem nyata, perpindahan proses ke versi baru bukan hal yang dibiarkan kebetulan: proses didesain mengganti kode dengan memanggil kembali dirinya pada titik aman, dan mekanisme yang menyelenggarakan urutan itu dikerjakan OTP.
Aturan pergantian yang aman#
Dua versi kode hidup berdampingan hanya bila versi lama dan baru tidak saling mengunci satu sama lain. Dua aturan praktis yang menahan kegagalan: pertama, jangan mengubah struktur yang dikenali kedua versi, seperti aritas fungsi atau bentuk pesan yang dipertukarkan antar proses. Kedua, sediakan titik perpindahan yang aman bagi proses berumur panjang, karena proses yang berjalan di kode lama tidak otomatis berpindah. Perubahan yang hanya menambah fungsi baru atau memperbaiki isi klausul dengan tata letak data yang sama aman untuk model dua versi, sedangkan perubahan struktur biasanya dikelola lewat penambahan fungsi baru lalu perpindahan proses yang direncanakan.
Pada level aplikasi, urutan pergantian dinyatakan di berkas .appup. Bentuk paling sederhananya memerintahkan emulator untuk dimulai ulang, dan bentuk yang lebih halus menyusun instruksi per modul:
{"0.1.1",
[{restart_new_emulator}],
[{restart_new_emulator}]
}.Entri di atas berlaku untuk arah naik dan turun versi 0.1.1, dengan instruksi restart_new_emulator yang memulai ulang VM dengan versi kode baru. Bentuk yang lebih halus menggantikan instruksi itu dengan rangkaian load_object_code dan load per modul, yang dibahas lengkap bersama relup dan release_handler pada modul Production.
Alur production dan kedudukannya#
Pembaruan yang benar-benar tanpa henti memakai berkas .appup, yaitu resep per aplikasi yang menyatakan urutan instruksi untuk naik dan turun versi, dan rebar3 merakit resep itu bersama relup serta instruksi release_handler pada rilis yang berjalan. Alur lengkapnya meliputi pembuatan release, penyusunan appup, pembuatan paket pembaruan, dan perintah release_handler:install_release/1, yang dituntaskan pada modul Production di topik release dengan rebar3. Meski demikian, kedudukan hot code upgrade di jalur ini dinyatakan apa adanya: mekanismenya nyata, teruji, dan dipakai pada sistem yang menuntut ketersediaan tinggi, tetapi biaya pemeliharaan versi ganda dan resep pembaruannya membuat banyak tim memilih pembaruan bergulir antar node dengan ketersediaan yang tetap terjaga. Topik ini cukup sampai mekanismenya dipahami sekali dengan benar.
Ringkasan#
- VM menyimpan paling banyak dua versi modul: current untuk pemanggilan baru dan old untuk proses yang masih mengeksekusinya.
- code:load_abs memuat versi baru seketika, dan pemanggilan berikutnya memakainya tanpa mengganggu proses lama.
- check_process_code/2 memeriksa ketergantungan proses pada kode lama, soft_purge/1 menolak membuang kode yang masih dipakai, dan purge/1 memaksa dengan mengakhiri prosesnya.
- Alur production memakai berkas .appup dan release_handler, sementara banyak tim memilih pembaruan bergulir antar node.
Kesalahan umum#
- Menghapus versi lama dengan purge saat proses masih menempelnya.
code:purge/1mengakhiri proses yang memegang kode lama tanpa peringatan. Gunakansoft_purge/1saat proses berumur panjang belum siap berpindah. - Membaca hot code upgrade sebagai kebiasaan bawaan. Setiap pembaruan menuntut desain perpindahan yang disadari per proses, dan biayanya melebihi manfaat bila diperlakukan sebagai pengganti rilis biasa.
- Mengubah struktur data yang dipakai kedua versi tanpa rencana. Pesan yang dibentuk versi baru lalu diuraikan versi lama, atau sebaliknya, menghasilkan kegagalan pencocokan di tengah pembaruan. Perubahan struktur membutuhkan instruksinya sendiri di appup.
Referensi#
- Erlang Reference Manual: Code Replacement — Ericsson — Dokumentasi resmi dua versi kode dan aturan pergantiannya.
- code — Ericsson — Dokumentasi resmi load_abs, soft_purge, purge, dan check_process_code.
- Learn You Some Erlang for Great Good! — Fred Hebert — Bab yang menyiapkan pola proses untuk pergantian kode.