Gunakan geo-redundansi untuk merancang aplikasi yang sangat tersedia

Infrastruktur berbasis cloud seperti Azure Storage menyediakan platform yang sangat tersedia dan tahan lama untuk hosting data dan aplikasi. Pengembang aplikasi berbasis awan harus mempertimbangkan dengan cermat cara memanfaatkan platform ini untuk memaksimalkan keuntungan tersebut bagi pengguna mereka. Azure Storage menawarkan opsi geo-redundansi untuk memastikan ketersediaan tinggi bahkan selama pemadaman regional. Akun penyimpanan yang dikonfigurasi untuk replikasi geo-redundan direplikasi secara sinkron di wilayah primer, dan direplikasi secara asinkron ke wilayah sekunder yang berjarak ratusan mil.

Azure Storage menawarkan dua opsi untuk replikasi geo-redundan: Penyimpanan geo-redundan (GRS) dan Penyimpanan geo-zona-redundan (GZRS). Untuk menggunakan opsi geo-redundansi Azure Storage, pastikan akun penyimpanan Anda dikonfigurasi untuk penyimpanan geo-redundan akses baca (RA-GRS) atau penyimpanan geo-zona-redundan akses baca (RA-GZRS). Jika tidak, Anda dapat mempelajari selengkapnya tentang cara mengubah jenis replikasi akun penyimpanan.

Artikel ini menunjukkan cara merancang aplikasi yang akan terus berfungsi, meskipun dalam kapasitas terbatas, bahkan jika terjadi pemadaman yang signifikan di wilayah primer. Jika wilayah primer menjadi tidak tersedia, aplikasi Anda dapat beralih dengan mulus untuk melakukan operasi baca terhadap wilayah sekunder hingga wilayah primer kembali responsif.

Pertimbangan desain aplikasi

Anda dapat merancang aplikasi untuk menangani kesalahan sementara atau pemadaman yang signifikan dengan membaca dari wilayah sekunder ketika terdapat masalah yang mengganggu pembacaan dari wilayah primer. Saat wilayah primer tersedia lagi, aplikasi Anda dapat kembali membaca dari wilayah primer.

Ingatlah pertimbangan utama ini saat merancang aplikasi Anda untuk ketersediaan dan ketahanan menggunakan RA-GRS atau RA-GZRS:

  • Salinan data baca-saja yang Anda simpan di wilayah primer direplikasi secara asinkron di wilayah sekunder. Replikasi asinkron ini berarti bahwa salinan baca-saja di wilayah sekunder pada akhirnya konsisten dengan data di wilayah primer. Layanan penyimpanan menentukan lokasi wilayah sekunder.

  • Anda dapat menggunakan pustaka klien Azure Storage untuk melakukan permintaan baca dan pembaruan terhadap titik akhir wilayah primer. Jika wilayah primer tidak tersedia, Anda dapat mengalihkan permintaan baca secara otomatis ke wilayah sekunder. Anda juga dapat mengonfigurasi aplikasi untuk mengirim permintaan baca langsung ke wilayah sekunder, jika diinginkan, bahkan saat wilayah primer tersedia.

  • Jika wilayah primer menjadi tidak tersedia, Anda dapat memulai failover akun. Saat Anda gagal ke wilayah sekunder, entri DNS yang menunjuk ke wilayah primer diubah untuk menunjuk ke wilayah sekunder. Setelah failover selesai, akses tulis dipulihkan untuk akun GRS dan RA-GRS. Untuk informasi selengkapnya, lihat Pemulihan bencana dan failover akun penyimpanan.

Bekerja dengan data yang pada akhirnya konsisten

Solusi yang diusulkan mengasumsikan bahwa mengembalikan data yang berpotensi kedaluwarsa ke aplikasi panggilan dapat diterima. Karena data di wilayah sekunder pada akhirnya konsisten, terdapat kemungkinan bahwa wilayah primer menjadi tidak dapat diakses sebelum pembaruan ke wilayah sekunder selesai direplikasi.

