Bagikan melalui


Terapkan pola Pemutus Sirkuit

Tip

Konten ini adalah kutipan dari eBook, .NET Microservices Architecture for Containerized .NET Applications, tersedia di .NET Docs atau sebagai PDF yang dapat diunduh gratis dan dapat dibaca secara offline.

.NET Microservices Architecture for Containerized .NET Applications eBook cover thumbnail.

Seperti disebutkan sebelumnya, Anda harus menangani kesalahan yang dapat membutuhkan waktu variabel untuk pulih, seperti yang dapat terjadi ketika Anda mencoba menyambungkan ke layanan atau sumber daya jarak jauh. Menangani jenis kesalahan ini dapat meningkatkan stabilitas dan ketahanan aplikasi.

Dalam lingkungan terdistribusi, panggilan ke sumber daya dan layanan jarak jauh dapat gagal karena kesalahan sementara, seperti koneksi jaringan yang lambat dan waktu habis, atau jika sumber daya merespons dengan lambat atau untuk sementara tidak tersedia. Kesalahan ini biasanya memperbaiki diri mereka sendiri setelah waktu yang singkat, dan aplikasi cloud yang kuat harus disiapkan untuk menanganinya dengan menggunakan strategi seperti "Pola coba lagi".

Tetapi, ada juga situasi di mana kesalahan disebabkan oleh kejadian tak terduga yang mungkin membutuhkan waktu lebih lama untuk diperbaiki. Keparahan kesalahan ini dapat berkisar mulai dari hilangnya sebagian konektivitas hingga kegagalan total layanan. Dalam situasi ini, mungkin tidak ada gunanya aplikasi terus mencoba kembali operasi yang sepertinya tidak akan berhasil.

Sebaliknya, aplikasi harus dikodekan untuk menerima bahwa operasi telah gagal dan menangani kegagalan yang sesuai.

Menggunakan percobaan ulang Http sembarangan dapat mengakibatkan serangan Penolakan serangan Layanan (DoS) dalam perangkat lunak Anda sendiri. Karena layanan mikro gagal atau berjalan lambat, beberapa klien mungkin berulang kali mencoba kembali permintaan yang gagal. Itu menciptakan risiko berbahaya dari peningkatan lalu lintas secara eksponensial yang ditargetkan pada layanan yang gagal.

Oleh karena itu, Anda memerlukan semacam penghalang pertahanan agar permintaan yang berlebihan berhenti ketika tidak layak untuk terus dicoba. Penghalang pertahanan itu adalah pemutus sirkuit.

Pola Pemutus Sirkuit memiliki tujuan yang berbeda dari "Pola coba lagi". "Pola coba lagi" memungkinkan aplikasi untuk mencoba kembali operasi dengan harapan bahwa operasi tersebut pada akhirnya akan berhasil. Pola Pemutus Sirkuit mencegah aplikasi melakukan operasi yang kemungkinan akan gagal. Aplikasi dapat menggabungkan kedua pola ini. Namun, percobaan ulang logika harus peka terhadap pengecualian yang dikembalikan oleh pemutus sirkuit, dan seharusnya meninggalkan upaya coba ulang jika pemutus sirkuit menunjukkan bahwa kesalahan tidak bersifat sementara.

Menerapkan pola Pemutus Sirkuit dengan IHttpClientFactory dan Polly

Seperti saat menerapkan percobaan ulang, rekomendasi pendekatan untuk pemutus sirkuit adalah memanfaatkan pustaka .NET yang terbukti seperti Polly dan integrasi aslinya dengan IHttpClientFactory.

Menambahkan kebijakan pemutus sirkuit ke dalam alur middleware keluar IHttpClientFactory semudah menambahkan satu bagian kode tambahan ke apa yang sudah Anda miliki saat menggunakan IHttpClientFactory.

Satu-satunya penambahan di sini untuk kode yang digunakan untuk percobaan ulang panggilan HTTP adalah kode tempat Anda menambahkan kebijakan Circuit Breaker ke daftar kebijakan yang akan digunakan, seperti yang ditunjukkan dalam kode inkremental berikut.

// Program.cs
var retryPolicy = GetRetryPolicy();
var circuitBreakerPolicy = GetCircuitBreakerPolicy();

builder.Services.AddHttpClient<IBasketService, BasketService>()
        .SetHandlerLifetime(TimeSpan.FromMinutes(5))  // Sample: default lifetime is 2 minutes
        .AddHttpMessageHandler<HttpClientAuthorizationDelegatingHandler>()
        .AddPolicyHandler(retryPolicy)
        .AddPolicyHandler(circuitBreakerPolicy);

