La estructura tradicional de la pila de software de las aplicaciones en línea de Taobao es Nginx + Velocity + Java, es decir::
En este sistema, Nginx reenvía la solicitud a una aplicación Java, que maneja la transacción y genera los datos en la página final utilizando una plantilla de velocidad.
Después de introducir Node.js, inevitablemente enfrentaremos los siguientes problemas:
Cómo diseñar la estructura de topología de la pila de tecnología y cómo elegir el método de implementación, ¿se considera científico y razonable? Después de completar el proyecto, ¿cómo dividir el tráfico, que es conveniente y rápido para la operación y el mantenimiento? Al encontrar problemas en línea, ¿cómo eliminar el peligro lo antes posible y evitar mayores pérdidas? ¿Cómo garantizar la salud de la aplicación y administrarla en el nivel de programación de equilibrio de carga? Topología del sistema
Según nuestro pensamiento y práctica sobre la separación de los extremos frontales y traseros (ii), según la exploración de la plantilla de los extremos delanteros y traseros, la velocidad debe ser reemplazada por Node.js, de modo que esta estructura se convierta en:
Este es, por supuesto, el objetivo ideal. Sin embargo, la primera introducción de la capa Node.js en la pila tradicional es un nuevo intento después de todo. Para estar seguros, decidimos solo habilitar nuevas tecnologías en la página de favoritos (shoucang.taobao.com/item_collect.htm) de nuestros favoritos, mientras que otras páginas continúan utilizando soluciones tradicionales. Es decir, Nginx determina el tipo de página de la solicitud y determina si la solicitud debe enviarse a Node.js o Java. Entonces, la estructura final se convirtió en:
Plan de implementación
La estructura anterior parece estar bien, pero de hecho el nuevo problema todavía está esperando el frente. En la estructura tradicional, Nginx y Java se implementan en el mismo servidor. Nginx escucha al puerto 80 y se comunica con Java escuchando el puerto 7001 en el bit alto. Ahora que se introduce Node.js, se necesita un nuevo proceso que necesita ejecutar un puerto de escucha. ¿Deberían implementarse Node.js en la misma máquina con Nginx + Java, o Node.js se implementará en un clúster separado?
Comparemos las características de los dos métodos:
Taobao Favorites es una aplicación con un PV promedio diario de decenas de millones, que tiene requisitos extremadamente altos para la estabilidad (de hecho, la inestabilidad en línea de cualquier producto es inaceptable). Si adopta la misma solución de implementación de clúster, solo necesita distribuir archivos una vez y reiniciar dos veces para completar la versión. En caso de que necesite retroceder, solo necesita operar el paquete de referencia una vez. En términos de rendimiento, la misma implementación de clúster también tiene algunas ventajas teóricas (aunque el ancho de banda y la latencia de la intranet son muy optimistas). En cuanto a la relación de uno a muchos o muchos a uno, en teoría puede ser utilizado más completamente por el servidor, pero en comparación con los requisitos de estabilidad, este punto no es tan urgente de resolver. Entonces, en la transformación de los favoritos, elegimos la misma solución de implementación de clúster.
Escala de grises
Para garantizar la máxima estabilidad, esta transformación no eliminó directamente el código de velocidad por completo. Hay casi 100 servidores en el clúster de aplicaciones. Utilizamos el servidor como granularidad e introducimos gradualmente el tráfico. En otras palabras, aunque los procesos Java + Node.js se ejecutan en todos los servidores, si existen reglas de reenvío correspondientes en NGINX determina si la solicitud para obtener la colección de bebés en este servidor se procesará a través de Node.js. La configuración de Nginx es:
ubicación = "/item_collect.htm" {proxy_pass http://127.0.0.1:6001; # Node.js Proceso de escucha de escucha}Solo los servidores que han agregado esta regla Nginx permitirán que Node.js maneje la solicitud correspondiente. A través de la configuración de Nginx, es muy conveniente y rápido para aumentar y disminuir el tráfico en escala de grises, y el costo es muy bajo. Si encuentra problemas, puede revertir la configuración de Nginx directamente e volver instantáneamente a la estructura de pila de tecnología tradicional para aliviar el peligro.
Cuando lanzamos por primera vez, solo habilitamos esta regla en dos servidores, lo que significa que menos del 2% del tráfico en línea se procesa en Node.js, y las solicitudes del tráfico restante todavía se producen por velocidad. En el futuro, el tráfico aumentará gradualmente según la situación, y finalmente en la tercera semana, todos los servidores estarán habilitados. En este punto, las páginas de recolección de productos con tráfico 100% en el entorno de producción se presentan mediante Node.js (puede verificar el código fuente para buscar la palabra clave Node.js).
cambiar
El proceso de escala de grises no es suave. Antes de cortar el flujo en su totalidad, encontré algunos problemas, ya sea grandes o pequeños. La mayor parte del negocio está relacionado con negocios específicos, y de lo que vale la pena aprender es una trampa relacionada con los detalles técnicos.
Cheque de salud
En la arquitectura tradicional, el sistema de programación de equilibrio de carga iniciará una solicitud get cada segundo a una URL específica en el puerto 80 de cada servidor, y determinará si el servidor funciona normalmente en función de si el código de estado HTTP devuelto es 200 . Si se solicita el tiempo de espera después de 1 o el código de estado HTTP no es 200 , no se introduce tráfico en el servidor para evitar problemas en línea.
La ruta a esta solicitud es Nginx -> java -> nginx, lo que significa que mientras se devuelva 200 , el Nginx y Java de este servidor están en un estado saludable. Después de introducir Node.js, esta ruta se convierte en nginx -> node.js -> java -> node.js -> nginx. El código correspondiente es:
var http = require ('http'); app.get ('/status.taobao', function (req, res) {http.get ({host: '127.1', puerto: 7001, path: '/status.taobao'}, function (res) {res.send (res.statuscode);}). on ('error', function (err) {logger.error (res.sendsend); });Sin embargo, durante el proceso de prueba, se descubrió que cuando Node.js reenvía tales solicitudes, tardó varios segundos o incluso diez segundos para que el lado de Java regrese una vez cada seis o siete veces. Esto hará que el sistema de programación de equilibrio de carga piense que se produjo una anormalidad en el servidor y luego corta el tráfico, pero de hecho, el servidor puede funcionar normalmente. Obviamente, este es un gran problema.
Después de una búsqueda, descubrí que de forma predeterminada, Node.js usará la clase HTTP Agent para crear conexiones HTTP. Esta clase implementa un grupo de conexión de socket. El límite superior predeterminado del número de conexiones para cada host + par de puertos es 5. Al mismo tiempo, las solicitudes iniciadas por HTTP Agent incluyen Connection: Keep-Alive de forma predeterminada, lo que resulta en que la conexión devuelta no se libere a tiempo, y las solicitudes iniciadas más tarde solo se pueden colocar.
Hay tres soluciones finales:
Desactive HTTP Agent , es decir, agregue agent: false al llamar al método get , y el código final es:
var http = require ('http'); app.get ('/status.taobao', function (req, res) {http.get ({host: '127.1', puerto: 7001, agente: falso, path: '/status.taobao'}, function (res) {res.send (res.statuscode);}). res.send (404); Establezca el límite superior del número de socket global de objetos http :
http.globalagent.maxsockets = 1000;
Cuando la solicitud regresa, se desconecta oportuna y proactivamente:
http.get (options, function (res) {}). on ("socket", function (socket) {socket.emit ("agenteRemove"); // Escuchar eventos de socket y enviar eventos de agente de agente en la devolución de llamada});En la práctica, elegimos el primer método. Después de este ajuste, no se encontraron otros problemas en el examen de salud.
combinar
La práctica de combinar Node.js con escenarios comerciales tradicionales acaba de comenzar, y todavía hay muchos puntos de optimización que vale la pena explorar en profundidad. Por ejemplo, después de que las aplicaciones Java están completamente centralizadas, ¿puede tomar la prueba de implementación de clúster para mejorar la utilización del servidor? O, ¿pueden los métodos de liberación y reversión ser más flexibles y controlables? Todos los detalles valen más investigaciones.