שיקולים ולבטים בתכנון בסיס הנתונים של FireStats

כשהתחלתי לפתח את פיירסטטס הייתי חסר נסיון מעשי בפיתוח של בסיסי נתונים, הייתי אומנם אחרי קורס של מבוא לבסיסי נתונים בפתוחה, שנתן לי את הרקע התאורטי, אבל לא היה לי את הרקע המעשי.
לאור זה, אני חושב שזה יפה שהצלחתי לתכנן בסיס נתונים בצורה מספיק חכמה כדי שהוא יוכל להתפתח ולהשתנות (כמעט מדי גרסא גדולה 1.x -> 1.y).
למרות זאת, לפעמים אני מפקפק בהחלטות תכנון שעשיתי אז וחושב שאולי הייתי עושה אחרת עכשיו.
למזלי, האפשרות לשנות את בסיס הנתונים מגרסא לגרסא קיימת ועובדת בפועל.

פיירסטאטס התבססה בהתחלה על Counteirze, שהיה בעל מבנה פשוט מאוד בבסיס הנתונים: טבלא אחת.
יש כמה בעיות עם התכנון הזה:
*הוא בזבזני מאוד במקום כי כל כתובת מפנה את מחרוזת דפדפן (UserAgent) תופיעה שוב ושוב ושוב.
* קשה להרחיב אותו לתמוך בנתונים נוספים בלי להחריף את בעיית המקום.
אחת ההחלטות הראשונות שעשיתי היתה לעבור למבנה מנורמל, שבו על כתובת מפנה ומחרוזת דפדפן נשמרות פעם אחת בטבלאות נפרדות, וטבלאת הכניסות מכילה מזהה יחודי של כל אחד מהשדות האלו בעמודה הרלוונטית.

טבלאת הכתובות נראית היום כ:
urls table
טבלאת ההמפנים נראית היום כך:
referrers table

אפשר לראות שיש דמיון:
url וreferer הם בעצם שדה הכתובת.
md5 הוא שדה של גיבוב md5 של הכתובת
אבל גם הבדלים:
בטבלאת המפנים יש עוד כמה שדות שקשורים לתמיכה במילות חיפוש (שנכנסה בגרסא האחרונה).

במסגרת רצון להוסיף תמיכה בווידג'ט של פוסטים פופולריים הוספתי טבלאת METADATA לטבלאת הURLים.
הmetadata יכול להכיל פרטים כמו כותרת של הפוסט, אם יש, וסוג הכתובת (post, לינק להורדה בהמשך ועוד).

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

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

Facebook Comments

ספאם ממשלתי

אפי איתם שיחיה שלח לי שנה טובה.
איש טוב, אפי.

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

כל הקשיים ויש קשיים, הם הצל החולף אל מול האמת הענקית והמאירה הזו.

כל אחד מאיתנו בחייו כאן, ובמפעלו, הוא תוספת אור ייחודית ויהודית לאור הכלל.

יהי רצון שנזכה כולנו לשנה של משמעות, התגברות ואומץ לב ומתוך ברכת העוז הזו יברך אותנו ה' גם בשלום.

שנה טובה ומתוקה,

אפי ועילית איתם

נחמד מצידו, רק שמעולם לא מסרתי את כתובת הדואר שלי לח"כ איתם.
ואיך אני יודע שזה הוא?
לפי הכותרת (header) של ההודעה, היא יצאה משרתי הממשלה:

Received: from outmail.tehila.gov.il (outmail.tehila.gov.il [147.237.70.200])
by yadan.net (Postfix) with ESMTP id C5080298FD9
for ; Tue, 11 Sep 2007 11:12:04 +0300 (IDT)
Received: from mail-int.tehila.gov.il (mail-int.tehila.gov.il [147.237.70.4])
by outmail.tehila.gov.il (Postfix) with ESMTP id D13E960A36;
Tue, 11 Sep 2007 11:04:50 +0300 (IDT)
Received: from av-int.tehila.gov.il (av-int.tehila.gov.il [147.237.70.35])
by mail-int.tehila.gov.il (8.12.11.20060308/8.12.11) with ESMTP id l8B84l6o026796;
Tue, 11 Sep 2007 11:04:47 +0300
Received: from av-int.tehila.gov.il (localhost.localdomain [127.0.0.1])
by localhost.tehila.gov.il (Postfix) with ESMTP id D5AD66EE8E;
Tue, 11 Sep 2007 11:04:46 +0300 (IDT)
Received: from zavitan.knesset.gov.il (unknown [10.2.5.19])
by av-int.tehila.gov.il (Postfix) with ESMTP id 99D926EE8A;
Tue, 11 Sep 2007 11:04:45 +0300 (IDT)
Received: by ZAVITAN with Internet Mail Service (5.5.2653.19)
id ; Tue, 11 Sep 2007 11:09:47 +0200

הייתכן שאפי איתם תומך במשלוח ספאם?