Metode AddPolicyHandler() inilah yang menambahkan kebijakan ke objek HttpClient yang akan Anda gunakan. Dalam hal ini, ini menambahkan kebijakan Polly untuk pemutus sirkuit.

Untuk memiliki pendekatan yang lebih modular, Kebijakan Pemutus Sirkuit didefinisikan dalam metode terpisah yang disebut GetCircuitBreakerPolicy(), seperti yang ditunjukkan dalam kode berikut:

// also in Program.cs
static IAsyncPolicy<HttpResponseMessage> GetCircuitBreakerPolicy()
{
    return HttpPolicyExtensions
        .HandleTransientHttpError()
        .CircuitBreakerAsync(5, TimeSpan.FromSeconds(30));
}

Dalam contoh kode di atas, kebijakan pemutus sirkuit dikonfigurasi sehingga memutus atau membuka sirkuit ketika ada lima kesalahan berturut-turut saat mencoba kembali permintaan Http. Ketika itu terjadi, sirkuit akan putus selama 30 detik: dalam periode itu, panggilan akan segera gagal oleh pemutus sirkuit alih-alih benar-benar dilakukan. Kebijakan secara otomatis menafsirkan pengecualian yang relevan dan kode status HTTP sebagai kesalahan.

Pemutus sirkuit juga harus digunakan untuk mengalihkan permintaan ke infrastruktur cadangan jika Anda mengalami masalah dalam sumber daya tertentu yang disebarkan di lingkungan yang berbeda dari aplikasi atau layanan klien yang melakukan panggilan HTTP. Dengan begitu, jika ada pemadaman di pusat data yang hanya berdampak pada layanan mikro ujung belakang Anda tetapi tidak pada aplikasi klien Anda, aplikasi klien dapat dialihkan ke layanan cadangan. Polly merencanakan kebijakan baru untuk mengotomatiskan skenario kebijakan failover ini.

Semua fitur tersebut untuk kasus di mana Anda mengelola failover dari dalam kode .NET, sebagai lawan dari mengelolanya secara otomatis untuk Anda oleh Azure, dengan transparansi lokasi.

dari sudut pandang penggunaan, saat menggunakan HttpClient, tidak perlu menambahkan sesuatu yang baru di sini karena kodenya sama dengan saat menggunakan HttpClient dengan IHttpClientFactory, seperti yang ditunjukkan pada bagian sebelumnya.

Menguji percobaan ulang Http dan pemutus sirkuit di eShopOnContainers

Setiap kali Anda memulai solusi eShopOnContainers di host Docker, itu perlu memulai beberapa kontainer. Beberapa kontainer memulai dan menginisialisasi lebih lambat seperti kontainer SQL Server. Ini terutama benar saat pertama kali Anda menyebarkan aplikasi eShopOnContainers ke Docker karena perlu menyiapkan gambar dan database. Fakta bahwa beberapa kontainer memulai lebih lambat dibandingkna yang lain dapat menyebabkan layanan lainnya pada awalnya membuang pengecualian HTTP, bahkan jika Anda menetapkan dependensi antara kontainer di tingkat pembuatan docker, seperti yang dijelaskan di bagian sebelumnya. Dependensi penulisan docker antara kontainer hanya pada tingkat proses. Proses titik masuk kontainer mungkin dimulai, tetapi SQL Server mungkin tidak siap untuk kueri. Hasilnya bisa berupa rangkaian kesalahan, dan aplikasi bisa mendapatkan pengecualian saat mencoba menggunakan kontainer tertentu.

Anda mungkin juga melihat jenis kesalahan ini saat memulai saat aplikasi disebarkan ke cloud. Dalam hal ini, orkestrator dapat memindahkan kontainer dari satu node atau mesin virtual ke node lain (yaitu, memulai instans baru) saat menyeimbangkan jumlah kontainer di seluruh node kluster.

Cara 'eShopOnContainers' memecahkan masalah tersebut saat memulai semua kontainer adalah dengan menggunakan pola Coba Lagi yang diilustrasikan sebelumnya.

Menguji pemutus sirkuit di eShopOnContainers

Ada beberapa cara untuk memecahkan/membuka sirkuit dan mengujinya dengan eShopOnContainers.

Salah satu opsinya adalah menurunkan jumlah percobaan ulang yang diizinkan menjadi 1 dalam kebijakan pemutus sirkuit dan menyebarkan ulang seluruh solusi ke Docker. Dengan sekali coba lagi, ada kemungkinan besar permintaan HTTP akan gagal selama penerapan, pemutus sirkuit akan terbuka, dan Anda mendapatkan kesalahan.

