احسان رزازیان
احسان رزازیان
خواندن ۱۰ دقیقه·۳ سال پیش

آشنایی با الگوی Event Sourcing

مقدمه:

در این مقاله قصد داریم تا الگوی Event Sourcing را معرفی کرده و جزییات آن را با هم برسی کنیم. این الگو در صنعت نرم افزار کاربرد دارد و مانند هر الگوی دیگری، استفاده از آن نیز مزایا و معایبی دارد که در انتهای مقاله به آن خواهیم پرداخت. همانطور که از اسم الگوی Event Sourcing پیداست، تاکید این الگو بر روی ذخیره رویداد ها یا تغییراتی است که بر روی یک موجودیت اتفاق می افتد. در ادامه بیشتر با جزییات این الگوی جالب آشنا می شویم.

معرفی الگوی Event Sourcing:

این الگو بر ذخیره رخداد هایی که روی داده ها انجام شده اند تاکید دارد. هر زمان وضعیت یک موجودیت تغییر می کند، یک رخداد جدید به محل ذخیره سازی رخداد ها اضافه خواهد شد:

کلیات الگوی Event Sourcing
کلیات الگوی Event Sourcing

همانطور که در شکل فوق مشخص است، هر گونه رخدادی که در سیستم اتفاق می افتد، در لیست رخدادها یا همان Event Store ذخیره می شود. سپس می توان با مرور لیست رخداد ها، وضعیت کنونی یک موجودیت را فهمید. Event Store جایی است که تمام رخدادهایی که روی هر موجودیتی در سیستم اتفاق افتاده است در آن جا ذخیره می شود. "اضافه شدن" یا "کم شدن" از لیست، مثال هایی از رخدادها هستند که در Event Store ذخیره می شوند. وقتی از این الگو استفاده می کنیم، به جای آنکه وضعیت کنونی یک موجودیت را ذخیره کنیم، لیست تاریخچه رخداد ها و اعمالی که روی آن اتفاق افتاده است را ذخیره می کنیم. سپس به کمک این لیست می توانیم به راحتی به وضعیت کنونی موجودیت نیز پی ببریم.

مثال از الگوی Event Sourcing:

در ادامه یک مثال از الگوی Event Sourcing می زنیم تا درک آن آسان تر شود:

فرض کنید مشتری یک فروشگاه اینترنتی هستی و قصد دارید تا یک کالا را خریداری کنید. وقتی این کالا را انختاب کردید، اقدام به ثبت سفارش می کنید. پس از اینکه پرداخت موفق هم انجام دادید، سفارش شما ثبت می شود و وضعیت سفارش شما در حالت "در انتظار تایید" قرار می گیرد. در ادامه حالت های مختلفی می توانند برای خرید شما پیش بیایند، مثلا وضعیت سفارش شما به "تایید فروشنده" تبدیل می شود، و سپس پس از اینکه فروشنده کالا را ارسال کرد، وضعیت سفارش شما به "در حال ارسال" تبدیل می شود. در نهایت وقتی شما سفارشتان را تحویل گرفتید، وضعیت سفارش شما "تحویل شده" خواهد شد.

برخی اوقات ما نیاز داریم که به تاریخچه تغییرات وضعیت سفارش دسترسی داشته باشیم. این تاریخچه در Event Store موجود است. به عنوان مثال شما می خواهید ببینید که در چه روزی و چه ساعتی فروشنده سفارش شما ارسال کرده است. با یک نگاه ساده به Event Store این زمان را متوجه خواهیم شد. این یک مثال ساده از زمانی بود که ما به داشتن لیست تغییرات وضعیت سفارش نیاز داریم.

آنچه واضح است این است که Event Store باید دارای یک قالب و چارچوب مشخص باشد:

نمونه ای از یک Event Store
نمونه ای از یک Event Store


همان طور که مشاهده می شود، هر خط شامل اطلاعاتی مانند شناسه رخداد، جزییات رخداد، نوع موجودیت حاضر در رخداد و ... می باشد. به طور مفهومی، هر خط از Event Store شکل بالا می تواند بیانگر جملات زیر باشد:

