¿Cómo evitan las arquitecturas de sistemas de microservicios los cuellos de botella de la red?


72

He estado leyendo mucho sobre arquitecturas de microservicios para aplicaciones de servidor y me he preguntado cómo el uso de la red interna no es un cuello de botella o una desventaja significativa en comparación con una arquitectura monolítica.

En aras de la precisión, aquí están mis interpretaciones de los dos términos:

  1. Arquitectura monolítica: una aplicación en un solo idioma que maneja todas las funciones, datos, etc. Un equilibrador de carga distribuye las solicitudes del usuario final a través de múltiples máquinas, cada una de las cuales ejecuta una instancia de nuestra aplicación.

  2. Arquitectura de microservicios: muchas aplicaciones (microservicios) manejan una pequeña porción de la funcionalidad y los datos. Cada microservicio expone una API común a la que se accede a través de la red (a diferencia de la comunicación entre procesos o la memoria compartida en la misma máquina). Las llamadas a la API se agrupan principalmente en el servidor para producir una página, aunque tal vez parte del trabajo lo realiza el cliente consultando microservicios individuales.

Para mi ingenua imaginación, parece que una arquitectura de microservicios utiliza un tráfico de red lento en lugar de recursos más rápidos en la misma máquina (la memoria y el disco). ¿Cómo se asegura que las consultas API a través de la red interna no disminuyan el tiempo de respuesta general?


La red interna suele ser de 1 Gbps, a veces más rápida. Piense en el tamaño promedio de la respuesta JSON de una API. ¿Cuántas de esas respuestas se pueden transmitir a través de una conexión de 1 Gbps en un segundo?
Arseni Mourzenko

3
si cree que necesita microservicios, ¡y podría hacerlo! - dos excelentes libros para preparar: amazon.com/Building-Microservices-Sam-Newman/dp/1491950358 y amazon.com/Release-It-Production-Ready-Pragmatic-Programmers/dp/…
Steven A. Lowe

@MainMa el problema no está en el ancho de banda, sino en el retraso. Y si necesita hacer un viaje de ida y vuelta, se sorprenderá del poco ancho de banda real que puede usar
Stephan Eggermont

Respuestas:


61

Las redes internas a menudo usan conexiones de 1 Gbps, o más rápido. Las conexiones o enlaces de fibra óptica permiten anchos de banda mucho más altos entre los servidores. Ahora imagine el tamaño promedio de una respuesta JSON de una API. ¿Cuántas de esas respuestas se pueden transmitir a través de una conexión de 1 Gbps en un segundo?

Realmente hagamos los cálculos. 1 Gbps es 131 072 KB por segundo. Si una respuesta JSON promedio es de 5 KB (¡lo cual es bastante!), Puede enviar 26 214 respuestas por segundo a través del cable con solo un par de máquinas . No está tan mal, ¿no?

Es por eso que la conexión de red no suele ser el cuello de botella.

Otro aspecto de los microservicios es que puede escalar fácilmente. Imagine dos servidores, uno que aloja la API y otro que la consume. Si alguna vez la conexión se convierte en el cuello de botella, simplemente agregue otros dos servidores y podrá duplicar el rendimiento.

Esto es cuando nuestras 26 214 respuestas por segundo anteriores se vuelven demasiado pequeñas para la escala de la aplicación. Agrega otros nueve pares y ahora puede atender 262 140 respuestas.

Pero volvamos a nuestro par de servidores y hagamos algunas comparaciones.

  • Si una consulta promedio no almacenada en caché a una base de datos tarda 10 ms., Está limitado a 100 consultas por segundo. 100 consultas. 26 214 respuestas. Lograr la velocidad de 26 214 respuestas por segundo requiere una gran cantidad de almacenamiento en caché y optimización (si la respuesta realmente necesita hacer algo útil, como consultar una base de datos; las respuestas de estilo "Hola Mundo" no califican).

  • En mi computadora, en este momento, DOMContentLoaded para la página de inicio de Google sucedió 394 ms. después de que se envió la solicitud. Eso es menos de 3 solicitudes por segundo. Para la página de inicio de Programmers.SE, sucedió 603 ms. después de que se envió la solicitud. Eso no es ni siquiera 2 solicitudes por segundo. Por cierto, tengo una conexión a Internet de 100 Mbps y una computadora rápida: muchos usuarios esperarán más.

    Si el cuello de botella es la velocidad de la red entre los servidores, esos dos sitios podrían literalmente hacer miles de llamadas a diferentes API mientras sirven la página.

