ניהול מחזור החיים של סכימה

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

מאגר הסכימות של השירות המנוהל ל-Apache Kafka תומך במחזור החיים המלא של ניהול הסכימות, וכולל את התכונות הבאות:

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

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

  • ניהול הפניות לסכימה כדי לקדם שימוש חוזר ועקביות בסכימות.

איך מתבצעת התפתחות של סכימה

  1. משנים את הגדרת הסכימה. לדוגמה – מוסיפים שדה אופציונלי לקובץ .proto או .avsc.

  2. התהליך מתבצע כשמפיק שהוגדר עם auto.register.schemas=true שולח הודעה באמצעות הסכימה החדשה, או כשמנסים לרשום את הסכימה החדשה באופן מפורש באמצעות ה-API או ספריות הלקוח.

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

  4. אם גרסת הסכימה תואמת, הסכימה החדשה נרשמת בהצלחה כגרסה הבאה בנושא, מקבלת מספר גרסה חדש, ואולי גם schema_id חדש אם ההגדרה ייחודית.

  5. המפיק (אם יש) מקבל את schema_id כדי לכלול אותו בהודעות.

  6. אם גרסת הסכימה לא תואמת, ניסיון ההרשמה נכשל ומוחזרת שגיאה.

מידע על סוג התאימות

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

  • ברמת המרשם: הגדרת ברירת מחדל לכל מרשם הסכימות.

    • נתיב: projects/project/locations/location/schemaRegistries/schema_registry/config
  • ברמת הנושא בהקשר ברירת המחדל: הגדרה ספציפית לנושא במאגר בהקשר ברירת המחדל.

    • נתיב: projects/project/locations/location/schemaRegistries/schema_registry/config/subject
  • ברמת הנושא בהקשר ספציפי: הגדרת תצורה ספציפית לנושא בהקשר עם שם.

    • נתיב: projects/project/locations/location/schemaRegistries/schema_registry/contexts/context/config/subject

ההגדרות שנקבעות ברמת הנושא מבטלות את ההגדרות שנקבעות ברמת המרשם. אם הגדרה לא מצוינת ברמת הנושא, היא מקבלת בירושה את הערך מרמת הרישום. אם לא מגדירים את הערך במפורש ברמת הרישום, ברירת המחדל היא Backward.

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

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

  • Backward (ברירת מחדל): אפליקציות לצרכנים שמשתמשות בסכימה החדשה יכולות לפענח נתונים שנוצרו רק באמצעות הסכימה שנרשמה קודם. כך אפשר להוסיף שדות אופציונליים ולמחוק שדות. צריך לשדרג את הצרכנים לפני השדרוג של היצרנים.

  • Backward_transitive: אפליקציות לצרכנים שמשתמשות בסכימה החדשה יכולות לפענח נתונים שנוצרו באמצעות כל הגרסאות הקודמות של הסכימה בנושא הזה. ההגדרה הזו מחמירה יותר מההגדרה Backward.

  • Forward: לקוחות שמשתמשים בסכימה הקודמת שרשומה צריכים להיות מסוגלים לקרוא את הנתונים שנוצרו באמצעות הסכימה החדשה. קודם צריך לשדרג את ה-Producers, אבל יכול להיות שה-Consumers שמשתמשים בסכימה החדשה לא יוכלו לקרוא נתונים שנוצרו באמצעות סכימות ישנות יותר. ההגדרה הזו מאפשרת למחוק שדות אופציונליים ולהוסיף שדות.

  • Forward_transitive: נתונים שנוצרו באמצעות הסכימה החדשה צריכים להיות קריאים באמצעות כל הגרסאות הקודמות של הסכימה. ההגדרה הזו מחמירה יותר מההגדרה Forward.

  • Full: הסכימה החדשה תואמת לאחור ולפנים לגרסת הסכימה שנרשמה קודם. אפשר לשדרג את הלקוחות בכל סדר ביחס ליוצר באמצעות הסכימה החדשה. אפשר להוסיף או למחוק שדות אופציונליים.

  • Full_transitive: הסכימה החדשה תואמת לאחור וגם קדימה לכל גרסאות הסכימה הקודמות בנושא הזה. ההגדרה הזו מחמירה יותר מההגדרה Full.

דוגמה לסוג התאימות

נניח שיש לכם מאגר סכימות עם סוג תאימות Backward. בנוסף, אתם יכולים ליצור כמה נושאים במרשם הזה, והם יירשו את התאימות של המרשם.Backward

כדי להשתמש בנושא ספציפי בשם user-events, צריך כללי תאימות מחמירים יותר. אתם מעדכנים את רמת התאימות של הסכימה לנושא user-events בהתאם לFull.

