Bermigrasi dari Java 8 ke runtime Java terbaru

Halaman ini membahas petunjuk untuk bermigrasi dari runtime Java generasi pertama ke generasi kedua. Untuk mengupgrade aplikasi generasi kedua agar dapat menggunakan versi Java terbaru yang didukung, lihat Mengupgrade aplikasi yang ada.

Java 8 telah mencapai akhir dukungan pada 31 Januari 2024. Aplikasi Java 8 yang ada akan terus berjalan dan menerima traffic. Namun, App Engine mungkin memblokir deployment ulang aplikasi yang menggunakan runtime setelah tanggal akhir dukungannya. Sebaiknya Anda bermigrasi ke versi Java terbaru yang didukung dengan menggunakan panduan di halaman ini.

Dengan bermigrasi ke runtime Java generasi kedua, Anda dapat menggunakan fitur bahasa terbaru dan mem-build aplikasi yang lebih portabel dengan kode idiomatis.

Memahami opsi migrasi Anda

Untuk mengurangi upaya dan kompleksitas migrasi runtime, lingkungan standar App Engine memungkinkan Anda mengakses banyak layanan dan API paket lama, seperti Memcache, di runtime Java generasi kedua. Aplikasi Java Anda dapat memanggil API layanan paket melalui JAR API App Engine, dan mengakses sebagian besar kemampuan yang sama seperti pada runtime Java 8.

Anda juga memiliki opsi untuk menggunakan produk Google Cloud yang menawarkan fungsi serupa dengan layanan paket lama. Produk Google Cloud ini menyediakan Library Klien Cloud untuk Java yang idiomatis. Untuk paket layanan yang tidak tersedia sebagai produk terpisah di Google Cloud, seperti pemrosesan gambar, penelusuran, dan pesan, Anda dapat menggunakan penyedia pihak ketiga atau solusi lain yang disarankan.

Untuk mempelajari lebih lanjut cara bermigrasi ke layanan yang tidak dipaketkan, lihat Bermigrasi dari layanan paket.

Ada beberapa perbedaan dalam melakukan migrasi runtime, tergantung apakah Anda memilih untuk menggunakan layanan paket lama atau tidak:

Bermigrasi ke runtime Java generasi kedua dengan paket layanan Bermigrasi ke runtime Java generasi kedua tanpa paket layanan
Akses layanan paket menggunakan JAR API App Engine. Atau, gunakan produk Google Cloud atau layanan pihak ketiga yang direkomendasikan.

Gunakan appengine-web.xml dan web.xml untuk konfigurasi aplikasi.

Anda mungkin juga perlu mengonfigurasi file YAML tambahan, tergantung pada fitur yang digunakan aplikasi Anda.

Gunakan app.yaml untuk konfigurasi aplikasi.

Anda mungkin juga perlu mengonfigurasi file YAML tambahan, tergantung pada fitur yang digunakan aplikasi Anda.

Aplikasi di-deploy melalui Jetty. Menggunakan format WAR untuk mengemas aplikasi Anda. Aplikasi di-deploy menggunakan server Anda sendiri. Gunakan format JAR untuk mengemas aplikasi Anda. Untuk mempelajari lebih lanjut cara mengonversi file WAR yang sudah ada menjadi JAR yang dapat dieksekusi, lihat Memaketkan ulang file WAR.

Ringkasan proses migrasi

Berikut beberapa perubahan yang mungkin harus Anda buat pada aplikasi Java 8 App Engine yang ada dan proses deployment untuk menggunakan runtime Java generasi kedua:

Perbedaan utama antara Java 8 dan runtime Java generasi kedua

Berikut adalah ringkasan perbedaan antara runtime Java 8 dan runtime Java generasi kedua di lingkungan standar App Engine:

Runtime Java 8 Runtime Java generasi kedua
Deployment server Server di-deploy untuk Anda menggunakan Jetty Jika aplikasi Anda tidak menggunakan layanan paket lama, Anda harus men-deploy server sendiri.1
Layanan paket lama App Engine Tersedia Tersedia
Kemampuan menggunakan Library Klien Cloud untuk Java Ya Ya
Dukungan Ekstensi bahasa dan library sistem Ya Ya
Akses jaringan eksternal Ya Ya
Akses sistem file Akses baca/tulis ke /tmp Akses baca/tulis ke /tmp
Runtime bahasa Diubah untuk App Engine Runtime open source yang tidak dimodifikasi
Mekanisme isolasi Sandbox container berbasis gVisor Sandbox container berbasis gVisor
Menguji dengan server pengembangan lokal Didukung Didukung
Konfigurasi keamanan thread Dapat ditentukan dalam file appengine-web.xml. Tidak dapat ditentukan dalam file konfigurasi. Semua aplikasi dianggap aman untuk thread.3
Logging Menggunakan java.util.logging.
ConsoleHandler, yang menulis ke
stderr dan mengosongkan aliran data
setelah setiap pencatatan data.
Cloud Logging Standar 2
Dukungan plugin DataNucleus 2.x Didukung Tidak didukung 4

Catatan:

  1. Jika aplikasi Anda tidak menggunakan layanan paket lama, runtime Java generasi kedua dapat menjalankan framework Java apa pun selama Anda mengemas server web yang dikonfigurasi untuk merespons permintaan HTTP pada port yang ditentukan oleh variabel lingkungan PORT (direkomendasikan) atau pada port 8080. Misalnya, runtime Java generasi kedua dapat menjalankan Spring Boot Uber JAR sebagaimana adanya. Untuk contoh lainnya, lihat bagian Fleksibilitas framework.

    Jika aplikasi Anda menggunakan layanan paket lama, App Engine akan men-deploy-nya menggunakan Jetty dengan cara yang sama seperti pada runtime Java 8.

  2. Logging di runtime Java generasi kedua mengikuti standar logging di Cloud Logging. Pada runtime Java generasi kedua, log aplikasi tidak lagi dipaketkan dengan log permintaan, tetapi dipisahkan dalam data yang berbeda. Untuk mempelajari lebih lanjut cara membaca dan menulis log di runtime Java generasi kedua, lihat panduan logging.

  3. Untuk mengonfigurasi aplikasi non-threadsafe di runtime Java generasi kedua, mirip dengan cara menetapkan <threadsafe>false</threadsafe> di Java 8, tetapkan konkurensi maksimum ke 1 di file app.yaml atau file appengine-web.xml jika menggunakan layanan paket lama.

  4. Google tidak mendukung library DataNucleus di runtime generasi kedua. DataNucleus versi yang lebih baru tidak kompatibel dengan versi yang digunakan di Java 8. Untuk mengakses Datastore, sebaiknya gunakan solusi library klien mode Datastore atau Objectify Java (versi 6 atau yang lebih baru). Objectify adalah API open source untuk Datastore yang memberikan tingkat abstraksi lebih tinggi.

Perbedaan penggunaan memori

Runtime generasi kedua memiliki dasar penggunaan memori yang lebih tinggi dibandingkan dengan runtime generasi pertama. Hal ini disebabkan oleh beberapa faktor, seperti versi gambar dasar yang berbeda, dan perbedaan dalam cara kedua generasi menghitung penggunaan memori.

Runtime generasi kedua menghitung penggunaan memori instance sebagai jumlah dari yang digunakan proses aplikasi, dan jumlah file aplikasi yang di-cache secara dinamis di memori. Agar aplikasi yang intensif memori tidak mengalami penghentian instance karena melebihi batas memori, upgrade ke class instance yang lebih besar dengan lebih banyak memori.

Perbedaan penggunaan CPU

Runtime generasi kedua dapat melihat baseline penggunaan CPU yang lebih tinggi setelah cold start instance. Bergantung pada konfigurasi penskalaan aplikasi, hal ini mungkin memiliki efek samping yang tidak diinginkan, seperti jumlah instance yang lebih tinggi dari yang diperkirakan jika aplikasi dikonfigurasi untuk diskalakan berdasarkan penggunaan CPU. Untuk menghindari masalah ini, tinjau dan uji konfigurasi penskalaan aplikasi untuk memastikan jumlah instance dapat diterima.