Esos dos casos muestran que la red probablemente no será su cuello de botella en teoría (en la práctica, debe hacer los puntos de referencia y los perfiles reales para determinar la ubicación exacta del cuello de botella de su sistema particular alojado en un hardware en particular). El tiempo dedicado a hacer el trabajo real (serían consultas SQL, compresión, lo que sea) y enviar el resultado al usuario final es mucho más importante.

Piensa en bases de datos

Por lo general, las bases de datos se alojan por separado de la aplicación web que las usa. Esto puede plantear una preocupación: ¿qué pasa con la velocidad de conexión entre el servidor que aloja la aplicación y el servidor que aloja la base de datos?

Parece que hay casos en los que, de hecho, la velocidad de conexión se vuelve problemática, es decir, cuando almacena grandes cantidades de datos que no necesitan ser procesados ​​por la base de datos y que deberían estar disponibles en este momento (es decir, archivos binarios grandes). Pero tales situaciones son raras: en la mayoría de los casos, la velocidad de transferencia no es tan grande en comparación con la velocidad de procesamiento de la consulta en sí.

Cuando la velocidad de transferencia realmente importa es cuando una empresa aloja grandes conjuntos de datos en un NAS, y varios clientes acceden al NAS al mismo tiempo. Aquí es donde una SAN puede ser una solución. Dicho esto, esta no es la única solución. Los cables Cat 6 pueden soportar velocidades de hasta 10 Gbps; La unión también se puede utilizar para aumentar la velocidad sin cambiar los cables o adaptadores de red. Existen otras soluciones, que implican la replicación de datos en múltiples NAS.

Olvídate de la velocidad; pensar en la escalabilidad

Un punto importante de una aplicación web es poder escalar. Si bien el rendimiento real es importante (porque nadie quiere pagar por servidores más potentes), la escalabilidad es mucho más importante, ya que le permite lanzar hardware adicional cuando sea necesario.

  • Si tiene una aplicación no particularmente rápida, perderá dinero porque necesitará servidores más potentes.

  • Si tiene una aplicación rápida que no puede escalar, perderá clientes porque no podrá responder a una demanda creciente.

Del mismo modo, las máquinas virtuales fueron percibidas hace una década como un gran problema de rendimiento. De hecho, alojar una aplicación en un servidor frente a alojarla en una máquina virtual tuvo un importante impacto en el rendimiento. Si bien la brecha es mucho más pequeña hoy, todavía existe.

A pesar de esta pérdida de rendimiento, los entornos virtuales se hicieron muy populares debido a la flexibilidad que brindan.

Al igual que con la velocidad de la red, puede encontrar que VM es el cuello de botella real y dada su escala real, ahorrará miles de millones de dólares al alojar su aplicación directamente, sin las VM. Pero esto no es lo que sucede para el 99.9% de las aplicaciones: su cuello de botella está en otro lugar, y el inconveniente de una pérdida de unos pocos microsegundos debido a la VM se compensa fácilmente con los beneficios de la abstracción y escalabilidad del hardware.


Claro, podemos decir que las respuestas JSON son pequeñas, pero ¿qué pasa con su cantidad ? Siento que un sitio web con mucha carga tendría más tráfico de red en una arquitectura de microservicio que una arquitectura monolítica (donde el único tráfico de red es hacia / desde el servidor de la base de datos). El almacenamiento en caché puede ayudar, pero en tiempo real y / o contenido generado dinámicamente, no sé qué tan lejos llegaría el almacenamiento en caché.
James Mishra

@JamesMishra: Edité mi respuesta para abordar sus inquietudes.
Arseni Mourzenko

Tu respuesta es perfecta . No solo respondiste todas las objeciones que se me ocurren, sino que respondiste objeciones en las que no pensé.
James Mishra

55
Mis 2 centavos del mundo real: un sistema compuesto por microservicios muy habladores puede sufrir problemas de rendimiento simplemente debido a una red bloqueada. El almacenamiento en caché y un diseño basado en Event Stream es tu amigo en tales casos. Además de la red, la CPU y la memoria, un sistema basado en microservicios también necesita incorporar resistencia en su diseño: ¿qué sucede si un microservicio está inactivo? ¿Cómo construir reintentos, transacciones distribuidas, autocuración, monitoreo? Sugiero buscar "debes ser tan alto para usar microservicios"
Sudhanshu Mishra

