Introducción

La creciente popularidad de JavaScript ha traído consigo varios cambios, incluyendo la superficie del desarrollo web, ya que hoy en día es radicalmente diferente. Las cosas que podemos hacer en la web hoy, con JavaScript ejecutando en el servidor, como también en el navegador, eran difíciles de imaginar hace varios años, o se encapsulan dentro de entornos “sandbox” como Flash y Java.

Antes de indagar en Node.js, es posible que desees leer acerca de los beneficios de utilizar JavaScript a través del stack, que unifica el idioma y el formato de datos (JSON), lo que permite reutilizar de manera óptima los recursos del desarrollador. Como esto es más un beneficio de JavaScript que de Node.js específicamente, no hablaremos mucho de ello aquí. Sin embargo, es una ventaja clave para la incorporación de Node en su pila.

Tal y como Wikipedia sugiere: “Node.js es un entorno en tiempo de ejecución multiplataforma, de código abierto, para la capa del servidor (pero no limitándose a ello) basado en el lenguaje de programación ECMAScript, asíncrono, con I/O de datos en una arquitectura orientada a eventos y basado en el motor V8 de Google.” Más allá de eso, vale la pena señalar que el creador de Node.js, Ryan Dahl fue destinado a crear sitios web en tiempo real con función de inserción, “inspirado por aplicaciones como Gmail”. En Node.js, dio a los desarrolladores una herramienta para trabajar en la no-bloqueante, event-driven I/O paradigma.

Después de dos décadas de protocolo sin estado basado en el paradigma de petición-respuesta de protocolos, finalmente tenemos aplicaciones web en tiempo real, las conexiones bidireccionales.

En una frase: Node.js brilla en aplicaciones web de tiempo real empleando la tecnología push a través de Websockets. ¿Qué es tan revolucionario acerca de eso? Bueno, después de más de 20 años de webs apátridas basadas en el paradigma de petición-respuesta de apátridas, finalmente tenemos aplicaciones web en tiempo real, las conexiones bidireccionales, donde tanto el cliente como el servidor pueden iniciar la comunicación, lo que les permite intercambiar datos libremente. Esto está en contraste con el paradigma de respuesta web típica, donde el cliente siempre inicia la comunicación. Además, todo se basa en el Open Web Stack (HTML, CSS y JS) que se ejecuta en el puerto estándar 80.

Podríamos argumentar que hemos tenido este formato durante años en forma de Flash y Applets de Java, pero en realidad, eran simplemente un entorno de Sandbox usando la web como un protocolo de transporte para ser entregado al cliente. Además, se ejecutan en aislamiento y a menudo operan a través de un puerto no estándar, el cual podía tener requisitos adicionales para su uso.

Con todas sus ventajas, Node.js ahora juega un papel crítico en la pila de tecnología de muchas empresas de alto perfil que dependen de sus exclusivas ventajas.

En este artículo voy a analizar no sólo cómo estas ventajas son obtenidas, sino también por qué es posible que desees utilizar Node.js y por qué no usar algunos de los clásicos modelos de aplicaciones web como ejemplos.

¿Cómo funciona?

La idea principal de Node.js: uso no-bloqueante, event-driven I/O, permanecer ligero y eficiente en la superficie del uso intensivo de datos en tiempo real de las aplicaciones que se ejecutan en dispositivos distribuidos.

Increíble ¿no?

Lo que en realidad significa es que Node.js no es nueva plataforma que dominará el mundo del desarrollo web. Al contrario, se trata de una plataforma que llena una necesidad en particular.

Y este entendimiento es absolutamente esencial. Definitivamente no quieres usar Node.js para operaciones intensivas de CPU; de hecho, utilizándolo para el cálculo pesado anulará casi todas sus ventajas. Donde Node REALMENTE destaca es en la construcción rápida y escalable de aplicaciones de red, debido a que es capaz de manejar un gran número de conexiones simultáneas con alto rendimiento, lo que equivale a una alta escalabilidad.