Perbedaan header permintaan

Runtime generasi pertama memungkinkan header permintaan dengan garis bawah (misalnya, X-Test-Foo_bar) diteruskan ke aplikasi. Runtime generasi kedua memperkenalkan Nginx ke dalam arsitektur host. Sebagai akibat dari perubahan ini, runtime generasi kedua dikonfigurasi untuk otomatis menghapus header dengan garis bawah (_). Untuk mencegah masalah aplikasi, hindari penggunaan garis bawah di header permintaan aplikasi.

Fleksibilitas framework

Runtime Java generasi kedua tidak menyertakan framework penayangan web apa pun kecuali jika Anda menggunakan layanan paket lama. Artinya, Anda dapat menggunakan framework selain framework berbasis servlet. Jika Anda menggunakan layanan paket lama, runtime Java generasi kedua akan menyediakan framework penayangan web Jetty.

Ada hello world contoh yang menggunakan framework web Java populer di repositori GitHub Google Cloud:

Memigrasikan format file XML ke YAML

gcloud CLI tidak mendukung format file berikut:

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

Contoh berikut menunjukkan cara memigrasikan file xml ke file yaml.

Memigrasikan file secara otomatis

Untuk memigrasikan file xml secara otomatis:

  1. Anda harus memiliki gcloud CLI versi 226.0.0 atau yang lebih baru. Untuk mengupdate ke versi terbaru:

    gcloud components update
    
  2. Untuk setiap file yang ingin dimigrasikan, tentukan salah satu subperintah berikut (cron-xml-to-yaml, datastore-indexes-xml-to-yaml, dispatch-xml-to-yaml, queue-xml-to-yaml) dan nama file:

    gcloud beta app migrate-config queue-xml-to-yaml MY-QUEUE-XML-FILE.xml
    
  3. Periksa kembali file yang dikonversi secara manual sebelum men-deploy ke produksi.

    Untuk mengetahui contoh konversi file xml ke yaml yang berhasil, lihat tab Memigrasikan file secara manual.

Memigrasikan file secara manual

Untuk memigrasikan file xml secara manual ke file yaml:

cron.yaml

Buat file cron.yaml dengan objek cron yang berisi daftar objek, masing-masing dengan kolom yang sesuai dengan setiap atribut tag <cron> dalam file cron.xml, sebagai yang ditunjukkan di bawah ini.

File cron.yaml yang dikonversi:

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'

File cron.xml asli:

<?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>

Untuk informasi selengkapnya, lihat dokumentasi referensi cron.yaml.

dispatch.yaml

Buat file dispatch.yaml dengan objek dispatch yang berisi daftar objek, masing-masing dengan kolom yang sesuai dengan setiap atribut tag <dispatch> dalam file dispatch.xml, sebagai yang ditunjukkan di bawah ini.

File dispatch.yaml yang dikonversi:

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

File dispatch.xml asli

<?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>

Untuk informasi selengkapnya, lihat dokumentasi referensi dispatch.yaml

index.yaml

Buat file index.yaml dengan objek indexes yang berisi daftar objek, masing-masing dengan kolom yang sesuai dengan setiap atribut tag <datastore-index> dalam file datastore-indexes.xml, sebagai yang ditunjukkan di bawah ini.

File index.yaml yang dikonversi:

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

File datastore-index.xml asli:

<?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>

Untuk informasi selengkapnya, lihat dokumentasi referensi index.yaml.

queue.yaml

Buat file queue.yaml dengan objek queue yang berisi daftar objek, masing-masing dengan kolom yang sesuai dengan setiap atribut tag <queue> dalam file queue.xml, sebagai yang ditunjukkan di bawah ini.

File queue.yaml yang dikonversi:

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

File queue.xml asli:

<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>