Pemutus litar mengesan kegagalan dan merangkum logik pengendalian kegagalan tersebut dengan cara yang menghalang kegagalan daripada terus berulang. Contohnya, ia berguna apabila berurusan dengan panggilan rangkaian ke perkhidmatan luaran, pangkalan data, atau benar-benar, mana-mana bahagian sistem anda yang mungkin gagal buat sementara waktu. Dengan menggunakan pemutus litar, anda boleh mengelakkan kegagalan melata, mengurus ralat sementara dan mengekalkan sistem yang stabil dan responsif di tengah-tengah kerosakan sistem.
Kegagalan berlatarkan berlaku apabila kegagalan dalam satu bahagian sistem mencetuskan kegagalan di bahagian lain, yang membawa kepada gangguan yang meluas. Contohnya ialah apabila perkhidmatan mikro dalam sistem teragih menjadi tidak bertindak balas, menyebabkan perkhidmatan bergantung tamat masa dan akhirnya gagal. Bergantung pada skala aplikasi, impak kegagalan ini boleh menjadi malapetaka yang akan merendahkan prestasi dan mungkin juga memberi kesan kepada pengalaman pengguna.
Pemutus litar itu sendiri ialah teknik/corak dan terdapat tiga keadaan berbeza ia beroperasi yang akan kita bincangkan:
2. Keadaan Terbuka : Dalam keadaan terbuka, pemutus litar serta-merta gagal semua permintaan masuk tanpa cuba menghubungi perkhidmatan sasaran. Negeri itu dimasukkan untuk mengelakkan lebihan beban perkhidmatan yang gagal dan memberi masa untuk pulih. Selepas tamat masa yang telah ditetapkan, pemutus litar bergerak ke keadaan separuh terbuka. Contoh yang boleh dikaitkan ialah ini; Bayangkan kedai dalam talian mengalami isu mendadak di mana setiap percubaan pembelian gagal. Untuk mengelak daripada membebankan sistem, kedai berhenti menerima sebarang permintaan pembelian baharu buat sementara waktu.
3. Keadaan Separuh Terbuka : Dalam keadaan separuh terbuka, pemutus litar membenarkan bilangan permintaan ujian terhad (boleh dikonfigurasikan) untuk melalui perkhidmatan sasaran. Dan jika permintaan ini berjaya, litar beralih kembali ke keadaan tertutup. Jika gagal, litar kembali ke keadaan terbuka. Dalam contoh kedai dalam talian yang saya berikan dalam keadaan terbuka di atas, di sinilah kedai dalam talian mula membenarkan beberapa percubaan pembelian untuk melihat sama ada isu itu telah dibetulkan. Jika beberapa percubaan ini berjaya, kedai akan membuka semula perkhidmatannya sepenuhnya untuk menerima permintaan pembelian baharu.
Rajah ini menunjukkan apabila pemutus litar cuba untuk melihat sama ada permintaan untuk Perkhidmatan B berjaya dan kemudian ia gagal/putus:
Rajah susulan kemudian menunjukkan apabila ujian meminta Perkhidmatan B berjaya, litar ditutup dan semua panggilan selanjutnya dihalakan ke Perkhidmatan B sekali lagi:
Nota : Konfigurasi utama untuk pemutus litar termasuk ambang kegagalan (bilangan kegagalan yang diperlukan untuk membuka litar), tamat masa untuk keadaan terbuka dan bilangan permintaan ujian dalam separuh terbuka negeri.
Adalah penting untuk menyatakan bahawa pengetahuan awal tentang Go diperlukan untuk diikuti dalam artikel ini.
Seperti mana-mana corak kejuruteraan perisian, pemutus litar boleh dilaksanakan dalam pelbagai bahasa. Walau bagaimanapun, artikel ini akan menumpukan pada pelaksanaan di Golang. Walaupun terdapat beberapa perpustakaan yang tersedia untuk tujuan ini, seperti goresilience, go-resiliency dan gobreaker, kami secara khusus akan menumpukan pada menggunakan perpustakaan gobreaker.
Petua Pro : Anda boleh melihat pelaksanaan dalaman pakej gobreaker, semak di sini.
Mari kita pertimbangkan aplikasi Golang mudah di mana pemutus litar dilaksanakan untuk mengendalikan panggilan ke API luaran. Contoh asas ini menunjukkan cara membungkus panggilan API luaran dengan teknik pemutus litar:
Mari kita sentuh beberapa perkara penting:
Mari kita tulis beberapa ujian unit untuk mengesahkan pelaksanaan pemutus litar kami. Saya hanya akan menerangkan ujian unit yang paling kritikal untuk difahami. Anda boleh menyemak di sini untuk kod penuh.
t.Run("FailedRequests", func(t *testing.T) { // Override callExternalAPI to simulate failure callExternalAPI = func() (int, error) { return 0, errors.New("simulated failure") } for i := 0; i < 4; i++ { _, err := cb.Execute(func() (interface{}, error) { return callExternalAPI() }) if err == nil { t.Fatalf("expected error, got none") } } if cb.State() != gobreaker.StateOpen { t.Fatalf("expected circuit breaker to be open, got %v", cb.State()) } })
//Simulates the circuit breaker being open, //wait for the defined timeout, //then check if it closes again after a successful request. t.Run("RetryAfterTimeout", func(t *testing.T) { // Simulate circuit breaker opening callExternalAPI = func() (int, error) { return 0, errors.New("simulated failure") } for i := 0; i < 4; i++ { _, err := cb.Execute(func() (interface{}, error) { return callExternalAPI() }) if err == nil { t.Fatalf("expected error, got none") } } if cb.State() != gobreaker.StateOpen { t.Fatalf("expected circuit breaker to be open, got %v", cb.State()) } // Wait for timeout duration time.Sleep(settings.Timeout + 1*time.Second) //We expect that after the timeout period, //the circuit breaker should transition to the half-open state. // Restore original callExternalAPI to simulate success callExternalAPI = func() (int, error) { resp, err := http.Get(server.URL) if err != nil { return 0, err } defer resp.Body.Close() return resp.StatusCode, nil } _, err := cb.Execute(func() (interface{}, error) { return callExternalAPI() }) if err != nil { t.Fatalf("expected no error, got %v", err) } if cb.State() != gobreaker.StateHalfOpen { t.Fatalf("expected circuit breaker to be half-open, got %v", cb.State()) } //After verifying the half-open state, another successful request is simulated to ensure the circuit breaker transitions back to the closed state. for i := 0; i < int(settings.MaxRequests); i++ { _, err = cb.Execute(func() (interface{}, error) { return callExternalAPI() }) if err != nil { t.Fatalf("expected no error, got %v", err) } } if cb.State() != gobreaker.StateClosed { t.Fatalf("expected circuit breaker to be closed, got %v", cb.State()) } })
t.Run("ReadyToTrip", func(t *testing.T) { failures := 0 settings.ReadyToTrip = func(counts gobreaker.Counts) bool { failures = int(counts.ConsecutiveFailures) return counts.ConsecutiveFailures > 2 // Trip after 2 failures } cb = gobreaker.NewCircuitBreaker(settings) // Simulate failures callExternalAPI = func() (int, error) { return 0, errors.New("simulated failure") } for i := 0; i < 3; i++ { _, err := cb.Execute(func() (interface{}, error) { return callExternalAPI() }) if err == nil { t.Fatalf("expected error, got none") } } if failures != 3 { t.Fatalf("expected 3 consecutive failures, got %d", failures) } if cb.State() != gobreaker.StateOpen { t.Fatalf("expected circuit breaker to be open, got %v", cb.State()) } })
Kami boleh melangkah lebih jauh dengan menambahkan strategi mundur eksponen pada pelaksanaan pemutus litar kami. Kami akan memastikan artikel ini ringkas dan ringkas dengan menunjukkan contoh strategi mundur eksponen. Walau bagaimanapun, terdapat strategi lanjutan lain untuk pemutus litar yang patut disebut, seperti penumpahan beban, sekat, mekanisme sandaran, konteks dan pembatalan. Strategi ini pada asasnya meningkatkan keteguhan dan kefungsian pemutus litar. Berikut ialah contoh menggunakan strategi mundur eksponen:
Penyingkiran Eksponen
Pemutus litar dengan mundur eksponen
Mari kita jelaskan beberapa perkara:
Fungsi Backoff Tersuai: Fungsi ExponentialBackoff melaksanakan strategi backoff eksponen dengan jitter. Ia pada asasnya mengira masa mundur berdasarkan bilangan percubaan, memastikan bahawa kelewatan meningkat secara eksponen dengan setiap percubaan mencuba semula.
Mengendalikan Percubaan Semula: Seperti yang anda lihat dalam pengendali /api, logik kini termasuk gelung yang cuba memanggil API luaran sehingga bilangan percubaan yang ditentukan ( percubaan := 5). Selepas setiap percubaan yang gagal, kami menunggu tempoh yang ditentukan oleh fungsi ExponentialBackoff sebelum mencuba semula.
Perlaksanaan Pemutus Litar: Pemutus litar digunakan dalam gelung. Jika panggilan API luaran berjaya ( err == nil), gelung pecah, dan hasil yang berjaya dikembalikan. Jika semua percubaan gagal, ralat HTTP 503 (Perkhidmatan Tidak Tersedia) dikembalikan.
Mengintegrasikan strategi mundur tersuai dalam pelaksanaan pemutus litar sememangnya bertujuan untuk mengendalikan ralat sementara dengan lebih anggun. Kelewatan yang semakin meningkat antara percubaan semula membantu mengurangkan beban pada perkhidmatan yang gagal, memberikan masa untuk pulih. Seperti yang terbukti dalam kod kami di atas, fungsi ExponentialBackoff kami telah diperkenalkan untuk menambah kelewatan antara percubaan semula apabila memanggil API luaran.
Selain itu, kami boleh menyepadukan metrik dan pengelogan untuk memantau perubahan keadaan pemutus litar menggunakan alat seperti Prometheus untuk pemantauan dan amaran masa nyata. Berikut ialah contoh mudah:
Melaksanakan corak pemutus litar dengan strategi lanjutan semasa
Seperti yang anda akan lihat, kini kami telah melakukan perkara berikut:
Petua Pro : Fungsi init dalam Go digunakan untuk memulakan keadaan pakej sebelum fungsi utama atau mana-mana kod lain dalam pakej dilaksanakan. Dalam kes ini, fungsi init mendaftarkan metrik requestCount dengan Prometheus. Dan ini pada asasnya memastikan bahawa Prometheus mengetahui metrik ini dan boleh mula mengumpul data sebaik sahaja aplikasi mula berjalan.
Kami mencipta pemutus litar dengan tetapan tersuai, termasuk fungsi ReadyToTrip yang meningkatkan pembilang kegagalan dan menentukan masa untuk mengelirukan litar.
OnStateChange untuk mencatat perubahan keadaan dan menambah metrik prometheus yang sepadan
Kami mendedahkan metrik Prometheus pada titik akhir /metrics
Untuk mengakhiri artikel ini, saya harap anda melihat bagaimana pemutus litar memainkan peranan yang besar dalam membina sistem yang berdaya tahan dan boleh dipercayai. Dengan secara proaktif mencegah kegagalan melata, mereka mengukuhkan kebolehpercayaan perkhidmatan mikro dan sistem yang diedarkan, memastikan pengalaman pengguna yang lancar walaupun dalam menghadapi kesukaran.
Perlu diingat, mana-mana sistem yang direka untuk skalabiliti mesti menggabungkan strategi untuk menangani kegagalan dengan anggun dan pulih dengan pantas — Oluwafemi , 2024
Asalnya diterbitkan di https://oluwafemiakinde.dev pada 7 Jun 2024.
Atas ialah kandungan terperinci Pemutus Litar dalam Go: Hentikan Kegagalan Lata. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!