En este tutorial se muestra cómo crear un servicio de chat en tiempo real con varias salas mediante WebSockets con una conexión persistente para la comunicación bidireccional. Con WebSockets, tanto el cliente como el servidor pueden enviarse mensajes entre sí sin sondear el servidor para obtener actualizaciones.
Aunque puedes configurar Cloud Run para que use la afinidad de sesión, esta proporciona una afinidad de mejor esfuerzo, lo que significa que cualquier solicitud nueva se puede enrutar a otra instancia. Por lo tanto, los mensajes de los usuarios del servicio de chat deben sincronizarse en todas las instancias, no solo entre los clientes conectados a una instancia.
Descripción general del diseño
Este servicio de chat de ejemplo usa una instancia de Memorystore para Redis para almacenar y sincronizar los mensajes de los usuarios en todas las instancias. Redis usa un mecanismo Pub/Sub, que no debe confundirse con el producto Cloud Pub/Sub, para enviar datos a los clientes suscritos conectados a cualquier instancia y eliminar el sondeo HTTP para obtener actualizaciones.
Sin embargo, incluso con las actualizaciones push, cualquier instancia que se ponga en marcha solo recibirá los mensajes nuevos que se envíen al contenedor. Para cargar los mensajes anteriores, el historial de mensajes tendría que almacenarse y recuperarse de una solución de almacenamiento persistente. En este ejemplo se usa la función convencional de Redis de un almacén de objetos para almacenar en caché y recuperar el historial de mensajes.

