En esta página se explica cómo migrar de los entornos de ejecución de Java de primera generación a los de segunda generación. Para actualizar tu aplicación de segunda generación a la versión más reciente compatible de Java, consulta Actualizar una aplicación.
Java 8 llegó al final del ciclo de asistencia el 31 de enero del 2024. Tus aplicaciones Java 8 seguirán ejecutándose y recibiendo tráfico. Sin embargo, App Engine puede bloquear el nuevo despliegue de aplicaciones que usen tiempos de ejecución después de la fecha de finalización de su asistencia. Te recomendamos que migres a la versión más reciente compatible de Java siguiendo las directrices de esta página.
Si migras a los runtimes de Java de segunda generación, podrás usar funciones de lenguaje actualizadas y crear aplicaciones más portátiles con código idiomático.
Información sobre las opciones de migración
Para reducir el esfuerzo y la complejidad de la migración del tiempo de ejecución, el entorno estándar de App Engine te permite acceder a muchos servicios y APIs antiguos agrupados, como Memcache, en los tiempos de ejecución de Java de segunda generación. Tu aplicación Java puede llamar a las APIs de los servicios empaquetados a través del archivo JAR de la API de App Engine y acceder a la mayoría de las mismas funciones que en el entorno de ejecución de Java 8.
También puedes usar Google Cloud productos que ofrecen funciones similares a las de los servicios antiguos agrupados. Estos Google Cloud productos proporcionan bibliotecas de cliente de Cloud para Java idiomáticas. En el caso de los servicios incluidos que no están disponibles como productos independientes enGoogle Cloud, como el procesamiento de imágenes, la búsqueda y la mensajería, puedes usar proveedores externos u otras soluciones alternativas.
Para obtener más información sobre cómo migrar a servicios independientes, consulta el artículo Migrar de servicios agrupados.
Hay algunas diferencias en la forma de realizar la migración en tiempo de ejecución, en función de si decides usar los servicios agrupados antiguos:
Migrar a los entornos de ejecución de Java de segunda generación con servicios agrupados | Migrar a los entornos de ejecución de Java de segunda generación sin servicios agrupados |
---|---|
Accede a los servicios agrupados mediante el archivo JAR de las APIs de App Engine. | Si quieres, usa productos recomendados Google Cloud o servicios de terceros. |
Usa
También puede que tengas que configurar archivos YAML adicionales en función de las funciones que use tu aplicación. |
Usa
También es posible que tengas que configurar archivos YAML adicionales en función de las funciones que use tu aplicación. |
Las aplicaciones se implementan a través de Jetty. Usa el formato WAR para empaquetar tu aplicación. | Las aplicaciones se implementan mediante tu propio servidor. Usa el formato JAR para empaquetar tu aplicación. Para obtener más información sobre cómo convertir un archivo WAR en un archivo JAR ejecutable, consulta Volver a empaquetar un archivo WAR. |
Visión general del proceso de migración
A continuación, se indican algunos cambios que puede que tengas que hacer en tu aplicación Java 8 de App Engine y en tu proceso de implementación para usar los tiempos de ejecución de Java de segunda generación:
- Descarga Google Cloud CLI.
- Migra del complemento Maven independiente de App Engine al complemento Maven basado en gcloud CLI o al complemento Gradle basado en gcloud CLI.
- Instala el archivo JAR de la API de App Engine si utilizas los servicios agrupados antiguos.
Principales diferencias entre Java 8 y los tiempos de ejecución de Java de segunda generación
A continuación, se resumen las diferencias entre los entornos de ejecución de Java 8 y de segunda generación de Java en el entorno estándar de App Engine:
Tiempo de ejecución de Java 8 | Entornos de ejecución de Java de segunda generación | |
---|---|---|
Despliegue de servidores | Servidor desplegado para ti con Jetty | Si tu aplicación no usa los servicios empaquetados antiguos, debes implementar un servidor por tu cuenta.1 |
Servicios agrupados antiguos de App Engine | Proporcionado | Proporcionado |
Posibilidad de usar las bibliotecas de cliente de Cloud para Java | Sí | Sí |
Compatibilidad con extensiones de idiomas y bibliotecas del sistema | Sí | Sí |
Acceso a redes externas | Sí | Sí |
Acceso al sistema de archivos | Acceso de lectura y escritura a /tmp
|
Acceso de lectura y escritura a /tmp
|
Entorno de ejecución de lenguaje | Modificado para App Engine | Tiempo de ejecución de código abierto sin modificaciones |
Mecanismo de aislamiento | Entorno aislado de contenedores basado en gVisor | Entorno aislado de contenedores basado en gVisor |
Pruebas con el servidor de desarrollo local | Compatible | Compatible |
Configuración de seguridad en hilos | Se puede especificar en el archivo appengine-web.xml .
|
No se puede especificar en los archivos de configuración. Se presupone que todas las aplicaciones son seguras para los subprocesos.3 |
Almacenamiento de registros | Usa un java.util.logging. ConsoleHandler , que escribe en stderr y vacía el flujo después de cada registro. |
Cloud Logging estándar 2 |
Compatibilidad con el complemento DataNucleus 2.x | Compatible | No disponible 4 |
Notas:
Si tu aplicación no usa los servicios empaquetados antiguos, los tiempos de ejecución de Java de segunda generación pueden ejecutar cualquier framework de Java siempre que empaquetes un servidor web configurado para responder a las solicitudes HTTP en el puerto especificado por la variable de entorno
PORT
(recomendado) o en el puerto 8080. Por ejemplo, los tiempos de ejecución de Java de segunda generación pueden ejecutar un Uber JAR de Spring Boot tal cual. Para ver más ejemplos, consulta la sección Flexibilidad de los frameworks.Si tu aplicación usa los servicios agrupados antiguos, App Engine la desplegará con Jetty de la misma forma que en el entorno de ejecución de Java 8.
El registro en los entornos de ejecución de Java de segunda generación sigue el estándar de registro de Cloud Logging. En los tiempos de ejecución de Java de segunda generación, los registros de aplicaciones ya no se incluyen en los registros de solicitudes, sino que se separan en registros diferentes. Para obtener más información sobre cómo leer y escribir registros en los tiempos de ejecución de Java de segunda generación, consulta la guía de registro.
Para configurar una aplicación que no sea segura para subprocesos en el runtime de Java de segunda generación, de forma similar a como se configura
<threadsafe>false</threadsafe>
en Java 8, define la simultaneidad máxima en 1 en el archivoapp.yaml
o en el archivoappengine-web.xml
si usas los servicios empaquetados antiguos.Google no admite la biblioteca DataNucleus en los tiempos de ejecución de segunda generación. Las versiones más recientes de DataNucleus no son compatibles con las versiones usadas en Java 8. Para acceder a Datastore, te recomendamos que uses la biblioteca de cliente del modo Datastore o la solución Objectify (versión 6 o posterior) de Java. Objectify es una API de código abierto para Datastore que proporciona un nivel de abstracción superior.
Diferencias en el uso de memoria
Los tiempos de ejecución de segunda generación tienen un uso de memoria de referencia más alto que los de primera generación. Esto se debe a varios factores, como las diferentes versiones de la imagen base y las diferencias en la forma en que las dos generaciones calculan el uso de memoria.
Los tiempos de ejecución de segunda generación calculan el uso de memoria de las instancias como la suma de lo que usa un proceso de aplicación y el número de archivos de aplicación almacenados dinámicamente en caché en la memoria. Para evitar que las aplicaciones que consumen mucha memoria experimenten cierres de instancias debido a que superan los límites de memoria, cambia a una clase de instancia más grande con más memoria.
Diferencias en el uso de la CPU
Los tiempos de ejecución de segunda generación pueden experimentar un aumento del uso de la CPU al iniciar una instancia por primera vez. En función de la configuración de escalado de una aplicación, esto puede tener efectos secundarios no deseados, como un número de instancias superior al previsto si una aplicación está configurada para escalarse en función de la utilización de la CPU. Para evitar este problema, revisa y prueba las configuraciones de escalado de la aplicación para asegurarte de que el número de instancias sea aceptable.
Diferencias en los encabezados de solicitud
Los tiempos de ejecución de primera generación permiten que los encabezados de solicitud con guiones bajos (por ejemplo, X-Test-Foo_bar
) se reenvíen a la aplicación. Los runtimes de segunda generación
introducen Nginx en la arquitectura del host. Como resultado de este cambio, los tiempos de ejecución de segunda generación se configuran para eliminar automáticamente los encabezados con guiones bajos (_
). Para evitar problemas con las aplicaciones, no utilices guiones bajos en los encabezados de las solicitudes de las aplicaciones.
Flexibilidad del framework
Los entornos de ejecución de Java de segunda generación no incluyen ningún framework de servicio web, a menos que uses los servicios empaquetados antiguos. Esto significa que puedes usar un framework que no esté basado en servlets. Si usas los servicios agrupados antiguos, los tiempos de ejecución de Java de segunda generación proporcionan el framework de servicio web Jetty.
Hay hello world
ejemplos que usan frameworks web de Java populares en el Google Cloud repositorio de GitHub:
Migrar formatos de archivo XML a YAML
gcloud CLI no admite los siguientes formatos de archivo:
cron.xml
datastore-index.xml
dispatch.xml
queue.xml
En los siguientes ejemplos se muestra cómo migrar los archivos xml
a archivos yaml
.
Migrar tus archivos automáticamente
Para migrar tus archivos xml
automáticamente, sigue estos pasos:
Debes tener la versión 226.0.0 o una posterior de la CLI de gcloud. Para actualizar a la versión más reciente, sigue estos pasos:
gcloud components update
Para cada archivo que quieras migrar, especifica uno de los siguientes subcomandos (
cron-xml-to-yaml
,datastore-indexes-xml-to-yaml
,dispatch-xml-to-yaml
oqueue-xml-to-yaml
) y el nombre del archivo:gcloud beta app migrate-config queue-xml-to-yaml MY-QUEUE-XML-FILE.xml
Comprueba manualmente el archivo convertido antes de implementarlo en producción.
Para ver un ejemplo de conversión correcta de un archivo
xml
ayaml
, consulta las pestañas Migrar archivos manualmente.
Migrar tus archivos manualmente
Para migrar manualmente tus archivos xml
a archivos yaml
, sigue estos pasos:
cron.yaml
Crea un archivo cron.yaml
con un objeto cron
que contenga una lista de objetos, cada uno con campos que correspondan a cada uno de los atributos de la etiqueta <cron>
de tu archivo cron.xml
, como se muestra a continuación.
Archivo cron.yaml
convertido:
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'
Archivo cron.xml
original:
<?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>
Para obtener más información, consulta la documentación de referencia de cron.yaml
.
dispatch.yaml
Crea un archivo dispatch.yaml
con un objeto dispatch
que contenga una lista de objetos, cada uno con campos que correspondan a los atributos de la etiqueta <dispatch>
de tu archivo dispatch.xml
, tal como se muestra a continuación.
Archivo dispatch.yaml
convertido:
dispatch:
- url: '*/favicon.ico'
module: default
- url: 'simple-sample.uc.r.appspot.com/'
module: default
- url: '*/mobile/*'
module: mobile-frontend
Archivo dispatch.xml
original
<?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>
Para obtener más información, consulta la referencia de dispatch.yaml
index.yaml
Crea un archivo index.yaml
con un objeto indexes
que contenga una lista de objetos, cada uno con campos que correspondan a los atributos de la etiqueta <datastore-index>
de tu archivo datastore-indexes.xml
, como se muestra a continuación.
Archivo index.yaml
convertido:
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
Archivo datastore-index.xml
original:
<?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>
Para obtener más información, consulta la documentación de referencia de index.yaml
.
queue.yaml
Crea un archivo queue.yaml
con un objeto queue
que contenga una lista de objetos, cada uno con campos que correspondan a los atributos de la etiqueta <queue>
de tu archivo queue.xml
, tal como se muestra a continuación.
Archivo queue.yaml
convertido:
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
Archivo queue.xml
original:
<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>