En esta página se describen las condiciones previas de las solicitudes, que se usan para evitar que las solicitudes se apliquen a un recurso cuando este se encuentra en un estado inesperado.
Introducción
Cuando se usan las condiciones previas en una solicitud a Cloud Storage, la solicitud solo se lleva a cabo si el recurso de destino cumple los criterios definidos en las condiciones previas. Las comprobaciones de las condiciones previas aseguran que un cubo u objeto se encuentre en el estado esperado, lo que le permite realizar actualizaciones de lectura-modificación-escritura seguras y operaciones condicionales.
Las condiciones previas se suelen usar para evitar condiciones de carrera en solicitudes de mutación, como subidas, eliminaciones o actualizaciones de metadatos. Las condiciones de carrera pueden surgir cuando se envía la misma solicitud repetidamente o cuando procesos independientes intentan modificar el mismo recurso. Consulta más información en Ejemplos de condiciones de carrera y corrupción de datos. Las condiciones previas también se suelen usar al recuperar metadatos y datos de objetos en solicitudes sucesivas para asegurarse de que el objeto no ha cambiado entre las dos solicitudes.
Criterios de condición previa
Cloud Storage admite el uso de varias propiedades de recursos inmutables en las condiciones previas:
- Números de generación y metageneración
- ETags
- La fecha
Last-Modified
(solo disponible al obtener datos de objetos o metadatos mediante la API XML)
En la siguiente tabla se indican las condiciones previas admitidas por la API JSON y la API XML:
API JSON | API XML | Descripción |
---|---|---|
Parámetro de consulta ifGenerationMatch |
Encabezado x-goog-if-generation-match |
La solicitud se procesa si el generation del recurso de destino coincide con el valor utilizado en la condición previa. Si los valores no coinciden, la solicitud falla y se devuelve una respuesta 412 Precondition Failed . |
Parámetro de consulta ifMetagenerationMatch |
Encabezado x-goog-if-metageneration-match |
La solicitud se procesa si el metageneration del recurso de destino coincide con el valor utilizado en la condición previa. Si los valores no coinciden, la solicitud falla y se devuelve una respuesta 412 Precondition Failed . |
Parámetro de consulta ifGenerationNotMatch |
N/A | La solicitud se procesa si el generation del recurso de destino no coincide con el valor utilizado en la condición previa. Si los valores coinciden, la solicitud falla y se devuelve una respuesta 304 Not Modified . |
Parámetro de consulta ifMetagenerationNotMatch |
N/A | La solicitud se procesa si el metageneration del recurso de destino no coincide con el valor utilizado en la condición previa. Si los valores coinciden, la solicitud falla y se devuelve una respuesta 304 Not Modified . |
Encabezado If-Match |
Encabezado If-Match |
Se aplica a las solicitudes que obtienen datos. La solicitud se procesa si el ETag del recurso de destino coincide con el valor utilizado en la condición previa. Si los valores no coinciden, la solicitud falla y se devuelve una respuesta 412 Precondition Failed . |
Encabezado If-None-Match |
Encabezado If-None-Match |
Se aplica a las solicitudes que obtienen datos. La solicitud se procesa si el ETag del recurso de destino no coincide con el valor utilizado en la condición previa. Si los valores coinciden, la solicitud falla y se devuelve una respuesta 304 Not Modified . |
N/A | Encabezado If-Modified-Since |
La solicitud se procesa si el recurso de destino tiene una fecha Last-Modified posterior al valor utilizado en la precondición. Si el recurso de destino no cumple esta condición previa, la solicitud falla y se devuelve una respuesta 304 Not Modified . |
N/A | Encabezado If-Unmodified-Since |
La solicitud se procesa si el recurso de destino tiene una fecha Last-Modified anterior o igual al valor utilizado en la condición previa. Si el recurso de destino no cumple esta condición previa, la solicitud falla y se devuelve una respuesta 412 Precondition Failed . |
Requisitos previos de la composición de objetos
Cuando se realiza la composición de objetos, tanto la API JSON como la API XML admiten lo siguiente:
Las condiciones previas de coincidencia de generación y de metageneración del objeto de destino.
La condición previa de coincidencia de generación de cada objeto de origen. Si se usa esta condición previa, se evita que se utilicen componentes incorrectos en el caso de que un proceso independiente sobrescriba uno de los componentes previstos de la composición. Si usas las condiciones previas y se produce una sobrescritura de este tipo, la operación
compose
falla y devuelve una respuesta412 Precondition Failed
.
Condiciones previas de copia de objetos
Cuando se copia o se reescribe un objeto en Cloud Storage, tanto la API JSON como la API XML admiten el uso de precondiciones estándar para el objeto de destino. Cada API tiene compatibilidad adicional con las condiciones previas para los objetos de origen:
La API JSON admite las condiciones previas de generación y metageneración del objeto de origen, que se especifican mediante parámetros de consulta con el prefijo
ifSource
.Se pueden usar todas las condiciones previas admitidas por la API XML para el objeto de origen. Estas condiciones previas se especifican en encabezados con el prefijo
x-goog-copy-source-
.
El valor 0
en una condición previa de coincidencia de generación
La condición previa de coincidencia de generación acepta el valor 0
como caso especial. Cuando se incluye en una solicitud una condición previa de coincidencia de generación con el valor 0
, la solicitud solo se lleva a cabo si no existe ningún objeto con el nombre especificado en el cubo o si solo hay versiones no actuales del objeto en el cubo. Si hay una versión activa con el nombre especificado, la solicitud falla y devuelve el código de estado 412 Precondition Failed
.
Prácticas recomendadas y consideraciones
Puedes usar varias condiciones previas en una sola solicitud. Si no se cumple alguna de las condiciones previas, la solicitud general falla.
Los contenedores no tienen un número de generación, pero sí un número de metageneración. No debes usar condiciones previas que especifiquen un número de generación en una solicitud de un cubo.
Si usas una condición previa de metageneración en una solicitud de objeto, siempre debes usar también una condición previa de generación. De esta forma, se evita que la solicitud se complete correctamente en un objeto diferente que, por casualidad, tenga un número de metageneración que cumpla la condición previa.
En el caso de los segmentos que tienen versiones de objetos activas y no actuales, las solicitudes de objetos no se aplican a las versiones no actuales, a menos que se incluya explícitamente un número de generación en la solicitud. Esto significa que, en el caso de una solicitud general que use condiciones previas, la solicitud fallará si la versión publicada no coincide con la condición previa, independientemente de si una versión no actual coincide con las condiciones previas.
Por lo general, debe usar las condiciones previas de generación y metageneración en lugar de las condiciones previas de ETag. Los números de generación y metageneración registran todas las actualizaciones de los objetos, incluidos los cambios en los metadatos, lo que ofrece una garantía mayor que las etiquetas ETag. Además, los números de generación y metageneración son coherentes en todas las APIs, mientras que los ETag no lo son.
Las condiciones previas no se pueden usar en las subidas multiparte de la API XML. Si intentas hacerlo, se producirá un error
400 NotImplemented
.
Coste de las condiciones previas
En muchas arquitecturas que utilizan precondiciones, debes enviar una solicitud de metadatos de objeto antes de la solicitud principal para determinar el número de generación o metageneración actual:
- Una solicitud adicional significa que puedes duplicar la parte de la red de la latencia general de la operación añadiendo un viaje de ida y vuelta adicional, lo que puede ser un factor importante en las operaciones sensibles a la latencia.
- Una solicitud adicional conlleva un cargo por operación y, en la mayoría de los casos, un cargo por red.
En función de tu aplicación, hay formas de reducir los efectos de usar precondiciones, como las siguientes:
- Almacenar localmente los números de generación y metageneración de tus objetos para que ya sepas los números correctos que debes usar en tu condición previa.
- Tener conocimientos sobre la aplicación para saber qué objetos se han creado recientemente, de modo que ya sepas cuándo usar la condición previa
if-generation-match:0
.
Ejemplo: usar una condición previa
En el siguiente ejemplo se usa la precondición de coincidencia de generación en una solicitud para subir un objeto. Para que se pueda procesar la solicitud, debe haber un objeto almacenado en el segmento con el nombre especificado y el número de generación del objeto debe coincidir con el número proporcionado en la condición previa:
Línea de comandos
Usa la marca --if-generation-match
junto con el comando normal:
gcloud storage cp OBJECT_LOCATION gs://DESTINATION_BUCKET_NAME --if-generation-match=GENERATION
Donde:
GENERATION
es el número de generación del objeto que quieres sustituir. Por ejemplo,1122334455667788
.OBJECT_LOCATION
es la ruta local a tu objeto. Por ejemplo,Desktop/dog.png
.DESTINATION_BUCKET_NAME
es el nombre del contenedor al que sube el objeto. Por ejemplo,my-bucket
.
API JSON
Tener instalada e inicializadala CLI de gcloud, que te permite generar un token de acceso para el encabezado
Authorization
.Usa
cURL
para llamar a la API JSON con una solicitud dePOST
Object:curl -X POST --data-binary @OBJECT_LOCATION \ -H "Authorization: Bearer $(gcloud auth print-access-token)" \ -H "Content-Type: OBJECT_CONTENT_TYPE" \ "https://storage.googleapis.com/upload/storage/v1/b/BUCKET_NAME/o?uploadType=media&name=OBJECT_NAME"&ifGenerationMatch=GENERATION"
Donde:
OBJECT_LOCATION
es la ruta local a tu objeto. Por ejemplo,Desktop/dog.png
.OBJECT_CONTENT_TYPE
es el tipo de contenido del objeto. Por ejemplo,image/png
.BUCKET_NAME
es el nombre del segmento al que subes el objeto. Por ejemplo,my-bucket
.OBJECT_NAME
es el nombre que quieres dar al objeto. Por ejemplo,dog.png
.GENERATION
es el número de generación del objeto que quieres sustituir. Por ejemplo,1122334455667788
.
API XML
Tener instalada e inicializadala CLI de gcloud, que te permite generar un token de acceso para el encabezado
Authorization
.Usa
cURL
para llamar a la API XML con una solicitud dePUT
Object:curl -X PUT --data-binary @OBJECT_LOCATION \ -H "Authorization: Bearer $(gcloud auth print-access-token)" \ -H "Content-Type: OBJECT_CONTENT_TYPE" \ -H "x-goog-if-generation-match: GENERATION" \ "https://storage.googleapis.com/BUCKET_NAME/OBJECT_NAME"
Donde:
OBJECT_LOCATION
es la ruta local a tu objeto. Por ejemplo,Desktop/dog.png
.OBJECT_CONTENT_TYPE
es el tipo de contenido del objeto. Por ejemplo,image/png
.GENERATION
es el número de generación del objeto que quieres sustituir. Por ejemplo,1122334455667788
.BUCKET_NAME
es el nombre del segmento al que subes el objeto. Por ejemplo,my-bucket
.OBJECT_NAME
es el nombre que quieres dar al objeto. Por ejemplo,dog.png
.
Situaciones en las que se pueden usar las condiciones previas
En los siguientes casos prácticos se analizan las condiciones de carrera y se muestran ejemplos de almacenamiento en caché que se benefician del uso de las condiciones previas.
Reintentos de varias solicitudes
Cloud Storage es un sistema distribuido. Como las solicitudes pueden fallar debido a las condiciones de la red o del servicio, la forma recomendada de reintentar los errores es con interrupción exponencial. Sin embargo, debido a la naturaleza de los sistemas distribuidos, a veces estos reintentos pueden provocar comportamientos sorprendentes.
Supongamos que quieres eliminar un objeto, file.txt
, almacenado en uno de tus segmentos. Después, quieres añadir un objeto nuevo con el mismo nombre al segmento. Para ello, debes enviar una solicitud de eliminación para eliminar el objeto. Sin embargo, una condición de red, como que un router intermedio pierda la conectividad temporalmente, impide que la solicitud llegue a Cloud Storage y no recibes ninguna respuesta.
Como no has recibido ninguna respuesta a la primera solicitud, envías una segunda solicitud de eliminación del objeto, que se completa correctamente, y recibes una respuesta que confirma la eliminación. Un minuto después, subes un nuevo file.txt
y la subida se completa correctamente.
Se produce una condición de carrera si el router que ha perdido la conectividad la recupera posteriormente y envía tu solicitud de eliminación original, que parecía perdida, a Cloud Storage. Cuando la solicitud llega a Cloud Storage, se completa correctamente porque hay un nuevo file.txt
. Cloud Storage envía una respuesta que no recibes porque tu cliente ha dejado de escucharla.
No solo se elimina el archivo nuevo, al contrario de lo que pretendías, sino que tampoco te das cuenta de que se ha eliminado por segunda vez.
En el siguiente diagrama se muestra lo que ha ocurrido:
Evitar la condición de carrera
Para evitar que se produzca la situación anterior, debe empezar obteniendo los metadatos de file.txt
para determinar su generación actual. A continuación, usa la generación en una condición previa de coincidencia de generación que incluyes como parte de la solicitud de eliminación. La condición previa asegura que solo se elimine el objeto con ese número de generación específico, independientemente de cuándo llegue la solicitud de eliminación a Cloud Storage o de cuántas veces se envíe la solicitud de eliminación con la condición previa. Cualquier intento no intencionado de eliminar una generación diferente de file.txt
fallará con el código de respuesta 412 Precondition Failed
.
Como las interrupciones de red similares podrían provocar condiciones de carrera en la solicitud de subida que sigue a la solicitud de eliminación, puedes evitar muchas de estas condiciones de carrera usando el valor 0
en una precondición de coincidencia de generación incluida en la solicitud de subida. Si se usa esta condición previa, se asegura de que los reintentos de la subida no escriban el objeto por error dos veces, ya que la condición previa permite que la solicitud se lleve a cabo solo si no hay ninguna generación actual del objeto.
Si se cumplen estas condiciones previas, protegerá sus datos para que no se pierdan accidentalmente al realizar las solicitudes de eliminación y carga. Esto se puede ver en el siguiente diagrama:
Asociación de metadatos de objetos
Los datos y los metadatos de un objeto son entidades independientes que, en conjunto, definen el objeto en Cloud Storage. Como existen por separado, es posible que los datos del objeto cambien mientras trabajas con los metadatos del objeto.
Considera los siguientes casos:
Quieres descargar los metadatos y los datos de un objeto, que deben recuperarse de Cloud Storage en dos solicitudes independientes. Primero solicitas los metadatos del objeto, pero antes de que puedas solicitar los datos del objeto, un proceso o un usuario independiente sustituye el objeto. Tu solicitud de datos del objeto sigue siendo correcta, pero ahora tienes los metadatos del objeto antiguo y los datos del objeto nuevo.
Quieres actualizar los metadatos de un objeto, por lo que recuperas los metadatos actuales del objeto para determinar su estado. Antes de poder enviar la solicitud para actualizar los metadatos con las modificaciones que quieras, un proceso o un usuario independiente sustituye el objeto. Tu solicitud para cambiar los metadatos del nuevo objeto se sigue realizando correctamente, pero ahora está asociada a datos de objeto diferentes a los que querías.
Evitar la condición de carrera
Para evitar que se produzcan estas situaciones, debe usar el número de generación que se devuelve en la solicitud inicial de metadatos del objeto y, a continuación, usar este valor en una condición previa de coincidencia de generación en la segunda solicitud. De esta forma, se asegura de que los metadatos coincidan correctamente con los datos o de que la segunda solicitud falle con un código de respuesta 412 Precondition Failed
, lo que le permitirá solicitar los metadatos correctos del nuevo objeto.
Si le preocupa que los metadatos del objeto puedan cambiar entre la primera y la segunda solicitud, también puede copiar el número de metageneración que se encuentra en la solicitud inicial y usarlo en una condición previa de coincidencia de metageneración en la segunda solicitud.
Antigüedad de la copia local
En los casos en los que tenga una copia local de un objeto almacenado en Cloud Storage, a menudo querrá que su copia local esté actualizada con la copia almacenada en su segmento. Sin embargo, si el objeto almacenado en tu contenedor no cambia, no querrás perder tiempo ni recursos descargándolo de nuevo, sobre todo si el objeto es grande.
Para evitar descargas innecesarias de contenido que aún está actualizado, puede usar el número de generación de su copia local como valor en una condición previa de generación no coincidente, que debe incluir en su solicitud de descarga:
Si los datos de tu contenedor siguen coincidiendo con tu copia local, los números de generación coincidirán, lo que provocará que falle la condición previa. Como resultado, la solicitud general falla y se devuelve una respuesta
304 Not Modified
, y los datos no se descargan innecesariamente.Si los datos de su contenedor han cambiado, los números de generación no coinciden y la condición previa se cumple. Esto significa que la solicitud general se procesa con normalidad y se descarga la versión actualizada del contenido.
Siguientes pasos
- Consulta información sobre los números de generación y metageneración.
- Obtener los metadatos de un objeto, como su número de generación.
- Consulta información sobre la coherencia en Cloud Storage.
- Consulta información sobre las operaciones condicionalmente idempotentes que deben usar precondiciones.