Desain sistem: Persiapkan diri Anda untuk yang terburuk
Saat mengembangkan aplikasi baru atau fitur baru, salah satu hal penting yang perlu Anda perhatikan adalah kemampuan aplikasi Anda untuk pulih sendiri jika terjadi kegagalan. Kode Anda bisa bagus dan memenuhi persyaratan bisnis TETAPI, apakah cukup baik untuk melakukannya juga pada saat terjadi kegagalan yang tidak terduga? Apakah ketahanan aplikasi Anda cukup untuk secara otomatis mengatasi kegagalan tersebut?
Kadang-kadang Anda tidak akan secara implisit diinstruksikan untuk menerapkan mekanisme ketahanan dan fallback sebagai bagian dari persyaratan bisnis karena skenario yang seharusnya ditangani bisa sangat teknis dan didorong oleh pengembangan. Mekanisme tersebut terkait dengan kelompok kebutuhan non fungsional.
Apa itu "Kegagalan tak terduga" yang sedang kita bicarakan?
Nah, ada berbagai skenario yang bisa terjadi yang akan menyebabkan aplikasi Anda gagal/tidak stabil. Sebagai contoh:
- Timeout / Layanan tidak tersedia dari API eksternal yang digunakan aplikasi Anda
- Bug di pihak ketiga yang digunakan oleh aplikasi Anda
- Kegagalan operasi Database
- Pemuatan tak terduga pada aplikasi yang menyebabkan penurunan kinerja dan penolakan permintaan masuk
- Kesalahan tak terduga yang menyebabkan hilangnya data
- proses berumur panjang yang dikelola oleh aplikasi macet di statusnya karena kehilangan data
Memiliki aplikasi tanpa mekanisme pemulihan diri dan cadangan yang relevan tidak akan bertahan untuk jangka panjang. “Kegagalan tak terduga” itu pada akhirnya akan terjadi, itu akan merusak SLA dan pengalaman pelanggan Anda. Ini dapat menyebabkan kehilangan data yang akan sulit dipulihkan dan mengharuskan ANDA untuk campur tangan secara manual dan melakukan beberapa sihir untuk memperbaiki masalah tersebut. Sekarang pikirkan tentang aplikasi yang menangani ratusan ribu permintaan per menit, kegagalan kecil dapat menyebabkan dampak besar yang sulit diperbaiki secara manual dan akan menghabiskan banyak waktu dan uang untuk organisasi Anda.
Karena itu Anda harus bersiap untuk yang terburuk.
Mari kita membahas beberapa skenario umum dan memberikan solusi yang dapat meningkatkan tingkat ketahanan aplikasi dan kemampuan fallback sehingga Anda dapat tidur nyenyak di malam hari :)
Mekanisme coba lagi
Terutama ketika berhadapan dengan operasi I/O seperti mengirim permintaan http, membaca/menulis dari database atau file, dll. kemungkinan Anda akan menemukan kesalahan adalah hal biasa. Misalnya: Layanan tidak tersedia, Kesalahan server internal, Batas waktu operasi, dan lainnya.
Banyak dari kesalahan ini dapat bersifat sementara dan berhenti dalam hitungan detik, artinya ada kemungkinan besar upaya berikutnya setelah beberapa detik akan berhasil.
Jadi… mengapa bisnis Anda gagal hanya karena masalah sementara yang kecil? Coba lagi! Gunakan mekanisme coba ulang atas operasi yang akan memastikan bahwa jika masalah bersifat sementara, aplikasi Anda akan mengatasinya secara otomatis.
Perhatikan hal-hal berikut:
- Mampu mengonfigurasi dan membatasi jumlah percobaan ulang yang coba dijalankan oleh aplikasi Anda. Percobaan ulang yang tidak terbatas / tinggi dapat menyebabkan aplikasi Anda macet dan menolak permintaan lain karena akan sibuk pada percobaan ulang tanpa akhir
- menerapkan bakeoff eksponensial. Secara eksponensial tingkatkan interval antara percobaan ulang.
Ini akan meningkatkan kemungkinan bahwa masalah sementara (di server/database/pihak ke-3) telah diselesaikan dan usaha Anda berikutnya akan berhasil. Selain itu menggunakan interval eksponensial juga memberi kelonggaran bagi pihak ke-3 yang sedang dalam beban sehingga tidak dapat melayani kliennya. Menjalankan percobaan ulang segera tanpa penundaan dapat memperburuk masalah. - Pastikan Anda memahami kesalahan mana yang harus dicoba lagi dan mana yang tidak. Tidak setiap kesalahan dapat diselesaikan dengan upaya coba lagi. Misalnya permintaan http Anda gagal dengan kode status 'Permintaan buruk' (400). Artinya ada sesuatu dengan data permintaan yang salah dan ditolak oleh server. Tidak peduli berapa banyak percobaan ulang yang akan dilakukan aplikasi Anda, itu akan berakhir dengan hasil yang sama — kegagalan.
Melakukan percobaan ulang pada kesalahan semacam itu berlebihan dan akan memengaruhi kinerja aplikasi Anda. Anda harus membedakan antara kesalahan yang berbeda dan memutuskan percobaan ulang mana yang dapat dilakukan.
Ada beberapa pustaka sumber terbuka yang sudah memberi Anda semua fitur yang relevan dari mekanisme coba ulang sehingga Anda tidak perlu menulisnya dari awal. Misalnya, di .NET Anda memiliki pustaka bernama Polly.
Jangan lupa untuk bertanya, apa yang harus saya lakukan jika semua percobaan ulang gagal? Ini adalah pertanyaan bisnis dan jawabannya dapat diubah di antara skenario.
Tentukan batas waktu untuk proses Anda
Beberapa aplikasi mengelola proses yang berumur panjang. Proses memiliki status yang menunjukkan kemajuan. Kemajuan proses terkadang bergantung pada operasi yang lama atau respons asinkron dari pihak ketiga. Karena ada yang salah (dan selalu salah), proses Anda dapat macet selamanya pada keadaan non-final dan tetap "terbuka". Misalnya, pihak ke-3 mengalami kegagalan dalam mengirimkan kembali tanggapan.
Oke, Jadi mereka akan tetap buka. Apa masalahnya?
Kemungkinan besar sistem lain bergantung pada proses Anda dan mereka menunggu hasilnya. Aplikasi Anda akan menghentikan seluruh aliran bisnis, memengaruhi SLA layanan lain dan pengalaman pengguna.
Selain itu, proses terbuka tersebut akan mempersulit investigasi dan analisis data karena berperilaku berbeda dan dapat merusak statistik Anda.
Saya tidak menginginkan ini! Bagaimana cara mengatasinya?
Pertama, tentukan waktu yang cocok dan dapat diterima agar proses Anda dapat tetap dalam keadaan tidak final. Ini adalah pertanyaan bisnis dan harus ditentukan oleh SLA yang menjadi kewajiban Anda dan dengan evaluasi berapa total waktu yang wajar yang harus diambil untuk operasi di dalam proses. Misalnya, jika proses saya bergantung pada pihak ke-3 yang waktu respons rata-ratanya adalah 10 menit, Anda dapat menentukan batas waktu 20–30 menit.
Sekarang Anda dapat melompat ke implementasi. Implementasi dasar dapat membuat operasi terjadwal yang berjalan setiap X menit dan mencari proses terbuka lebih dari Y menit (nilai timeout). Jika ditemukan, cukup pindahkan proses ke keadaan akhir, bisa berupa keadaan gagal/keadaan batal.
Dengan cara ini Anda memiliki kemampuan untuk menggagalkan/membatalkan proses dengan anggun. Itu dilakukan dengan cara yang dapat dikelola dan memberikan aplikasi Anda kemampuan untuk memberi tahu hasil yang relevan kepada klien yang tertunda.
Melihat! polanya tidak menyelesaikan masalah itu sendiri TETAPI itu memberi Anda kemampuan untuk mengelolanya secara otomatis dan menjalankan alur mundur. Mampu mengomunikasikan bahwa ada masalah dan tetap berpegang pada SLA yang dijanjikan.
Mari kita lihat skenario kehidupan nyata yang menggunakan pola ini:
Tim saya di Payoneer bertanggung jawab atas proses persetujuan otomatis dokumen pelanggan. Proses persetujuan dokumen adalah proses offline yang dibangun dari beberapa langkah dan melibatkan integrasi dengan vendor eksternal yang memberikan hasil analisis melalui komunikasi asinkron.
Sistem kami menerapkan pola timeout dan setelah timeout, sistem memindahkan dokumen pelanggan untuk ditinjau secara manual oleh perwakilan alih-alih menunggu hasil otomatis.
Dengan cara ini kami tidak memengaruhi SLA yang kami miliki di depan pelanggan terkait waktu yang diperlukan untuk meninjau dokumennya.
Jangan menyampaikan hanya pada panggilan balik/webhook - Terapkan mekanisme polling
Saat berhadapan dengan komunikasi asinkron, respons dikembalikan ke klien sebagai panggilan balik. Itu bisa berupa server yang memicu webhook dengan data atau server yang menerbitkan acara melalui bus acara/ broker pesan.
Ada skenario ketika pesan tidak diterima oleh klien atau diterima tetapi gagal ditangani dengan benar dan oleh karena itu dihapus yang menyebabkan hilangnya data. Dalam skenario tersebut, klien masih menunggu respons tetapi server sudah mengirimkannya dan tidak akan mengirimkannya lagi.
di bagian sebelumnya kami menyebutkan pola batas waktu yang tidak menyelesaikan masalah tetapi membiarkan Anda gagal dengan anggun dan mengaktifkan alur fallback yang dapat dikelola. Dengan menerapkan mekanisme pemungutan suara, Anda akan dapat menyelesaikan beberapa masalah secara otomatis dan tetap berada di “jalur bahagia” alur bisnis.
Alih-alih hanya menunggu server memberikan respons secara asinkron dengan push, implementasikan proses terjadwal yang akan dijalankan setiap X menit dan akan mencari permintaan yang tertunda lebih dari Y menit. Untuk permintaan tersebut, aplikasi Anda akan mengirimkan permintaan sinkron ke server untuk mendapatkan data respons. Jika permintaan asli selesai diproses oleh server, itu akan dapat mengirimkan hasilnya kepada Anda. Dalam hal ini, aplikasi Anda akan melanjutkan alur bisnis yang sama seperti yang dilakukan jika data diterima oleh webhook. Kalau tidak, permintaan asli masih diproses oleh server dan ada catatan untuk dikirim kembali. Anda hanya perlu terus menunggu.
Dengan menerapkan mekanisme ini, Anda dapat secara otomatis menyelesaikan masalah tak terduga yang terkait dengan komunikasi asinkron dan dengan menghindari kegagalan aliran atau campur tangan secara manual untuk memulihkan data dari server.
Melihat! Tidak semua layanan yang akan Anda integrasikan akan memiliki kemampuan untuk memberi Anda titik akhir untuk pemungutan suara selain komunikasi asinkron yang mereka tawarkan. Jika mereka tidak memilikinya, ada baiknya menanyakan apakah itu dapat dilakukan di masa mendatang.
Memang benar ada overhead kinerja dengan solusi ini TETAPI dengan memilih interval yang tepat akan mulus dan manfaat yang diberikannya pada saat kegagalan tak ternilai harganya.
Hindari dari kunci vendor
Biasanya aplikasi menggunakan vendor eksternal untuk mencapai tujuan bisnisnya. Tidak mungkin setiap organisasi akan mengembangkan setiap bagian dari logika di rumah terutama jika logika itu kompleks dan jauh dari bisnis utama organisasi. Oleh karena itu, Anda mungkin akan lebih memilih untuk berintegrasi dengan vendor yang dapat menyediakan bagian dari logika yang Anda perlukan untuk melengkapi alur bisnis Anda.
Jadi setelah melakukan riset dan POC Anda menemukan vendor yang cocok untuk kebutuhan Anda.
Integrasi berjalan lancar dan… VOILA! Anda menjalankan bisnis Anda dan melayani ratusan ribu pelanggan setiap hari.
Sekarang izinkan saya mengajukan pertanyaan. Apa yang akan terjadi jika suatu saat vendor eksternal ini berhenti bekerja? apa yang akan terjadi jika itu akan bangkrut? Jika diretas dan layanan tidak akan tersedia untuk jangka waktu yang lama? Atau mungkin Anda tidak akan puas dengan kinerja vendor atau mungkin dari cara pengelolaannya karena setiap bulan ada perubahan baru yang menyebabkan tim pengembangan Anda bekerja sepanjang waktu untuk menyesuaikan integrasi?
Terutama ketika berhadapan dengan arus bisnis utama dan sensitif, skenario ini sangat penting dan dapat melumpuhkan bagian dari organisasi Anda dan berdampak besar pada pelanggan Anda.
Kembali lagi ke proses persetujuan otomatis dokumen pelanggan yang dikelola oleh tim saya di Payoneer, sebagai bagian dari proses kami menggunakan vendor eksternal untuk mengekstrak teks yang relevan dari dokumen dan memprosesnya. Kami memilih untuk berintegrasi dengan 2 vendor yang memberi kami hasil ini dan memiliki prioritas di antara mereka sehingga jika salah satu gagal atau memiliki banyak false positive, kami dapat beralih ke yang lain tanpa waktu henti aliran bisnis. Ini tentu saja juga memberi kami keyakinan bahwa jika sesuatu akan terjadi pada salah satu dari mereka, kami selalu memiliki yang lain untuk disampaikan.
Tentu saja Anda tidak selalu harus membuat cadangan ini. Ini masalah nilai uang dan seberapa kritis aliran bisnis yang Anda hadapi.
Pola pemutus arus
Berbeda dengan pola coba lagi yang diharapkan untuk mengatasi kegagalan transien, pola pemutus sirkuit ada di sini untuk mencegah aplikasi menjalankan operasi yang kemungkinan besar gagal.
Pikirkan Anda menggunakan pihak ke-3 melalui REST API yang saat ini memiliki bug yang menyebabkan semua permintaan gagal. Katakanlah ETA untuk perbaikan adalah 4 jam.
Dengan pola coba ulang, aplikasi akan mencoba berkali-kali untuk memohon permintaan yang akhirnya gagal. Upaya coba ulang yang tidak berguna tersebut akan berdampak pada kinerja aplikasi dan pihak ke-3.
Alih-alih itu, pola pemutus sirkuit akan memungkinkan aplikasi gagal dengan cepat dan mencoba pulih secara bertahap saat masalah teratasi. Dengan itu menghindari dari peningkatan kesalahan dan penurunan kinerja.
Jadi bagaimana cara kerjanya?
Mekanisme tersebut bertindak sebagai proksi untuk operasi yang ingin Anda jalankan.
Ini memiliki 3 status:
- Tertutup- Artinya operasi diizinkan untuk dijalankan secara teratur.
Jumlah kegagalan sedang dihitung dalam status ini. Jika jumlah kegagalan melewati ambang yang ditentukan dalam interval waktu yang ditentukan, mekanisme akan berpindah ke keadaan terbuka. - Terbuka - Artinya mekanisme akan mencegah operasi untuk dieksekusi karena mengalami banyak kegagalan dan oleh karena itu akan lebih memilih untuk gagal dengan cepat tanpa mencoba menjalankannya. Dalam keadaan ini kita memiliki batas waktu. Saat tercapai, mekanismenya bergerak ke keadaan Setengah terbuka.
- Setengah terbuka- Artinya permintaan terbatas untuk menjalankan operasi diizinkan dan diteruskan. Status ini untuk memeriksa apakah masalah sudah teratasi. Jika jumlah operasi yang terbatas itu berhasil dijalankan, mekanisme menganggap bahwa masalah telah diselesaikan dan memindahkan status mekanisme ke tertutup. Kalau tidak, itu akan kembali ke Open karena masalahnya masih ada.
Titik akhir khusus untuk intervensi manual yang mudah dan efisien
Karena itu, terkadang kami tidak siap dengan solusi otomatisasi untuk kasus apa pun yang akan datang. Terkadang solusi otomatis kami akan datang hanya setelah kami pertama kali menemukan skenario dan memahami cara menyelesaikannya dengan otomatisasi. Oleh karena itu dalam kasus tersebut intervensi manual tidak dapat dihindari. Sebagian besar waktu, intervensi manual ini mengharuskan Anda untuk melalui "nyali" layanan seperti: langsung mengubah nilai melalui database atau, secara manual merestrukturisasi pesan dan mengirimkannya langsung melalui broker pesan.
Juga di sini kita dapat mempersiapkan sebelumnya sehingga intervensi manual ini dapat dikelola, aman dan efisien. Buat saja API internal di aplikasi Anda yang akan mengaktifkan operasi manual umum tersebut.
Misalnya, buat titik akhir yang memungkinkan Anda membatalkan proses yang dikelola aplikasi Anda. Atau buat titik akhir yang memungkinkan untuk menerbitkan ulang hasil dari proses lama sehingga sistem lain dapat menggunakannya lagi jika hilang atau tidak pernah diaktifkan.
Dengan membuat API internal ini, Meskipun membutuhkan seseorang untuk memicunya, ini memiliki banyak manfaat:
- Operasi dapat dikelola oleh aplikasi. Aplikasi adalah pemilik perubahan dan mengetahuinya.
- Operasi tersebut diuji oleh QA karena merupakan bagian dari pengembangan. Oleh karena itu Anda mengurangi kemungkinan kesalahan
- terkadang operasinya tidak sesederhana memperbarui nilai di DB. Terkadang ada juga tindakan sampingan yang perlu dilakukan. Semua tindakan sampingan tersebut dapat dikelola di bawah API internal agar mudah digunakan.
- Hemat waktu
Untuk menyimpulkan
Aplikasi Anda HARUS selalu siap untuk yang terburuk!
Semakin banyak aplikasi Anda tahu untuk memulihkan diri dan memiliki solusi fallback, semakin meningkat kinerjanya, dampaknya pada pengalaman pelanggan akan rendah, semakin cepat Anda dapat mengatasi kegagalan dan menghemat waktu dan uang yang berharga untuk organisasi Anda.
Selama desain aplikasi / fitur Anda harus memperhatikan hal ini. Anda harus mengajukan pertanyaan yang tepat dan mengidentifikasi titik lemah untuk menyiapkan perawatan yang relevan dan menghindari kejutan yang tidak menyenangkan dalam produksi.