Pola Sumber Kejadian

Bookings

Sebagai ganti hanya menyimpan status data saat ini dalam domain, gunakan penyimpanan khusus tambahan untuk merekam serangkaian tindakan lengkap yang diambil pada data tersebut. Penyimpanan bertindak sebagai sistem rekaman dan dapat digunakan untuk mewujudkan objek domain. Hal ini dapat menyederhanakan tugas dalam domain yang kompleks, dengan menghindari kebutuhan untuk menyinkronkan model data dan domain bisnis, sambil meningkatkan performa, skalabilitas, dan responsivitas. Penyimpanan ini juga dapat memberikan konsistensi untuk data transaksional, dan mempertahankan jalur audit penuh dan riwayat yang dapat memungkinkan tindakan kompensasi.

Konteks dan masalah

Sebagian besar aplikasi menggunakan data, dan pendekatan khasnya adalah aplikasi untuk mempertahankan status data saat ini dengan memperbaruinya saat pengguna menggunakannya. Misalnya, dalam model buat, baca, perbarui, dan hapus tradisional (CRUD), proses data yang khas adalah membaca data dari penyimpanan, membuat beberapa modifikasi, dan memperbarui status data saat ini dengan nilai baru—sering kali menggunakan transaksi yang mengunci data.

Pendekatan CRUD memiliki beberapa keterbatasan:

  • Sistem CRUD melakukan operasi pembaruan secara langsung terhadap penyimpanan data. Operasi ini dapat memperlambat performa dan responsivitas dan dapat membatasi skalabilitas, karena overhead pemrosesan yang diperlukannya.

  • Dalam domain kolaboratif dengan banyak pengguna bersamaan, konflik pembaruan data lebih mungkin terjadi karena operasi pembaruan terjadi pada satu item data.

  • Kecuali ada mekanisme audit lain yang merekam detail setiap operasi dalam log terpisah, riwayat akan hilang.

Solusi

Pola Event Sourcing mendefinisikan pendekatan untuk menangani operasi pada data yang didorong oleh urutan peristiwa, yang masing-masing dicatat di penyimpanan khusus tambahan. Kode aplikasi mengirimkan serangkaian peristiwa yang secara imperatif menggambarkan setiap tindakan yang telah terjadi pada data ke penyimpanan peristiwa, tempat data disimpan. Setiap peristiwa mewakili serangkaian perubahan pada data (seperti AddedItemToOrder).

Peristiwa tersebut disimpan di penyimpanan peristiwa yang bertindak sebagai sistem catatan (sumber data otoritatif) tentang status data saat ini. Penyimpanan peristiwa biasanya menerbitkan peristiwa ini sehingga konsumen dapat diberi tahu dan dapat menanganinya jika diperlukan. Konsumen dapat, misalnya, memulai tugas yang menerapkan operasi dalam peristiwa ke sistem lain, atau melakukan tindakan terkait lainnya yang diperlukan untuk menyelesaikan operasi. Perhatikan bahwa kode aplikasi yang menghasilkan peristiwa dipisahkan dari sistem yang berlangganan ke peristiwa.

Penggunaan khas dari peristiwa yang diterbitkan oleh penyimpanan peristiwa adalah untuk mempertahankan pandangan entitas yang terwujud ketika tindakan dalam aplikasi mengubahnya, dan untuk integrasi dengan sistem eksternal. Misalnya, sistem dapat mempertahankan pandangan yang terwujud dari semua pesanan pelanggan yang digunakan untuk mengisi bagian UI. Aplikasi menambahkan pesanan baru, menambahkan atau menghapus item pada pesanan, dan menambahkan informasi pengiriman. Peristiwa yang menjelaskan perubahan ini dapat ditangani dan digunakan untuk memperbarui tampilan materialisasi.

Kapan saja, aplikasi dapat membaca riwayat peristiwa. Anda kemudian dapat menggunakannya untuk mewujudkan status entitas saat ini dengan memutar kembali dan mengkonsumsi semua peristiwa yang terkait dengan entitas tersebut. Proses ini dapat terjadi sesuai permintaan untuk mewujudkan objek domain saat menangani permintaan. Atau, proses terjadi melalui tugas terjadwal sehingga status entitas dapat disimpan sebagai tampilan materialisasi, untuk mendukung lapisan presentasi.

Gambar menunjukkan ringkasan tentang pola, termasuk beberapa opsi untuk menggunakan stream peristiwa seperti membuat tampilan yang terwujud, yang mengintegrasikan peristiwa dengan aplikasi dan sistem eksternal, dan memutar ulang peristiwa untuk membuat proyeksi status entitas tertentu saat ini.

