Cloud Intelligence™Cloud Intelligence™

Cloud Intelligence™

AWS S3 Multipart Uploads: cómo evitar costos ocultos por cargas inconclusas

By Avi KeinanJun 18, 20215 min read

Esta página también está disponible en English, Deutsch, Français, Italiano, 日本語 y Português.

Cuando subes un archivo de más de 5 Mb a un bucket de AWS S3, el AWS SDK/CLI divide automáticamente la carga en varias solicitudes HTTP PUT. Es más eficiente, permite reanudar cargas y, si alguna parte falla, esa parte se vuelve a subir sin detener el progreso general.

No dejes restos después de tus cargas a AWS S3.

Sin embargo, las cargas multipart esconden una trampa:

Si la carga se interrumpió antes de completarse, te cobran por las partes ya subidas hasta que las elimines.

El resultado es un aumento oculto en los costos de almacenamiento que no salta a la vista.

Sigue leyendo para descubrir cómo identificar las partes cargadas y cómo reducir costos cuando hay cargas multipart sin terminar.

Imagen del post de Jeff Barr.

¿Cómo encuentro las partes cargadas en la consola de AWS S3?

Acá viene lo interesante: no se pueden ver estos objetos en la consola de AWS S3.

Para este artículo, creé un bucket de S3 y subí un archivo de 100 Gb. Detuve la carga después de que se subieran 40 Gb.

Al entrar a la consola de S3, vi que había 0 objetos en el bucket y que la consola no mostraba los 40 Gb que ya se habían subido (multipart).

Luego hice clic en la pestaña Metrics y vi que el tamaño del bucket era de 40 Gb.

Las métricas actualizadas pueden tardar varias horas en aparecer.

Es decir, aunque no veas el objeto en la consola porque la carga no terminó, te siguen cobrando por las partes ya subidas.

¿Cómo se aborda esto en la práctica?

Hablé con varios colegas en distintas empresas que manejan cuentas de AWS con un consumo mensual considerable de AWS S3.

La mayoría tenía entre +100 Mb y hasta +10 Tb de cargas multipart sin terminar. El consenso fue claro: a mayor uso de S3 y cuanto más antigua la cuenta, más objetos incompletos se acumulan.

Cómo calcular el tamaño multipart de un solo objeto

Primero, desde el AWS CLI, lista los objetos multipart actuales con el siguiente comando:

aws s3api list-multipart-uploads --bucket <bucket-name>

Esto devuelve una lista de todos los objetos incompletos que tienen varias partes:

Después, lista todos los objetos de la carga multipart con el comando list-parts usando el valor de "UploadId":

aws s3api list-parts --upload-id 5IBStnpJl6REH... --bucket <bucket-name> --key example.exe

Luego, suma el tamaño (en bytes) de todas las partes cargadas y convierte el resultado a Gb usando JQ (procesador JSON de línea de comandos):

jq '.Parts | map(.Size/1024/1024/1024) | add'

Si quieres eliminar manualmente un objeto de carga multipart, puedes ejecutar:

aws s3api abort-multipart-upload --bucket <bucket-name> --key example.exe --upload-id 5IBStnpJl6REH...

¿Cómo dejar de pagar por cargas multipart sin terminar?

A nivel de bucket, puedes crear una regla de ciclo de vida (lifecycle rule) que elimine automáticamente los objetos multipart incompletos al cabo de unos días.

"Una configuración de S3 Lifecycle es un conjunto de reglas que definen las acciones que Amazon S3 aplica a un grupo de objetos" (documentación de AWS).

A continuación, dos soluciones:

  • Una solución manual para buckets existentes.
  • Una solución automática al crear un nuevo bucket.

Eliminar cargas multipart en buckets existentes

En esta solución vas a crear una regla de ciclo de vida para eliminar los objetos multipart antiguos en un bucket existente.

Atención: ten cuidado al definir una regla de Lifecycle. Un error en la definición puede borrar objetos existentes en tu bucket.

Primero, abre la consola de AWS S3, selecciona el bucket que quieras y entra a la pestaña Management.

En Lifecycle rules, haz clic en Create lifecycle rule.

Ponle nombre a la regla de ciclo de vida y define el alcance de la regla para todos los objetos del bucket.

Marca la casilla "I acknowledge that this rule will apply to all objects in the bucket".

Después, ve a Lifecycle rule actions y marca la casilla "Delete expired delete markers or incomplete multipart upload".

Marca la casilla "Delete incomplete multipart uploads" y configura el número de días según tus necesidades (en mi opinión, tres días son suficientes para terminar las cargas pendientes).

Una vez completados los pasos anteriores, los archivos multipart cargados se eliminarán, aunque no de inmediato (tarda un poco).

Dos cosas a tener en cuenta:

  • Las operaciones de eliminación son gratuitas.
  • Una vez definida la regla de ciclo de vida, no se cobra por los datos que vayan a eliminarse.

Crear una regla de ciclo de vida para nuevos buckets

En esta solución vas a crear una regla de ciclo de vida que se aplica automáticamente cada vez que se crea un nuevo bucket.

Esto se logra con un script sencillo de automatización en lambda que se dispara cada vez que se crea un bucket. Esta función lambda implementa una regla de ciclo de vida que elimina todos los objetos multipart con más de 3 días de antigüedad.

Nota: como EventBridge solo se ejecuta en la región donde se crea, debes desplegar la función lambda en cada región en la que operes.

S3 Management Console — Ver video

¿Cómo implementar esta automatización?

  1. Activa un trail de AWS CloudTrail. Una vez configurado el trail, puedes usar AWS EventBridge para disparar una función Lambda.
  2. Crea una nueva función lambda con Python 3.8 como Runtime.
  3. Pega el siguiente código (Github gist):

4. Selecciona create function.

5. Vuelve a la parte superior de la página y, en Trigger, selecciona 'Add trigger'. En la configuración del trigger, elige EventBridge.

Luego crea una nueva regla y asígnale un nombre y una descripción.

6. Elige Event pattern en el tipo de regla y selecciona Simple Storage Services (S3) y AWS API call via CloudTrail en las dos casillas siguientes.

En la casilla Detail, elige CreateBucket en Operation.

Baja y haz clic en el botón Add.

7. Baja hasta la pestaña Basic settings, selecciona Edit → IAM role y adjunta la policy que aparece a continuación.

Esta policy permitirá que la función lambda cree una configuración de lifecycle en todos los buckets de la cuenta de AWS.

{
    "Version": "2012-10-17",
    "Statement": [\
        {\
            "Sid": "VisualEditor0",\
            "Effect": "Allow",\
            "Action": "s3:PutLifecycleConfiguration",\
            "Resource": "*"\
        }\
    ]
}

8. Crea un bucket para comprobar que la función lambda funciona correctamente.

9. ¡Listo! A partir de ahora, cada vez que crees un nuevo bucket (en la región configurada), la función lambda creará automáticamente un lifecycle para ese bucket.

¡Gracias por leer! Para mantenerte al día, síguenos en el DoiT Engineering Blog, el canal de DoiT en LinkedIn y el canal de DoiT en Twitter. Para explorar oportunidades laborales, visita https://careers.doit-intl.com.