תגית: redis

IPC באמצעות Redis ורובי

Redis הוא מסד נתונים אשר אינו מבוסס SQL וכתבתי עליו רבות כאן בעבר.

לאחרונה נדרשתי לפרק מערכת שלי למספר תתי מערכות, ולהעביר מידע בניהם. כמובן שיש הרבה מאוד דרכים לעשות זאת, כדוגמת Message Queue ‏(RabitMQ, ZeroMQ וכו'), עבודה עם PIPES ביוניקס, עבודה בתצורת client server ועוד הרבה מאוד דרכים כיד הדמיון והמערכת הטובה לכם. אני החלטתי ללכת על Redis.

הסיבה לכך פשוטה: אני צריך לבצע פעולה, ואחרי שתפסתי את האירוע, המידע לא צריך להישמר בזיכרון. יותר מזה, אם וכאשר יש הפסקת חשמל, אתחול או אפילו איבוד מידע, אזי אין לי צורך לבצע שוב את הפעולה. כלומר היא נכונה רק לשלב שבו היא נשלחה.

דבר נוסף, הוא שהמערכות שלי כתובות ברובי, ורק מה שצריך לקבל כאירוע לא נכתב, וRedis גם ככה כבר מותקן, ואני כבר מכיר אותו, ויש לי מעט מאוד זמן לכתוב את השינויים.

לRedis יש מספר דרכים לשלוח ולקבל אירועים, אבל אני הולך לדבר כאן על Publish ו PSubscribe. האחרון מאפשר להאזין להודעות באמצעות תבנית חיפוש (עם כוכביות), במקום שם מלא ומדוייק שאחיו Subscribe מספק.

לשם כך צריך לפחות 2 פרוססים שונים, האחד שולח הודעות, והשני מקבל.

שליחת הודעות מאוד פשוטה:

require 'rubygems'
require 'redis'

redis = Redis.new(:host => 'localhost')

10.times do |i|
  redis.publish("number_#{i + 1}", Marshal.dump({:number => i}))
  sleep( (i + 1) / 10.0)
end

התחברתי לRedis, והתחלתי לרוץ על כל המספרים מ0 ועד 9.
יצרתי מפתח שההתחלה שלו הוא number_‎ ולאחר מכן המספר. המבנה חשוב מאוד בשביל להצליח להאזין לאירוע.
לאחר מכן, יצרתי תצורה בינארית עבור Ruby Hash ושלחתי אותה כמידע שאני זקוק לו לשימוש.
כאשר הפעולה מסתיימת, אני נח כמות של מילישניות לפי המספר, החישוב לדעתי די ברור כאן.

הפרוסס השני צריך להקשיב לאירוע:

require 'rubygems'
require 'redis
redis = Redis.new(:host => 'localhost')

redis.psubscribe('number_*') do |on|
  on.pmessage do |pattern, event, message|
    puts "pattern: #{pattern}, event: #{event}, message: #{Marshal.load(message)}"
  end
end

כאן אנחנו מקשיבים לפעולות אשר נשלחות עם סוגי publish השונים.
יש האזנה לאירועים באמצעות תבנית (pattern) ומכאן המקדם בעצם של הפקודה (p).
הפקודה בעצם מכניסה אותנו לתוך בלוק אשר דרכו אפשר להאזין למגוון סוגים של אירועים.
כן האירוע שצריך הוא pmessage לו אני מאזין, וכאשר הוא מתרחש, הקוד בתוכו מורץ.
אני משחזר כאן את המידע הבינארי חזרה למחלקות של רובי, ובכך העברתי מידע סיריאלי לחלוטין של רובי.
חשוב להבין כי זוהי פעולה שהיא blocking, ולכן כאשר מריצים אותה, אין המשך כלפי מטה לקוד.

התוצר כאן יהיה בסגנון הבא:

pattern: number_*, event: number_1, message: {:number=>0}
pattern: number_*, event: number_2, message: {:number=>1}
pattern: number_*, event: number_3, message: {:number=>2}
pattern: number_*, event: number_4, message: {:number=>3}
pattern: number_*, event: number_5, message: {:number=>4}
pattern: number_*, event: number_6, message: {:number=>5}
pattern: number_*, event: number_7, message: {:number=>6}
pattern: number_*, event: number_8, message: {:number=>7}
pattern: number_*, event: number_9, message: {:number=>8}
pattern: number_*, event: number_10, message: {:number=>9}

Redis – From client to execution

העברתי בפרל מונגרס הרצאה על לקוח הרדיס שאני יוצר.

שעה לפני התחלת ההרצאה, קיבלתי בדיוק דוא"ל מבחור מיוון שהודה לי מקרב לב על הלקוח שעוזר לו מאוד. שזה בפני עצמו היה ממש כיף לקבל.

את ההרצאה לא תוכלו לקבל ברשת, אבל את השקפים המטורפים שלי כן:

Redis סיבוב שני

אומרים הרבה פעמים לא לבדוק את שיני הסוס, במידה והוא מוכשר. אני לא מסכים עם האמירה הזו. היות והיא לרוב שגויה. סוס שלא מסוגל לאכול כמו שצריך, לא משנה כמה הוא מוכשר, לא יהיה סוס מרוץ/מלחמה טוב, אם להמשיך את המטפורה הזו (וסליחה אם זה פוגע במישהו, זו לא הכוונה).

עברתי בRedis משלב כתיבת הפרוטוקול, לשלב יצירת הפונקציות השונות. ואם בכתיבת הפרוטוקול היו לי חששות כבדים, אז לצערי הם הרבה יותר ממתממשים. לא רק שהתעוד לפעמים לוקה בחסר. הוא הרבה פעמים לא נכון. כלומר מה שקורה בפועל ומה שכתוב בתעוד אם הוא כבר כתוב, ובכן, לא תמיד הוא נכון. יותר מזה, יש פקודות אשר אפשר לשחק איתן בדף התעוד, אז הן לא תמיד מגיבות זהה לredis עצמו בפועל.

אני מוצא את עצמי משקיע המון אנרגיה בלעשות סוג של reverse engineering למסד הנתונים הזה, מאשר ליצור משהו. יש פקודות שלוקחות כל כך הרבה אנרגיה סתם בגלל תעוד שגוי.

ניסיתי לפנות לפני שבועיים למפתח של Redis,אבל עד עכשיו לא קיבלתי תשובה. יותר מזה, יש בתעוד הרבה תגובות. חלקן אפילו מצביעות על כשלים בתעוד עצמו, וגם הן לא זוכות למענה.

מצד אחד במימוש שלי, יכולתי לעשות לעצמי חיים קלים הרבה יותר, היות וכתבתי מימוש די אגנוסטי, אשר אם תצפו בקוד, תראו שאין לי משהו מיוחד שנעשה בתוך הקריאה לפקודות וחזרה. כלומר זה די copy paste המימוש הזה. אבל חשוב לי להבין לעומק. יותר מזה, חשוב לי לכתוב תעוד מדוייק במימוש שלי. למעשה אם תקראו את הקוד, אתם תראו שיש הרבה יותר תעוד מאשר קוד בהרבה מקומות. מימוש של שורה אחת לקוד, ו10-15 שורות הסבר על הפקודה עצמה.

ככול שאני נכנס יותר ויותר לקרביים של Redis מבחינת המימוש שלו (לא קראתי את הקוד עצמו), ככה אני פחות ופחות סגור על כך שהוא בכלל שווה נגיעה. אני ממשיך לממש את הפרוטוקול והפקודות שלו, אבל זה כבר לא מרגיש טוב כמו בהתחלה.

Redis or not

טוב זה קצת pun על הצליל, אבל הפוסט הזה עוסק בRedis – עוד מסד נתונים בקוד פתוח שאומר לא לSQL. ואת האמת, הוא לא זקוק לשפה הזו בכלל …

למי שלא מכיר, אז Redis הוא מסד נתונים אשר מספק מערכת Key value עם הרבה יכולות. הוא מאפשר לי ליצור הרבה מעבר ל key value, ולמעשה הוא סוג של data struct manager.

פירוש השם הוא קיצור של מספר מילים ולא כתיבה שגויה של צנון: REmote Dictionary Server. רק אם תהיתם במקרה.

במסד הנתונים הזה, הכל הוא מחרוזת, רשימה של מחרוזות, רשימה מסודרת של רשומות מסוג מחרוזת, או קבוצה של מחרוזות. האורך המקסימלי של כל מחרוזת, יכול להיות עד גיגה בית שלם ! אבל ככול שהאורך גדול יותר, כך היעילות של המידע פוחתת, ולוקחת הרבה יותר משאבים, היות ורוב המידע נמצא בזיכרון, ורק נשמר בדיסק לצורך גיבוי.  העניין הוא שמחרוזת זו מילה מופשטת מידי, היות והמסד יודע לטפל בבתים. כלומר מידע בינארי או מידע טקסטואלי הוא זהה לגמרי עבורו. כך שהוא byte safe.

זה על רגל אחת על מסד הנתונים הזה. להמשיך לקרוא