44
Corríjame si me equivoco, pero que yo sepa, si tiene una red de 1 Gbps, significa que, en teoría, puede enviar 1 Gb de datos por segundo a través de esa red. Independientemente del número de conexiones. Cuanto mayor sea el número de conexiones, menor será el ancho de banda para cada conexión. Por lo tanto, su límite real sin actualizar su red para admitir un mayor ancho de banda sería de 26.214 respuestas por segundo. Agregar más servidores no aumentará el ancho de banda de su red. Si un solo clúster puede escupir esa cantidad de tráfico, agregar más servidores que generen aún más datos congestionará su red.
Sebbe

7

Creo que estás leyendo demasiado en la parte 'micro'. No significa reemplazar cada clase con un servicio de red, sino crear componentes de una aplicación monolítica en componentes de tamaño razonable, cada uno de los cuales se ocupa de un aspecto de su programa. Los servicios no se comunican entre sí, por lo que en el peor de los casos, ha dividido una solicitud de red grande en varias más pequeñas. De todos modos, los datos devueltos no serán significativamente diferentes de los que recibe (aunque podría devolver más datos y consolidarlos en el cliente)


3
"Los servicios no se hablarán entre sí". Me imagino que los microservicios podrían tener dependencias compartidas (¿autenticación, tal vez?) Que uno podría separar en otro microservicio. LDAP, en cierto sentido, es un microservicio de autenticación e imagino que todos los demás microservicios le hablan. O ... ¿la autenticación solo ocurre una vez? ¿Cómo verifica cada microservicio los permisos contra la autenticación para evitar ataques de acceso directo a objetos?
James Mishra

2
@JamesMishra bueno ... depende. La última vez que utilicé la arquitectura de microservicios, cada servicio era totalmente independiente de los demás por motivos de seguridad (pero también por razones de silos corporativos). Auth fue manejado por cada uno de manera diferente, aunque controlado por una política de arquitectura. Aún así, no hay razón para que no puedan hablar con auth, por ejemplo, o simplemente tener autenticación basada en una biblioteca. Pero ... estaba tratando de decir que no deberían pasar muchas llamadas entre ellos, no que no deberían consumir servicios como clientes.
gbjbaanb

@JamesMishra, la autenticación es a menudo su propio servicio en estos entornos, por lo que cada servicio debería hacer uso de eso en lugar de hacer una implementación completa ellos mismos.
Paul

2

Al estructurar su código y acceso a los recursos de manera que el sistema resultante pueda ser lo suficientemente flexible como para ejecutarse como una aplicación monolítica o distribuida a través de la configuración. Si abstrae el mecanismo de comunicación detrás de alguna interfaz común y construye su sistema con concurrencia en mente, puede optimizar fácilmente todo después de haber perfilado su sistema y encontrado los cuellos de botella reales.


Un ejemplo para explicar lo que supongo que @mortalapeman significa: tiene una interfaz java / c # IProductAvailibitiy donde todos los consumidores de IProductAvailibitiy están vinculados. También hay una clase ProductAvailibitiyImpl que implementa esta interfaz y un ProductAvailibitiyMicroservice que usa ProductAvailibitiyImpl. Los consumidores pueden configurarse para usar un ProductAvailibitiyImpl local o un proxy remoto para ProductAvailibitiyMicroservice
k3b

2

Me gustaría agregar una perspectiva diferente, desde una industria diferente con supuestos muy diferentes: simulación distribuida (a nivel de entidad). Conceptualmente, esto se parece mucho a un videojuego FPS distribuido. Diferencias clave: todos los jugadores comparten algún estado: dónde está el dragón en este momento; sin llamadas a la base de datos; todo se mantiene en la RAM para velocidad y baja latencia, el rendimiento es menos relevante (pero supongo que tampoco se puede ignorar por completo).

Puede pensar en cada aplicación participante como un monolito (que representa todas las facetas de un jugador) o como un microservicio (que representa solo un jugador en una multitud).

Mis colegas han mostrado interés en desglosar una sola aplicación participante, más allá en microservicios más pequeños que podrían compartirse, por ejemplo, arbitraje de daños o cálculos de línea de visión, cosas que generalmente se agrupan en las simulaciones.

El problema es la latencia de despachar llamadas y esperar solicitudes. El ancho de banda es irrelevante y abundante de todos modos, como han señalado otros. Pero si un cálculo de la línea de visión pasa de 1 microsec a 100 microsec (por ejemplo, debido a la cola en el nuevo microservicio compartido entre todas las aplicaciones del reproductor), es una pérdida enorme (podría necesitar varios o muchos cálculos de línea de visión para cada actualización, varias actualizaciones / segundo).

