مدل actor در 10 دقیقه
هر چه چیزها بیشتر تغییر کنند، بیشتر ثابت می مانند. در دهه 1970 دانشمندان کامپیوتر سخت افزار را به حد خود رساندند. مهندسان آن روز انواع و اقسام هکها را برای بالابردن عملکرد انجام دادند. امروز ما فایل های package.json رو داریم که پر شده از این چیزا. هنوز با مشکلات مقیاسپذیری مواجه میشویم که ما را مجبور میکند پایه کد خود را به میکروسرویسها تقسیم کنیم و پیامها را بین این میکروسرویسها ارسال کنیم.
این دقیقاً همان مشکلی است که افرادی مانند کارل هیویت و آلن کی در دهه 70 با آن مواجه بودند. آنها با مشکلات حافظه و برنامه های کند مواجه بودند. سخت افزار فعلی نمی تواند ادامه یابد. اختراع آنها در آن زمان ایجاد سیستم های ارسال پیام بود. آلن کی این ایده را به Smalltalk آورد که به محبوبیت سبک برنامه نویسی شی گرا کمک کرد. کارل هویت این ایده را گرفت و مدل بازیگر را خلق کرد. سالها بعد، همین ایدههای انتقال پیام، ارلنگ را تحت تأثیر قرار داد تا یک مدل بازیگر نیز ایجاد کند. Erlang اغلب به عنوان اولین و موفق ترین اجرای مدل actorذکر می شود. در واقع بدون اطلاع قبلی نوشته شده بود که مدل actor وجود داشته است. این نشانه یک الگوی طراحی عالی است.
امروزه چندین پروژه دیگر از مدل بازیگر استفاده می کنند. Akka برای JVM و Orleans و Akka.NET و... برخی از شناخته شده ترین پروژه ها هستند. Web Workers در جاوا اسکریپت نیز از همان ایده های اصلی ارسال پیام استفاده می کنند. Microsoft Azure معماری میکروسرویس سرویس Fabric خود را پیاده سازی کرد. Service Fabric از بازیگران مجازی برای مدیریت ارتباط بین سرورها استفاده می کند.
معرفی مدل
الگوی اصلی طراحی Actor Model ساده است. وقتی می شنوید actor ، در ذهنتان یک process یا یک function تصور کنید. یک قطعه کدیست که قرار است پیامی را به آن ارسال کنید، مانند فراخوانی یک تابع. اساساً شما دستورالعمل های برای actor ارسال می کنید و آن یکسری اطلاعات را به شما برمی گرداند. اکنون احتمالاً فکر می کنید که این چیزی انقلابی نیست. پس اجازه دهید یکسری جزئیات را تجزیه تحلیل کنیم. به خاطر داشته باشید که هر framework یا زبانی که مدل actor را پیادهسازی میکند، این کار را با تنظیمات جزئی انجام میدهد.
Actor
بازیگر(Actor) واحد اولیه محاسبات است. این چیزی است که پیامی را دریافت می کند و بر اساس آن نوعی محاسبات انجام می دهد.
این ایده بسیار شبیه به آنچه در زبان های شی گرا داریم است: یک شی یک پیام (یک متد فراخوانی) دریافت می کند و بسته به اینکه کدام پیام را دریافت می کند (کدام روش را فراخوانی می کنیم) کاری انجام می دهد.
تفاوت اصلی این است که actor کاملاً از یکدیگر جدا هستند و هیچ حافظه مشترکی ندارند. همچنین شایان ذکر است که یک actor می تواند حالت خصوصی را حفظ کند که هرگز نمی تواند مستقیماً توسط actor دیگری تغییر کند.
ویژگی های یک Actor
بازیگر(Actor) یک پراسس با آدرس است. آدرس نحوه ارسال پیام به یک بازیگر است. این معادل آدرس ایمیل است. مانند آدرس های ایمیل، بازیگران می توانند چندین آدرس یا یک آدرس واحد داشته باشند. همچنین می توانید یک آدرس را به چندین بازیگر اختصاص دهید. به این ترتیب اگر یک بازیگر کافی نباشد، میتوانید برنامه خود را برای برآورده کردن نیازهای ترافیکی مقیاس کنید.
یک مورچه مورچه نیست
و یک actor یک actor نیست. آنها وارد سیستم می شوند. در مدل actor همه چیز یک actor است و آنها باید آدرسی داشته باشند تا یک actor بتواند به دیگری پیام بفرستد.
Actor ها صندوق پستی دارند
درک این نکته مهم است که اگرچه چندین actor می توانند همزمان اجرا شوند، اما یک actor پیام داده شده را به صورت متوالی پردازش می کند. این به این معنی است که اگر شما 3 پیام را برای یک actor ارسال کنید، فقط یکی یکی اجرا می شود. برای اینکه این 3 پیام به صورت همزمان اجرا شوند، باید 3 actor ایجاد کنید و هر کدام یک پیام ارسال کنید.
پیامها بهصورت ناهمزمان برای یک actor ارسال میشوند، که باید آنها را در جایی ذخیره کند، در حالی که پیام دیگری را پردازش میکند. صندوق پست مکانی است که این پیام ها در آن ذخیره می شوند.
actor با ارسال پیام های Async با یکدیگر ارتباط برقرار می کنند. این پیامها تا زمانی که پردازش نشوند در صندوقهای پستی actor های دیگر ذخیره میشوند.
کاری که بازیگران انجام می دهند
هنگامی که یک actor پیامی را دریافت می کند، می تواند یکی از این 3 کار را انجام دهد:
• actor بیشتری ایجاد کنید
• برای سایر actor ها پیام بفرستید
• مشخص کنید که با پیام بعدی چه کاری انجام دهید
دو مورد اول واضح است، اما مورد آخر جالب است.
قبلا هم گفتم که یک actor می تواند حالت خصوصی را حفظ کند. «تعیین کاری که باید با پیام بعدی انجام شود» اساساً به معنای تعریف این است که این وضعیت برای پیام بعدی که دریافت میکند چگونه خواهد بود. یا، واضح تر، نحوه تغییر حالت actor است.
بیایید تصور کنیم بازیگری داریم که مانند یک ماشین حساب رفتار می کند و حالت اولیه آن فقط عدد 0 است. وقتی این بازیگر پیام add(1) را دریافت می کند، به جای تغییر حالت اولیه خود، تعیین می کند که برای پیام بعدی که دریافت می کند، حالت 1 خواهد بود.
تحمل خطا
Erlang فلسفه «بگذار خراب شود» را معرفی کرد. ایده این است که شما نیازی به برنامهریزی تدافعی ندارید، سعی کنید تمام مشکلات احتمالی را که ممکن است رخ دهد را پیشبینی کنید و راهی برای هندل به آنها بیابید، فقط به این دلیل که هیچ راهی برای فکر کردن به تک تک نقاط شکست وجود ندارد.
کاری که Erlang انجام می دهد این است که به سادگی اجازه می دهد تا خراب کاری اتفاق بیفتد، اما کاری می کند که این کد حیاتی توسط شخصی نظارت شود که تنها مسئولیتش این است که بداند هنگام وقوع این خرابی چه کاری باید انجام دهد (مانند بازنشانی این واحد کد به حالت پایدار)، و چه چیزی این کار را ممکن می کند. مدل actor است
هر کدی که در یک فرآیند اجرا میشود (که Erlang بهشون میگه Actor). این فرآیند کاملاً ایزوله است، به این معنی که وضعیت آن بر هیچ فرآیند دیگری تأثیر نخواهد گذاشت. ما یک سرپرست داریم، که اساساً فرآیند دیگری است (همه چیز یک Actor است، یادتون هست؟)، زمانی که فرآیند نظارت شده از کار بیفتد به او اطلاع داده می شود و سپس می تواند کاری در مورد آن انجام دهد.
این امکان ایجاد سیستمهایی را فراهم میکند که «خود شفا میدهند» نامیده میشوند، به این معنی که اگر یک Actor به یک وضعیت Exception برسد و به هر دلیلی از کار بیفتد، یک سرپرست میتواند کاری در مورد آن انجام دهد و سعی کند دوباره آن Actorرا در یک وضعیت ثابت قرار دهد (و در آنجا راهبردهای متعددی برای انجام آن وجود دارد، رایج ترین آنها فقط راه اندازی مجدد بازیگر با وضعیت اولیه اش است).
توزیع
یکی دیگر از جنبههای جالب مدل Actor این است که فرقی نمیکند Actorیی که من برایش پیام میفرستم به صورت محلی اجرا شود یا در نود دیگری.
فکر کنید، اگر یک Actor فقط این واحد کد با یک صندوق پستی و یک وضعیت داخلی است و فقط به پیامها پاسخ میدهد، چه کسی اهمیت میدهد که واقعاً در کدام دستگاه کار میکند؟ تا زمانی که بتوانیم پیام را به آنجا برسانیم، حالمان خوب است.
این به ما امکان میدهد تا سیستمهایی ایجاد کنیم که از چندین رایانه استفاده میکنند و در صورت خرابی یکی از آنها به ما کمک میکند تا بازیابی کنیم.
چه موقع نباید از مدل بازیگر استفاده کنیم
مانند هر ابزار دیگری، باید بدانید چه زمانی از آن استفاده کنید. ما قبلاً مواردی را پوشش داده ایم که مدل بازیگر ایده آل نیست. مانند زمانی که شما نیاز به یک ترتیب متوالی از اتفاقات دارید. اگر متوجه شدید که چندین پیام ارسال میکنید و در صورت عدم موفقیت یکی، باید آن فرآیندها را بازگردانید، ممکن است بخواهید در استفاده از مدل بازیگر تجدید نظر کنید. یک مثال رایج در این مورد یک حساب بانکی است. اگر 100 دلار برای شما بفرستم، سیستم بانکی باید آن را از حساب من کم کند و به حساب شما اضافه کند. اگر هر یک از این مراحل اتفاق نیفتد، سیستم بانک باید تراکنش را به عقب برگرداند و یک خطا صادر کند. البته شما می توانید از مدل Actor برای ارسال پیام به چیزی مانند پایگاه داده SQL تراکنشی برای پردازش این نوع دستورالعمل استفاده کنید. برخی از چارچوبهای Actor Model مانند Akka ابزارهای اضافی برای کمک به تراکنشها نیز دارند. لازم به ذکر است که برخی از افراد ممکن است استدلال کنند که وقتی چیزهای خارج از یک بازیگر را پردازش می کنید، دیگر از مدل بازیگر استفاده نمی کنید. هر چند این بحث برای یک روز دیگر است.
مراحل بعدی و سایر منابع
این یک مرور سریع از مدل مفهومی بود که پایه زبانهای بزرگی مانند Erlang و Elixir و کتابخانههایی مانند Akka (برای JVM) و Celluloid (برای Ruby) است.
اگر موفق شدم در مورد نحوه پیاده سازی و استفاده از این مدل در دنیای واقعی شما را کنجکاو کنم، این لیست کتاب هایی است که در مورد این موضوع می توانم توصیه کنم: