Rumah > pembangunan bahagian belakang > Golang > Pemutus Litar dalam Go: Hentikan Kegagalan Lata

Pemutus Litar dalam Go: Hentikan Kegagalan Lata

WBOY
Lepaskan: 2024-07-17 17:41:11
asal
1002 orang telah melayarinya

Circuit Breakers in Go: Stop Cascading Failures

Pemutus Litar

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 Lata

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.

Corak Pemutus Litar

Pemutus litar itu sendiri ialah teknik/corak dan terdapat tiga keadaan berbeza ia beroperasi yang akan kita bincangkan:

  1. Keadaan Tertutup: Dalam keadaan tertutup, pemutus litar membenarkan semua permintaan melalui perkhidmatan sasaran seperti biasa. Jika permintaan berjaya, litar tetap ditutup. Walau bagaimanapun, jika ambang kegagalan tertentu dicapai, litar beralih ke keadaan terbuka. Anggap ia seperti perkhidmatan yang beroperasi sepenuhnya di mana pengguna boleh log masuk dan mengakses data tanpa masalah. Semuanya berjalan lancar.

Circuit Breakers in Go: Stop Cascading Failures

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.

Circuit Breakers in Go: Stop Cascading Failures

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:

Circuit Breakers in Go: Stop Cascading Failures

Rajah susulan kemudian menunjukkan apabila ujian meminta Perkhidmatan B berjaya, litar ditutup dan semua panggilan selanjutnya dihalakan ke Perkhidmatan B sekali lagi:

Circuit Breakers in Go: Stop Cascading Failures

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.

Melaksanakan Pemutus Litar dalam Go

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:

  1. Fungsi gobreaker.NewCircuitBreaker memulakan pemutus litar dengan tetapan tersuai kami
  2. Kaedah cb.Execute membungkus permintaan HTTP, mengurus keadaan litar secara automatik.
  3. Permintaan Maksimum ialah bilangan maksimum permintaan yang dibenarkan untuk dilalui apabila keadaan separuh terbuka
  4. Selang ialah tempoh kitaran keadaan tertutup untuk pemutus litar mengosongkan kiraan dalaman
  5. Tamat masa ialah tempoh sebelum beralih daripada keadaan terbuka kepada separuh terbuka.
  6. ReadyToTrip dipanggil dengan salinan kiraan apabila permintaan gagal dalam keadaan tertutup. Jika ReadyToTrip kembali benar, pemutus litar akan diletakkan dalam keadaan terbuka. Dalam kes kami di sini, ia kembali benar jika permintaan telah gagal lebih daripada tiga kali berturut-turut.
  7. OnStateChange dipanggil apabila keadaan pemutus litar berubah. Anda biasanya ingin mengumpulkan metrik perubahan keadaan di sini dan melaporkan kepada mana-mana pengumpul metrik pilihan anda.

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.

  1. Kami akan menulis ujian yang mensimulasikan permintaan gagal berturut-turut dan menyemak sama ada pemutus litar bergerak ke keadaan terbuka. Pada asasnya, selepas 3 kegagalan, apabila kegagalan keempat berlaku, kami menjangkakan pemutus litar akan tersandung (terbuka) kerana keadaan kami berkata penting.Kegagalan Berturut-turut > 3 . Begini rupa ujian itu:
 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())
         }
     })
Salin selepas log masuk
  1. Kami akan menguji terbuka > separuh - terbuka > ditutup menyatakan. Tetapi kita akan mula-mula mensimulasikan litar terbuka dan memanggil tamat masa. Selepas tamat masa, kita perlu membuat sekurang-kurangnya satu permintaan kejayaan untuk litar beralih kepada separuh terbuka. Selepas keadaan separuh terbuka, kita perlu membuat satu lagi permintaan kejayaan untuk litar ditutup sepenuhnya semula. Jika atas sebarang sebab, tiada rekod permintaan kejayaan dalam kes itu, ia akan kembali dibuka. Begini rupa ujian itu:
     //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())
             }
         })
    
    Salin selepas log masuk
    1. Mari kita uji keadaan ReadyToTrip yang tercetus selepas 2 permintaan kegagalan berturut-turut. Kami akan mempunyai pembolehubah yang menjejaki kegagalan berturut-turut. Panggilan balik ReadyToTrip dikemas kini untuk memeriksa sama ada pemutus litar terputus selepas 2 kegagalan ( dikira.ConsecutiveFailures > 2). Kami akan menulis ujian yang mensimulasikan kegagalan dan mengesahkan kiraan dan peralihan pemutus litar ke keadaan terbuka selepas bilangan kegagalan yang ditentukan.
       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())
               }
           })
      
      Salin selepas log masuk

      Strategi Lanjutan

      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:

      1. Dalam L16–21, kami mentakrifkan vektor pembilang prometheus untuk menjejaki bilangan permintaan dan keadaannya (berjaya, kegagalan, perubahan keadaan pemutus litar).
      2. Dalam L25–26, metrik yang ditakrifkan didaftarkan dengan Prometheus dalam fungsi init.

      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.

      1. Kami mencipta pemutus litar dengan tetapan tersuai, termasuk fungsi ReadyToTrip yang meningkatkan pembilang kegagalan dan menentukan masa untuk mengelirukan litar.

      2. OnStateChange untuk mencatat perubahan keadaan dan menambah metrik prometheus yang sepadan

      3. Kami mendedahkan metrik Prometheus pada titik akhir /metrics

      Membungkus

      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!

sumber:dev.to
Kenyataan Laman Web ini
Kandungan artikel ini disumbangkan secara sukarela oleh netizen, dan hak cipta adalah milik pengarang asal. Laman web ini tidak memikul tanggungjawab undang-undang yang sepadan. Jika anda menemui sebarang kandungan yang disyaki plagiarisme atau pelanggaran, sila hubungi admin@php.cn
Tutorial Popular
Lagi>
Muat turun terkini
Lagi>
kesan web
Kod sumber laman web
Bahan laman web
Templat hujung hadapan