Cómo funciona internamente es bastante interesante. Frente a las tradicionales técnicas de servicio web donde cada conexión (solicitud) genera un nuevo subproceso, retomando la RAM del sistema y finalmente a tope a la cantidad de RAM disponible, Node.js opera en un solo subproceso, no utiliza el bloqueo de llamadas de E/S, lo que le permite admitir decenas de miles de conexiones simultáneas (celebrada en el caso de loop).

Un cálculo rápido: suponiendo que cada subproceso tiene un potencial acompañado de 2 MB de memoria, el cual se ejecutará dentro de un sistema con 8 GB de RAM nos pone a un máximo teórico de 4.000 conexiones simultáneas, además del costo de cambio de contexto entre subprocesos. Ese es el escenario que se suelen tratar con técnicas de servicio web tradicional. Evitando todo eso, Node.js alcanza niveles de escalabilidad de más de 1M de conexiones simultáneas (como una prueba de concepto).

Existe por supuesto, la posibilidad de compartir un único subproceso entre todas las solicitudes de clientes, convirtiéndola en una falla potencial de escribir aplicaciones Node.js. En primer lugar, el cómputo pesado podría estancarse y provocar problemas para todos los clientes (más sobre esto más adelante) como las peticiones entrantes, las cuales serían bloqueadas hasta que dicho cálculo se haya completado. En segundo lugar, los desarrolladores necesitan ser muy cuidadosos en no permitir una excepción burbujeante hacia el núcleo (la superior), lo que provocaría que la instancia de Node.js se terminase (efectivamente bloqueando el programa).

La técnica utilizada para evitar excepciones transfiere los errores a la llamada como llamada de parámetros (en lugar de tirar de ellos, al igual que en otros entornos). Inclusive si alguna excepción llegase a burbujear, existen varias herramientas disponibles para supervisar el proceso de Node y realizar la recuperación necesaria en caso de una emergencia(aunque no serás capaz de recuperar las sesiones de los usuarios); siendo la emergencia más común el módulo Forever, o un enfoque diferente con herramientas de sistema externo advenedizo y monit.

NPM: El Node Package Manager

Cuando hablamos de Node.js, una cosa que definitivamente no debe omitirse es integrarlo en el apoyo de la gestión de paquetes utilizando la herramienta NPM que viene por defecto con cada instalación de Node.js. La idea de los módulos NPM es muy similar a la de Ruby Gemas: un conjunto de componentes reutilizables disponibles públicamente a través de una fácil instalación a través de un repositorio en línea, con la versión y la dependencia de gestión.

Una lista completa de los paquetes de módulos puede encontrarse en el sitio web de NPM Https://npmjs.org/ o acceder utilizando la herramienta de la CLI de NPM que automáticamente se instala con Node.js. El módulo es un ecosistema abierto a todos, y cualquiera puede publicar su propio módulo que será incluido en el repositorio de NPM. Una breve introducción a la NPM (un poco viejo, pero sigue siendo válido) se puede encontrar en http://howtonode.org/introduction-to-npm.

Algunos de los más populares hoy en día son módulos de NPM:

  • express - Express.js, inspirado en el framework de desarrollo web para Node.js, y el estándar de facto para la mayoría de aplicaciones Node.js de hoy en día.

  • connect - Connect es un servidor HTTP extensible framework para Node.js, que proporciona una colección de alto rendimiento de plugins conocidos como middleware; sirve como fundamento para expresar.

  • socket.io y sockjs - Componente del servidor de los dos componentes de websockets más comúnes en la actualidad.

  • Jade - Uno de los más populares motores de plantillas, inspirados por HAML, un defecto en Express.js.

  • mongo y mongojs - mongoDB wrappers para proporcionar la API para bases de datos de objetos MongoDB en Node.js.

  • redis - Redis biblioteca cliente.

  • coffee-script - CoffeeScript compilador que permite a los desarrolladores escribir sus programas Node.js con café.

  • Underscore (lodash, lazy) - La biblioteca de utilidades más popular de JavaScript, empaquetados para ser utilizado con Node.js, así como sus dos contrapartes, que prometen mejorar el rendimiento mediante la adopción de un enfoque de aplicación ligeramente diferente.

  • forever - Probablemente la utilidad más común para asegurar que un determinado Node script se ejecuta continuamente. Mantiene su proceso de Node.js en la producción y en el rostro de cualquier fallo inesperado.

