Zero downtime reload sudah menjadi keharusan pada kebanyakan sistem, terutama sistem yang diakses user sepanjang waktu. User menginginkan sistem yang memilik high availability. Jadi merupakan hal buruk apabila sistem memerlukan downtime untuk reload walaupun hanya dalam hitungan milisecond. Socketmaster hadir untuk membantu kita membuat sistem dengan zero downtime reload.
Apa itu socketmaster
Socketmaster adalah sebuah aplikasi yang memungkinkan kita untuk me-reload aplikasi tanpa downtime. Socketmaster melakukannya dengan menjalankan aplikasi kita sebagai child nya. Pada saat reload, socketmaster akan membuat proses baru untuk menjalankan aplikasi dan mengirim sinyal ke proses yang lama untuk berhenti. Sehingga kita tetap dapat menghandle request-request baru yang masuk sambil menunggu proses yang sedang berjalan selesai. Dengan cara ini semua request dapat di handle walaupun sedang reload. Zero downtime reload is achieved.
Untuk menginstal socketmaster, buka https://github.com/zimbatm/socketmaster kemudian download binary atau download source code dan compile sendiri.
Seperti yang tertulis pada Readme, ada beberapa hal yang perlu kita lakukan untuk mengintegrasikan service socketmaster dengan service kita.
Your server is responsible for:
- opening the socket passed on fd 3
- not crashing
- gracefully shutdown on SIGTERM (close the listener, wait for the child connections to close)
Kita akan membahasnya satu per satu.
Untuk bereksperimen dengan socketmaster, saya membuat web server sederhana dengan Go. Kemudian mengirim request secara terus menerus ke server tersebut dan mereload service nya. Yang diharapkan adalah semua request dapat dihandle walaupun server sedang reload. Perlu diketahui bahwa walaupun socketmaster ditulis dengan bahasa pemrograman Go, dia juga dapat digunakan dengan bahasa pemrograman lainnya.
My web server in Go
Code di bawah ini yang digunakan untuk membuat web server. Kemudian kita akan mengintegrasikannya dengan socketmaster untuk membuat zero downtime reload.
|
|
Pada line 7 sampai 11, dapat dilihat kalau web server akan listen fd 3, seperti yang diterangkan pada requirement point 1 sebelumnya, yaitu
opening the socket passed on fd 3
.Untuk requirement berikutnya yaitu not crashing
, by default Go HTTP server sudah memiliki panic recovery. Tapi jika ingin menggunakan panic recovery kita sendiri, bisa cek post saya sebelumnya di sini.
Kemudian untuk requirement terakhir yaitu gracefully shutdown on SIGTERM (close the listener, wait for the child connections to close)
, lihat pada line 22 - 23 pada code diatas. Server me-listen sinyal SIGTERM
dan menampungnya ke dalam sebuah channel. Pada line 26, server menunggu sampai SIGTERM
diterima. Code di bawahnya tidak akan dieksekusi sebelum sinyal tersebut diterima. Ketika SIGTERM
diterima, eksekusi code akan dilanjutkan sampai line 28 di mana server akan di shutdown secara graceful, yaitu menunggu sampai semua proses selesai, baru server benar-benar mati. Ketika service yang lama dishutdown, socketmaster sudah membuat proses baru untuk menghandle request-request baru yang masuk.
Saya menggunakan handler berikut untuk testing. Dia akan sleep selama 3 detik, lalu memberikan response berupa pid dari proses saat ini.
|
|
Jalankan socketmaster & test it
Build go app kemudian gunakan command berikut untuk menjalankan web server dengan socketmaster.
socketmaster -listen tcp://:7008 -command=./mygoapp
-listen tcp://:7008
socket master akan listen ke tcp port 7008.-command=./mygoapp
ini adalah command untuk menjalankan service. Socketmaster akan menjalankan command di sini ketika reload, kemudian mengirim sinyal ke proses yang lama untuk berhenti.Ketika dijalankan, akan muncul log seperti ini
socketmaster[2969] 2021/02/10 15:39:25 Listening on tcp://:7008
socketmaster[2969] 2021/02/10 15:39:25 Starting ./mygoapp [./mygoapp]
socketmaster[2969] 2021/02/10 15:39:26 [2970] listening...
Untuk reload, kita mengirim sinya HUP
ke pid dari socketmaster, dalam contoh di sini pid nya adalah 2969
.
kill -HUP <pid>
Untuk mengetest nya, saya mengirim request secara terus menerus ke server kemudian reload server tersebut. Berikut hasilnya.
|
|
Server direload ketika menghandle request pada line 3.
Yang perlu dipastikan adalah semua request mendapatkan response dari server. Bisa dilihat bahwa pid pada response di line 6 berubah karena di handle oleh service pada process yang baru di buat oleh socketmaster.
Jalankan dengan systemd
Biasanya, seperti pada aplikasi server lainnya, socketmaster dijalankan sebagai daemon. Yang berarti proses nya jalan di background. Di Linux, ada systemd
untuk menjalankan aplikasi di background. Berikut ini adalah contoh file configurasi untuk menjalankan socketmaster sebagai daemon. File ini disimpan di /etc/systemd/system/myservice.service
.
[Unit]
Description=<description about this service>
[Service]
ExecStart=socketmaster -listen tcp://:7008 -command=./mygoapp
ExecReload=/bin/kill -HUP $MAINPID
[Install]
WantedBy=multi-user.target
Untuk menjalankannya
systemctl start myservice
Untuk reload
systemctl reload myservice
Untuk mendapatkan status
systemctl status myservice
root@d6bc11757efd:/# systemctl status myservice
* myservice.service - <description about this service>
Loaded: loaded (/etc/systemd/system/myservice.service; disabled; vendor preset: enabled)
Active: active (running) since Wed 2021-02-10 04:21:27 UTC; 1min 7s ago
Process: 378 ExecReload=/bin/kill -HUP $MAINPID (code=exited, status=0/SUCCESS)
Main PID: 352 (socketmaster)
Tasks: 14 (limit: 2227)
Memory: 2.7M
CGroup: /docker/d6bc11757efdb63c8a359353764b29e72e752d39b2c6a8a2ca7514d56b6bcb86/system.slice/myservice.service
|-352 /usr/local/bin/socketmaster -listen tcp://:7008 -command=./mygoapp
`-379 ./mygoapp
Kesimpulan
Dengan socketmaster kita dapat mereload aplikasi kita tanpa downtime. Ada beberapa hal yang perlu dilakukan untuk mengintegrasikan aplikasi kita dengan socketmaster. Tapi hal-hal tersebut simple dan tidak memerlukan banyak perubahan code. Socketmaster dapat digunakan di production. If you have any questions, leave a comment below.