Misalnya, pelanggan Anda berhasil mengirimkan pembaruan, tetapi wilayah primer gagal sebelum pembaruan disebarkan ke wilayah sekunder. Ketika pelanggan meminta untuk membaca kembali data, mereka menerima data basi dari wilayah sekunder alih-alih data yang diperbarui. Saat merancang aplikasi, Anda harus memutuskan apakah perilaku ini dapat diterima atau tidak. Jika dapat diterima, Anda juga perlu mempertimbangkan cara memberi tahu pengguna.

Di bagian lain dalam artikel ini, Anda akan mempelajari selengkapnya tentang menangani data yang pada akhirnya konsisten dan cara memeriksa properti Waktu Sinkronisasi Terakhir guna mengevaluasi perbedaan antara data di wilayah primer dan sekunder.

Menangani layanan secara terpisah atau bersama-sama

Meski tidak mungkin, bisa saja satu layanan (blob, antrean, tabel, atau file) menjadi tidak tersedia sementara layanan lain masih berfungsi penuh. Anda dapat menangani pengulangan untuk setiap layanan secara terpisah, atau menangani pengulangan secara umum untuk semua layanan penyimpanan sekaligus.

Misalnya, jika Anda menggunakan antrean dan blob di aplikasi, Anda dapat memutuskan untuk memasukkan kode terpisah guna menangani kesalahan yang dapat diulang untuk setiap layanan. Dengan begitu, kesalahan layanan blob hanya akan memengaruhi bagian dari aplikasi yang menangani blob, membuat antrean terus berjalan seperti biasa. Namun, jika Anda memutuskan untuk menangani semua pengulangan layanan penyimpanan sekaligus, permintaan ke layanan blob dan antrean akan terpengaruh jika salah satu layanan mengembalikan kesalahan yang dapat diulang.

Pada akhirnya, keputusan ini bergantung pada kompleksitas aplikasi Anda. Anda mungkin lebih suka menangani kegagalan berdasarkan layanan untuk membatasi dampak pengulangan. Atau Anda dapat memutuskan untuk mengalihkan permintaan baca bagi semua layanan penyimpanan ke wilayah sekunder ketika Anda mendeteksi masalah dengan layanan penyimpanan apa pun di wilayah primer.

Menjalankan aplikasi Anda dalam mode baca-saja

Untuk mempersiapkan terjadinya pemadaman secara efektif di wilayah primer, aplikasi Anda harus dapat menangani permintaan baca yang gagal dan permintaan pembaruan yang gagal. Jika wilayah primer gagal, permintaan baca dapat dialihkan ke wilayah sekunder. Namun, permintaan pembaruan tidak dapat dialihkan karena data yang direplikasi di wilayah sekunder bersifat baca-saja. Oleh karena itu, Anda perlu merancang aplikasi agar dapat berjalan dalam mode baca-saja.

Misalnya, Anda dapat mengatur bendera yang dicek sebelum permintaan pembaruan dikirimkan ke Azure Storage. Ketika permintaan pembaruan masuk, Anda dapat melewati permintaan dan mengembalikan respons yang sesuai kepada pengguna. Anda bahkan dapat memilih untuk menonaktifkan fitur tertentu sepenuhnya hingga masalah teratasi, dan memberi tahu pengguna bahwa fitur tersebut untuk sementara tidak tersedia.

Jika memutuskan untuk menangani kesalahan setiap layanan secara terpisah, Anda juga harus menangani kemampuan untuk menjalankan aplikasi dalam mode baca-saja berdasarkan layanan. Misalnya, Anda dapat menyiapkan bendera baca-saja untuk setiap layanan. Lalu Anda dapat mengaktifkan atau menonaktifkan bendera dalam kode, sesuai kebutuhan.

Mampu menjalankan aplikasi dalam mode baca-saja juga memberi Anda kemampuan untuk memastikan fungsionalitas terbatas selama peningkatan aplikasi utama. Anda dapat memicu aplikasi untuk berjalan dalam mode baca-saja dan mengarahkan ke pusat data sekunder, memastikan tidak ada yang mengakses data di wilayah primer saat Anda melakukan pembaruan.

Menangani pembaruan saat berjalan dalam mode baca-saja