Facebook Comments

הניגרים באים, ועדר בוטים מאחוריהם

זו לא הפעם הראשונה שהאינטרנט הופך לשדה קרב בין כוחות השחור לכוחות האור.
בתקופה האחרונה נראה שהתקפות בפרופיל גבוה הופכות להיות יותר ויותר נפוצות, מי זוכר היום את בלו-סקוריטי ז"ל שניסתה לפתח צפרדע כחולה ומבוזרת שתלחם בספאמרים?
לא תמיד המתקפות קוצרות כזו הצלחה, EveryDNS למשל עדיין מתפקדים היטב למרות ההתקפה האחרונה (למעשה אני משתמש בשרותים של EveryDNS, ואפילו תרמתי 15$).

הפעם הקורבנות הם מספר אתרים שנלחמים בסקאמרים, שהם האחים הגדולים של הספאמרים.
מכירים את האתרים שמתחזים לאתרים אחרים בנסיון לקצור סיסמאות של בנקים, Paypal Ebay וכו'?
אלו אתרים שמופעלים על ידי סקאמרים – Scammers או Scumbags כמו שהם מכונים בחוגים מסויימים.
סקאמרים אחרים לא מפחדים ללכלך את הידיים כדי לנסות להוציא כסף מהקורבנות, וממש לדבר איתם ולהשקיע בהם זמן ומאמץ – אלו כמובן הסקאמרים שמפעלים את העוקץ הניגרי, הידוע גם בשם תרמית ה419 (על שם מספר הקטע בחוק הניגרי שמתייחס לעברה).
הפעם האתרים שהותקפו הם אתרים שנלחמים ישירות בעוקצים הניגרים, כמו 419eaters, scamwarners וaa419.
האתרים לא זמינים כרגע עקב ההתקפה.

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

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