"سفارش ثبت شد"

"سفارش تایید شد"

"سفارش ارسال شد"

"سفارش تحویل شد"

و ...

کاربرد دیگر Event Store، اطلاع یافتن سایر سرویس ها یا سامانه ها از رخداد ها به کمک Subscribe کردن روی آن است. برای این که این امر محقق شود، هر بخش از سامانه باید اتفاقاتی که در موجودیت هایش رخ می دهد را در معرض عموم قرار دهد تا بقیه از بیرون به آن دسترسی داشته باشند. اما این اتفاق به صورت زیبا تری به کمک اضافه کردن الگوی CQRS رخ خواهد داد که در ادامه مقاله آن را خواهیم دید.

در همین مثال حالتی را در نظر بگیرید که چند سرویس دیگر منتظر تغییر وضعیت سفارشات هستند تا اقدامات مربوطه را انجام بدهند. مثلا سرویس اطلاع رسانی منتظر است تا اگر وضعیت سفارش تغییر کرد، به مشتری اطلاع بدهد. در این حالت سرویس اطلاع رسانی می تواند بر روی Event Store یا همان لیست تفییرات وضعیت ها Subscribe کرده و به محض تغییر وضعیت، خودش متوجه تغییر شود و اقدامات مربوطه را انجام دهد. از جمله این اقدامات می توان به این مورد اشاره کرد که برای مشتری پیامک ارسال می شود. همچنین چندین سرویس دیگر مانند سرویس حمل و نقل و ... نیز می توانند Subscribe کنند.

توجه داشته باشید که هنگامی که از الگوی Event Sourcing استفاده می کنیم، در Event Store فقط تغییرات یا همان به روز شدن ها ذخیره نمی شود. بلکه هر نوع عمل <<اضافه شدن>>، <<حذف شدن>> و <<به روز شدن>> که باعث تغییر در موجودیت ها می شوند می توانند در این منبع ذخیره شود.

شباهت Event Sourcing به Log کردن:

شاید تا به اینجا متوجه شده باشید که این الگو شباهت زیادی به مکانیزم های Log کردن در پایگاه داده دارد. اکثر پایگاه داده های امروزی (می توان گفت همه ی آن ها) دارای فایل Log یا همان Log File هستند که درون آن ها نیز تغییراتی که در پایگاه داده رخ داده نوشته می شود. پس تفاوت این الگو با Log چیست؟! در پاسخ باید بگوییم اولا فرمت Log های هر پایگاه داده با فرمت Log های پایگاه داده دیگر متفاوت است. ثانیا در برخی موارد Log File های یک نسخه از یک پایگاه داده، با Log File های نسخه پیشین همان پایگاه داده تفاوت هایی دارد! ثالثا ممکن است در Log File ها اطلاعاتی وجود داشته باشد که به کار نیایند و فقط باعث هدر رفت حافظه شوند. چرا که در بسیاری از پایگاه داده ها، به صورت پیش فرض Log ها فقط تا یک مدت مشخصی وجود دارند و پس از اتمام آن مدت به صورت خودگار پاک می شوند.

اما از مزیت ها Log File نسبت به الگوی Event Sourcing می توان به این نکته اشاره کرد که سرعت جستجو در آن بیشتر است. به همین دلیل است که الگوی CQRS را با الگوی Event Sourcing تلفیق میکنند تا سرعت جستجو در بین رکورد ها بیشتر شود. در ادامه تلفیق این دو الگو را برسی خواهیم کرد.

استفاده از Event Sourcing به همراه CQRS:

استفاده از این الگو به همراه الگوی CQRS بسیار رایج است (مخصوصا در معماری میکروسرویس). اگر با الگوی CQRS آشنایی داشته باشید، می دانید که در این الگو Command ها (نوشتن، به روز کردن، حذف کردن) از Query ها (خواندن) تفکیک می شوند.