Ada banyak cara untuk menangani permintaan pembaruan saat berjalan dalam mode baca-saja. Bagian ini berfokus pada beberapa pola umum untuk dipertimbangkan.

  • Anda dapat merespons pengguna dan memberi tahu mereka bahwa permintaan pembaruan saat ini tidak sedang diproses. Misalnya, sistem manajemen kontak dapat memungkinkan pengguna mengakses informasi kontak tetapi tidak membuat pembaruan.

  • Anda dapat mengantre pembaruan di wilayah lain. Dalam hal ini, Anda akan menulis permintaan pembaruan tertunda ke antrean di wilayah berbeda, lalu memproses permintaan tersebut setelah pusat data primer kembali online. Dalam skenario ini, Anda harus memberi tahu pengguna bahwa permintaan pembaruan diantrekan untuk diproses nanti.

  • Anda dapat menulis pembaruan ke akun penyimpanan di wilayah lain. Ketika wilayah primer kembali online, Anda dapat menggabungkan pembaruan tersebut ke dalam data primer, tergantung pada struktur data. Misalnya, jika Anda membuat file terpisah dengan stempel tanggal/waktu dalam nama, Anda dapat menyalin file tersebut kembali ke wilayah primer. Solusi ini dapat diterapkan pada beban kerja seperti pengelogan dan data IoT.

Menangani pengulangan

Aplikasi yang berkomunikasi dengan layanan yang berjalan di cloud harus peka terhadap terjadinya kesalahan dan kejadian dan kesalahan yang tidak direncanakan. Kesalahan ini dapat bersifat sementara atau terus-menerus, mulai dari hilangnya konektivitas sesaat hingga pemadaman yang signifikan karena bencana alam. Penting untuk merancang aplikasi cloud dengan penanganan pengulangan yang sesuai untuk memaksimalkan ketersediaan dan meningkatkan stabilitas aplikasi secara keseluruhan.

Permintaan baca

Jika wilayah primer menjadi tidak tersedia, permintaan baca dapat dialihkan ke penyimpanan sekunder. Seperti disebutkan sebelumnya, aplikasi Anda berpotensi untuk membaca data kedaluwarsa. Pustaka klien Azure Storage menawarkan opsi untuk menangani pengulangan dan mengalihkan permintaan baca ke wilayah sekunder.

Dalam contoh ini, penanganan pengulangan untuk penyimpanan Blob dikonfigurasi di kelas BlobClientOptions dan akan diterapkan ke objek BlobServiceClient yang kami buat menggunakan opsi konfigurasi ini. Konfigurasi ini adalah pendekatan primer kemudian sekunder, ketika pengulangan permintaan baca dari wilayah primer dialihkan ke wilayah sekunder. Pendekatan ini paling sesuai ketika kegagalan di wilayah primer diperkirakan bersifat sementara.

string accountName = "<YOURSTORAGEACCOUNTNAME>";
Uri primaryAccountUri = new Uri($"https://{accountName}.blob.core.windows.net/");
Uri secondaryAccountUri = new Uri($"https://{accountName}-secondary.blob.core.windows.net/");

// Provide the client configuration options for connecting to Azure Blob storage
BlobClientOptions blobClientOptions = new BlobClientOptions()
{
    Retry = {
        // The delay between retry attempts for a fixed approach or the delay
        // on which to base calculations for a backoff-based approach
        Delay = TimeSpan.FromSeconds(2),

        // The maximum number of retry attempts before giving up
        MaxRetries = 5,

        // The approach to use for calculating retry delays
        Mode = RetryMode.Exponential,

        // The maximum permissible delay between retry attempts
        MaxDelay = TimeSpan.FromSeconds(10)
    },

    // If the GeoRedundantSecondaryUri property is set, the secondary Uri will be used for 
    // GET or HEAD requests during retries.
    // If the status of the response from the secondary Uri is a 404, then subsequent retries
    // for the request will not use the secondary Uri again, as this indicates that the resource 
    // may not have propagated there yet.
    // Otherwise, subsequent retries will alternate back and forth between primary and secondary Uri.
    GeoRedundantSecondaryUri = secondaryAccountUri
};

// Create a BlobServiceClient object using the configuration options above
BlobServiceClient blobServiceClient = new BlobServiceClient(primaryAccountUri, new DefaultAzureCredential(), blobClientOptions);