במצב כזה, הכללים הבאים חלים:

  • כל גרסה חדשה של סכימה שנרשמת בנושא user-events צריכה להיות תואמת לאחור ולפנים לגרסה הקודמת של הסכימה שנרשמה לאותו נושא.

  • נושאים אחרים במאגר הסכימות עדיין פועלים בהתאם להגדרת התאימות Backward ברמת המאגר, אלא אם התאימות שלהם הוגדרה באופן מפורש.

אם תשנו בהמשך את רמת התאימות של מאגר הסכימות ל-Forward, השינוי הזה ישפיע על תאימות ברירת המחדל של כל הנושאים החדשים שייווצרו במאגר. עם זאת, user-events הנושא ישמור על התאימות שהוגדרה לו באופן מפורש, כי הגדרות ברמת הנושא מבטלות הגדרות ברמת המרשם.Full

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

מידע נוסף זמין במאמר בנושא עדכון סוג התאימות.

שיטות מומלצות לשימוש במצב תאימות

  • אל תשתמשו ב-None כשיטה לסוג תאימות, כי אתם עלולים לגרום ללקוחות לא לפעול בגלל שינויים בסכימה.

  • אם רוצים לעדכן קודם את המפיקים, כדאי לבחור אסטרטגיה שמבוססת על העברה קדימה, כמו Forward או Forward-transitive. אם רוצים לעדכן קודם את הצרכנים, כדאי לבחור אסטרטגיה שמבוססת על נתונים היסטוריים, כמו Backward או Backward-transitive.

  • מומלץ לבחור אסטרטגיה טרנזיטיבית אם רוצים לשמור על תאימות לכמה גרסאות קודמות של הסכימה. אם רוצים למקסם את התאימות ולצמצם את הסיכון לשבירת לקוחות כשמעדכנים גרסאות סכימה, כדאי להשתמש באסטרטגיה Full-transitive.

מידע על הפניות לסכימה

הפניות לסכימה מאפשרות להגדיר מבנים משותפים פעם אחת ולהפנות אליהם מכמה סכימות. לדוגמה, אפשר להשתמש בסכימה Address כחלק מסכימה Customer וגם כחלק מסכימה Supplier.

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

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

ל-SchemaReference יש את הרכיבים הבאים:

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

  • subject (מחרוזת): השם של הנושא שבו הסכימה שאליה יש הפניה רשומה במאגר הסכימות.

  • version (int32): מספר הגרסה הספציפי של הסכימה שאליה מתייחסים.

סכימה שמשתמשת בסכימות אחרות מכריזה על התלות הזו בשדה references. השדה הזה מכיל רשימה של SchemaReference אובייקטים.

דוגמה להפניות לסכימה

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

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

  1. יוצרים נושא בשם address_schema ורושמים את ההגדרה של כתובת רגילה. כשיוצרים נושא בפעם הראשונה, יוצרים גם את גרסה 1 של הסכימה של הנושא הזה.

    Avro

    יוצרים את הנושא ושומרים אותו כנושא address_schema_avro גרסה 1.

    {
      "type": "record",
      "name": "Address",
      "namespace": "com.example.common",
      "fields": [
        {"name": "street", "type": "string"},
        {"name": "city", "type": "string"},
        {"name": "zipCode", "type": "string"},
        {"name": "country", "type": "string", "default": "USA"}
      ]
    }
    

    Protobuf

    יוצרים את הנושא ושומרים אותו כנושא address_schema_proto גרסה 1.

    syntax = "proto3";
    
    package com.example.common;
    
    message Address {
      string street = 1;
      string city = 2;
      string zip_code = 3;
      string country = 4;
    }
    
  2. יוצרים את סכימת customer_schema. במקום לחזור על שדות הכתובת, מציינים את סכימת address_schema.

    Avro

    הסוג com.example.common.Address של השדה billingAddress מתייחס לסכימה Address שהוגדרה בשלב הקודם.

    {
      "type": "record",
      "name": "Customer",
      "namespace": "com.example.crm",
      "fields": [
        {"name": "customerId", "type": "long"},
        {"name": "customerName", "type": "string"},
        // This field's type refers to the Address schema
        {"name": "billingAddress", "type": "com.example.common.Address"}
      ]
    }
    

    כשרושמים את customer_schema_avro, המטא-נתונים שלו כוללים הפניה לסכימה:

    // Conceptual metadata for customer_schema_avro
    "references": [
      {
        "name": "com.example.common.Address",
        "subject": "address_schema_avro",
        "version": 1
      }
    ]
    

    Protobuf

    קובץ customer.proto מייבא את address.proto ומשתמש ב-com.example.common.Address בשדה billing_address.

    syntax = "proto3";
    package com.example.crm;
    import "address.proto";
    
    message Customer {
      int64 customer_id = 1;
      string customer_name = 2;
      // This field's type refers to the imported Address message
      com.example.common.Address billing_address = 3;
    }
    

    כשרושמים את customer_schema_proto, המטא-נתונים שלו כוללים הפניה לסכימה:

    // Conceptual metadata for customer_schema_proto
    "references": [
      {
        "name": "address.proto",
        "subject": "address_schema_proto",
        "version": 1
      }
    ]
    
  3. באופן דומה, בסכימה Supplier, מוסיפים הפניה לסכימה שמפנה לאותה סכימה נפוצה Address.