La instancia de Redis está protegida de Internet mediante IPs privadas con acceso controlado y limitado a los servicios que se ejecutan en la misma red privada virtual que la instancia de Redis. Por lo tanto, se necesita un conector de acceso a VPC sin servidor para que el servicio de Cloud Run se conecte a Redis. Consulta más información sobre Acceso a VPC sin servidor.
Limitaciones
En este tutorial no se muestra la autenticación de usuarios finales ni el almacenamiento en caché de sesiones. Para obtener más información sobre la autenticación de usuarios finales, consulta el tutorial de Cloud Run sobre la autenticación de usuarios finales.
En este tutorial no se implementa una base de datos como Firestore para almacenar y recuperar indefinidamente el historial de mensajes de chat.
Se necesitan elementos adicionales para que este servicio de ejemplo esté listo para producción. Se recomienda usar una instancia de Redis de nivel estándar para ofrecer alta disponibilidad mediante la replicación y la conmutación por error automática.
Configurar los valores predeterminados de gcloud
Para configurar gcloud con los valores predeterminados de tu servicio de Cloud Run, sigue estos pasos:
Configura tu proyecto predeterminado:
gcloud config set project PROJECT_ID
Sustituye PROJECT_ID por el nombre del proyecto que has creado para este tutorial.
Configura gcloud para la región que hayas elegido:
gcloud config set run/region REGION
Sustituye REGION por la región de Cloud Run compatible que quieras.
Ubicaciones de Cloud Run
Cloud Run es regional, lo que significa que la infraestructura que ejecuta tus servicios de Cloud Run se encuentra en una región específica y Google la gestiona para que esté disponible de forma redundante en todas las zonas de esa región.
Cumplir tus requisitos de latencia, disponibilidad o durabilidad son factores primordiales para seleccionar la región en la que se ejecutan tus servicios de Cloud Run.
Por lo general, puedes seleccionar la región más cercana a tus usuarios, pero debes tener en cuenta la ubicación de los otros Google Cloudproductos que utiliza tu servicio de Cloud Run.
Usar Google Cloud productos juntos en varias ubicaciones puede afectar a la latencia y al coste de tu servicio.
Cloud Run está disponible en las siguientes regiones:
Con sujeción a los precios del nivel 1
asia-east1
(Taiwán)asia-northeast1
(Tokio)asia-northeast2
(Osaka)asia-south1
(Bombay, la India)europe-north1
(Finlandia)CO2 bajo
europe-north2
(Estocolmo)CO2 bajo
europe-southwest1
(Madrid)CO2 bajo
europe-west1
(Bélgica)CO2 bajo
europe-west4
(Países Bajos)CO2 bajo
europe-west8
(Milán)europe-west9
(París)CO2 bajo
me-west1
(Tel Aviv)northamerica-south1
(México)us-central1
(Iowa)CO2 bajo
us-east1
(Carolina del Sur)us-east4
(Norte de Virginia)us-east5
(Columbus)us-south1
(Dallas)CO2 bajo
us-west1
(Oregón)CO2 bajo
Con sujeción a los precios del nivel 2
africa-south1
(Johannesburgo)asia-east2
(Hong Kong)asia-northeast3
(Seúl, Corea del Sur)asia-southeast1
(Singapur)asia-southeast2
(Yakarta)asia-south2
(Delhi, la India)australia-southeast1
(Sídney)australia-southeast2
(Melbourne)europe-central2
Varsovia (Polonia)europe-west10
(Berlín)europe-west12
(Turín)europe-west2
(Londres, Reino Unido)CO2 bajo
europe-west3
(Fráncfort, Alemania)europe-west6
(Zúrich, Suiza)Bajas emisiones de CO2
me-central1
(Doha)me-central2
(Dammam)northamerica-northeast1
(Montreal)CO2 bajo
northamerica-northeast2
(Toronto)CO2 bajo
southamerica-east1
(São Paulo, Brasil)CO2 bajo
southamerica-west1
(Santiago, Chile)CO2 bajo
us-west2
(Los Ángeles)us-west3
(Salt Lake City)us-west4
(Las Vegas)
Si ya has creado un servicio de Cloud Run, puedes ver la región en el panel de control de Cloud Run de la Google Cloud consola.
Obtener el código de ejemplo
Para obtener el código de muestra que vas a usar, sigue estos pasos:
Clona el repositorio de ejemplo en tu máquina local:
Node.js
git clone https://github.com/GoogleCloudPlatform/nodejs-docs-samples.git
También puedes descargar el ejemplo como un archivo ZIP y extraerlo.
Cambia al directorio que contiene el código de ejemplo de Cloud Run:
Node.js
cd nodejs-docs-samples/run/websockets/
Información sobre el código
Socket.io es una biblioteca que permite la comunicación bidireccional en tiempo real entre el navegador y el servidor. Aunque Socket.io no es una implementación de WebSocket, sí que envuelve la función para proporcionar una API más sencilla para varios protocolos de comunicación con funciones adicionales, como una mayor fiabilidad, la reconexión automática y la difusión a todos los clientes o a un subconjunto de ellos.
Integración del lado del cliente
El cliente crea una nueva instancia de Socket para cada conexión. Como esta muestra se renderiza del lado del servidor, no es necesario definir la URL del servidor. La instancia de socket puede emitir y detectar eventos.
Integración del lado del servidor
En el lado del servidor, el servidor Socket.IO se inicializa y se adjunta al servidor HTTP. Al igual que en el lado del cliente, una vez que el servidor Socket.io establece una conexión con el cliente, se crea una instancia de socket para cada conexión, que se puede usar para emitir y recibir mensajes. Socket.io también proporciona una interfaz sencilla para crear "salas" o canales arbitrarios a los que los sockets pueden unirse y abandonar.
Socket.io también proporciona un adaptador de Redis para emitir eventos a todos los clientes, independientemente del servidor que esté sirviendo el socket. Socket.io solo usa el mecanismo Pub/Sub de Redis y no almacena ningún dato.
El adaptador Redis de Socket.io puede reutilizar el cliente Redis que se usa para almacenar el historial de mensajes de la sala. Cada contenedor creará una conexión a la instancia de Redis y Cloud Run puede crear un gran número de instancias. Es muy inferior a las 65.000 conexiones que admite Redis. Si necesitas admitir este volumen de tráfico, también debes evaluar el rendimiento del conector de acceso a VPC sin servidor.
Reconexión
Cloud Run tiene un tiempo de espera máximo de 60 minutos. Por lo tanto, debes añadir una lógica de reconexión para posibles tiempos de espera. En algunos casos, Socket.io intenta volver a conectarse automáticamente después de que se produzcan eventos de desconexión o error de conexión. No hay ninguna garantía de que el cliente vuelva a conectarse a la misma instancia.
Las instancias se conservarán si hay una conexión activa hasta que se cierren todas las solicitudes o se agote el tiempo de espera. Aunque uses la afinidades de sesión de Cloud Run, es posible que las nuevas solicitudes se equilibren de carga en contenedores activos, lo que permite que los contenedores se escalen. Si te preocupa que se conserven un gran número de contenedores después de un pico de tráfico, puedes reducir el valor máximo del tiempo de espera para que los sockets no utilizados se eliminen con más frecuencia.
Envío del servicio
Crea una instancia de Memorystore para Redis:
gcloud redis instances create INSTANCE_ID --size=1 --region=REGION
Sustituye INSTANCE_ID por el nombre de la instancia, como
my-redis-instance
, y REGION_ID por la región de todos tus recursos y servicios (por ejemplo,europe-west1
).Se asignará automáticamente a la instancia un intervalo de direcciones IP del intervalo de red de servicio predeterminado. En este tutorial se usa 1 GB de memoria para la caché local de mensajes de la instancia de Redis. Consulta más información sobre cómo determinar el tamaño inicial de una instancia de Memorystore para tu caso práctico.
Configura un conector de Acceso a VPC sin servidor:
Para conectarse a tu instancia de Redis, tu servicio de Cloud Run necesita acceso a la red VPC autorizada de la instancia de Redis.
Cada conector de VPC requiere su propia subred
/28
para colocar instancias del conector. Este intervalo de IPs no debe solaparse con ninguna reserva de direcciones IP de tu red de VPC. Por ejemplo,10.8.0.0
(/28
) funcionará en la mayoría de los proyectos nuevos, o bien puedes especificar otro intervalo de IP personalizado que no se esté usando, como10.9.0.0
(/28
). Puedes ver qué intervalos de IP están reservados en la consolaGoogle Cloud .gcloud compute networks vpc-access connectors create CONNECTOR_NAME \ --region REGION \ --range "10.8.0.0/28"
Sustituye CONNECTOR_NAME por el nombre del conector.
Este comando crea un conector en la red VPC predeterminada, igual que la instancia de Redis, con el tamaño de máquina
e2-micro
. Aumentar el tamaño de la máquina del conector puede mejorar el rendimiento del conector, pero también aumentará el coste. El conector también debe estar en la misma región que la instancia de Redis. Más información sobre cómo configurar Acceso a VPC sin servidorDefine una variable de entorno con la dirección IP de la red autorizada de tu instancia de Redis:
export REDISHOST=$(gcloud redis instances describe INSTANCE_ID --region REGION --format "value(host)")
Crea una cuenta de servicio que actúe como identidad del servicio. De forma predeterminada, no tiene más privilegios que la pertenencia al proyecto.
gcloud iam service-accounts create chat-identity gcloud projects add-iam-policy-binding PROJECT_ID \ --member=serviceAccount:chat-identity@PROJECT_ID.iam.gserviceaccount.com \ --role=roles/serviceusage.serviceUsageConsumer
Crea y despliega la imagen de contenedor en Cloud Run:
gcloud run deploy chat-app --source . \ --vpc-connector CONNECTOR_NAME \ --allow-unauthenticated \ --timeout 3600 \ --service-account chat-identity \ --update-env-vars REDISHOST=$REDISHOST
Responde
y
cuando se te pida que instales las APIs necesarias. Solo tienes que hacerlo una vez por proyecto. Responde a otras peticiones proporcionando la plataforma y la región, si no has definido valores predeterminados para estos elementos tal como se describe en la página de configuración. Más información sobre la implementación desde el código fuente
Probar la función
Para probar el servicio completo, sigue estos pasos:
En tu navegador, ve a la URL que se ha proporcionado en el paso de implementación anterior.
Añade tu nombre y una sala de chat para iniciar sesión.
Envía un mensaje a la sala.
Si decides seguir desarrollando estos servicios, recuerda que tienen acceso restringido a la gestión de identidades y accesos (IAM) al resto de Google Cloud y que tendrás que asignarles roles de IAM adicionales para acceder a muchos otros servicios.