Jika Anda menentukan bahwa wilayah primer kemungkinan tidak tersedia untuk jangka waktu yang lama, Anda dapat mengonfigurasi semua permintaan baca agar mengarah ke wilayah sekunder. Konfigurasi ini adalah pendekatan sekunder saja. Seperti yang dibahas sebelumnya, Anda memerlukan strategi guna menangani permintaan pembaruan selama waktu ini, dan cara untuk memberi tahu pengguna bahwa hanya permintaan baca yang sedang diproses. Dalam contoh ini, kami membuat instans baru BlobServiceClient yang menggunakan titik akhir wilayah sekunder.

string accountName = "<YOURSTORAGEACCOUNTNAME>";
Uri primaryAccountUri = new Uri($"https://{accountName}.blob.core.windows.net/");
Uri secondaryAccountUri = new Uri($"https://{accountName}-secondary.blob.core.windows.net/");

// Create a BlobServiceClient object pointed at the secondary Uri
// Use blobServiceClientSecondary only when issuing read requests, as secondary storage is read-only
BlobServiceClient blobServiceClientSecondary = new BlobServiceClient(secondaryAccountUri, new DefaultAzureCredential(), blobClientOptions);

Mengetahui kapan harus beralih ke mode baca-saja dan permintaan sekunder saja adalah bagian dari pola desain arsitektur yang disebut Pola Pemutus Sirkuit, yang akan dibahas di bagian selanjutnya.

Permintaan pembaruan

Permintaan pembaruan tidak dapat dialihkan ke penyimpanan sekunder yang bersifat baca-saja. Seperti yang dijelaskan sebelumnya, aplikasi Anda harus dapat menangani permintaan pembaruan ketika wilayah primer tidak tersedia.

Pola Pemutus Sirkuit juga dapat diterapkan untuk memperbarui permintaan. Untuk menangani kesalahan permintaan pembaruan, Anda dapat menetapkan ambang batas dalam kode, seperti 10 kegagalan berturut-turut, dan melacak jumlah kegagalan untuk permintaan ke wilayah primer. Setelah ambang batas terpenuhi, Anda dapat mengalihkan aplikasi ke mode baca-saja sehingga permintaan pembaruan ke wilayah primer tidak lagi dikeluarkan.

Cara menerapkan pola Pemutus Sirkuit

Menangani kegagalan yang mungkin memerlukan waktu bervariasi untuk pulih adalah bagian dari pola desain arsitektur yang disebut pola Pemutus Sirkuit. Implementasi yang tepat dari pola ini dapat mencegah aplikasi berulang kali mencoba menjalankan operasi yang kemungkinan akan gagal sehingga meningkatkan stabilitas dan ketahanan aplikasi.

Salah satu aspek dari pola Pemutus Sirkuit adalah mengidentifikasi ketika terdapat masalah yang sedang berlangsung pada titik akhir primer. Untuk membuat penetapan ini, Anda dapat memantau seberapa sering klien mengalami kesalahan yang dapat diulang. Karena setiap skenario berbeda, Anda perlu menentukan ambang batas yang sesuai untuk digunakan dalam keputusan beralih ke titik akhir sekunder dan menjalankan aplikasi dalam mode baca-saja.

Misalnya, Anda dapat memutuskan untuk beralih jika terdapat 10 kegagalan berturut-turut di wilayah primer. Anda dapat melacaknya dengan menghitung jumlah kegagalan dalam kode. Jika terdapat keberhasilan sebelum mencapai ambang batas, atur hitungan kembali ke nol. Jika hitungan mencapai ambang batas, maka alihkan aplikasi untuk menggunakan wilayah sekunder untuk permintaan baca.

Sebagai pendekatan alternatif, Anda dapat memutuskan untuk menerapkan komponen pemantauan kustom dalam aplikasi Anda. Komponen ini dapat terus-menerus melakukan ping ke titik akhir penyimpanan primer Anda dengan permintaan baca trivial (seperti membaca blob kecil) untuk menentukan kesehatannya. Pendekatan ini memerlukan sejumlah sumber daya, tetapi jumlahnya tidak signifikan. Ketika terdapat masalah yang mencapai ambang batas, Anda akan beralih ke permintaan baca sekunder saja dan mode baca-saja. Untuk skenario ini, saat melakukan ping ke titik akhir penyimpanan primer menjadi kembali berhasil, Anda dapat beralih kembali ke wilayah primer dan terus mengizinkan pembaruan.

