Perbedaan antara Java 8 dan Java 11+

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

Dengan bermigrasi ke runtime Java 11+, yang juga dikenal sebagai runtime Java generasi kedua, Anda dapat menggunakan fitur bahasa terbaru dan membangun aplikasi yang lebih portabel dengan kode idiomatis.

Memahami opsi migrasi Anda

Untuk mengurangi upaya dan kerumitan migrasi runtime, lingkungan standar App Engine memungkinkan Anda mengakses banyak layanan dan API lama yang dipaketkan, seperti Memcache, dalam runtime Java generasi kedua. Aplikasi Java Anda dapat memanggil API layanan yang dipaketkan melalui JAR App Engine API, 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 11+ dengan layanan yang dipaketkan Bermigrasi ke runtime Java 11+ 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 ini daftar beberapa perubahan yang mungkin harus Anda lakukan pada aplikasi App Engine Java 8 yang ada dan proses deployment agar dapat menggunakan runtime Java generasi kedua:

Perbedaan utama antara runtime Java 8 dan Java 11+

Berikut adalah ringkasan perbedaan antara runtime Java 8 dan Java 11+ di lingkungan standar App Engine:

Runtime Java 8 Runtime Java 11+
Deployment server Server di-deploy untuk Anda melalui 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 versi 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 di 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 dalam 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 catatan yang berbeda. Untuk mempelajari lebih lanjut cara membaca dan menulis log dalam runtime Java generasi kedua, lihat panduan logging.

  3. Untuk mengonfigurasi aplikasi non-threadsafe di runtime Java generasi kedua, yang mirip dengan menyetel <threadsafe>false</threadsafe> di Java 8, tetapkan konkurensi maksimal 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. Versi DataNucleus yang lebih baru tidak kompatibel dengan versi yang digunakan di Java 8. Untuk mengakses Datastore, sebaiknya gunakan library klien mode Datastore atau solusi Objectify (versi 6 atau yang lebih baru) Java. Objectify adalah API open source untuk Datastore yang menyediakan tingkat abstraksi yang lebih tinggi.

Perbedaan penggunaan memori

Runtime generasi kedua mengalami dasar penggunaan memori yang lebih tinggi dibandingkan runtime generasi pertama. Hal ini disebabkan oleh beberapa faktor, seperti versi image dasar yang berbeda, dan perbedaan cara penghitungan penggunaan memori oleh kedua generasi.

Runtime generasi kedua menghitung penggunaan memori instance sebagai jumlah penggunaan proses aplikasi, dan jumlah file aplikasi yang di-cache secara dinamis dalam memori. Untuk menghindari aplikasi yang menggunakan banyak memori mengalami penonaktifan instance karena melebihi batas memori, upgrade ke class instance yang lebih besar dengan memori yang lebih besar.

Perbedaan penggunaan CPU

Runtime generasi kedua dapat melihat dasar penggunaan CPU yang lebih tinggi saat cold start instance. Bergantung pada konfigurasi penskalaan aplikasi, hal ini mungkin memiliki efek samping yang tidak diinginkan, seperti jumlah instance yang lebih tinggi daripada 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. Akibat perubahan ini, runtime generasi kedua dikonfigurasi untuk otomatis menghapus header dengan garis bawah (_). Untuk mencegah masalah aplikasi, hindari penggunaan garis bawah dalam header permintaan aplikasi.

Fleksibilitas framework

Runtime Java generasi kedua tidak menyertakan framework layanan 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 layanan 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>