La lista es interminable. Hay toneladas de paquetes realmente útiles y disponible para todos (sin ofender a los que he omitido aquí).

Ejemplos en donde Node.js debe utilizarse:

Chat

Es la forma más típica en tiempo real y una multi-aplicación de usuario. Desde IRC (en el día), a través de muchos propietarios y protocolos abiertos girando en puertos no estándar, con la capacidad de instrumentar todo en Node.js con websockets corriendo sobre el puerto estándar 80.

La aplicación de chat es realmente perfecta para Node.js: es ligera, tiene un alto tráfico de datos intensivos (pero baja/procesamiento de cómputo) y es una aplicación que funciona en dispositivos distribuidos. También es un gran caso de uso para el aprendizaje, ya que es demasiado simple, pero al mismo tiempo que cubre la mayoría de herramientas que puedes utilizar en una típica aplicación Node.js.

Vamos a tratar de describir cómo funciona.

En el ejemplo más sencillo, tenemos una sola sala de chat en nuestro sitio web donde la gente puede venir e intercambiar mensajes ya sea con una persona o con varias. Por ejemplo, supongamos que tenemos tres personas en el sitio todos los conectados a nuestro tablero de mensajes.

En el lado del servidor, tenemos un simple Express.js que implementa dos cosas: 1) Obtener un controlador de solicitudes ‘/’ que sirve la página web que contiene un tablero de mensajes y un botón ‘Enviar’ para inicializar el nuevo mensaje de entrada, y 2) un servidor websockets que escucha los mensajes emitidos por los clientes de websocket.

En el cliente, tenemos una página HTML con un par de controladores, uno para el Send’ evento de clic de botón, que recoge el mensaje de entrada y lo envía hacia abajo el websocket, y otro que escucha los mensajes entrantes del nuevo cliente de websockets (es decir, los mensajes enviados por otros usuarios, que el servidor ahora quiere que el cliente muestre).

Cuando uno de los clientes envía un mensaje, lo que sucede es lo siguiente:

  1. El explorador atrapa el clic con el botón ‘Send’ a través de un controlador de JavaScript que recoge el valor del campo de entrada (es decir, el texto del mensaje), y emite un mensaje websocket websocket utilizando el cliente conectado a nuestro servidor (inicializado en la inicialización de la página web).

  2. El componente del servidor de la conexión websocket recibe el mensaje y lo reenvía a todos los demás clientes conectados mediante el método de difusión.

  3. Todos los clientes reciben el mensaje como un mensaje de inserción a través de un componente de cliente websockets que se ejecuta dentro de la página web. Ellos entonces recogen el contenido del mensaje y actualizan la página web en lugar de anexar el nuevo mensaje a la junta.

Este es el ejemplo más sencillo. Para una solución más robusta, podrías utilizar un caché simple basado en la Redis store. O incluso en una solución más avanzada, una cola de mensajes para gestionar el enrutamiento de mensajes a los clientes y un mecanismo de entrega más robusto que pueda cubrir pérdidas de conexión temporal o almacenar mensajes para clientes registrados mientras está desconectado. Pero independientemente de las mejoras que realices, Node.js todavía operará bajo los mismos principios básicos: reaccionar a eventos, manejo de muchas conexiones simultáneas, y mantenimiento en la fluidez de la experiencia del usuario.

API en la parte superior de un OBJETO DB

Aunque Node.js realmente destaca entre aplicaciones de tiempo real, es una adaptación natural para exponer los datos de objeto DBs (p. ej. MongoDB). El almacenamiento de datos JSON permite que Node.js funcione sin la desigualdad de impedancia y la conversión de datos.

Por ejemplo, si estás utilizando Rails, tendrías que convertir los datos de JSON para modelos binarios y después exponer nuevamente como JSON sobre HTTP cuando el dato es consumido por el backbone.js, angulares, etc., o incluso llamadas AJAX jQuery normal. Con Node.js, simplemente puedes exponer tus objetos JSON con una API REST para que el cliente consuma. Además, no necesitas preocuparte por la conversión entre JSON y cualquier otra cosa al leer o escribir desde su base de datos (si estás usando MongoDB). En conclusión, puedes evitar la necesidad de realizar varias conversiones mediante un formato de la serialización de datos uniformes a través del cliente, servidor y base de datos.