Ambang batas kesalahan yang digunakan untuk menentukan kapan harus beralih dapat bervariasi untuk setiap layanan dalam aplikasi, jadi Anda harus mempertimbangkan untuk menjadikannya parameter yang dapat dikonfigurasi.

Pertimbangan lain adalah cara menangani beberapa instans aplikasi, dan apa yang harus dilakukan saat Anda mendeteksi kesalahan yang dapat diulang dalam setiap kasus. Misalnya, Anda mungkin memiliki 20 VM yang berjalan dengan aplikasi yang sama. Apakah Anda menangani setiap instans secara terpisah? Jika satu instans mulai mengalami masalah, apakah Anda ingin membatasi respons hanya pada satu instans tersebut? Atau apakah Anda ingin semua instans merespons dengan cara yang sama ketika satu instans mengalami masalah? Menangani instans secara terpisah jauh lebih sederhana daripada mencoba mengoordinasikan respons di seluruhnya, tetapi pendekatan Anda akan bergantung pada arsitektur aplikasi Anda.

Menangani data yang akhirnya konsisten

Penyimpanan geo-redundan bekerja dengan mereplikasi transaksi dari wilayah primer ke sekunder. Proses replikasi menjamin bahwa data di wilayah sekunder pada akhirnya konsisten. Ini berarti bahwa semua transaksi di wilayah primer pada akhirnya akan muncul di wilayah sekunder, tetapi mungkin ada jeda sebelum muncul. Selain itu, tidak ada jaminan bahwa transaksi tiba di wilayah sekunder dalam urutan yang sama seperti awalnya diterapkan di wilayah primer. Jika transaksi Anda tiba di wilayah sekunder tak berurutan, Anda dapat mempertimbangkan data Anda di wilayah sekunder untuk berada dalam keadaan inkonsisten sampai layanan menyusul.

Contoh berikut untuk penyimpanan Tabel Azure memperlihatkan hal yang mungkin terjadi saat Anda memperbarui detail karyawan untuk menjadikannya anggota peran administrator. Demi contoh, ini mengharuskan Anda memperbarui entitas karyawan dan memperbarui entitas peran administrator dengan hitungan jumlah total administrator. Perhatikan bagaimana pembaruan diterapkan secara tidak berurut di wilayah sekunder.

Waktu Transaksi Replikasi Waktu sinkronisasi terakhir Hasil
T0 Transaksi A:
Masukkan karyawan
entitas di primer
Transaksi A dimasukkan ke primer,
belum direplikasi.
T1 Transaksi A
direplikasi ke
sekunder
T1 Transaksi A direplikasi ke sekunder.
Waktu Sinkron Terakhir diperbarui.
T2 Transaksi B:
Pembaruan
entitas karyawan
di primer
T1 Transaksi B ditulis ke primer,
belum direplikasi.
T3 Transaksi C:
Pembaruan
administrator
entitas peran dalam
primer
T1 Transaksi B ditulis ke primer,
belum direplikasi.
T4 Transaksi C
direplikasi ke
sekunder
T1 Transaksi C direplikasi ke sekunder.
LastSyncTime tidak diperbarui karena
transaksi B belum direplikasi.
T5 Baca entitas
dari sekunder
T1 Anda mendapatkan nilai basi untuk entitas
karyawan karena transaksi B belum
belum direplikasi. Anda mendapatkan nilai baru untuk
entitas peran administrator karena C telah
direplikasi. Waktu Sinkron Terakhir masih belum
diperbarui karena transaksi B
belum direplikasi. Anda tahu bahwa
entitas peran administrator inkonsisten
karena tanggal/waktu entitas setelah
Waktu Sinkron Terakhir.
T6 Transaksi B
direplikasi ke
sekunder
T6 T6 – Semua transaksi melalui C telah
telah direplikasi, Waktu Sinkron Terakhir
diperbarui.

