Questa pagina fornisce istruzioni per la migrazione dai runtime Java di prima alla seconda generazione. Per eseguire l'upgrade dell'app di seconda generazione in modo che utilizzi l'ultima versione supportata di Java, vedi Eseguire l'upgrade di un'applicazione esistente.
Java 8 ha raggiunto la fine del supporto il 31 gennaio 2024. Le tue applicazioni Java 8 esistenti continueranno a essere eseguite e a ricevere traffico. Tuttavia, App Engine potrebbe bloccare il redeployment delle applicazioni che utilizzano runtime dopo la data di fine del supporto. Ti consigliamo di eseguire la migrazione all'ultima versione supportata di Java seguendo le linee guida riportate in questa pagina.
La migrazione ai runtime Java di seconda generazione ti consente di utilizzare funzionalità del linguaggio aggiornate e creare app più portatili, con codice idiomatico.
Informazioni sulle opzioni di migrazione
Per ridurre lo sforzo e la complessità della migrazione del runtime, l'ambiente standard App Engine ti consente di accedere a molti servizi e API in bundle legacy, come Memcache, nei runtime Java di seconda generazione. La tua app Java può chiamare le API dei servizi in bundle tramite il file JAR dell'API App Engine e accedere alla maggior parte delle stesse funzionalità del runtime Java 8.
Hai anche la possibilità di utilizzare i prodotti Google Cloud che offrono funzionalità simili a quelle dei servizi legacy in bundle. Questi Google Cloud prodotti forniscono librerie client di Cloud per Java idiomatiche. Per i servizi in bundle che non sono disponibili come prodotti separati in Google Cloud, come l'elaborazione delle immagini, la ricerca e la messaggistica, puoi utilizzare fornitori di terze parti o altre soluzioni alternative.
Per saperne di più sulla migrazione ai servizi separati, consulta la pagina Eseguire la migrazione dai servizi in bundle.
Esistono alcune differenze nel modo in cui esegui la migrazione in fase di runtime, a seconda che tu scelga di utilizzare i servizi in bundle legacy:
Migrazione ai runtime Java di seconda generazione con servizi in bundle | Migrazione ai runtime Java di seconda generazione senza servizi in bundle |
---|---|
Accedi ai servizi integrati utilizzando il file JAR delle API App Engine. | Se vuoi, utilizza prodotti Google Cloud consigliati o servizi di terze parti. |
Utilizza
Potresti anche dover configurare altri file YAML a seconda delle funzionalità utilizzate dalla tua app. |
Utilizza
Potresti anche dover configurare altri file YAML a seconda delle funzionalità utilizzate dalla tua app. |
Le app vengono eseguite il deployment tramite Jetty. Utilizza il formato WAR per pacchettizzare l'app. | Le app vengono implementate utilizzando il tuo server. Utilizza il formato JAR per pacchettizzare la tua app. Per scoprire di più sulla conversione del file WAR esistente in un file JAR eseguibile, consulta Ripacchettizzazione di un file WAR. |
Panoramica del processo di migrazione
Di seguito sono elencate alcune modifiche che potresti dover apportare alla tua app App Engine Java 8 esistente e al tuo processo di deployment per utilizzare i runtime Java di seconda generazione:
- Scarica Google Cloud CLI.
- Esegui la migrazione dal plug-in Maven di App Engine autonomo al plug-in Maven basato su gcloud CLI o al plug-in Gradle basato su gcloud CLI.
- Installa il file JAR dell'API App Engine se utilizzi i servizi in bundle legacy.
Eseguire la migrazione dei file XML ai file
yaml
equivalenti.
Differenze principali tra Java 8 e i runtime Java di seconda generazione
Di seguito è riportato un riepilogo delle differenze tra i runtime Java 8 e Java di seconda generazione nell'ambiente standard di App Engine:
Runtime Java 8 | Runtime Java di seconda generazione | |
---|---|---|
Deployment del server | Server di cui è stato eseguito il deployment per te utilizzando Jetty | Se la tua app non utilizza i servizi in bundle legacy, devi eseguire il deployment di un server autonomamente.1 |
Servizi integrati legacy di App Engine | Fornito da Google | Fornito da Google |
Possibilità di utilizzare le librerie client di Cloud per Java | Sì | Sì |
Supporto delle estensioni linguistiche e delle librerie di sistema | Sì | Sì |
Accesso alla rete esterna | Sì | Sì |
Accesso al file system | Accesso in lettura/scrittura a /tmp
|
Accesso in lettura/scrittura a /tmp
|
Runtime del linguaggio | Modificato per App Engine | Runtime open source non modificato |
Meccanismo di isolamento | Sandbox dei container basata su gVisor | Sandbox dei container basata su gVisor |
Test con il server di sviluppo locale | Supportato | Supportato |
Configurazione della sicurezza dei thread | Può essere specificato nel file appengine-web.xml .
|
Non può essere specificato nei file di configurazione. Si presume che tutte le app siano thread-safe.3 |
Logging | Utilizza un java.util.logging. ConsoleHandler , che scrive in stderr e svuota lo stream dopo ogni record. |
Cloud Logging standard 2 |
Supporto del plug-in DataNucleus 2.x | Supportato | Non supportato 4 |
Note:
Se la tua app non utilizza i servizi in bundle legacy, i runtime Java di seconda generazione possono eseguire qualsiasi framework Java, a condizione che tu pacchettizzi un web server configurato per rispondere alle richieste HTTP sulla porta specificata dalla variabile di ambiente
PORT
(consigliato) o sulla porta 8080. Ad esempio, i runtime Java di seconda generazione possono eseguire un file JAR Uber di Spring Boot così com'è. Per altri esempi, consulta la sezione Flessibilità del framework.Se la tua app utilizza i servizi integrati legacy, App Engine esegue il deployment utilizzando Jetty nello stesso modo del runtime Java 8.
Il logging nei runtime Java di seconda generazione segue lo standard di logging in Cloud Logging. Nei runtime Java di seconda generazione, i log delle app non sono più raggruppati con i log delle richieste, ma sono separati in record diversi. Per saperne di più sulla lettura e la scrittura dei log nei runtime Java di seconda generazione, consulta la guida alla registrazione.
Per configurare un'app non thread-safe nel runtime Java di seconda generazione, in modo simile all'impostazione di
<threadsafe>false</threadsafe>
in Java 8, imposta la concorrenza massima su 1 nel fileapp.yaml
o nel fileappengine-web.xml
se utilizzi i servizi in bundle legacy.Google non supporta la libreria DataNucleus nei runtime di seconda generazione. Le versioni più recenti di DataNucleus non sono compatibili con le versioni utilizzate in Java 8. Per accedere a Datastore, ti consigliamo di utilizzare la libreria client in modalità Datastore o la soluzione Java Objectify (versione 6 o successive). Objectify è un'API open source per Datastore che fornisce un livello di astrazione superiore.
Differenze nell'utilizzo della memoria
I runtime di seconda generazione hanno una base di utilizzo della memoria più elevata rispetto ai runtime di prima generazione. Ciò è dovuto a diversi fattori, ad esempio versioni diverse dell'immagine di base e differenze nel modo in cui le due generazioni calcolano l'utilizzo della memoria.
I runtime di seconda generazione calcolano l'utilizzo della memoria dell'istanza come somma di ciò che utilizza un processo dell'applicazione e del numero di file dell'applicazione memorizzati dinamicamente nella cache in memoria. Per evitare che le applicazioni che utilizzano molta memoria subiscano arresti anomali delle istanze a causa del superamento dei limiti di memoria, esegui l'upgrade a una classe di istanze più grande con più memoria.
Differenze di utilizzo della CPU
I runtime di seconda generazione possono registrare una baseline più elevata di utilizzo della CPU all'avvio a freddo dell'istanza. A seconda della configurazione di scalabilità di un'applicazione, ciò potrebbe avere effetti collaterali indesiderati, ad esempio un numero di istanze superiore al previsto se un'applicazione è configurata per la scalabilità in base all'utilizzo della CPU. Per evitare questo problema, rivedi e testa le configurazioni di scalabilità dell'applicazione per assicurarti che il numero di istanze sia accettabile.
Differenze tra le intestazioni delle richieste
I runtime di prima generazione consentono di inoltrare all'applicazione le intestazioni delle richieste con trattini bassi
(ad es. X-Test-Foo_bar
). I runtime di seconda generazione
introducono Nginx nell'architettura host. A seguito di questa
modifica, i runtime di seconda generazione sono configurati per rimuovere automaticamente
le intestazioni con trattini bassi (_
). Per evitare problemi con l'applicazione, evita di utilizzare
trattini bassi nelle intestazioni delle richieste dell'applicazione.
Flessibilità del framework
I runtime Java di seconda generazione non includono alcun framework di pubblicazione web, a meno che tu non utilizzi i servizi in bundle legacy. Ciò significa che puoi utilizzare un framework diverso da uno basato su servlet. Se utilizzi i servizi in bundle legacy, i runtime Java di seconda generazione forniscono il framework di servizio web Jetty.
Nel Google Cloud repository GitHub sono disponibili hello world
esempi che utilizzano i framework web Java più diffusi:
Migrazione dei formati di file XML a YAML
gcloud CLI non supporta i seguenti formati file:
cron.xml
datastore-index.xml
dispatch.xml
queue.xml
Gli esempi seguenti mostrano come eseguire la migrazione dei file xml
ai file
yaml
.
Eseguire la migrazione automatica dei file
Per eseguire automaticamente la migrazione dei file xml
:
Devi avere gcloud CLI versione 226.0.0 o successive. Per eseguire l'aggiornamento all'ultima versione:
gcloud components update
Per ogni file che vuoi migrare, specifica uno dei seguenti sottocomandi (
cron-xml-to-yaml
,datastore-indexes-xml-to-yaml
,dispatch-xml-to-yaml
,queue-xml-to-yaml
) e il nome del file:gcloud beta app migrate-config queue-xml-to-yaml MY-QUEUE-XML-FILE.xml
Controlla manualmente il file convertito prima di eseguire il deployment in produzione.
Per una conversione riuscita del file di esempio
xml
inyaml
, consulta le schede Eseguire la migrazione dei file manualmente.
Eseguire la migrazione manuale dei file
Per eseguire manualmente la migrazione dei file xml
ai file yaml
:
cron.yaml
Crea un file cron.yaml
con un oggetto cron
contenente un elenco di oggetti,
ognuno con campi che corrispondono a ciascuno degli attributi del tag <cron>
nel
tuo file cron.xml
, come mostrato di seguito.
File cron.yaml
convertito:
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
originale:
<?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>
Per saperne di più, consulta la documentazione di riferimento di cron.yaml
.
dispatch.yaml
Crea un file dispatch.yaml
con un oggetto dispatch
contenente un elenco di
oggetti, ognuno con campi che corrispondono a ciascuno degli attributi del tag <dispatch>
nel file dispatch.xml
, come mostrato di seguito.
File dispatch.yaml
convertito:
dispatch:
- url: '*/favicon.ico'
module: default
- url: 'simple-sample.uc.r.appspot.com/'
module: default
- url: '*/mobile/*'
module: mobile-frontend
File dispatch.xml
originale
<?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>
Per saperne di più, consulta la documentazione di riferimento di dispatch.yaml
.
index.yaml
Crea un file index.yaml
con un oggetto indexes
contenente un elenco di
oggetti, ognuno con campi che corrispondono a ciascuno degli attributi dei tag <datastore-index>
nel file datastore-indexes.xml
, come mostrato di seguito.
File index.yaml
convertito:
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
originale:
<?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>
Per saperne di più, consulta la documentazione di riferimento di index.yaml
.
queue.yaml
Crea un file queue.yaml
con un oggetto queue
contenente un elenco di
oggetti, ognuno con campi che corrispondono a ciascuno degli attributi del tag <queue>
nel file queue.xml
, come mostrato di seguito.
File queue.yaml
convertito:
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
originale:
<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>