فرض کنیم دو میکروسرویس داریم. هر کدام از آن ها Write DB و Read DB مخصوص خودشان را دارند. (اگر با Write DB و Read DB آشنایی ندارید حتما در مورد CQRS مطالعه کنید). پس از تلفیق این دو الگو، Write DB معادل با همان Event Store است. یعنی هر میکروسرویس یک پایگاه داده دارد که تغییرات اعمال شده بر روی موجودیت ها بر روی آن نوشته می شود و یک پایگاه داده دارد که فقط مخصوص خواندن این تغییرات است (طبق الگوی CQRS). در واقع پایگاه داده نوشتن با خواندن فرق دارد. اگر بر الگوی CQRS مسلط باشید می دانید که برای اینکه Write DB و Read DB با یکدیگر sync باشند، نیاز است تا تغییراتی که بر روی Write DB یک سامانه اتفاق می افتد، به کمک یک سیستم پیام رسانی به گوش Read DB همان سامانه هم هم برسد تا Read DB هم خودش را به روز کند. اما وقتی از الگوی Event Sourcing استفاده می کنیم، از آن جایی که تغییرات موجودیت های یک میکروسرویس می تواند برای سایر میکروسرویس ها هم ارزشمند باشد. وقتی CQRS نیز اضافه می شود، میکروسرویس ها می توانند به جای آن که از Event Store های هم دیگر Subscribe کنند، از Read Storage یا همان Read DB یکدیگر Subscribe کنند. حتی به جای این کار می توانند از یک صف که همه میکروسرویس ها Event Store خود را در آن منتشر کرده اند Subscribe کنند و یا این که یک پایگاه داده کلی داشته باشیم که از آن به عنوان view استفاده شود:

تلفیق Event Sourcing و CQRS در میکروسرویس
تلفیق Event Sourcing و CQRS در میکروسرویس

اگر از الگوی Event Sourcing استفاده نمی شد، میکروسرویس ها ناچار بودند تا تغییرات را از روی Log ها یکدیگر بفهمند (که معایب خودش را به همراه داشت). و اگر از الگوی CQRS استفاده نمی شد، دیگر Read Storage نداشتیم و میکروسرویس ها باید تغییرات را از روی Event Store هم دیگر می فهمیدند که این کارآیی را کاهش می داد و سرعت سیستم کمتر می شد.

مزایای الگوی Event Sourcing:

الگوی Event Sourcing مزایای زیادی دارد که برخی از آن ها عبارت اند از:

  1. بازیابی راحت تر اطلاعات: به کمک الگوی Event Sourcing، ما یک لیستی از تغییرات وضعیت موجودیت ها خواهیم داشت. این امر به ما کمک می کند که اگر نیاز شد تا بخواهیم مقادیر داده ها یا رکورد ها را در یک زمان خاص به دست بیاوریم و یا متوجه شدیم که در جایی از سیستم اطلاعات مربوط به داده ها غلطط هستند، به راحتی به سراغ لیست تغییرات رفته و به وضعیت سیستم و مقادیر داده ها در یک زمان خاص پی ببریم.
  2. شفاف تر شدن سیستم: وقتی از الگوی Event Sourcing استفاده می کنیم، به راحتی می توانیم متوجه شویم که هر تغییری که در سیستم رخ داده توسط چه بخشی بوده و در چه زمانی اتفاق افتاده است. در واقع از Event Store می توان به عنوان لیستی از اسناد تغییرات استفاده کرد و از هر تغییر به عنوان یک مدرک استفاده کرد. در این حالت علت هر تغییر و وضعیت سیستم و اینکه چرا سیستم به یک حالت مشخص رسید بسیار شفاف خواهد بود.
  3. امکان آنالیز دقیق تر سیستم: در بسیاری از اوقات ما می خواهیم یه آنالیز از سیستم داشته باشیم و رفتار کاربران را شبیه سازی کنیم. به کمک الگوی Event Sourcing می توان هر گونه آمار و آنالیزی از سیستم داشته باشیم چرا که زمان هر رخداد مشخص استو مثلا می خواهیم ببینیم در چه ساعاتی از شبانه روز بیشترین ویرایش سفارش اتفاق می افتد، این امر به راحتی با مراجعه به Event Store قابل فهم خواهد بود.
  4. عیب یابی راحت تر سیستم: اگر هر خطایی در سیستم رخ بدهد و داده ها به یک state بروند که از لحاظ مفهومی غلط هستند، می توان با مراجه به لیست رخداد هایی که روی آن داده اتفاق افتاده اند علت این عیب را پیدا کرد. مثلا می توان متوجه شد که این تغییر دارد توسط که بخشی از سیستم صورت می گیرد و جلوی آن بخش را گرفت یا آن بخش را اصلاح کرد تا دیگر باعث عیب در وضعیت داده ها نشود.

