Minimalkan koordinasi

Azure Storage
Azure SQL Database
Azure Cosmos DB

Meminimalkan koordinasi untuk mencapai skalabilitas

Sebagian besar aplikasi cloud terdiri dari beberapa layanan aplikasi — ujung depan web, database, proses bisnis, pelaporan dan analisis, dan sebagainya. Untuk mencapai skalabilitas dan keandalan, masing-masing layanan tersebut harus berjalan di banyak instans.

Sistem yang tidak terkoordinasi, di mana pekerjaan dapat ditangani secara independen tanpa perlu meneruskan pesan antar mesin, umumnya lebih sederhana untuk diskalakan. Koordinasi biasanya bukan status biner, tetapi spektrum. Koordinasi terjadi pada lapisan yang berbeda, seperti data atau komputasi.

Apa yang terjadi ketika dua instans mencoba melakukan operasi bersamaan yang memengaruhi beberapa status bersama? Dalam beberapa kasus, harus ada koordinasi antar node, misalnya untuk menjaga jaminan ACID. Dalam diagram ini, Node2 sedang menunggu Node1 untuk melepaskan kunci database:

Diagram kunci database

Koordinasi membatasi manfaat skala horizontal dan menciptakan kemacetan. Dalam instans ini, saat Anda menskalakan aplikasi dan menambahkan lebih banyak instans, Anda akan melihat peningkatan pertentangan kunci. Dalam kasus terburuk, instans front-end akan menghabiskan sebagian besar waktunya menunggu kunci.

Semantik "tepat sekali" adalah sumber koordinasi lain yang sering. Misalnya, pesanan harus diproses tepat satu kali. Dua pekerja sedang mendengarkan pesanan baru. Worker1 mengambil pesanan untuk diproses. Aplikasi harus memastikan bahwa Worker2 tidak menduplikasi pekerjaan, tetapi juga jika Worker1 mogok, pesanan tidak dibatalkan.

Diagram koordinasi

Anda dapat menggunakan pola seperti Scheduler Agent Supervisor untuk mengoordinasikan antar pekerja, tetapi dalam kasus ini pendekatan yang lebih baik adalah dengan mempartisi pekerjaan. Setiap pekerja diberi rentang pesanan tertentu (misalnya, berdasarkan wilayah penagihan). Jika seorang pekerja mogok, sebuah instans baru melanjutkan dari tempat yang ditinggalkan oleh instans sebelumnya, tetapi beberapa instans tidak bersaing.

Rekomendasi

Gunakan komponen yang dipisahkan yang berkomunikasi secara asinkron. Komponen idealnya harus menggunakan peristiwa untuk berkomunikasi satu sama lain.

Menerima konsistensi akhir. Ketika data didistribusikan, dibutuhkan koordinasi untuk menegakkan jaminan konsistensi yang kuat. Misalnya, anggaplah sebuah operasi memperbarui dua database. Daripada memasukkannya ke dalam satu lingkup transaksi, lebih baik jika sistem dapat mengakomodasi konsistensi akhirnya, mungkin dengan menggunakan pola Transaksi Kompensasi untuk memutar kembali secara logis setelah kegagalan.

Gunakan peristiwa domain untuk menyinkronkan status. Peristiwa domain adalah peristiwa yang mencatat ketika sesuatu terjadi yang memiliki signifikansi dalam domain. Layanan yang tertarik dapat mendengarkan acara tersebut, daripada menggunakan transaksi global untuk berkoordinasi di beberapa layanan. Jika pendekatan ini digunakan, sistem harus menoleransi konsistensi akhirnya (lihat item sebelumnya).

Pertimbangkan pola seperti CQRS dan sumber acara. Kedua pola ini dapat membantu mengurangi perselisihan antara beban kerja baca dan beban kerja tulis.

  • Pola CQRS memisahkan operasi baca dari operasi tulis. Dalam beberapa implementasi, data baca secara fisik dipisahkan dari data tulis.

  • Dalam Pola Sumber Peristiwa, perubahan status dicatat sebagai rangkaian peristiwa ke penyimpanan data tambahan saja. Menambahkan acara ke aliran adalah operasi atom, yang membutuhkan penguncian minimal.

Kedua pola ini saling melengkapi. Jika penyimpanan hanya-tulis di CQRS menggunakan sumber peristiwa, penyimpanan hanya-baca dapat mendengarkan peristiwa yang sama untuk membuat snapshot status saat ini yang dapat dibaca, dioptimalkan untuk kueri. Namun, sebelum mengadopsi CQRS atau sumber acara, waspadai tantangan pendekatan ini.

Data dan status partisi. Hindari menempatkan semua data Anda ke dalam satu skema data yang digunakan bersama di banyak layanan aplikasi. Arsitektur layanan mikro menerapkan prinsip ini dengan membuat setiap layanan bertanggung jawab atas penyimpanan datanya sendiri. Dalam database tunggal, mempartisi data ke dalam pecahan dapat meningkatkan konkurensi, karena penulisan layanan ke satu pecahan tidak memengaruhi penulisan layanan ke pecahan yang berbeda. Meskipun partisi menambahkan beberapa tingkat koordinasi, Anda dapat menggunakan partisi untuk meningkatkan paralelisme untuk skalabilitas yang lebih baik. Status monolitik partisi menjadi gugus yang lebih kecil sehingga data dapat dikelola secara independen.

Merancang operasi idempoten. Bila memungkinkan, operasi desain menjadi idempoten. Dengan begitu, mereka dapat ditangani menggunakan semantik setidaknya sekali. Misalnya, Anda dapat meletakkan item pekerjaan dalam antrean. Jika seorang pekerja mogok di tengah operasi, pekerja lain hanya mengambil item pekerjaan. Jika pekerja perlu memperbarui data serta memancarkan pesan lain sebagai bagian dari logikanya, pola pemrosesan pesan idempogen harus digunakan.

Gunakan konkurensi optimis bila memungkinkan. Kontrol konkurensi pesimis menggunakan kunci database untuk mencegah konflik. Hal ini dapat menyebabkan performa yang buruk dan mengurangi ketersediaan. Dengan kontrol konkurensi optimis, setiap transaksi memodifikasi salinan atau snapshot data. Ketika transaksi dilakukan, mesin database memvalidasi transaksi dan menolak setiap transaksi yang akan mempengaruhi konsistensi database.

Azure SQL Database dan SQL Server mendukung konkurensi optimis melalui isolasi snapshot. Beberapa layanan penyimpanan Azure mendukung konkurensi optimis melalui penggunaan Etags, termasuk Azure Cosmos DB dan Azure Storage.

Pertimbangkan MapReduce atau paralel lain, algoritma terdistribusi. Bergantung pada data dan jenis pekerjaan yang akan dilakukan, Anda mungkin dapat membagi pekerjaan menjadi tugas independen yang dapat dilakukan oleh beberapa node yang bekerja secara paralel. Lihat Gaya arsitektur komputasi besar.

Gunakan pemilihan pemimpin untuk koordinasi. Dalam kasus di mana Anda perlu mengoordinasikan operasi, pastikan koordinator tidak menjadi satu titik kegagalan dalam aplikasi. Menggunakan pola Pemilihan Pemimpin, satu instansi adalah pemimpin setiap saat, dan bertindak sebagai koordinator. Jika pemimpin gagal, instans baru dipilih untuk menjadi pemimpin.