מעבר מ-Java 8 לזמן הריצה העדכני ביותר של Java

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

‫Java 8 יצא משימוש. לא תוכלו לפרוס אפליקציות Java 8, גם אם הארגון שלכם השתמש בעבר במדיניות ארגונית כדי להפעיל מחדש פריסות של סביבות ריצה מדור קודם. האפליקציות הקיימות שלכם ב-Java 8 ימשיכו לפעול ולקבל תנועה. מומלץ לעבור לגרסה העדכנית ביותר של Java שנתמכת.

מעבר לזמני הריצה של Java מהדור השני מאפשר לכם להשתמש בתכונות שפה עדכניות ולבנות אפליקציות ניידות יותר עם קוד אידיומטי.

הסבר על אפשרויות ההעברה

כדי לצמצם את המאמץ והמורכבות של המעבר בזמן הריצה, סביבת App Engine standard מאפשרת לכם לגשת להרבה שירותים וממשקי API מדור קודם, כמו Memcache, בזמן הריצה של Java מהדור השני. אפליקציית Java יכולה לקרוא לממשקי ה-API של השירותים הכלולים דרך ה-JAR של App Engine API, ולקבל גישה לרוב היכולות כמו בסביבת זמן הריצה של Java 8.

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

מידע נוסף על מעבר לשירותים לא משולבים זמין במאמר מעבר משירותים משולבים.

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

מעבר לסביבות זמן ריצה של Java מדור שני עם שירותים בחבילה מעבר לזמני ריצה של Java מדור שני בלי שירותים בחבילה
גישה לשירותים בחבילה באמצעות קובץ ה-JAR של App Engine APIs. אפשר גם להשתמש ב מוצרים מומלצים Google Cloud או בשירותים של צד שלישי.

משתמשים ב- appengine-web.xml וב- web.xml כדי להגדיר את האפליקציה.

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

משתמשים ב- app.yaml כדי להגדיר את האפליקציה.

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

הפריסה של האפליקציות מתבצעת באמצעות Jetty. משתמשים בפורמט WAR כדי לארוז את האפליקציה. הפריסה של האפליקציות מתבצעת באמצעות השרת שלכם. משתמשים בפורמט JAR כדי לארוז את האפליקציה. כדי לקבל מידע נוסף על המרת קובץ WAR קיים ל-JAR שניתן להפעלה, אפשר לעיין במאמר בנושא אריזה מחדש של קובץ WAR.

סקירה כללית של תהליך המיגרציה

בהמשך מפורטים כמה שינויים שאולי תצטרכו לבצע באפליקציית Java 8 הקיימת שלכם ב-App Engine ובתהליך הפריסה כדי להשתמש בסביבות זמן הריצה של Java מהדור השני:

ההבדלים העיקריים בין Java 8 לבין סביבות זמן הריצה של Java מהדור השני

בטבלה הבאה מפורטים ההבדלים בין Java 8 לבין סביבות זמן הריצה של Java מהדור השני בסביבת App Engine סטנדרטית:

זמן ריצה של Java 8 סביבות זמן ריצה של Java מהדור השני
פריסת השרת השרת נפרס בשבילכם באמצעות Jetty אם האפליקציה שלכם לא משתמשת בשירותים הישנים בחבילה, תצטרכו לפרוס שרת בעצמכם.1
שירותים מדור קודם בחבילה של App Engine מסופק מסופק
אפשרות להשתמש בספריות לקוח של Cloud ל-Java כן כן
תמיכה בתוסף שפה ובספריית המערכת כן כן
גישה לרשת חיצונית כן כן
גישה למערכת הקבצים גישת קריאה/כתיבה אל /tmp גישת קריאה/כתיבה אל /tmp
שפת זמן הריצה הותאם ל-App Engine זמן ריצה של קוד פתוח ללא שינויים
מנגנון בידוד ארגז חול לקונטיינרים מבוסס gVisor ארגז חול לקונטיינרים מבוסס gVisor
בדיקה באמצעות שרת פיתוח מקומי נתמך נתמך
הגדרת thread safety אפשר לציין את הגרסה בקובץ appengine-web.xml. אי אפשר לציין את ההגדרה הזו בקובצי התצורה. כל האפליקציות נחשבות בטוחות לשימוש עם שרשורים.3
רישום ביומן משתמשים ב-java.util.logging.
ConsoleHandler, שכותב ל-
stderr ומרוקן את הזרם
אחרי כל רשומה.
‫Cloud Logging רגיל 2
תמיכה בפלאגין DataNucleus בגרסה 2.x נתמך לא אפשרי 4