Entradas en espera

Si estás recibiendo una gran cantidad de datos concurrentes, tu base de datos puede ahogarse. Como se ha descrito más arriba, Node.js puede manejar fácilmente las conexiones simultáneas al mismo tiempo. Pero debido a que el acceso a la base de datos es una operación de bloqueo (en este caso), nos topamos con problemas. La solución es reconocer el comportamiento del cliente antes de que los datos se escriban en la verdadera base de datos.

Con ese enfoque, el sistema mantiene su sensibilidad bajo una carga pesada, lo que es particularmente útil cuando el cliente no necesita una firme confirmación de la correcta escritura de datos. Ejemplos típicos incluyen: el registro o la escritura de datos de seguimiento de usuario, procesamiento en lotes que no se utilizan hasta un momento posterior, así como las operaciones que no necesitan ser reflejadas al instante (como actualizar el recuento de Likes en Facebook) donde la coherencia final (tan a menudo utilizadas en el mundo NoSQL) es aceptable.

Los datos se ponen en cola a través de algún tipo de caché o de Message Queue Server (por ejemplo, infraestructura, RabbitMQ, ZeroMQ) y resumido por un proceso separado escrito en lote, cálculo o procesamiento intensivo servicios backend, escrito en un mejor desempeño de plataforma para tales tareas. Un comportamiento similar puede implementarse con otros lenguajes/frameworks, pero no con el mismo hardware o con el mismo alto, para mantener su rendimiento.

En resumen: con Node, puedes empujar la base de datos escrita a un lado y tratar con ella más tarde, para proceder como que si esta hubiera sido exitosa.

Transmisión de Datos

En plataformas web más tradicional, las peticiones y respuestas HTTP son tratadas como eventos aislados; de hecho, son realmente corrientes. Esta observación puede ser utilizada en Node.js para construir algunas características interesantes. Por ejemplo, es posible procesar archivos mientras están siendo cargados, ya que los datos entran a través de un arroyo, y pueden ser procesados en una línea de moda. Esto podría hacerse en tiempo real para la codificación de audio o vídeo, como proxy entre diferentes fuentes de datos (véase la sección siguiente).

PROXY

Node PROXY.js es empleado como un servidor proxy el cual puede manejar una gran cantidad de conexiones simultáneas en un modo de no-bloqueo. Es especialmente útil para proxy de diferentes servicios con distintos tiempos de respuesta, o para la recopilación de datos desde varios puntos de origen.

Un ejemplo: considere una aplicación de servidor que se comunica con recursos de terceros, extrayendo datos de diferentes fuentes, o almacenando los activos como imágenes y vídeos a servicios terceros de Cloud.

Aunque existen servidores de proxy dedicados, utilizando en su lugar Node podría ser útil si su infraestructura de servidores proxy es inexistente o si necesita una solución para el desarrollo local. Con esto, quiero decir que se podría construir una aplicación del lado del cliente con un servidor de desarrollo Node.js para activos como proxy/stubbing solicitudes de API, mientras que en la producción manejarías tales interacciones con un dedicado servicio de proxy (nginx, HAProxy, etc.).

Brokerage-Dashboard del Stock Trader

Volvamos al nivel de aplicación. Otro ejemplo donde domina el software de escritorio, sin embargo podría ser fácilmente reemplazado con una web en tiempo real es la solución comercial de los agentes de software; se utiliza para realizar el seguimiento de los precios de las existencias, realizar cálculos y análisis técnico y crear los gráficos y diagramas.

Cambiar a tiempo real es una solución basada en la web que permitiría a los corredores cambiar fácilmente de estaciones de trabajo o lugares de trabajo. Pronto podríamos comenzar a verlos en la playa de Florida, Ibiza…o Bali.

Panel de Supervisión de Aplicaciones