معایب الگوی Event Sourcing:

در کنار مزایایی که الگوی Event Sourcing دارد، معایبی نیز مطرح است که برخی از آن ها عبارت اند از:

  1. به روز رسانی صفات دشوار است: تصور کنید که قصد داشته باشیم به یک موجودیت، صفاتی را اضافه یا کم کنیم. در این صورت تکلیف رخداد های قبلی چیست؟! مثلا اگر بخواهیم صفت "وضعیت" را به کلی از موجودیت "سفارش" حذف کنیم، در این صورت تعداد بسیار زیادی Event در Event Store وجود داشته اند که تغییرات "وضعیت" سفارشات را ذخیره کرده اند. تکلیف آنان چه می شود؟ شاید ساده ترین کار حذف آن ها باشد. اما ممکن است حذف کردن آنان ایرادی به وجود بیاورد. لذا باید در این خصوص مشورت و تصمیم گیری شود.
  2. استفاده زیاد از حافظه: بدیهی است که اگر بخواهیم تمام رخداد ها را ذخیره کنیم، حافظه بسیار زیادی از سیستم اشغال می شود، چرا که رخداد های زیادی بر روی موجودیت ها رخ می دهد. از طرفی باید تمام تغییرات را داشته باشیم تا بتوانیم وضعیت نهایی یک موجودیت را به دست آوریم.

جمع بندی:

الگوی Event Sourcing الگویی است که مبنای آن ذخیره جزییات رخداد هایی است که بر روی موجودیت ها در یک پایگاه داده اتفاق می افتد. استفاده از این الگو بیشتر در معماری میکروسرویس و به همراه الگوی CQRS رایج است. استفاده از این الگو مزایا و معایبی به همراه دارد که باید با توجه به مزایا و معایب آن دید که استفاده از آن به صرفه است یا خیر. در انتها باید به این نکته اشاره کنیم که این الگو شباهت زیادی به سازوکار Log های پایگاه داده ها دارد که البته تفاوت های آن باعث شده تا هر کدام مزایا و معایب خودشان را داشته باشند.

منابع:

[1] https://microservices.io/patterns/data/event-sourcing.html

[2] https://codeopinion.com/event-sourcing-example-explained-in-plain-english/

[3] https://martinfowler.com/eaaDev/EventSourcing.html

[4] https://docs.microsoft.com/en-us/azure/architecture/patterns/event-sourcing

[5] https://eventuate.io/whyeventsourcing.html

[6] https://www.lagomframework.com/documentation/1.6.x/java/ESAdvantage.html

[7] https://dzone.com/articles/microservices-with-cqrs-and-event-sourcing

[8] https://www.eventstore.com/blog/event-sourcing-and-cqrs

[9] M. Overeem, M. Spoor, S. Jansen, "The Dark Side of Event Sourcing: Managing Data Conversion", IEEE 24th International Conference on Software Analysis, Evolution and Reengineering (SANER), 2017

این مطلب، بخشی از تمرینهای درس معماری نرم‌افزار در دانشگاه شهیدبهشتی است

#معماری_نرم_افزار_بهشتی

معماری_نرم_افزار_بهشتیcqrsevent sourcingمعماری نرم افزار
شاید از این پست‌ها خوشتان بیاید