Piense detenidamente sobre cómo funcionan los servicios, cuándo se llaman y qué datos se intercambian. Nuestras aplicaciones ya no intercambian solo información de posición, intercambian información de cálculo muerto: estoy en la posición x, en dirección y a la velocidad q. Y no tengo que actualizar mi información hasta que esos supuestos cambien. Muchas menos actualizaciones, y la latencia (aunque sigue siendo un problema) aparece proporcionalmente con menos frecuencia.

Entonces, en lugar de solicitar un servicio de grano fino a una frecuencia más alta, intente reducir la frecuencia de la siguiente manera:

  1. cambiar qué datos se solicitan y usar cálculos locales
  2. Enviar consultas o parámetros de activación para una respuesta asincrónica
  3. solicitudes por lotes
  4. anticipando solicitudes y preparando una respuesta por adelantado, sobre especulación (contrario a la evaluación perezosa)
  5. siempre que sea posible, evite microservicios llamando a otros microservicios; Esto agrava el problema, obviamente. Entiendo que esto es un incentivo para hacer que los microservicios sean más grandes y de alguna manera derrota el punto, pero los microservicios no son amigos de la latencia. Tal vez solo admítelo y supéralo.

Ahora recuerde verificar sus suposiciones sobre su sistema. Si está más preocupado por el rendimiento que por la latencia, o no ha tenido un estado compartido, etc., entonces, por todos los medios, use microservicios donde tengan sentido. Solo digo que tal vez no los uses donde no tengan sentido.


1

Tu ingenua imaginación es correcta. Y a menudo eso no importa. Las máquinas modernas son rápidas. Las principales ventajas de la arquitectura de micro servicios se ven en el esfuerzo y el tiempo de desarrollo y mantenimiento.

Y, por supuesto, no hay una regla que diga que no puede usar la memoria compartida o incluso desplegar físicamente múltiples servicios en un ejecutable. Siempre y cuando lo diseñes no dependas de eso.


Las CPU son rápidas. La memoria es rapida. Los SSD son rápidos. Pero, ¿las tarjetas de red, los enrutadores y los conmutadores son "rápidos"? Otra respuesta insiste en eso, pero no estoy seguro.
James Mishra

Definitivamente es fácil encontrarse con problemas de velocidad de red. Ejecute un servicio en San Francisco, otro en Amsterdam, y consúmalos en Sydney. El retraso es la clave, no el ancho de banda. Entonces no hagas eso. Y hacer que los servicios sean tan grandes como tengan sentido
Stephan Eggermont

1

Como mucha gente mencionó, no se trata de cuellos de botella en la red. Se trata más de la fragilidad de la red. Entonces, el primer paso es evitar la comunicación sincrónica. Es más fácil de lo que parece. Todo lo que necesita son servicios con límites correctos. Los límites correctos dan como resultado que los servicios sean autónomos, débilmente acoplados y altamente cohesivos. Un buen servicio no necesita información de otro servicio, ya la tiene. La única forma en que los buenos servicios se comunican es a través de eventos. Los buenos servicios son eventualmente consistentes también, por lo que no hay transacciones distribuidas.

La forma de lograr esta bondad es identificar primero las capacidades de su negocio. La capacidad empresarial es una responsabilidad empresarial específica. Alguna contribución al valor comercial general. Así que aquí está mi secuencia de pasos que tomo cuando pienso en los límites del sistema:

  1. Identificar responsabilidades empresariales de nivel superior. Habrá algunos de ellos. Trate estos servicios como pasos que su organización debe seguir para lograr su objetivo comercial.
  2. Profundizar en cada servicio. Identificar servicios de servicios de nivel inferior que comprenden uno primario.
  3. Junto a los dos primeros puntos, piense en la comunicación del servicio. Deben hacerlo principalmente a través de eventos, solo para notificarse mutuamente sobre el resultado de su proceso comercial. Los eventos no deben considerarse como transportadores de datos.

Tenga en cuenta que el servicio comercial incluye personas, aplicaciones, procesos comerciales. Por lo general, solo una parte está representada como autoridad técnica.

Esto podría sonar un poco abstracto, por lo que probablemente un ejemplo de identificación de límites de servicio sería de algún interés.


0

Solo otro factor para agregar a las respuestas actuales. Con un servicio de grano grueso . Desea evitar la latencia de todas las llamadas, por lo que en lugar de hacer 10 llamadas, realice una llamada que obtenga 10 datos necesarios en un DTO.

Y recuerde que los microservicios no son tan micro como la gente piensa.

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.