הערות:

  1. אם האפליקציה לא משתמשת בשירותים הקודמים שצורפו, סביבות זמן הריצה של Java מהדור השני יכולות להריץ כל מסגרת Java, כל עוד אורזים שרת אינטרנט שמוגדר להגיב לבקשות HTTP ביציאה שצוינה במשתנה הסביבה PORT (מומלץ) או ביציאה 8080. לדוגמה, בסביבות זמן הריצה של Java מהדור השני אפשר להריץ קובץ Spring Boot Uber JAR כמו שהוא. דוגמאות נוספות מופיעות בקטע גמישות של מסגרות.

    אם האפליקציה שלכם משתמשת בשירותים הקודמים בחבילה, App Engine פורס אותה באמצעות Jetty באותו אופן כמו בסביבת זמן הריצה של Java 8.

  2. הרישום ביומן בזמני הריצה של Java מדור שני מתבצע לפי תקן הרישום ביומן ב-Cloud Logging. בזמן הריצה של Java מהדור השני, יומני האפליקציות כבר לא מצורפים ליומני הבקשות, אלא מופרדים ברשומות שונות. מידע נוסף על קריאה וכתיבה של יומנים בסביבות זמן הריצה של Java מהדור השני זמין במדריך לרישום ביומן.

  3. כדי להגדיר אפליקציה לא בטוחה לשימוש עם שרשור (non-threadsafe) בסביבת זמן הריצה של Java מהדור השני, בדומה להגדרה של <threadsafe>false</threadsafe> ב-Java 8, צריך להגדיר את הערך של max concurrency ל-1 בקובץ app.yaml או בקובץ appengine-web.xml אם משתמשים בשירותים מדור קודם שצורפו.

  4. ‫Google לא תומכת בספריית DataNucleus בסביבות זמן הריצה מהדור השני. גרסאות חדשות יותר של DataNucleus לא תואמות לאחור לגרסאות שבהן נעשה שימוש ב-Java 8. כדי לגשת ל-Datastore, מומלץ להשתמש בספריית לקוח במצב Datastore או בפתרון Java Objectify (גרסה 6 ואילך). ‫Objectify הוא API קוד פתוח ל-Datastore שמספק רמת הפשטה גבוהה יותר.

הבדלים בשימוש בזיכרון

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

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

הבדלים בשימוש במעבד

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

הבדלים בכותרות הבקשות

סביבות זמן ריצה מהדור הראשון מאפשרות להעביר לאפליקציה כותרות של בקשות עם קווים תחתונים (לדוגמה, X-Test-Foo_bar). בזמן ריצה מדור שני,‏ Nginx מוצג בארכיטקטורת המארח. כתוצאה מהשינוי הזה, סביבות זמן ריצה מהדור השני מוגדרות להסרה אוטומטית של כותרות עם קווים תחתונים (_). כדי למנוע בעיות באפליקציה, מומלץ להימנע משימוש בקווים תחתונים בכותרות של בקשות באפליקציה.

גמישות המסגרת

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

יש hello world דוגמאות לשימוש במסגרות פופולריות של Java לאינטרנט במאגרGoogle Cloud GitHub:

העברה של קובצי XML לפורמטים של קובצי YAML

ה-CLI של gcloud לא תומך בפורמטים הבאים של קבצים:

  • cron.xml
  • datastore-index.xml
  • dispatch.xml
  • queue.xml

בדוגמאות הבאות מוסבר איך להעביר קובצי xml לקובצי yaml.

העברת הקבצים באופן אוטומטי

כדי להעביר את קובצי xml באופן אוטומטי:

  1. צריך לוודא שמותקנת גרסה 226.0.0 ואילך של ה-CLI של gcloud. כדי לעדכן לגרסה האחרונה:

    gcloud components update
    
  2. לכל קובץ שרוצים להעביר, מציינים אחת מהפקודות המשניות הבאות (cron-xml-to-yaml, ‏ datastore-indexes-xml-to-yaml,‏ dispatch-xml-to-yaml, ‏ queue-xml-to-yaml) ואת שם הקובץ:

    gcloud beta app migrate-config queue-xml-to-yaml MY-QUEUE-XML-FILE.xml
    
  3. לפני שפורסים את הקובץ המומר בסביבת הייצור, כדאי לבדוק אותו ידנית.

    כדי לראות דוגמה להמרת קובץ xml ל-yaml מוצלחת, אפשר לעבור לכרטיסיות העברה ידנית של קבצים.

העברת הקבצים באופן ידני

כדי להעביר ידנית את קובצי xml לקובצי yaml:

cron.yaml