Dalam contoh ini, anggap klien beralih ke membaca dari wilayah sekunder di T5. Saat ini berhasil membaca entitas peran administrator, tetapi entitas tersebut berisi nilai untuk hitungan administrator yang inkonsisten dengan jumlah entitas karyawan yang ditandai sebagai administrator di wilayah sekunder saat ini. Klien Anda dapat menampilkan nilai ini, dengan risiko informasi menjadi inkonsisten. Atau, klien dapat mencoba untuk menentukan bahwa peran administrator berada dalam keadaan yang berpotensi inkonsisten karena pembaruan telah terjadi di luar urutan, lalu memberi tahu pengguna tentang fakta ini.

Untuk menentukan apakah akun penyimpanan memiliki data yang berpotensi inkonsisten, klien dapat memeriksa nilai properti Waktu Sinkronisasi Terakhir. Waktu Sinkronisasi Terakhir memberi tahu Anda waktu ketika data di wilayah sekunder terakhir konsisten dan ketika layanan telah menerapkan semua transaksi sebelum titik waktu tersebut. Dalam contoh yang ditunjukkan di atas, setelah layanan menyisipkan entitas karyawan di wilayah sekunder, waktu sinkronisasi terakhir diatur ke T1. Waktu Sinkronisasi Terakhir tetap di T1 hingga layanan memperbarui entitas karyawan di wilayah sekunder ketika diatur ke T6. Jika klien mengambil waktu sinkronisasi terakhir ketika membaca entitas di T5, ia dapat membandingkannya dengan tanda waktu pada entitas. Jika stempel waktu pada entitas lebih lambat dari waktu sinkronisasi terakhir, maka entitas berada dalam keadaan yang berpotensi inkonsisten, dan Anda dapat mengambil tindakan yang sesuai. Menggunakan bidang ini mengharuskan Anda mengetahui kapan pembaruan terakhir ke primer selesai.

Untuk mempelajari cara memeriksa waktu sinkronisasi terakhir, lihat Memeriksa properti Waktu Sinkronisasi Terakhir untuk akun penyimpanan.

Pengujian

Penting untuk menguji bahwa aplikasi Anda berperilaku seperti yang diharapkan ketika mengalami kesalahan yang dapat diulang. Misalnya, Anda perlu menguji bahwa aplikasi beralih ke wilayah sekunder saat mendeteksi masalah, lalu beralih kembali saat wilayah primer kembali tersedia. Untuk menguji perilaku ini dengan benar, Anda memerlukan cara untuk menyimulasikan kesalahan yang dapat diulang dan mengontrol seberapa sering kesalahan tersebut terjadi.

Salah satu opsinya adalah menggunakan Fiddler untuk mencegat dan memodifikasi respons HTTP dalam skrip. Skrip ini dapat mengidentifikasi respons yang berasal dari titik akhir primer Anda dan mengubah kode status HTTP menjadi salah satu yang dikenali Pustaka klien penyimpanan sebagai kesalahan yang dapat diulang. Cuplikan kode ini menunjukkan contoh sederhana skrip Fiddler yang mencegat respons permintaan baca terhadap tabel employeedata untuk mengembalikan status 502:

static function OnBeforeResponse(oSession: Session) {
    ...
    if ((oSession.hostname == "\[YOURSTORAGEACCOUNTNAME\].table.core.windows.net")
      && (oSession.PathAndQuery.StartsWith("/employeedata?$filter"))) {
        oSession.responseCode = 502;
    }
}

Anda dapat memperluas contoh ini untuk mencegat berbagai permintaan yang lebih luas dan hanya mengubah responseCode pada beberapa dari mereka untuk menyimulasikan skenario dunia nyata dengan lebih baik. Untuk informasi selengkapnya tentang kustomisasi skrip Fiddler, lihat Memodifikasi Permintaan atau Respons dalam dokumentasi Fiddler.

Jika Anda telah menyiapkan ambang batas yang dapat dikonfigurasi untuk mengalihkan aplikasi Anda ke baca-saja, akan lebih mudah untuk menguji perilaku dengan volume transaksi non-produksi.


Langkah berikutnya

Untuk sampel lengkap yang memperlihatkan cara melakukan pengalihan bolak-balik antara titik akhir primer dan sekunder, lihat Sampel Azure – Menggunakan Pola Pemutus Sirkuit dengan penyimpanan RA-GRS.