Tamir Dresher is a software architect, consultant, and instructor who specializes in reactive systems and the Reactive Extensions (Rx) framework. The presentation discusses architectural concepts like responsiveness, resilience, and reactiveness that are important for distributed and reactive systems. It provides examples of using Rx and the actor model with Akka to build systems that can react to various stimuli like user input, failures, or messages in an elastic and resilient manner. The presentation encourages adopting reactive principles and reactive frameworks to build systems that can adequately respond to and recover from changes.
6. Resiliency
6
You know you have a distributed system when the crash of a
computer you’ve never heard of stops you from getting any
work done.
- Leslie Lamport -
11. Reacting to Changes (notifications) with Rx
• Observables
• Observers
• Operators
• www.ReactiveX.io
11
g(x)
f(x)
12. Rx Example
12
1. At least 4 characters
2. Don’t overflow server (0.5 sec delay)
3. Don’t send the same string again
4. Discard results if another search was requested
13. Rx Example
13
Rx.Observable.fromEvent($('#input'),'keyup')
.map(e => e.target.value)
.filter(text => text.length > 3)
.throttle(500 /* ms */)
.distinctUntilChanged()
.flatMapLatest(searchWikipedia)
.subscribe(
data => {
/* handle the results */},
error => {
/* handle any errors */});
Observable.FromEventPattern(txtBox,“TextChanged”)
.Select(_ => txtBox.Text);
.Where(txt => txt.Length > 3);
.Throttle(TimeSpan.FromSeconds(0.5))
.DistinctUntilChanged()
.Select(text => SearchAsync(text))
.Switch()
.Subscribe(
results => {
/* handle the results */ },
ex => {
/* handle any errors */ } );
RxJS Rx.NET
14. Back Pressure
14
3 per sec 1 per sec
http://www.reactive-streams.org/
Publisher Subscriber
demand
• “Push” behavior when consumer is
faster
• “Pull” behavior when producer is
faster
15. The Actor Model (Hewitt et al. 1973)
15
Alice
Mailbox
Bob
Sally
Mailbox
Mailbox
“the Actor model retained
more of what I thought
were the good features of
the object idea.”
Alan Kay
Object Orientation pioneer
and Smalltalk co-designer
Alice
Parent
Bob
Parent
Sally
Parent
16. Akka Example
16
class SimpleActor extends Actor {
override def receive: Receive = {
case x =>
println("Received message: " + x)
}
}
object Main extends App {
val system = ActorSystem(“actor-system")
val anActor: ActorRef =
system.actorOf(Props[SimpleActor])
anActor ! "Hello world"
} akka {
actor.deployment {
/simpleActor {
remote = "akka://actor-system@127.0.0.1:3232"
}
}
}
17. Akka Parental Supervision
17
override val supervisorStrategy =
OneForOneStrategy(maxNrOfRetries = 10, withinTimeRange = 1 minute) {
case _: ArithmeticException => Resume
case _: NullPointerException => Restart
case _: IllegalArgumentException => Stop
case _: Exception => Escalate
}
1. OneForOneStrategy – affect only the failing child
2. AllForOneStrategy – affects the failing child & it’s siblings
Child
Parent
Child
שמי תמיר דרשר, אני יועץ בחברת קוד ווליו שמלבד היותה חברת יעוץ במגוון נושאים וטכנולוגיות, היא גם מרכז הפיתוח של כלי הDebugging OzCode ו
כמו כן אני מרצה במרכז האקדמי רופין
אחד הbuzzwords שאנחנו שומעים יותר ויותר בשנים האחרונות הוא נושא ה Reactiveness של מערכות ושל אפליקציות ובשפות תכנות באופן כללי.
גם אותי זה נורא הלהיב, ובפרט הטכנולוגיה שנקראת
זה הלהיב אותי כל כך שכתבתי ספר בנושא Reactive Extensions in Action בהוצאת manning
קצת Self Promotion לא הזיק
אבל בוא נקח רגע צעד אחורה ונסתכל על האבולוציה של הארכיטקטורות שלנו
כמו כן אני מרצה במרכז האקדמי רופין
אחד הbuzzwords שאנחנו שומעים יותר ויותר בשנים האחרונות הוא נושא ה Reactiveness של מערכות ושל אפליקציות ובשפות תכנות באופן כללי.
גם אותי זה נורא הלהיב, ובפרט הטכנולוגיה שנקראת
זה הלהיב אותי כל כך שכתבתי ספר בנושא Reactive Extensions in Action בהוצאת manning
קצת Self Promotion לא הזיק
ארכיטקטורת תוכנה היא נורא דומה לפסטה
ואפשר לראות את ההתפתחות שלנו כתעשיה בוסג הפסטה שאנחנו משתמשים
בהתחלה כולנו כתבנו ספגטי קוד עם GOTO
ואז למדנו שאי אפשר אפילו להבין ולתחזק את מה שאנחנו כתבנו אז עברנו למודל הלזניה והתחלנו לכתוב הכל בשכבות
ואז ראינו שלהכין את הלזניה כחתיכה אחת זה לא מספיק טוב, בטח כשיש לנו המון סועדים ועדיף לנו לחלק אותה לחתיכות קטנות יותר
מה שיצר את מודל הרביולי – אותם microservices שהם הBUZZWORD שכולם נהנים להגיד
איך שלא יהיה, בסופו של דבר יש לנו משתמש שנמצא בקצה אחד שרוצה לקבל שירות, בין אם המשתמש אנושי או מערכת אחרת.
והמטרה הסופית שלנו כשעשינו את המערכת זה שהיא תדע להגיב
כמו כן אני מרצה במרכז האקדמי רופין
אחד הbuzzwords שאנחנו שומעים יותר ויותר בשנים האחרונות הוא נושא ה Reactiveness של מערכות ושל אפליקציות ובשפות תכנות באופן כללי.
גם אותי זה נורא הלהיב, ובפרט הטכנולוגיה שנקראת
זה הלהיב אותי כל כך שכתבתי ספר בנושא Reactive Extensions in Action בהוצאת manning
קצת Self Promotion לא הזיק
אבל בוא נקח רגע צעד אחורה ונסתכל על האבולוציה של הארכיטקטורות שלנו
המערכת שאתנחנו כותבים היום, יותר מתמיד, צריכות להגיב למסה הולכת וגדלה של אירועים ושל שינויים
מרכיבי מסך שמעלים אירועים
ועד לחיישנים שמזרימים לנו עדכונים
המערכת שלנו צריכה להגיב לכל זה, ולעשות את זה בזמן סביר
אחרת המשתמשים שלנו מתעצבנים ועוזבים
ההגדרה למה זה מערכות שהם reaectiv מפורט במסמך שנקרא reactive manifesto שפורסם בשנת 2014
ובעצם מסכם סדרה של עקרונות ומאייפינים למערכת שהיא ריאקטיבית
הדבר הראשון שאנחנו מגדירים במערכת שהיא ריאקטיבית הוא:
responsive
הדבר הראשון והחשוב ביותר הוא הצורך שלנו להגיב למשתמשים (בין אם הם אנושיים או שהם מערכות אחרות)
המערכת צריכה להגיב בזמן הגיוני לפניות שמתקבלות. אנחנו לא רוצים שהמערכת תעבור סף זמן מסוים לפני שהיא תחזיר תשובה
ואני מדבר פה על כל סוג של תשובה. גם להגיד תודה קיבלתי את הפניה זאת תשובה נהדרת
זה מה שנקרא להיות רספונסיבי וזה היעד שאנחנו מנסים להגיע אליו.
resilient
כמובן שעובדת החיים היא שתקלות ושגיאות קורות. זה לא שאנחנו רוצים את זה או מכוונים שזה מה שיקרה אבל אין מה לעשות זה יקרה.
ולכן המערכת שלנו צריכה לדעת להגיב לכשלונות (react to failures)
להגיב במובן הזה אומר לדעת להתמודד ולהתאושש. כיוון שאחרת לא יהיה לנו responsiveness
לדעת להיות resilient לא אומר שאנחנו מנסים לבנות מערכת מושלמת, כזו שאף פעם לא נכשלת. זה רק אומר שאנחנו צריכים לתכנן את המערכת כך שהיא תדע להתמודד עם כשלונות של החלקים שלה. זה אומר למשל לבנות את המערכת בצורה מחולקת כך שכשלון של חלק אחד לא ישפיע על חלק אחר. או לבנות את המערכת כך שחלקים מסוימים ישוכפלו ככה שאם אחד מהם קורס יש אחר שיקח את מקומו.
גישה הreactive מקובלת היא לנקוט במבנה של supervision כך שחלק אחד ינטר חלק אחר ויגיב כשהוא נכשל
Message driven
אם כל המאפיינים שדיברנו עליהם עד עכשיו הם היעדים שאנחנו רוצים מהמערכת
אז גישה מונחית הודעות היא ישום של איך אפשר להשיג אותם.
כשנעבוד בגישה כזו אנחנו אוטומטית הופכים את התקשורת של לאסינכרונית ולכן באופן מיידי עושים decoupling בין החלקים של המערכת גם במובן של ה-interfaces שהם חושפים וגם מבחינת הזמן
הרבה יותר קל לנו לעשות שינויים במבנה המערכת כך שיחידה מסוימת תטפל בהודעה מסוימת או תעשה לה ראוטינג. והרבה יותר קל לשנות את הpriority והסדר של הטיפול בהודעות. כל רכיב במערכת בוחר איך להגיב להודעות בצורה שונה.
הודעה מסוימת יכולה להיות הטריגר שלנו לעשות שינוי על כמות הnodes שאנחנו מרימים כדי לטפל בבקשות הבאות. כך שמערכת מגיבה בצורה דינמית ויחד עם האלסטיות אנחנו זוכים למערכת נושמת שמותאמת לצרכים האמיתיים בשטח.
ה-decoupling שאנחנו מקבלים בעבודה מבוססת הודעות כך שאין תלות בclient מסוים על מי יטפל בבקשה מאפשר לנו לשלוט בlatency
כל החלקים יחד
בסופו של דבר כל המרכיבים מתחברים ביחד. כדי להשיג רספונסיביות אנחנו צריכים שהמערכת תהיה resilience.
כדי שנשיג reslieincy אננו רוצים מימד של בקרה על התקשורות ועל הנפילות של החלקים השונים בלי לאבד את הבקשות בדרך. וזה מתקבל על ידי התקשורת שמבוססת על הודעות. כמו כן, ההודעות שמתקבלות מחזקות את היכולת של המערכת להיות רספונסיבית כי קבלת ההודעה לא אומר טיפול בה ולכן תגובה מיידית על קבלת ההודעה עושה את המערכת רספונסיבית.
על בסיס ההודעות הללו אנחנו יכולים להשיג אלסטיות שמשנה את מבנה המערכת בסיס כמות ההודעות שיש והמשמעות הספציפית לכל אחת. וכמובן ברגע שהערכת אלסטית אנחנו משיגים resiliency
elastic
ככל שהזמן חולף ככה המערכת שלנו תיחשף לעומסים שונים
אני מקווה בשביל כולכם שהעומס על המערכת שלכם רק יגדל, אבל עומס יכול לגדול בתקופה מסוימת ולרדת בתקופה אחרת
כדי להיות responsive ו-resilient המערכת חייבת להיות גמישה. כשהעומס עולה נוסיף Nodes או שנעלה את ה-scale של Nodes אחרים.
בסופו של דבר כל המרכיבים מתחברים ביחד. כדי להשיג רספונסיביות אנחנו צריכים שהמערכת תהיה resilience.
כדי שנשיג reslieincy אננו רוצים מימד של בקרה על התקשורות ועל הנפילות של החלקים השונים בלי לאבד את הבקשות בדרך. וזה מתקבל על ידי התקשורת שמבוססת על הודעות. כמו כן, ההודעות שמתקבלות מחזקות את היכולת של המערכת להיות רספונסיבית כי קבלת ההודעה לא אומר טיפול בה ולכן תגובה מיידית על קבלת ההודעה עושה את המערכת רספונסיבית.
על בסיס ההודעות הללו אנחנו יכולים להשיג אלסטיות שמשנה את מבנה המערכת בסיס כמות ההודעות שיש והמשמעות הספציפית לכל אחת. וכמובן ברגע שהערכת אלסטית אנחנו משיגים resiliency
הרכיבים במערכת שלנו צריכים לדעת עכשיו להגיב להודעות שמתקבלות
אצל חלק מהרכיבים, למשל הclients שלנו, צריכים להגיב לשינויים שקורים והם לא בהכרח הודעות, למשל תגובה לסנסורים או להקלדות של משתמש – או בקצרה שינוים.
זה דורש מאתנו מודל של תגובה לשינויים ואבטסטרקציה על מקור השינויים. בין המקור הוא queue שאנחנו קוראים ממנו הודעות או תיבת טקסט על המסך.
אנחנו צריכים מודל שגם יודע להסתכל על אוסף המקורות הללו ועל איך מטפלים במקרים שהם תלויים אחד בשני, או קורים ביחד.
בטרמינולוגיה של Rx מקור של הודעות או שינויים נקראה observable
והצרכן של השינויים נקרא observer
בין שניהם יכולים לבוא אוסף של אופרטורים שמאפשרים להגדיר טרנספורמציות, קומבינציות, פילטורים, אגרגציות ושליטה באורך החיים של הקשר. כך שאפשר לקבל complex event processing
היופי בRx שהטרימינלוגיה והסגנון הוא פורטבילי ולא משהו שספציפי רק לשפה אחת – יש לנו Rx לJAVA ל-C++ C# Swift וזה נראה כמעט אותו דבר
כך נראת דוגמא בJS וב-C#
בשתי הדוגמאות אנחנו הופכים תיבת טקסט לobservable עבור כל שינוי טקסט
לוקחים את הערך של הטקסט
אם הוא ארוך משלושה תוים
ואם עבר זמן של חצי שניה מההקלדה האחרונה
ואם ערך הטקסט שונה מהטקסט שכבר קיבלנו עבורו תוצאות בפעם האחרונה
אנחנו מבצעים חיפוש על פי הטקסט בצורה אסינכרונית
ודואגים שאם הטקסט שונה בזמן שממתינים לתוצאות של החיפודש הקודם אחנו נזרוק את התוצאות שיגיעו ונחכה לתוצאות של הטקסט החדש
בסופו של דבר הobserver שלנו מקבל תוצאות אם שגיאות ויכול להציג אותן על המסך או לעבד אותן
המודל של הObservable והobserver עובד מאוד טוב אבל אחת הבעיות היא שאם הקצב של הObservable גבוה מהקצב של הobserver אנחנו מגיעים למצב של backpresuure , נוצר לנו עומס שדוחף אחורה,
כדי לנסות לתת מענה נוצר הspec של reactive streams שבעצם מוסיף לפרוטוקול בין הobservable ל-observer אפשרות לobserver להודיע לobservable שהוא עמוס ולסמן לו מתי הוא פנוי לקבל עוד נוטיפיקציות
Rx לכשעצמו עדיין לא עובד לפי הreactive streams.
מודל נוסף שמקיים את הדרישות של ארכיטקטורה שהיא reactive הוא הActor model
הוצג ע"י Carl Hewitt ב1973
Resume the subordinate, keeping its accumulated internal state
Restart the subordinate, clearing out its accumulated internal state
Stop the subordinate permanently
Escalate the failure, thereby failing itself