Ringkasan dan contoh pola Event Sourcing

Pola Event Sourcing memberikan keuntungan berikut:

  • Peristiwa tidak berubah dan dapat disimpan menggunakan operasi khusus tambahan. Antarmuka pengguna, alur kerja, atau proses yang memulai suatu peristiwa dapat berlanjut, dan tugas yang menangani peristiwa dapat berjalan di latar belakang. Proses ini, dikombinasikan dengan fakta bahwa tidak ada pertikaian selama pemrosesan transaksi, dapat sangat meningkatkan performa dan skalabilitas untuk aplikasi, terutama untuk tingkat presentasi atau antarmuka pengguna.

  • Peristiwa adalah objek sederhana yang menjelaskan beberapa tindakan yang terjadi, bersama dengan data terkait yang diperlukan untuk menjelaskan tindakan yang diwakili oleh peristiwa. Peristiwa tidak secara langsung memperbarui penyimpanan data. Peristiwa hanya direkam untuk penanganan pada waktu yang tepat. Menggunakan peristiwa dapat menyederhanakan implementasi dan manajemen.

  • Peristiwa biasanya memiliki arti bagi seorang ahli domain, sedangkan ketidakcocokan impedansi objek-relasional dapat membuat tabel database yang kompleks menjadi sulit dipahami. Tabel adalah konstruksi buatan yang mewakili status sistem saat ini, bukan peristiwa yang terjadi.

  • Sumber peristiwa dapat membantu mencegah pembaruan bersamaan menyebabkan konflik karena menghindari persyaratan untuk memperbarui objek secara langsung di penyimpanan data. Namun, model domain masih harus dirancang untuk melindungi diri dari permintaan yang mungkin mengakibatkan status tidak konsisten.

  • Penyimpanan peristiwa khusus tambahan menyediakan jejak audit yang dapat digunakan untuk memantau tindakan yang diambil terhadap penyimpanan data. Ini dapat meregenerasi status saat ini sebagai tampilan atau proyeksi materialisasi dengan memutar ulang peristiwa kapan saja, dan dapat membantu dalam pengujian dan penelusuran kesalahan sistem. Selain itu, persyaratan untuk menggunakan kompensasi peristiwa untuk membatalkan perubahan dapat memberikan riwayat perubahan yang dibalik. Kemampuan ini tidak akan terjadi jika model menyimpan status saat ini. Daftar peristiwa juga dapat digunakan untuk menganalisis performa aplikasi dan untuk mendeteksi tren perilaku pengguna. Atau, ini dapat digunakan untuk mendapatkan informasi bisnis berguna lainnya.

  • Penyimpanan acara menimbulkan peristiwa, dan tugas melakukan operasi sebagai respons atas peristiwa tersebut. Pemisahan tugas dari peristiwa ini memberikan fleksibilitas dan ekstensibilitas. Tugas tahu tentang jenis peristiwa dan data peristiwa, tetapi bukan tentang operasi yang memicu peristiwa. Selain itu, beberapa tugas dapat menangani setiap peristiwa. Hal ini memungkinkan integrasi yang mudah dengan layanan dan sistem lain yang hanya mendengarkan peristiwa baru yang diangkat oleh penyimpanan acara. Namun, peristiwa sumber peristiwa cenderung tingkat yang sangat rendah, dan mungkin perlu untuk menghasilkan peristiwa integrasi tertentu sebagai gantinya.

Event sourcing umumnya dikombinasikan dengan pola CQRS dengan melakukan tugas manajemen data dalam menanggapi peristiwa, dan dengan mewujudkan tampilan dari peristiwa yang disimpan.

Masalah dan pertimbangan

Pertimbangkan poin-poin berikut saat memutuskan cara menerapkan pola ini:

Sistem hanya akan konsisten pada akhirnya ketika membuat pandangan yang terwujud atau menghasilkan proyeksi data dengan memutar ulang peristiwa. Ada beberapa keterlambatan antara aplikasi yang menambahkan peristiwa ke penyimpanan peristiwa sebagai akibat dari menangani permintaan, peristiwa yang diterbitkan, dan konsumen peristiwa yang menanganinya. Selama periode ini, peristiwa baru yang menggambarkan perubahan lebih lanjut pada entitas mungkin telah tiba di penyimpanan peristiwa. Sistem harus dirancang untuk memperhitungkan konsistensi akhir dalam skenario ini.

Catatan

Lihat Primer Konsistensi Data untuk informasi tentang konsistensi akhirnya.

Penyimpanan peristiwa adalah sumber informasi permanen, sehingga data peristiwa tidak boleh diperbarui. Satu-satunya cara untuk memperbarui entitas untuk membatalkan perubahan adalah dengan menambahkan peristiwa kompensasi ke penyimpanan peristiwa. Jika format (bukan data) dari peristiwa yang bertahan perlu diubah, mungkin selama migrasi, mungkin sulit untuk menggabungkan peristiwa yang ada di penyimpanan dengan versi baru. Mungkin perlu untuk melakukan iterasi melalui semua peristiwa yang membuat perubahan sehingga sesuai dengan format baru, atau menambahkan peristiwa baru yang menggunakan format baru. Pertimbangkan untuk menggunakan stempel versi pada setiap versi skema peristiwa untuk mempertahankan format peristiwa lama dan baru.

Aplikasi multi-utas dan beberapa contoh aplikasi mungkin menyimpan peristiwa di penyimpanan peristiwa. Konsistensi peristiwa di penyimpanan peristiwa sangat penting, seperti urutan peristiwa yang mempengaruhi entitas tertentu (urutan perubahan terjadi pada entitas memengaruhi status saat ini). Menambahkan stempel waktu ke setiap acara dapat membantu menghindari masalah. Praktik umum lainnya adalah membuat anotasi setiap peristiwa yang dihasilkan dari permintaan dengan pengidentifikasi bertambah bertahap. Jika dua tindakan mencoba menambahkan peristiwa untuk entitas yang sama secara bersamaan, penyimpanan peristiwa dapat menolak peristiwa yang cocok dengan pengidentifikasi entitas dan pengidentifikasi peristiwa yang ada.

Tidak ada pendekatan standar, atau mekanisme yang ada seperti kueri SQL, untuk membaca peristiwa untuk mendapatkan informasi. Satu-satunya data yang dapat diekstraksi adalah stream peristiwa menggunakan pengidentifikasi peristiwa sebagai kriteria. ID peristiwa biasanya memetakan ke entitas individual. Status entitas saat ini hanya dapat ditentukan dengan memutar ulang semua peristiwa yang berhubungan terhadap status asli entitas tersebut.

Panjang setiap stream peristiwa memengaruhi pengelolaan dan pembaruan sistem. Jika stream besar, pertimbangkan untuk membuat snapshot pada interval tertentu seperti jumlah peristiwa tertentu. Status entitas saat ini dapat diperoleh dari snapshot dan dengan memutar ulang peristiwa apa pun yang terjadi setelah titik waktu tersebut. Untuk informasi selengkapnya tentang membuat snapshot data, lihat Replikasi Snapshot Subordinat Utama.

Meskipun sumber peristiwa meminimalkan kemungkinan pembaruan data yang bertentangan, aplikasi harus tetap dapat menangani inkonsistensi yang dihasilkan dari konsistensi akhirnya dan kurangnya transaksi. Misalnya, peristiwa yang menunjukkan pengurangan inventaris stok mungkin tiba di penyimpanan data saat pesanan untuk item tersebut sedang ditempatkan. Situasi ini menghasilkan persyaratan untuk mendamaikan dua operasi, baik dengan memberi tahu pelanggan atau dengan membuat pesanan balik.

Publikasi peristiwa mungkin setidaknya sekali, sehingga konsumen peristiwa harus idempotent. Mereka tidak boleh mengajukan permohonan kembali pembaruan yang dijelaskan dalam suatu peristiwa jika peristiwa ditangani lebih dari sekali. Beberapa instans konsumen dapat memelihara dan menggabungkan properti entitas, seperti jumlah total pesanan yang dilakukan. Hanya satu yang harus berhasil dalam meningkatkan agregat, ketika peristiwa yang ditempatkan pesanan terjadi. Meskipun hasil ini bukan karakteristik utama sumber peristiwa, ini adalah keputusan implementasi yang biasa.

Penyimpanan peristiwa yang dipilih perlu mendukung beban peristiwa yang dihasilkan oleh aplikasi Anda.
Perhatikan skenario di mana pemrosesan satu peristiwa melibatkan pembuatan satu atau beberapa peristiwa baru karena ini dapat menyebabkan perulangan tak terbatas.

Kapan menggunakan pola ini