יוצרים קובץ cron.yaml עם אובייקט cron שמכיל רשימה של אובייקטים, כל אחד עם שדות שתואמים למאפייני התג <cron> בקובץ cron.xml, כמו שמוצג בהמשך.

קובץ cron.yaml שהומר:

cron:
- url: '/recache'
  schedule: 'every 2 minutes'
  description: 'Repopulate the cache every 2 minutes'
- url: '/weeklyreport'
  schedule: 'every monday 08:30'
  target: 'version-2'
  timezone: 'America/New_York'
  description: 'Mail out a weekly report'

קובץ cron.xml מקורי:

<?xml version="1.0" encoding="UTF-8"?>
<cronentries>
  <cron>
    <url>/recache</url>
    <description>Repopulate the cache every 2 minutes</description>
    <schedule>every 2 minutes</schedule>
  </cron>
  <cron>
    <url>/weeklyreport</url>
    <description>Mail out a weekly report</description>
    <schedule>every monday 08:30</schedule>
    <timezone>America/New_York</timezone>
    <target>version-2</target>
  </cron>
</cronentries>

מידע נוסף מופיע במאמרי העזרה בנושא cron.yaml.

dispatch.yaml

יוצרים קובץ dispatch.yaml עם אובייקט dispatch שמכיל רשימה של אובייקטים, שלכל אחד מהם יש שדות שתואמים למאפיינים של תג <dispatch> בקובץ dispatch.xml, כמו שמוצג בהמשך.

קובץ dispatch.yaml שהומר:

dispatch:
- url: '*/favicon.ico'
  module: default
- url: 'simple-sample.uc.r.appspot.com/'
  module: default
- url: '*/mobile/*'
  module: mobile-frontend

קובץ dispatch.xml מקורי

<?xml version="1.0" encoding="UTF-8"?>
<dispatch-entries>
  <dispatch>
      <url>*/favicon.ico</url>
      <module>default</module>
  </dispatch>
  <dispatch>
      <url>simple-sample.uc.r.appspot.com/</url>
      <module>default</module>
  </dispatch>
  <dispatch>
      <url>*/mobile/*</url>
      <module>mobile-frontend</module>
  </dispatch>
</dispatch-entries>

מידע נוסף מופיע במאמרי העזרה בנושא dispatch.yaml.

index.yaml

יוצרים קובץ index.yaml עם אובייקט indexes שמכיל רשימה של אובייקטים, שלכל אחד מהם יש שדות שתואמים לכל אחד ממאפייני התג <datastore-index> בקובץ datastore-indexes.xml, כמו שמוצג בהמשך.

קובץ index.yaml שהומר:

indexes:
- ancestor: false
  kind: Employee
  properties:
  - direction: asc
    name: lastName
  - direction: desc
    name: hireDate
- ancestor: false
  kind: Project
  properties:
  - direction: asc
    name: dueDate
  - direction: desc
    name: cost

קובץ datastore-index.xml מקורי:

<?xml version="1.0" encoding="utf-8"?>
<datastore-indexes
 autoGenerate="true">
   <datastore-index kind="Employee" ancestor="false">
       <property name="lastName" direction="asc" />
       <property name="hireDate" direction="desc" />
   </datastore-index>
   <datastore-index kind="Project" ancestor="false">
       <property name="dueDate" direction="asc" />
       <property name="cost" direction="desc" />
   </datastore-index>
</datastore-indexes>

מידע נוסף מופיע במאמרי העזרה בנושא index.yaml.

queue.yaml

יוצרים קובץ queue.yaml עם אובייקט queue שמכיל רשימה של אובייקטים, שלכל אחד מהם יש שדות שתואמים למאפיינים של תג <queue> בקובץ queue.xml, כמו שמוצג בהמשך.

קובץ queue.yaml שהומר:

queue:
- name: fooqueue
  mode: push
  rate: 1/s
  retry_parameters:
    task_retry_limit: 7
    task_age_limit: 2d
- name: barqueue
  mode: push
  rate: 1/s
  retry_parameters:
    min_backoff_seconds: 10
    max_backoff_seconds: 200
    max_doublings: 0

קובץ queue.xml מקורי:

<queue-entries>
  <queue>
    <name>fooqueue</name>
    <rate>1/s</rate>
    <retry-parameters>
      <task-retry-limit>7</task-retry-limit>
      <task-age-limit>2d</task-age-limit>
    </retry-parameters>
  </queue>
  <queue>
    <name>barqueue</name>
    <rate>1/s</rate>
    <retry-parameters>
      <min-backoff-seconds>10</min-backoff-seconds>
      <max-backoff-seconds>200</max-backoff-seconds>
      <max-doublings>0</max-doublings>
    </retry-parameters>
  </queue>
<queue-entries>