Otro caso de uso común en qué el Node-con-web-sockets encaja perfectamente es el siguiente: el seguimiento de los visitantes del sitio web y la visualización de sus interacciones a tiempo real. (Si estás interesado, esta idea ya se produjo por Colibrí).

Podrías recopilar estadísticas a tiempo real desde tu usuario, o inclusive subir al siguiente nivel mediante la introducción de interacciones selectivas con tus visitantes abriendo un canal de comunicación cuando llegan a un punto específico en el embudo. (Si estás interesado, esta idea ya se produjo por CANDDi).

Imagina cómo podría mejorar tu negocio si supieras lo que estuvieran haciendo tus visitantes en tiempo real; si pudieras visualizar sus interacciones. Con el tiempo real, ahora puedes tomar dos vías de Node.js.

Ahora el panel de monitorización del sistema, vamos a conocer la perspectiva de la infraestructura de las cosas. Imagínate, por ejemplo, un proveedor de SaaS que le quiere ofrecer a sus usuarios un servicio de supervisión (por ejemplo, la página de GitHub). Con el evento Node.js-loop, podemos crear un poderoso tablero basado en la web que comprueba los servicios de los estados de manera asíncrona y envía datos a los clientes usando Websockets.

Tanto internos (intra-empresa) como también los de los servicios públicos de los Estados, pueden ser reportados en vivo y a tiempo real utilizando esta tecnología. Empuja esta idea un poco más lejos y trata de imaginar un centro de operaciones de red (NOC) en aplicaciones de supervisión de un operador de telecomunicaciones, cloud/red/proveedor de servicios de hosting, o alguna institución financiera, todos se ejecutan en el open web stack respaldado por Node.js y Websockets en lugar de Java y/o applets de Java.

Nota: No intentes construir sistemas a tiempo real duros en Node (es decir, sistemas que requieran tiempos de respuesta coherentes). Erlang es probablemente una mejor elección para esta clase de aplicación.

Donde node.js se puede utilizar

Aplicaciones Web del lado del Servidor

Node.js con Express.js también pueden ser utilizados para crear aplicaciones web clásicas en el servidor. Sin embargo, mientras sea posible, este paradigma en petición-respuesta de Node.js sería llevar alrededor de HTML, no es el más típico de los casos de uso. Hay argumentos para estar a favor y en contra de este enfoque. Aquí están algunos hechos a considerar:

Pros:

  • Si tu aplicación no tiene ningún cálculo intensivo del CPU, puedes construir en Javascript de arriba a abajo, inclusive a nivel de base de datos si utilizas el objeto de almacenamiento JSON como MongoDB DB. Esto facilita el desarrollo (incluyendo la contratación) significativamente.

  • Los Crawlers reciben una respuesta totalmente HTML, que es mucho más SEO-friendly, digamos, una sola página o en una aplicación de Websockets app se ejecuta sobre Node.js.

Cons:

  • Un CPU de cálculo intensivo bloqueará la receptividad del Node.js, por lo que una plataforma de roscado es un mejor enfoque. Alternativamente, podrías intentar escalar el cómputo [*].

  • Utilizando Node.js con una base de datos relacional es aún bastante doloroso (leer más abajo para ver más detalles). Hazte un favor y escoge cualquier otro entorno como Rails, Django, o ASP.NET MVC si estás intentando realizar operaciones relacionales.

Donde Node.js no debe usarse

En el lado del Servidor de Aplicaciones Web deon una Relación DB detrás

Comparando Node.js con Express.js en contra de Ruby on Rails, por ejemplo, hay una decisión clara en favor de esta última cuando se trata de acceso a datos relacionales.El DB relacional con herramientas para Node.js está aún en sus primeras etapas; es bastante prematuro y por ende no tan agradable trabajar con ello. Por otro lado, Rails automáticamente proporciona datos de configuración del acceso a la derecha de la caja junto con el esquema de base de datos y herramientas de soporte de migraciones de otras Gemas (con doble sentido). Rails y su homólogo marco han madurado y probado que Active Record Data Mapper recopila implementaciones del acceso a datos y que echarás de menos si intentas replicarlo con JavaScript puro.[*]