Opsi lain adalah menggunakan middleware kustom yang diterapkan dalam layanan mikro Keranjang. Ketika middleware ini diaktifkan, ini akan menangkap semua permintaan HTTP dan mengembalikan kode status 500. Anda dapat mengaktifkan middleware dengan membuat permintaan GET ke URI yang gagal, seperti berikut ini:

  • GET http://localhost:5103/failing
    Permintaan ini mengembalikan status middleware saat ini. Jika middleware diaktifkan, permintaan mengembalikan kode status 500. Jika middleware dinonaktifkan, maka tidak akan ada respons.

  • GET http://localhost:5103/failing?enable
    Permintaan ini mengaktifkan middleware.

  • GET http://localhost:5103/failing?disable
    Permintaan ini menonaktifkan middleware.

Misalnya, setelah aplikasi berjalan, Anda dapat mengaktifkan middleware dengan membuat permintaan menggunakan URI berikut di browser apa pun. Perhatikan bahwa layanan mikro pemesanan menggunakan port 5103.

http://localhost:5103/failing?enable

Anda kemudian dapat memeriksa status menggunakan URI http://localhost:5103/failing, seperti yang ditunjukkan pada Gambar 8-5.

Screenshot of checking the status of failing middleware simulation.

Gambar 8-5. Memeriksa status middleware ASP.NET "Gagal" – Dalam kasus ini, dinonaktifkan.

Pada titik ini, layanan mikro Keranjang merespons dengan kode status 500 setiap kali Anda memanggilnya.

Setelah middleware berjalan, Anda dapat mencoba membuat pesanan dari aplikasi web MVC. Karena permintaan gagal, maka sirkuit akan terbuka.

Dalam contoh berikut, Anda dapat melihat bahwa aplikasi web MVC memiliki blok tangkap dalam logika untuk menempatkan pesanan. Jika kode menangkap pengecualian sirkuit terbuka, itu menunjukkan kepada pengguna pesan ramah yang meminta mereka untuk menunggu.

public class CartController : Controller
{
    //…
    public async Task<IActionResult> Index()
    {
        try
        {
            var user = _appUserParser.Parse(HttpContext.User);
            //Http requests using the Typed Client (Service Agent)
            var vm = await _basketSvc.GetBasket(user);
            return View(vm);
        }
        catch (BrokenCircuitException)
        {
            // Catches error when Basket.api is in circuit-opened mode
            HandleBrokenCircuitException();
        }
        return View();
    }

    private void HandleBrokenCircuitException()
    {
        TempData["BasketInoperativeMsg"] = "Basket Service is inoperative, please try later on. (Business message due to Circuit-Breaker)";
    }
}

Berikut ringkasannya. Kebijakan Coba Lagi mencoba beberapa kali untuk membuat permintaan HTTP dan mendapatkan kesalahan HTTP. Ketika jumlah percobaan ulang mencapai jumlah maksimum yang ditetapkan untuk kebijakan Pemutus Sirkuit (dalam hal ini, 5), aplikasi akan menghasilkan BrokenCircuitException. Hasilnya adalah pesan yang ramah, seperti yang ditunjukkan pada Gambar 8-6.

Screenshot of the MVC web app with basket service inoperative error.

Gambar 8-6. Pemutus sirkuit akan mengembalikan kesalahan ke UI

Anda dapat menerapkan logika yang berbeda kapan harus membuka/memutus sirkuit. Atau Anda dapat mencoba permintaan HTTP terhadap layanan mikro ujung belakang yang berbeda jika ada pusat data fallback atau sistem ujung belakang yang berlebihan.

Akhirnya, kemungkinan lain untuk CircuitBreakerPolicy adalah menggunakan Isolate (yang memaksa sirkuit terbuka dan menahan agar tetap terbuka) dan Reset (yang menutupnya lagi). Ini dapat digunakan untuk membangun titik akhir HTTP utilitas yang memanggil Isolasi dan Reset langsung pada kebijakan. Titik akhir HTTP semacam itu juga dapat digunakan, diamankan dengan tepat, dalam produksi untuk mengisolasi sementara sistem hilir, seperti saat Anda ingin meningkatkannya. Atau itu bisa membuat sirkuit tersandung secara manual untuk melindungi sistem hilir yang Anda curigai mengalami gangguan.

Sumber daya tambahan