Gunakan pola ini dalam skenario berikut:

  • Ketika Anda ingin menangkap niat, tujuan, atau alasan dalam data. Misalnya, perubahan pada entitas pelanggan dapat ditangkap sebagai serangkaian jenis peristiwa tertentu, seperti Beranda yang dipindahkan, Akun yang ditutup, atau Penonaktifan.

  • Ketika sangat penting untuk meminimalkan atau sepenuhnya menghindari terjadinya pembaruan data yang bertentangan.

  • Saat Anda ingin merekam peristiwa yang terjadi, untuk memutar ulang peristiwa tersebut untuk memulihkan status sistem, mengembalikan perubahan, atau menyimpan riwayat dan log audit. Misalnya, ketika tugas melibatkan beberapa langkah, Anda mungkin perlu menjalankan tindakan untuk mengembalikan pembaruan lalu memutar ulang beberapa langkah untuk membawa data kembali ke status yang konsisten.

  • Saat Anda menggunakan peristiwa. Ini adalah fitur alami dari pengoperasian aplikasi, dan membutuhkan sedikit upaya pengembangan atau implementasi ekstra.

  • Saat Anda perlu memisahkan proses input, atau memperbarui data dari tugas yang diperlukan untuk menerapkan tindakan ini. Perubahan ini mungkin untuk meningkatkan performa UI, atau untuk mendistribusikan peristiwa ke pendengar lain yang mengambil tindakan saat peristiwa terjadi. Misalnya, Anda dapat mengintegrasikan sistem penggajian dengan situs web pengiriman pengeluaran. Peristiwa yang dimunculkan oleh penyimpanan peristiwa sebagai respons terhadap pembaruan data yang dibuat di situs web akan digunakan oleh situs web dan sistem penggajian.

  • Saat Anda ingin fleksibilitas dapat mengubah format model terwujud dan data entitas jika persyaratan berubah, atau—saat digunakan dengan CQRS—Anda perlu menyesuaikan model baca atau tampilan yang mengekspos data.

  • Ketika digunakan dengan CQRS, dan konsistensi akhirnya dapat diterima saat model baca diperbarui, atau dampak performa entitas dan data rehidrasi dari aliran peristiwa dapat diterima.

Pola ini mungkin tidak berguna dalam situasi berikut:

  • Domain kecil atau sederhana, sistem yang memiliki sedikit atau tidak ada logika bisnis, atau sistem nondomain yang secara alami berfungsi dengan baik dengan mekanisme manajemen data CRUD tradisional.

  • Sistem tempat konsistensi dan pembaruan real-time untuk tampilan data diperlukan.

  • Sistem di mana jejak audit, riwayat, dan kemampuan untuk mengembalikan dan memutar ulang tindakan tidak diperlukan.

  • Sistem di mana hanya ada kemunculan rendah pembaruan yang bertentangan pada data yang mendasar. Misalnya, sistem yang sebagian besar menambahkan data, bukan memperbaruinya.

Desain beban kerja

Arsitek harus mengevaluasi bagaimana pola Sumber Peristiwa dapat digunakan dalam desain beban kerja mereka untuk mengatasi tujuan dan prinsip yang tercakup dalam pilar Azure Well-Architected Framework. Contohnya:

Pilar Bagaimana pola ini mendukung tujuan pilar
Keputusan desain keandalan membantu beban kerja Anda menjadi tahan terhadap kerusakan dan untuk memastikan bahwa keputusan tersebut pulih ke status berfungsi penuh setelah kegagalan terjadi. Karena menangkap riwayat perubahan dalam proses bisnis yang kompleks, itu dapat memfasilitasi rekonstruksi status jika Anda perlu memulihkan penyimpanan status.

- Pemartisian data RE:06
- RE:09 Pemulihan bencana
Efisiensi Performa membantu beban kerja Anda memenuhi tuntutan secara efisien melalui pengoptimalan dalam penskalaan, data, kode. Pola ini, biasanya dikombinasikan dengan CQRS, desain domain yang sesuai, dan rekam jepret strategis, dapat meningkatkan performa beban kerja karena operasi atom tambahan saja dan penghindaman penguncian database untuk penulisan dan bacaan.

- Performa DATA PE:08

Seperti halnya keputusan desain apa pun, pertimbangkan tradeoff terhadap tujuan pilar lain yang mungkin diperkenalkan dengan pola ini.

Contoh

