![Search icon](https://hackernoon.imgix.net/search-new.png?w=19&h=19)
Ketahanan dalam perisian merujuk kepada keupayaan aplikasi untuk terus berfungsi dengan lancar dan boleh dipercayai, walaupun dalam menghadapi isu atau kegagalan yang tidak dijangka. Dalam projek Fintech, daya tahan adalah sangat penting kerana beberapa sebab. Pertama, syarikat bertanggungjawab untuk memenuhi keperluan kawal selia dan pengawal selia kewangan menekankan daya tahan operasi untuk mengekalkan kestabilan dalam sistem. Selain itu, percambahan alat digital dan pergantungan kepada penyedia perkhidmatan pihak ketiga mendedahkan perniagaan Fintech kepada ancaman keselamatan yang lebih tinggi. Daya tahan juga membantu mengurangkan risiko gangguan yang disebabkan oleh pelbagai faktor seperti ancaman siber, wabak atau peristiwa geopolitik, melindungi operasi perniagaan teras dan aset kritikal.
Dengan corak daya tahan, kami memahami satu set amalan terbaik dan strategi yang direka untuk memastikan perisian dapat menahan gangguan dan mengekalkan operasinya. Corak ini bertindak seperti jaring keselamatan, menyediakan mekanisme untuk mengendalikan ralat, mengurus beban dan pulih daripada kegagalan, dengan itu memastikan aplikasi kekal teguh dan boleh dipercayai dalam keadaan buruk.
Strategi daya tahan yang paling biasa termasuk sekat, cache, sandaran, cuba semula dan pemutus litar. Dalam artikel ini, saya akan membincangkannya dengan lebih terperinci, dengan contoh masalah yang boleh mereka bantu selesaikan.
Mari kita lihat tetapan di atas. Kami mempunyai aplikasi yang sangat biasa dengan beberapa bahagian belakang di belakang kami untuk mendapatkan beberapa data daripadanya. Terdapat beberapa klien HTTP yang disambungkan ke bahagian belakang ini. Ternyata kesemua mereka berkongsi kumpulan sambungan yang sama! Dan juga sumber lain seperti CPU dan RAM.
Apakah yang akan berlaku, Jika salah satu bahagian belakang mengalami beberapa jenis masalah yang mengakibatkan kependaman permintaan yang tinggi? Disebabkan oleh masa tindak balas yang tinggi, keseluruhan kumpulan sambungan akan diduduki sepenuhnya oleh permintaan menunggu respons daripada bahagian belakang1. Akibatnya, permintaan yang ditujukan untuk backend2 dan backend3 yang sihat tidak akan dapat diteruskan kerana kolam telah habis. Ini bermakna bahawa kegagalan dalam salah satu bahagian belakang kami boleh menyebabkan kegagalan pada keseluruhan aplikasi. Sebaik-baiknya, kami hanya mahu kefungsian yang dikaitkan dengan bahagian belakang yang gagal mengalami kemerosotan, manakala aplikasi yang lain terus beroperasi seperti biasa.
Apakah Corak Bulkhead?
Istilah, corak Bulkhead, berasal daripada pembinaan kapal, ia melibatkan penciptaan beberapa petak terpencil di dalam kapal. Jika kebocoran berlaku dalam satu petak, ia akan diisi dengan air, tetapi petak yang lain tetap tidak terjejas. Pengasingan ini menghalang keseluruhan kapal daripada tenggelam disebabkan oleh satu pelanggaran.
Corak Bulkhead boleh digunakan untuk mengasingkan pelbagai jenis sumber dalam aplikasi, menghalang kegagalan dalam satu bahagian daripada menjejaskan keseluruhan sistem. Begini cara kita boleh mengaplikasikannya pada masalah kita:
Katakan sistem bahagian belakang kami mempunyai kebarangkalian rendah untuk menghadapi ralat secara individu. Walau bagaimanapun, apabila operasi melibatkan pertanyaan semua bahagian belakang ini secara selari, setiap satu boleh mengembalikan ralat secara bebas. Oleh kerana ralat ini berlaku secara bebas, kebarangkalian keseluruhan ralat dalam aplikasi kami adalah lebih tinggi daripada kebarangkalian ralat mana-mana hujung belakang tunggal. Kebarangkalian ralat kumulatif boleh dikira menggunakan formula P_total=1−(1−p)^n, dengan n ialah bilangan sistem hujung belakang.
Sebagai contoh, jika kita mempunyai sepuluh hujung belakang, setiap satu dengan kebarangkalian ralat p=0.001 (bersamaan dengan SLA sebanyak 99.9%), kebarangkalian ralat yang terhasil ialah:
P_total=1−(1−0.001)^10=0.009955
Ini bermakna gabungan SLA kami menurun kepada kira-kira 99%, menggambarkan bagaimana kebolehpercayaan keseluruhan berkurangan apabila membuat pertanyaan berbilang hujung belakang secara selari. Untuk mengurangkan isu ini, kami boleh melaksanakan cache dalam memori.
Cache dalam memori berfungsi sebagai penimbal data berkelajuan tinggi, menyimpan data yang kerap diakses dan menghapuskan keperluan untuk mengambilnya daripada sumber yang berpotensi perlahan setiap kali. Memandangkan cache yang disimpan dalam memori mempunyai 0% kemungkinan ralat berbanding dengan mengambil data melalui rangkaian, ia meningkatkan kebolehpercayaan aplikasi kami dengan ketara. Selain itu, caching mengurangkan trafik rangkaian, seterusnya mengurangkan kemungkinan ralat. Akibatnya, dengan menggunakan cache dalam memori, kami boleh mencapai kadar ralat yang lebih rendah dalam aplikasi kami berbanding sistem bahagian belakang kami. Selain itu, cache dalam memori menawarkan pengambilan data yang lebih pantas daripada pengambilan berasaskan rangkaian, sekali gus mengurangkan kependaman aplikasi—satu kelebihan yang ketara.
Untuk data yang diperibadikan, seperti profil pengguna atau cadangan, menggunakan cache dalam memori juga boleh menjadi sangat berkesan. Tetapi kami perlu memastikan semua permintaan daripada pengguna secara konsisten pergi ke contoh aplikasi yang sama untuk menggunakan data yang dicache untuknya, yang memerlukan sesi melekit. Melaksanakan sesi melekit boleh menjadi mencabar, tetapi untuk senario ini, kami tidak memerlukan mekanisme yang rumit. Pengimbangan semula trafik kecil boleh diterima, jadi algoritma pengimbangan beban yang stabil seperti pencincangan yang konsisten sudah memadai.
Lebih-lebih lagi, sekiranya berlaku kegagalan nod, pencincangan yang konsisten memastikan bahawa hanya pengguna yang dikaitkan dengan nod yang gagal menjalani pengimbangan semula, meminimumkan gangguan kepada sistem. Pendekatan ini memudahkan pengurusan cache yang diperibadikan dan meningkatkan kestabilan dan prestasi keseluruhan aplikasi kami.
Jika data yang kami ingin cache adalah kritikal dan digunakan dalam setiap permintaan yang dikendalikan oleh sistem kami, seperti dasar akses, pelan langganan atau entiti penting lain dalam domain kami—sumber data ini boleh menimbulkan titik kegagalan yang ketara dalam sistem kami. Untuk menangani cabaran ini, satu pendekatan adalah untuk mereplikasi sepenuhnya data ini terus ke dalam memori aplikasi kami.
Dalam senario ini, jika volum data dalam sumber boleh diurus, kami boleh memulakan proses dengan memuat turun petikan data ini pada permulaan aplikasi kami. Selepas itu, kami boleh menerima peristiwa kemas kini untuk memastikan data cache kekal disegerakkan dengan sumber. Dengan mengguna pakai kaedah ini, kami meningkatkan kebolehpercayaan mengakses data penting ini, kerana setiap perolehan berlaku terus dari memori dengan kebarangkalian ralat 0%. Selain itu, mendapatkan semula data daripada memori adalah sangat pantas, dengan itu mengoptimumkan prestasi aplikasi kami. Strategi ini berkesan mengurangkan risiko yang berkaitan dengan bergantung pada sumber data luaran, memastikan akses yang konsisten dan boleh dipercayai kepada maklumat kritikal untuk operasi aplikasi kami.
Walau bagaimanapun, keperluan untuk memuat turun data pada permulaan aplikasi, sekali gus melambatkan proses permulaan, melanggar salah satu prinsip 'aplikasi 12-faktor' yang menyokong permulaan aplikasi pantas. Tetapi, kami tidak mahu kehilangan faedah menggunakan caching. Untuk menangani dilema ini, mari terokai penyelesaian yang berpotensi.
Permulaan pantas adalah penting, terutamanya untuk platform seperti Kubernetes, yang bergantung pada pemindahan aplikasi pantas ke nod fizikal yang berbeza. Nasib baik, Kubernetes boleh mengurus aplikasi yang mula perlahan menggunakan ciri seperti probe permulaan.
Cabaran lain yang mungkin kami hadapi ialah mengemas kini konfigurasi semasa aplikasi sedang berjalan. Selalunya, melaraskan masa cache atau meminta tamat masa diperlukan untuk menyelesaikan isu pengeluaran. Walaupun kami boleh menggunakan fail konfigurasi yang dikemas kini dengan cepat pada aplikasi kami, penggunaan perubahan ini biasanya memerlukan dimulakan semula. Dengan masa permulaan lanjutan setiap aplikasi, permulaan semula bergulir boleh melambatkan penggunaan pembetulan dengan ketara kepada pengguna kami.
Untuk menangani perkara ini, satu penyelesaian adalah untuk menyimpan konfigurasi dalam pembolehubah serentak dan mempunyai benang latar belakang mengemas kininya secara berkala. Walau bagaimanapun, parameter tertentu, seperti tamat masa permintaan HTTP, mungkin memerlukan pemulaan semula klien HTTP atau pangkalan data apabila konfigurasi yang sepadan berubah, menimbulkan potensi cabaran. Namun, sesetengah pelanggan, seperti pemacu Cassandra untuk Java, menyokong pemuatan semula automatik konfigurasi, memudahkan proses ini.
Melaksanakan konfigurasi boleh muat semula boleh mengurangkan kesan negatif masa permulaan aplikasi yang panjang dan menawarkan faedah tambahan, seperti memudahkan pelaksanaan bendera ciri. Pendekatan ini membolehkan kami mengekalkan kebolehpercayaan dan responsif aplikasi sambil menguruskan kemas kini konfigurasi dengan cekap.
Sekarang mari kita lihat masalah lain: dalam sistem kami, apabila permintaan pengguna diterima dan diproses dengan menghantar pertanyaan ke bahagian belakang atau pangkalan data, kadangkala, respons ralat diterima dan bukannya data yang dijangkakan. Selepas itu, sistem kami bertindak balas kepada pengguna dengan 'ralat'.
Walau bagaimanapun, dalam banyak senario, mungkin lebih baik untuk memaparkan data yang sedikit ketinggalan zaman bersama-sama dengan mesej yang menunjukkan terdapat kelewatan muat semula data, dan bukannya meninggalkan pengguna dengan mesej ralat merah yang besar.
Untuk menangani isu ini dan memperbaik tingkah laku sistem kami, kami boleh melaksanakan corak Fallback. Konsep di sebalik corak ini melibatkan mempunyai sumber data sekunder, yang mungkin mengandungi data yang lebih rendah kualiti atau kesegarannya berbanding dengan sumber utama. Jika sumber data utama tidak tersedia atau mengembalikan ralat, sistem boleh mengambil semula data daripada sumber kedua ini, memastikan bahawa beberapa bentuk maklumat dibentangkan kepada pengguna dan bukannya memaparkan mesej ralat.
Jika anda melihat gambar di atas, anda akan melihat persamaan antara isu yang kami hadapi sekarang dan isu yang kami temui dengan contoh cache.
Untuk menyelesaikannya, kita boleh mempertimbangkan untuk melaksanakan corak yang dikenali sebagai cuba semula. Daripada bergantung pada cache, sistem boleh direka bentuk untuk menghantar semula permintaan secara automatik sekiranya berlaku ralat. Corak cuba semula ini menawarkan alternatif yang lebih mudah dan boleh mengurangkan kemungkinan ralat dalam aplikasi kami dengan berkesan. Tidak seperti caching, yang selalunya memerlukan mekanisme penolakan cache yang kompleks untuk mengendalikan perubahan data, mencuba semula permintaan yang gagal adalah agak mudah untuk dilaksanakan. Memandangkan ketidaksahihan cache dianggap secara meluas sebagai salah satu tugas yang paling mencabar dalam kejuruteraan perisian, menggunakan strategi cuba semula boleh menyelaraskan pengendalian ralat dan meningkatkan daya tahan sistem.
Walau bagaimanapun, menggunakan strategi cuba semula tanpa mengambil kira kemungkinan akibat boleh membawa kepada komplikasi lanjut.
Mari bayangkan salah satu bahagian belakang kami mengalami kegagalan. Dalam senario sedemikian, memulakan percubaan semula ke bahagian belakang yang gagal boleh mengakibatkan peningkatan ketara dalam volum trafik. Lonjakan mendadak dalam trafik ini mungkin mengatasi bahagian belakang, memburukkan lagi kegagalan dan berpotensi menyebabkan kesan lata merentas sistem.
Untuk menghadapi cabaran ini, adalah penting untuk melengkapkan corak cuba semula dengan corak pemutus litar. Pemutus litar berfungsi sebagai mekanisme perlindungan yang memantau kadar ralat perkhidmatan hiliran. Apabila kadar ralat melebihi ambang yang telah ditetapkan, pemutus litar mengganggu permintaan kepada perkhidmatan yang terjejas untuk tempoh tertentu. Dalam tempoh ini, sistem mengelak daripada menghantar permintaan tambahan untuk membenarkan masa perkhidmatan yang gagal pulih. Selepas selang waktu yang ditetapkan, pemutus litar dengan berhati-hati membenarkan bilangan permintaan yang terhad untuk melalui, mengesahkan sama ada perkhidmatan telah stabil. Jika perkhidmatan telah pulih, trafik normal dipulihkan secara beransur-ansur; jika tidak, litar kekal terbuka, terus menyekat permintaan sehingga perkhidmatan menyambung semula operasi biasa. Dengan menyepadukan corak pemutus litar bersama logik cuba semula, kami boleh mengurus situasi ralat dengan berkesan dan mengelakkan beban sistem semasa kegagalan bahagian belakang.
Kesimpulannya, dengan melaksanakan corak daya tahan ini, kami boleh mengukuhkan aplikasi kami terhadap kecemasan, mengekalkan ketersediaan tinggi dan menyampaikan pengalaman yang lancar kepada pengguna. Selain itu, saya ingin menekankan bahawa telemetri adalah satu lagi alat yang tidak boleh diabaikan apabila menyediakan daya tahan projek. Log dan metrik yang baik boleh meningkatkan kualiti perkhidmatan dengan ketara dan memberikan cerapan berharga tentang prestasi mereka, membantu membuat keputusan termaklum untuk memperbaikinya lagi.