Aún, si estás muy inclinado a permanecer en JS todo el camino, mantén un ojo sobre Sequelize ORM y Nodo2 ya que ambos son todavía inmaduros, pero eventualmente pueden alcanzar a los demás lenguajes de programación.

[*] es posible y no es raro que utilices el Node únicamente como un front-end, manteniendo su back-end de Rails y su fácil acceso a una base de datos relacional.

Heavy Server-Side/Procesamiento de Cálculo

Cuando se trata de cómputo pesado, Node.js no es la mejor plataforma. Definitivamente no quieres construir un servidor de cálculo Fibonacci en Node.js. En general, cualquier operación de uso intensivo de CPU anula todas las ventajas de rendimiento y bloquearía cualquier petición entrante de un subproceso.

Como se dijo anteriormente, Node.js es Single-threaded y utiliza un único núcleo del CPU. Cuando se trata de la adición de la concurrencia en un servidor multi-core, hay algunos trabajos realizados por el Node básico en la forma de un módulo cluster [ref: http://nodejs.org/api/cluster.html]. También puedes ejecutar varias instancias del servidor Node.js bastante fácil detrás de un proxy inverso a través de nginx.

Con la agrupación, debes descargar todo el cómputo pesado para procesar un fondo escrito dentro de un entorno más apropiado, y que ellos se comuniquen a través de Message Queue Server como RabbitMQ.

Aunque tu procesamiento en segundo plano puede ejecutarse en el mismo servidor inicialmente, este enfoque tiene el potencial de una muy alta escalabilidad. Los servicios de procesamiento de fondo podrían ser fácilmente distribuidos al trabajador independientemente de de servidores sin la necesidad de configurar las cargas de los distintos servidores web.

Por supuesto utilizarías el mismo enfoque en otras plataformas también, pero con Node.js puedes conseguir un alto reqs/s del que hemos hablado, ya que cada petición es una tarea pequeña y un manejo muy rápido y eficientemente.

Conclusión

Hemos hablado del Node.js desde una teoría práctica, comenzando con sus objetivos y ambiciones, y terminando con sus dulces manchas y escollos. Cuando las personas tienen problemas con el Node, casi siempre deducen al hecho de que el bloqueo de operaciones son la raíz de todo mal. El 99% del abuso del Node viene como consecuencia directa.

Recuerda: el Node.js nunca fue creado para resolver el problema de escalado de computación. Fue creado para resolver el problema de escalado de E/S, lo que lo hace muy bien.

¿Por qué usar Node.js? Si el caso de uso no contiene operaciones intensivas del CPU ni el acceso a los recursos de bloqueo, puedes aprovechar los beneficios de Node.js y disfrutar de aplicaciones de red rápidas y escalables. Bienvenido a la web en tiempo real.

Acerca del autor

Tomislav Capan, Croacia

Tomislav es un ingeniero de software, consultor técnico y arquitecto con más de 10 años de experiencia. Se especializa en Full-Slack y es altamente capacitado en JavaScript y Node.jr. Tiene experiencia con trabajo en C#, Java y Ruby. Es ágil practicante en Kanban que ama colaborar en proyectos de desarrollo.

About the author

Tomislav Capan, Croatia
member since February 12, 2013
Tomislav is a software engineer, technical consultant, and architect with over 10 years of experience. He specializes in full-stack, highly scalable, real-time JavaScript and Node.js applications, with past experience in C#, Java, and Ruby. He is an agile Kanban practitioner who loves to collaborate on development projects. [click to continue...]
Hiring? Meet the Top 10 Freelance Node.js Developers for Hire in December 2016

Comments

comments powered by Disqus
Subscribe
The #1 Blog for Engineers
Get the latest content first.
No spam. Just great engineering and design posts.
The #1 Blog for Engineers
Get the latest content first.
Thank you for subscribing!
You can edit your subscription preferences here.
Trending articles
Relevant technologies
About the author
Tomislav Capan
JavaScript Developer
Tomislav is a software engineer, technical consultant, and architect with over 10 years of experience. He specializes in full-stack, highly scalable, real-time JavaScript and Node.js applications, with past experience in C#, Java, and Ruby. He is an agile Kanban practitioner who loves to collaborate on development projects.