מידע על מצב סכימה

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

  • מצב ברמת המאגר: חל על כל מאגר הסכימות.

    • נתיב: projects/project/locations/location/schemaRegistry/schema_registry/mode
  • מצב נושא ברמת המרשם: חל על נושא ספציפי בכל מרשם הסכימות.

    • נתיב: projects/project/locations/location/schemaRegistries/schema_registry/mode/subject

יש תמיכה במצבים הבאים:

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

  • Readwrite: במצב הזה אפשר לבצע פעולות כתיבה מוגבלות במאגר הסכימות או בנושאים שצוינו. היא מאפשרת לבצע שינויים כמו עדכון הגדרות והוספה של גרסאות סכימה חדשות. זהו מצב ברירת המחדל גם עבור מאגרי סכימות חדשים וגם עבור נושאים חדשים.

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

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

דוגמה למצב סכימה

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

נניח שיש לכם נושא בשם production-config שאתם רוצים להגן עליו מפני שינויים לא מכוונים. הגדרת את המצב של הנושא production-config ל-Readonly. כתוצאה מכך, התנאים הבאים חלים על הנושא production-config:

  • אי אפשר להוסיף גרסאות סכימה חדשות לנושא.

  • אי אפשר לעדכן את ההגדרה (למשל, סוג התאימות) של הנושא.

  • נושאים אחרים במרשם שלא הוגדר להם מצב משלהם באופן מפורש יישארו במצב Readwrite, כך שעדיין תוכלו לשנות אותם.

  • אפשר להמשיך ליצור נושאים במרשם כי המרשם עצמו עדיין במצב Readwrite.

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

  • מאגר הסכימות הוא עכשיו Readonly. אי אפשר ליצור נושאים חדשים.

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

  • production-config הנושא נשאר Readonly כמו שהוגדר במפורש.

  • הנושא staging-config נשאר במצב Readwrite כי ההגדרה שלו ברמת הנושא מבטלת את המצב Readonly ברמת הרישום. אפשר להמשיך להוסיף גרסאות סכימה ולעדכן את ההגדרות של staging-config.

הגישה ההיררכית הזו מאפשרת גמישות בניהול שינויים בסכימה ברמות שונות של פירוט.

מידע נוסף על עדכון מצב הסכימה זמין במאמר בנושא עדכון מצב הסכימה.

הגדרה מומלצת לשימוש במאגר סכימות בסביבת ייצור

כדי לאבטח את הסכימות בסביבת ייצור, צריך להחיל את ההגדרות הבאות:

  • כדי למנוע את הרישום של סכימות חדשות, צריך להגדיר את הערך mode=READONLY לכל מאגר הסכימות או לנושאי הייצור הספציפיים.

  • כדי למנוע מלקוחות Kafka ליצור גרסאות סכימה חדשות, צריך לוודא שאין להם הרשאה create version.

  • בסדרות של לקוח Kafka, מגדירים את auto.register.schemas=false. ב-Kafka Connect, מגדירים את ההגדרה הזו עבור סדרות המפתח והערך לפי הצורך:

    • key.serializer.auto.register.schemas=false
    • value.serializer.auto.register.schemas=false
  • (אופציונלי) כדי לחייב את הלקוחות להשתמש בסכימה העדכנית ביותר לנושא, צריך להגדיר את use.latest.version=true בסריאליזציה או בדסריאליזציה. ההגדרה הזו מכוונת את הלקוח להשתמש בגרסת הסכימה העדכנית ביותר שרשומה לנושא, במקום בגרסה שתואמת להודעה הספציפית.

המאמרים הבאים

Apache Kafka®‎ הוא סימן מסחרי רשום של The Apache Software Foundation או של השותפים העצמאיים שלה בארצות הברית או במדינות אחרות.