Compartir datos entre varios servidores a través de AWS S3

 

 

 

  • Implemente rápidamente. Implementar inteligentemente
  • ¡Registro!

  • Índice
    1. Creando el cubo
    2. Configurar los permisos de usuario
    3. Conexión a AWS a través del SDK
    4. Carga y descarga de archivos
    5. Mostrar el archivo directamente desde S3
    6. Listado de archivos
    7. Conclusión

    Al crear un formulario de varios pasos en el que se carga y manipula un archivo, si la aplicación se ejecuta en varios servidores detrás de un balanceador de carga, entonces debemos asegurarnos de que el archivo esté disponible durante toda la ejecución del proceso, para cualquiera que sea. El servidor maneja el proceso en cada paso. En este artículo, resolveremos este problema creando un repositorio accesible para todos los servidores donde cargar los archivos, basado en AWS S3.

     

    Al proporcionar alguna funcionalidad para procesar un archivo cargado por el usuario, el archivo debe estar disponible para el proceso durante toda la ejecución. Una simple operación de cargar y guardar no presenta problemas. Sin embargo, si además el archivo debe manipularse antes de guardarse y la aplicación se ejecuta en varios servidores detrás de un equilibrador de carga, entonces debemos asegurarnos de que el archivo esté disponible para cualquier servidor que esté ejecutando el proceso en cada momento.

    Por ejemplo, una funcionalidad de varios pasos "Cargar su avatar de usuario" puede requerir que el usuario cargue un avatar en el paso 1, lo recorte en el paso 2 y finalmente lo guarde en el paso 3. Después de cargar el archivo en un servidor en el paso 1, el archivo debe estar disponible para cualquier servidor que maneje la solicitud de los pasos 2 y 3, que puede ser o no el mismo que el del paso 1.

    Un enfoque ingenuo sería copiar el archivo cargado en el paso 1 a todos los demás servidores, de modo que el archivo esté disponible en todos ellos. Sin embargo, este enfoque no sólo es extremadamente complejo sino también inviable: por ejemplo, si el sitio se ejecuta en cientos de servidores, de varias regiones, entonces no se puede lograr.

    Una posible solución es habilitar "sesiones fijas" en el equilibrador de carga, que siempre asignará el mismo servidor para una sesión determinada. Luego, los pasos 1, 2 y 3 serán manejados por el mismo servidor, y el archivo cargado en este servidor en el paso 1 seguirá ahí para los pasos 2 y 3. Sin embargo, las sesiones fijas no son completamente confiables: si entre los pasos 1 y 2 ese servidor falló, entonces el equilibrador de carga tendrá que asignar un servidor diferente, lo que alterará la funcionalidad y la experiencia del usuario. Del mismo modo, asignar siempre el mismo servidor para una sesión puede, en circunstancias especiales, provocar tiempos de respuesta más lentos por parte de un servidor sobrecargado.

     

    Una solución más adecuada es mantener una copia del archivo en un repositorio accesible para todos los servidores. Luego, después de cargar el archivo en el servidor en el paso 1, este servidor lo cargará en el repositorio (o, alternativamente, el archivo podría cargarse en el repositorio directamente desde el cliente, sin pasar por el servidor); el servidor que maneja el paso 2 descargará el archivo del repositorio, lo manipulará y lo cargará allí nuevamente; y finalmente el servidor que maneja el paso 3 lo descargará del repositorio y lo guardará.

    En este artículo, describiré esta última solución, basada en una aplicación de WordPress que almacena archivos en el Servicio de almacenamiento simple (S3) de Amazon Web Services (AWS) (una solución de almacenamiento de objetos en la nube para almacenar y recuperar datos), que opera a través del SDK de AWS.

    Nota 1: Para una funcionalidad simple como recortar avatares, otra solución sería omitir completamente el servidor e implementarlo directamente en la nube a través de funciones Lambda . Pero dado que este artículo trata sobre cómo conectar una aplicación que se ejecuta en el servidor con AWS S3, no consideramos esta solución.

    Nota 2: Para poder utilizar AWS S3 (o cualquier otro de los servicios de AWS) necesitaremos tener una cuenta de usuario. Amazon ofrece aquí un nivel gratuito durante 1 año, que es suficiente para experimentar con sus servicios.

    Nota 3: Existen complementos de terceros para cargar archivos desde WordPress a S3. Uno de esos complementos es WP Media Offload (la versión lite está disponible aquí ), que proporciona una gran característica: transfiere sin problemas los archivos cargados en la biblioteca multimedia a un depósito S3, lo que permite desacoplar el contenido del sitio (como todo lo que se encuentra en /wp-content/uploads) del código de la aplicación. Al desacoplar el contenido y el código, podemos implementar nuestra aplicación de WordPress usando Git (de lo contrario no podemos, ya que el contenido subido por el usuario no está alojado en el repositorio de Git) y alojar la aplicación en múltiples servidores (de lo contrario, cada servidor necesitaría mantener una copia de todo el contenido subido por el usuario).

    Creando el cubo

    Al crear el depósito, debemos prestar atención al nombre del depósito: cada nombre de depósito debe ser globalmente único en la red de AWS, por lo que aunque nos gustaría llamar a nuestro depósito con algo simple como "avatares", es posible que ese nombre ya esté en uso. , entonces podremos elegir algo más distintivo como “avatares-nombre-de-mi-empresa”.

     

    También necesitaremos seleccionar la región donde se encuentra el depósito (la región es la ubicación física donde se encuentra el centro de datos, con ubicaciones en todo el mundo).

    La región debe ser la misma donde está desplegada nuestra aplicación, para que el acceso a S3 durante la ejecución del proceso sea rápido. De lo contrario, es posible que el usuario tenga que esperar segundos adicionales antes de cargar/descargar una imagen hacia/desde una ubicación distante.

    Nota: Tiene sentido utilizar S3 como solución de almacenamiento de objetos en la nube sólo si también utilizamos el servicio de Amazon para servidores virtuales en la nube, EC2 , para ejecutar la aplicación. Si por el contrario confiamos en alguna otra empresa para alojar la aplicación, como Microsoft Azure o DigitalOcean , entonces también deberíamos utilizar sus servicios de almacenamiento de objetos en la nube. De lo contrario, nuestro sitio sufrirá una sobrecarga debido a que los datos viajan entre las redes de diferentes empresas.

    En las capturas de pantalla a continuación veremos cómo crear el depósito donde cargar los avatares de los usuarios para recortarlos. Primero nos dirigimos al panel de S3 y hacemos clic en "Crear depósito":

    Panel de control de S3, que muestra todos nuestros depósitos existentes. ( Vista previa grande )

    Luego escribimos el nombre del depósito (en este caso, “avatars-smashing”) y elegimos la región (“UE (Frankfurt)”):

    Creando un depósito en S3. ( Vista previa grande )

    Solo el nombre del depósito y la región son obligatorios. Para los siguientes pasos podemos mantener las opciones predeterminadas, así que damos clic en “Siguiente” hasta finalmente hacer clic en “Crear depósito”, y con eso ya tendremos el depósito creado.

    Configurar los permisos de usuario

    Al conectarnos a AWS a través del SDK, se nos pedirá que ingresemos nuestras credenciales de usuario (un par de ID de clave de acceso y clave de acceso secreta), para validar que tenemos acceso a los servicios y objetos solicitados. Los permisos de usuario pueden ser muy generales (un rol de "administrador" puede hacer todo) o muy granulares, otorgando permiso únicamente para las operaciones específicas necesarias y nada más.

    Como regla general, cuanto más específicos sean los permisos que concedamos, mejor, para evitar problemas de seguridad . Al crear el nuevo usuario, necesitaremos crear una política, que es un documento JSON simple que enumera los permisos que se le otorgarán al usuario. En nuestro caso, nuestros permisos de usuario otorgarán acceso a S3, para "destrozar avatares", para las operaciones de "Put" (para cargar un objeto), "Get" (para descargar un objeto) y "List" ( para enumerar todos los objetos en el depósito), lo que da como resultado la siguiente política:

    { "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": [ "s3:Put*", "s3:Get*", "s3:List*" ], "Resource": [ "arn:aws:s3:::avatars-smashing", "arn:aws:s3:::avatars-smashing/*" ] } ]}

    En las capturas de pantalla siguientes, podemos ver cómo agregar permisos de usuario. Debemos ir al panel de Gestión de Identidades y Accesos (IAM) :

     

    Panel de control de IAM, que enumera todos los usuarios que hemos creado. ( Vista previa grande )

    En el panel de control hacemos clic en “Usuarios” e inmediatamente después en “Agregar Usuario”. En la página Agregar usuario, elegimos un nombre de usuario (“crop-avatars”) y marcamos “Acceso programático” como tipo de acceso, que proporcionará la ID de la clave de acceso y la clave de acceso secreta para conectarse a través del SDK:

    Agregar un nuevo usuario. ( Vista previa grande )

    Luego hacemos clic en el botón “Siguiente: Permisos”, hacemos clic en “Adjuntar políticas existentes directamente” y hacemos clic en “Crear política”. Esto abrirá una nueva pestaña en el navegador, con la página Crear política. Hacemos clic en la pestaña JSON e ingresamos el código JSON para la política definida anteriormente:

    Crear una política que otorgue operaciones 'Obtener', 'Publicar' y 'Lista' en el depósito 'destructor de avatares'. ( Vista previa grande )

    Luego hacemos clic en Revisar política, le damos un nombre (“CropAvatars”) y finalmente hacemos clic en Crear política. Una vez creada la política, volvemos a la pestaña anterior, seleccionamos la política CropAvatars (es posible que necesitemos actualizar la lista de políticas para verla), hacemos clic en Siguiente: Revisar y finalmente en Crear usuario. Una vez hecho esto, finalmente podremos descargar el ID de la clave de acceso y la clave de acceso secreta (tenga en cuenta que estas credenciales están disponibles para este momento único; si no las copiamos o descargamos ahora, tendremos que crear un nuevo par). ): Salarios y Sueldos medios 2023

    Una vez creado el usuario, se nos ofrece un tiempo único para descargar las credenciales. ( Vista previa grande )

    Conexión a AWS a través del SDK

    El SDK está disponible en una gran variedad de idiomas. Para una aplicación de WordPress, necesitamos el SDK para PHP que se puede descargar desde aquí , y las instrucciones sobre cómo instalarlo están aquí .

    Una vez que tengamos el depósito creado, las credenciales de usuario listas y el SDK instalado, podemos comenzar a cargar archivos a S3.

    Carga y descarga de archivos

    Para mayor comodidad, definimos las credenciales del usuario y la región como constantes en el archivo wp-config.php:

    define ('AWS_ACCESS_KEY_ID', '...'); // Your access key iddefine ('AWS_SECRET_ACCESS_KEY', '...'); // Your secret access keydefine ('AWS_REGION', 'eu-central-1'); // Region where the bucket is located. This is the region id for "EU (Frankfurt)"

    En nuestro caso, estamos implementando la funcionalidad de recortar avatar, para la cual los avatares se almacenarán en el depósito "destructor de avatares". Sin embargo, en nuestra aplicación podemos tener varios otros depósitos para otras funcionalidades, que requieren ejecutar las mismas operaciones de carga, descarga y listado de archivos. Por lo tanto, implementamos los métodos comunes en una clase abstracta AWS_S3y obtenemos las entradas, como el nombre del depósito definido a través de la función get_bucket, en las clases secundarias de implementación.

     

    // Load the SDK and import the AWS objectsrequire 'vendor/autoload.php';use AwsS3S3Client;use AwsExceptionAwsException;// Definition of an abstract classabstract class AWS_S3 { protected function get_bucket() { // The bucket name will be implemented by the child class return ''; }}

    La S3Clientclase expone la API para interactuar con S3. Creamos una instancia solo cuando es necesario (mediante inicialización diferida) y guardamos una referencia para $this-s3Clientseguir usando la misma instancia:

    abstract class AWS_S3 { // Continued from above... protected $s3Client; protected function get_s3_client() { // Lazy initialization if (!$this-s3Client) { // Create an S3Client. Provide the credentials and region as defined through constants in wp-config.php $this-s3Client = new S3Client([ 'version' = '2006-03-01', 'region' = AWS_REGION, 'credentials' = [ 'key' = AWS_ACCESS_KEY_ID, 'secret' = AWS_SECRET_ACCESS_KEY, ], ]); } return $this-s3Client; }}

    Cuando trabajamos $fileen nuestra aplicación, esta variable contiene la ruta absoluta al archivo en el disco (por ejemplo /var/app/current/wp-content/uploads/users/654/leo.jpg), pero al cargar el archivo en S3 no debemos almacenar el objeto en la misma ruta. En particular, debemos eliminar el bit inicial relativo a la información del sistema ( /var/app/current) por razones de seguridad, y opcionalmente podemos eliminar el /wp-contentbit (dado que todos los archivos se almacenan en esta carpeta, esta es información redundante), manteniendo solo la ruta relativa al archivo. ( /uploads/users/654/leo.jpg). Convenientemente, esto se puede lograr eliminando todo lo que sigue WP_CONTENT_DIRde la ruta absoluta. Las funciones get_filesiguientes get_file_relative_pathcambian entre las rutas de archivo absoluta y relativa:

    abstract class AWS_S3 { // Continued from above... function get_file_relative_path($file) { return substr($file, strlen(WP_CONTENT_DIR)); } function get_file($file_relative_path) { return WP_CONTENT_DIR.$file_relative_path; }}

    Al cargar un objeto en S3, podemos establecer a quién se le otorga acceso al objeto y el tipo de acceso, realizado a través de los permisos de la lista de control de acceso (ACL). Las opciones más comunes son mantener el archivo privado (ACL = “privado”) y hacerlo accesible para su lectura en Internet (ACL = “lectura pública”). Debido a que necesitaremos solicitar el archivo directamente desde S3 para mostrárselo al usuario, necesitamos ACL = “lectura pública”:

    abstract class AWS_S3 { // Continued from above... protected function get_acl() { return 'public-read'; }}

    Finalmente, implementamos los métodos para cargar un objeto y descargar un objeto del depósito S3:

    abstract class AWS_S3 { // Continued from above... function upload($file) { $s3Client = $this-get_s3_client(); // Upload a file object to S3 $s3Client-putObject([ 'ACL' = $this-get_acl(), 'Bucket' = $this-get_bucket(), 'Key' = $this-get_file_relative_path($file), 'SourceFile' = $file, ]); } function download($file) { $s3Client = $this-get_s3_client(); // Download a file object from S3 $s3Client-getObject([ 'Bucket' = $this-get_bucket(), 'Key' = $this-get_file_relative_path($file), 'SaveAs' = $file, ]); }}

    Luego, en la clase secundaria de implementación definimos el nombre del depósito:

     

    class AvatarCropper_AWS_S3 extends AWS_S3 { protected function get_bucket() { return 'avatars-smashing'; }}

    Finalmente, simplemente creamos una instancia de la clase para cargar o descargar los avatares desde S3. Además, al pasar de los pasos 1 al 2 y del 2 al 3, debemos comunicar el valor de $file. Podemos hacer esto enviando un campo “file_relative_path” con el valor de la ruta relativa a $filetravés de una operación POST (no pasamos la ruta absoluta por razones de seguridad: no es necesario incluir la información “/var/www/current” para que lo vean los forasteros):

    // Step 1: after the file was uploaded to the server, upload it to S3. Here, $file is known$avatarcropper = new AvatarCropper_AWS_S3();$avatarcropper-upload($file);// Get the file path, and send it to the next step in the POST$file_relative_path = $avatarcropper-get_file_relative_path($file);// ...// --------------------------------------------------// Step 2: get the $file from the request and download it, manipulate it, and upload it again$avatarcropper = new AvatarCropper_AWS_S3();$file_relative_path = $_POST['file_relative_path'];$file = $avatarcropper-get_file($file_relative_path);$avatarcropper-download($file);// Do manipulation of the file// ...// Upload the file again to S3$avatarcropper-upload($file);// --------------------------------------------------// Step 3: get the $file from the request and download it, and then save it$avatarcropper = new AvatarCropper_AWS_S3();$file_relative_path = $_REQUEST['file_relative_path'];$file = $avatarcropper-get_file($file_relative_path);$avatarcropper-download($file);// Save it, whatever that means// ...

    Mostrar el archivo directamente desde S3

    Si queremos mostrar el estado intermedio del archivo después de la manipulación en el paso 2 (por ejemplo, el avatar del usuario después de recortarlo), entonces debemos hacer referencia al archivo directamente desde S3; la URL no pudo apuntar al archivo en el servidor ya que, una vez más, no sabemos qué servidor manejará esa solicitud.

    A continuación, agregamos una función get_file_url($file)que obtiene la URL de ese archivo en S3. Si utiliza esta función, asegúrese de que la ACL de los archivos cargados sea de “lectura pública”; de lo contrario, el usuario no podrá acceder a ella.

    abstract class AWS_S3 { // Continue from above... protected function get_bucket_url() { $region = $this-get_region(); // North Virginia region is simply "s3", the others require the region explicitly $prefix = $region == 'us-east-1' ? 's3' : 's3-'.$region; // Use the same scheme as the current request $scheme = is_ssl() ? 'https' : 'http'; // Using the bucket name in path scheme return $scheme.'://'.$prefix.'.amazonaws.com/'.$this-get_bucket(); } function get_file_url($file) { return $this-get_bucket_url().$this-get_file_relative_path($file); }}

    Luego, simplemente podemos obtener la URL del archivo en S3 e imprimir la imagen:

    printf( "img src='%s'", $avatarcropper-get_file_url($file));

    Listado de archivos

    Si en nuestra aplicación queremos permitir que el usuario vea todos los avatares subidos previamente, podemos hacerlo. Para eso, introducimos una función get_file_urlsque enumera la URL de todos los archivos almacenados en una ruta determinada (en términos de S3, se llama prefijo):

    abstract class AWS_S3 { // Continue from above... function get_file_urls($prefix) { $s3Client = $this-get_s3_client(); $result = $s3Client-listObjects(array( 'Bucket' = $this-get_bucket(), 'Prefix' = $prefix )); $file_urls = array(); if(isset($result['Contents']) count($result['Contents']) 0 ) { foreach ($result['Contents'] as $obj) { // Check that Key is a full file path and not just a "directory" if ($obj['Key'] != $prefix) { $file_urls[] = $this-get_bucket_url().$obj['Key']; } } } return $file_urls; }}

    Luego, si almacenamos cada avatar en la ruta "/users/${user_id}/", al pasar este prefijo obtendremos la lista de todos los archivos:

    $user_id = get_current_user_id();$prefix = "/users/${user_id}/";foreach ($avatarcropper-get_file_urls($prefix) as $file_url) { printf( "img src='%s'", $file_url );}

    Conclusión

    En este artículo, exploramos cómo emplear una solución de almacenamiento de objetos en la nube para que actúe como un repositorio común para almacenar archivos para una aplicación implementada en múltiples servidores. Para la solución, nos centramos en AWS S3 y procedimos a mostrar los pasos necesarios para integrarse en la aplicación: crear el depósito, configurar los permisos de usuario y descargar e instalar el SDK. Finalmente, explicamos cómo evitar problemas de seguridad en la aplicación y vimos ejemplos de código que demuestran cómo realizar las operaciones más básicas en S3: cargar, descargar y enumerar archivos, que apenas requerían unas pocas líneas de código cada una. La simplicidad de la solución demuestra que integrar los servicios de la nube en la aplicación no es difícil y también lo pueden lograr desarrolladores que no tienen mucha experiencia con la nube.

    (rb, ra, yk, il)Explora más en

    • Actuación
    • backend
    • Tutoriales
    • javascript





    Tal vez te puede interesar:

    1. ¿Deberían abrirse los enlaces en ventanas nuevas?
    2. 24 excelentes tutoriales de AJAX
    3. 70 técnicas nuevas y útiles de AJAX y JavaScript
    4. Más de 45 excelentes recursos y repositorios de fragmentos de código

    Compartir datos entre varios servidores a través de AWS S3

    Compartir datos entre varios servidores a través de AWS S3

    Implemente rápidamente. Implementar inteligentemente ¡Registro! Índice Creando el cubo

    programar

    es

    https://aprendeprogramando.es/static/images/programar-compartir-datos-entre-varios-servidores-a-traves-de-aws-s3-956-0.jpg

    2024-05-20

     

    Compartir datos entre varios servidores a través de AWS S3
    Compartir datos entre varios servidores a través de AWS S3

    Si crees que alguno de los contenidos (texto, imagenes o multimedia) en esta página infringe tus derechos relativos a propiedad intelectual, marcas registradas o cualquier otro de tus derechos, por favor ponte en contacto con nosotros en el mail [email protected] y retiraremos este contenido inmediatamente

     

     

    Top 20