Sistem manajemen konferensi perlu melacak jumlah pemesanan yang telah selesai untuk konferensi. Dengan cara ini dapat memeriksa apakah ada kursi yang masih tersedia, ketika calon peserta mencoba membuat pemesanan. Sistem ini dapat menyimpan jumlah total pemesanan untuk konferensi setidaknya dalam dua cara:

  • Sistem dapat menyimpan informasi tentang jumlah total pemesanan sebagai entitas terpisah dalam database yang menyimpan informasi pemesanan. Karena pemesanan dilakukan atau dibatalkan, sistem dapat menambah atau mengurangi jumlah ini sebagaimana mestinya. Pendekatan ini sederhana secara teori, tetapi dapat menyebabkan masalah skalabilitas jika sejumlah besar peserta mencoba untuk memesan seat selama periode waktu yang singkat. Misalnya, pada hari terakhir atau lebih sebelum periode pemesanan ditutup.

  • Sistem dapat menyimpan informasi tentang pemesanan dan pembatalan sebagai peristiwa yang diadakan di penyimpanan peristiwa. Kemudian, sistem bisa menghitung jumlah seat yang tersedia dengan memutar ulang peristiwa ini. Pendekatan ini bisa lebih skalabel karena kekebalan peristiwa. Sistem hanya perlu dapat membaca data dari penyimpanan peristiwa, atau menambahkan data ke penyimpanan peristiwa. Informasi peristiwa tentang pemesanan dan pembatalan tidak pernah dimodifikasi.

Diagram berikut menggambarkan bagaimana subsistem reservasi seat dari sistem manajemen konferensi dapat diimplementasikan menggunakan sumber peristiwa.

Menggunakan sumber peristiwa untuk menangkap informasi tentang reservasi seat dalam sistem manajemen konferensi

Urutan tindakan untuk memesan dua seat adalah sebagai berikut:

  1. Antarmuka pengguna mengeluarkan perintah untuk memesan seat untuk dua peserta. Perintah ini ditangani oleh penangan perintah terpisah. Bagian logika yang dipisahkan dari antarmuka pengguna dan bertanggung jawab untuk menangani permintaan yang diposting sebagai perintah.

  2. Agregat yang berisi informasi tentang semua pemesanan untuk konferensi dibangun dengan mengkueri peristiwa yang menggambarkan pemesanan dan pembatalan. Agregat ini disebut SeatAvailability, dan berada dalam model domain yang mengekspos metode untuk kueri dan memodifikasi data secara agregat.

    Beberapa pengoptimalan yang perlu dipertimbangkan adalah menggunakan snapshot (sehingga Anda tidak perlu mengkueri dan memutar ulang daftar lengkap peristiwa untuk mendapatkan status agregat saat ini), dan mempertahankan salinan agregat yang di-cache dalam memori.

  3. Penangan perintah memanggil metode yang diekspos oleh model domain untuk membuat reservasi.

  4. Agregat SeatAvailability mencatat peristiwa yang berisi jumlah seat yang dipesan. Saat agregat menerapkan peristiwa di lain waktu, semua pemesanan akan digunakan untuk menghitung berapa banyak seat yang tersisa.

  5. Sistem menambahkan peristiwa baru ke daftar peristiwa di penyimpanan peristiwa.

Jika pengguna membatalkan seat, sistem mengikuti proses yang sama kecuali penangan perintah mengeluarkan perintah yang menghasilkan peristiwa pembatalan seat dan menambahkannya ke penyimpanan peristiwa.

Selain menyediakan lebih banyak cakupan untuk skalabilitas, menggunakan penyimpanan acara juga memberikan riwayat lengkap, atau jejak audit, dari pemesanan dan pembatalan untuk konferensi. Peristiwa di penyimpanan peristiwa adalah rekaman yang akurat. Tidak perlu mempertahankan agregat dengan cara lain karena sistem dapat dengan mudah memutar ulang peristiwa dan memulihkan status ke titik waktu mana pun.

Anda dapat menemukan informasi selengkapnya tentang contoh ini di Introducing Event Sourcing.

Langkah berikutnya

Pola dan panduan berikut mungkin relevan saat menerapkan pola ini:

  • Pola Command and Query Responsibility Segregation (CQRS). Penyimpanan tulis yang menyediakan sumber informasi permanen untuk implementasi CQRS sering didasarkan pada implementasi pola Event Sourcing. Menjelaskan cara memisahkan operasi yang membaca data dalam aplikasi dari operasi yang memperbarui data dengan menggunakan antarmuka terpisah.

  • Pola Tampilan Terwujud. Penyimpanan data yang digunakan dalam sistem yang didasarkan pada sumber peristiwa biasanya tidak cocok untuk kueri yang efisien. Sebaliknya, pendekatan umumnya adalah menghasilkan tampilan data yang telah diisi sebelumnya secara berkala, atau ketika data berubah.

  • Pola Transaksi Kompensasi. Data yang ada di penyimpanan sumber peristiwa tidak diperbarui. Sebaliknya, entri baru ditambahkan bahwa transisi status entitas ke nilai baru. Untuk membalikkan perubahan, mengkompensasi entri digunakan karena tidak dimungkinkan untuk membalikkan perubahan sebelumnya. Menjelaskan cara membatalkan pekerjaan yang dilakukan oleh operasi sebelumnya.