אז מה עושים?
זו מלחמה, וכמו בכל מלחמה צריך לפעול בכמה חזיתות.
1. צריך גיבוי טכנולוגי וכלכלי לאתרים שנלחמים בטינופות, אולי על ידי מדינות ואולי על ידי חברות גדולות שרוצות לעשות משהו טוב כדי להצטייר טוב.
2. צריך להלחם ברשתות הבוטים, זו בעיה אמיתית וקשה שצריכה התייחסות של רשויות החוק בעולם. למרות השיפור הטכנולוגי המרשים בבוטים (היום הבוטים מתקשרים בערוצים מוצפנים, והם מתוכננים עם יתירות (Redeundancy) בערוצי השליטה שלהם – עדיין אפשר לגלות הרבה מאוד פשוט על ידי הדבקה של מחשב בבוט כזה וסקירה של פעילות הרשת שלו.
אני חושב שהגיע הזמן שהאיום הזה יתחיל לקבל התייחסות רצינית, הרי באותה קלות שמפעילי רשתות הבוטים יכולים להפיל אתר אחד, הם יכולים להפיל אתר אחר. מישהו רוצה להמר כמה עמיד יהיו האתרים של הבית הלבן, הפנטגון או האתר של ממשלת ישראל בפני התקפה כזו?
3. צריך לבזר את המנגנונים שנלחמים בסקאמרים ובספאמרים: מה שעובד בשביל הרעים יכול לעבוד גם בשביל הטובים. זה אומנם הרבה יותר קשה הנדסית, אבל בהחלט אפשרי בהרבה מקרים.

דרך סלאשדוט.

Facebook Comments

911

Someone please call 911…
911

ככה:

Facebook Comments

Silverlight

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

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

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

Facebook Comments

שרשור פעולות בלינוקס

הפילוסופיה של יוניקס (ושל לינוקס) היא שכל כלי יעשה פעולה אחת, ויעשה אותה כמו שצריך – והמשתמש יחבר את הכלים כדי להשיג את המטרה שלו.
הפילוסופיה הזו שונה מזו של מערכות הפעלה יותר "ידידותיות", שנותנות למשתמש כלים שעושים את מה שהמתכנתים חשבו שהמשתמש ירצה לעשות – לא פחות ולא יותר.
מצד אחד אותם משתמשים ישיגו את המטרה שלהם – אם המתכנתים חשבו שהיא מטרה ראויה – יותר בקלות, מצד שני, אם המתכנתים לא חשבו שהמטרה הזו מספיק חשובה או אם הם בכלל לא חשבו על הצורך המסויים המשתמש פשוט לא יוכל להשיג את המטרה בעזרת אותם כלים ידידותיים.
אז אחרי ההקדמה הזו, הנה דוגמא עם בעיה אמיתית:
לFireStats יש כרגע 16 תרגומים, והמתרגמים אחראים לעדכן עצמאית את התרגום שלהם ברגע שאני מודיע על הזמינות של גרסא חדשה במערכת הגרסאות של הקוד (Subversion).
לפעמים המתרגמים לוקחים את הזמן, ומעדכנים רק אחרי כמה שבועות, ובדרך כלל מודיעים לי שהם עדכנו, אבל לא תמיד.
עכשיו, איך אני יכול לדעת מי עדיין לא עדכן את התרגום?
אני יכול לתחזק רשימה, ולמחוק מהרשימה כל אחד שהודיע לי שהוא תרגם, אבל אני עצלן מדי ובטח אשכח לתחזק אותה, מה שיהפוך אותה ללא שימושית מהר מאוד.
דרך נוספת היא להסתכל בקבצי התרגום, ולחפש תרגומים שלא מכילים מילה כלשהי שמופיעה רק בגרסא החדשה, אבל איך עושים את זה?
כלים לחיפוש בקבצים בדרך כלל ימצאו קבצים שמכילים משהו, לא קבצים שלא מכילים.
יש הרבה דרכים להשיג את המטרה הזו, רובן מערבות מציאה של כלי יעודי לא ידוע או כתיבת תוכנית – אבל לאור ההקדמה – ברור שאני אספר איך ניתן לעשות את זה בלינוקס (אפשר בעוד צורות, ואני בטוח שחלקן יותר אלגנטיות).
כמעט כל תוכנית לא גרפית בלינוקס קוראת מהקלט הסטנדרטי וכותבת לפלט הסטנדרטי. בשימוש של פקודות שרשור (|) של המעטפת (bash במקרה שלי) ניתן לשרשר את הפלט של תוכנית אחת לקלט של תוכנית שניה.
אבל לפני שאנחנו רצים, צריך לגלות איך מוצאים אם קובץ מסויים לא מכיל מחרוזת.
הפקודה שקופצת לראש אוטומטית כשרוצים למצוא משהו היא grep. שמאפשרת מציאה של תבניות שבנויות כביטויים רגולריים, אבל grep לא בדיוק מתאימה כי היא עובדת ברמת שורה, ואנחנו רוצים לעבוד ברמת קובץ.
במילים אחרות, נוכל למצוא בעזרת grep שורות מסויימות שלא מכילות את המילה, אבל זה לא מה שאנחנו רוצים.
למרבה המזל, grep מחזירה ערך לbash, שניתן לפרש כאמת אם ורק אם הקובץ מכיל את המחרוזת.
אז כדי לבדוק אם קובץ מכיל מחרוזת נריץ את זה:
[code lang="bash"]
grep -q WORD file.txt || echo Not found
[/code]
הפרמטר -q נועד לבטל הדפסות של שורות שמתאימות למחרוזת (כי זה לא מה שאנחנו רוצים).
הפקודה || היא פקודה למעטפת שאומרת שאומרת "או".
זה אומר שהערך של הביטוי כולו הוא אמת אם לפחות אחד משני הביטויים משני צידי ה|| הם אמת. במקרה שgrep מוצא את המילה הוא יחזיר אמת, ולכן המעטפת לא תפעיל את הצד השני של ה|| כי היא כבר יודעת שהביטוי כולו הוא אמת. במקרה והקובץ לא מכיל את המחרוזת grep יחזיר שקר ואז המעטפת תריץ את הפקודה השניה שתדפיס לנו שלא מצאנו את הביטוי בקובץ.

עכשיו רק נשאר להריץ את הדבר הזה לכל קובץ, ולהדפיס עבור כל קובץ שלא מכיל את המחרוזת את השם שלו.
שוב, יש כמה דרכים, כולל שימוש בלולאה, אבל אני מעדיף את השימוש בxargs.
במצב הרגיל xargs מקבלת קלט ומפעילה פקודה כאשר הקלט הוא פרמטר של הפקודה. כאשר קוראים לxargs עם הפרמטר -i, הפקודה תקרא מספר פעמים, כמספר השורות בקלט, כאשר בכל פעם הסימן {} יוחלף בשורה הנוכחית.
לדוגמה, אם נפעיל את הפקודה ls -1, שמדפיסה כל קובץ בשורה נפרדת, על ספריה שמכילה קובץ a וקובץ b, ונשרשר לxargs -i נקבל:
[code lang="bash"]
$ ls -1 | xargs -i echo 123 {} 456
123 a 456
123 b 456
[/code]

xargs קוראת לecho פעם אחת עבור כל קובץ.
אם נרצה לעשות משהו טיפה יותר מחוכם, שכולל קריאות לכמה פקודות עבור כל קובץ, נוכל להפעיל bash עם פרמטר -c (פקודה), למשל:
[code lang="bash"]
$ ls -1 | xargs -i bash -c "echo content of {} is;cat {}"
content of a is
hello
content of b is
world
[/code]

אחרי כל זה אנחנו כבר יודעים מספיק בשביל להבין איך להשיג את המטרה, שהיא למצוא את כל הקבצים שלא מכילים משהו:
[code lang="bash"]
ls -1 | xargs -i bash -c "grep -q WORD {} || echo {}"
[/code]

Facebook Comments