¿Son realmente significativas las llamadas a múltiples bases de datos con una llamada de red para una API web?

16

En uno de mis empleadores, trabajamos en una API REST (pero también se aplica a SOAP). El cliente, que es la interfaz de usuario de la aplicación, realizaría llamadas a través de la web (LAN en implementaciones de producción típicas) a la API. La API haría llamadas a la base de datos.

Un tema que se repite en nuestras discusiones es el rendimiento: algunas personas en el equipo creen que no debería tener múltiples llamadas a la base de datos (generalmente lecturas) de una sola llamada API debido al rendimiento; debe optimizarlos para que cada llamada a la API tenga (exactamente) una llamada a la base de datos.

¿Pero es eso realmente importante? Tenga en cuenta que la IU debe realizar una llamada de red a la API; eso es bastante grande (orden de magnitud de milisegundos). Las bases de datos están optimizadas para mantener las cosas en la memoria y ejecutar lecturas muy, muy rápidamente (por ejemplo, SQL Server carga y mantiene todo en RAM y consume casi toda su RAM libre si puede).

TLDR: ¿Es realmente importante preocuparse por las llamadas a múltiples bases de datos cuando ya estamos haciendo una llamada de red a través de LAN? Si es así, ¿por qué?

Para ser claros, estoy hablando del orden de magnitud: sé que depende de detalles (hardware de la máquina, elección de API y DB, etc.). Si tengo una llamada que toma O (milisegundos), ¿se optimiza para DB? llamadas que toman un orden de magnitud menos, ¿realmente importan? ¿O hay más en el problema que esto?

Editar: para la posteridad, creo que es bastante ridículo hacer afirmaciones de que necesitamos mejorar el rendimiento combinando llamadas a la base de datos en estas circunstancias, especialmente con la falta de perfiles. Sin embargo, no es mi decisión si hacemos esto o no; Quiero saber cuál es la razón detrás de pensar que esta es una forma correcta de optimizar las llamadas a la API web.

cenizas999
fuente
¿No hay otra llamada de red entre la capa API y la base de datos?
Firme el
44
¿Qué mostraron tus pruebas de tiempo?
Dan Pichelman
@Sign No hay llamadas de red entre la API y la base de datos. Se garantiza que estarán en la misma máquina, por lo que entiendo.
cenizas999
@DanPichelman, eso es lo que te pido también. Nadie parece estar tomando y cronometrando el rendimiento; solo tenemos requisitos para "arreglar el rendimiento en X combinando todas las llamadas de DB en una sola llamada".
cenizas999

Respuestas:

25

¿Pero es eso realmente importante? Tenga en cuenta que la IU debe realizar una llamada de red a la API; eso es bastante grande (orden de magnitud de milisegundos). Las bases de datos están optimizadas para mantener las cosas en la memoria y ejecutar lecturas muy, muy rápidamente (por ejemplo, SQL Server carga y mantiene todo en RAM y consume casi toda su RAM libre si puede).

La lógica

En teoría, tienes razón. Sin embargo, hay algunos defectos con esta justificación:

  1. Por lo que dijo, no está claro si realmente probó / perfiló su aplicación. En otras palabras, ¿ sabe realmente que las transferencias de red desde la aplicación a la API son el componente más lento? Como eso es intuitivo, es fácil suponer que lo es. Sin embargo, cuando se habla de rendimiento, nunca debe suponer. En mi empleador, soy el líder de rendimiento. Cuando me uní por primera vez, la gente seguía hablando de CDN, replicación, etc., basada en la intuición sobre cuáles deben ser los cuellos de botella. Resulta que nuestros mayores problemas de rendimiento fueron consultas de bases de datos de bajo rendimiento.

  2. Está diciendo que debido a que las bases de datos son buenas para recuperar datos, que la base de datos se ejecuta necesariamente al máximo rendimiento, se está utilizando de manera óptima y no hay nada que se pueda hacer para mejorarla. En otras palabras, las bases de datos están diseñadas para ser rápidas, por lo que nunca debería tener que preocuparme por eso. Otra peligrosa línea de pensamiento. Es como decir que un automóvil debe moverse rápidamente, por lo que no necesito cambiar el aceite.

  3. Esta forma de pensar supone un proceso único a la vez, o dicho de otra manera, sin concurrencia. Se supone que una solicitud no puede influir en el rendimiento de otra solicitud. Se comparten recursos, como E / S de disco, ancho de banda de red, agrupaciones de conexiones, memoria, ciclos de CPU, etc. Por lo tanto, reducir el uso de un recurso compartido por una llamada de la base de datos puede evitar que otras solicitudes se ralenticen. Cuando me uní a mi empleador actual por primera vez, la gerencia creía que ajustar una consulta de base de datos de 3 segundos era una pérdida de tiempo. 3 segundos es tan poco, ¿por qué perder el tiempo? ¿No estaríamos mejor con un CDN o compresión u otra cosa? Pero si puedo ejecutar una consulta de 3 segundos en 1 segundo, digamos agregando un índice, eso es 2/3 menos de bloqueo, 2/3 menos tiempo dedicado a ocupar un hilo y, lo que es más importante, menos datos leídos del disco,

La teoría

Existe una concepción común de que el rendimiento del software se trata simplemente de velocidad .

Desde una perspectiva puramente rápida, tienes razón. Un sistema es tan rápido como su componente más lento. Si ha perfilado su código y descubrió que Internet es el componente más lento, entonces todo lo demás obviamente no es la parte más lenta.

Sin embargo, dado lo anterior, espero que pueda ver cómo la contención de recursos, la falta de indexación, el código mal escrito, etc. pueden crear diferencias sorprendentes en el rendimiento.

Los supuestos

Una última cosa. Usted mencionó que una llamada a la base de datos debería ser barata en comparación con una llamada de red desde la aplicación a la API. Pero también mencionó que la aplicación y los servidores API están en la misma LAN. Por lo tanto, ¿no son ambos comparables como llamadas de red? En otras palabras, ¿por qué supone que la transferencia de API es un orden de magnitud más lento que la transferencia de la base de datos cuando ambos tienen el mismo ancho de banda disponible? Por supuesto, los protocolos y las estructuras de datos son diferentes, entiendo eso, pero disputo la suposición de que son órdenes de magnitud diferentes.

Donde se pone murkey

Toda esta pregunta es sobre llamadas de base de datos "múltiples" versus "únicas". Pero no está claro cuántos son múltiples. Debido a lo que dije anteriormente, como regla general, recomiendo hacer tan pocas llamadas a la base de datos como sea necesario. Pero eso es solo una regla general.

Aquí es por qué:

  1. Las bases de datos son excelentes para leer datos. Son motores de almacenamiento. Sin embargo, su lógica empresarial vive en su aplicación. Si establece una regla de que cada llamada a la API da como resultado exactamente una llamada a la base de datos, entonces su lógica empresarial puede terminar en la base de datos. Quizás eso está bien. Muchos sistemas hacen eso. Pero algunos no. Se trata de flexibilidad.
  2. A veces, para lograr un buen desacoplamiento, desea tener 2 llamadas a la base de datos separadas. Por ejemplo, quizás cada solicitud HTTP se enruta a través de un filtro de seguridad genérico que valida desde la base de datos que el usuario tiene los derechos de acceso correctos. Si lo hacen, proceda a ejecutar la función apropiada para esa URL. Esa función puede interactuar con la base de datos.
  3. Llamando a la base de datos en un bucle. Es por eso que pregunté cuántos es múltiple. En el ejemplo anterior, tendría 2 llamadas a la base de datos. 2 está bien. 3 pueden estar bien. N no está bien. Si llama a la base de datos en un bucle, ahora ha hecho que el rendimiento sea lineal, lo que significa que tomará más tiempo cuanto más haya en la entrada del bucle. Por lo tanto, decir categóricamente que el tiempo de red de la API es el más lento pasa por alto por completo las anomalías, como que el 1% de su tráfico tarda mucho tiempo debido a un bucle aún no descubierto que llama a la base de datos 10,000 veces.
  4. A veces hay cosas en las que su aplicación es mejor, como algunos cálculos complejos. Es posible que deba leer algunos datos de la base de datos, hacer algunos cálculos y luego, según los resultados, pasar un parámetro a una segunda llamada a la base de datos (tal vez para escribir algunos resultados). Si los combina en una sola llamada (como un procedimiento almacenado) solo por llamar a la base de datos una sola vez, se ha obligado a usar la base de datos para algo en lo que el servidor de aplicaciones podría ser mejor.
  5. Equilibrio de carga: tiene 1 base de datos (presumiblemente) y múltiples servidores de aplicaciones con equilibrio de carga. Por lo tanto, cuanto más trabaje la aplicación y menos haga la base de datos, más fácil será escalar porque generalmente es más fácil agregar un servidor de aplicaciones que configurar la replicación de la base de datos. Según el punto anterior, puede tener sentido ejecutar una consulta SQL, luego hacer todos los cálculos en la aplicación, que se distribuye en varios servidores, y luego escribir los resultados cuando haya terminado. Esto podría proporcionar un mejor rendimiento (incluso si el tiempo total de la transacción es el mismo).

TL; DR

TLDR: ¿Es realmente importante preocuparse por las llamadas a múltiples bases de datos cuando ya estamos haciendo una llamada de red a través de LAN? Si es así, ¿por qué?

Sí, pero solo hasta cierto punto. Debe intentar minimizar el número de llamadas a la base de datos cuando sea práctico, pero no combine las llamadas que no tienen nada que ver entre sí solo por el hecho de combinarlas. Además, evite llamar a la base de datos en un bucle a toda costa.

Brandon
fuente
3

Parece que su equipo está optimizando antes de tener una razón para hacerlo. ¿Ha medido el tiempo para ejecutar estas solicitudes? Es probable que este paradigma cree un peor rendimiento para el usuario final ya que los viajes de ida y vuelta al servidor web tendrán una latencia mucho mayor que el tiempo de conexión del servidor web a la base de datos. Además de eso, la mayoría de los navegadores web solo harán 2 conexiones simultáneas a un solo servidor web, por lo que para páginas complejas es probable que encuentres un cuello de botella allí.

De cualquier manera, las decisiones de optimización no deben tomarse sin datos que lo respalden. Mídalo y descubra qué es lo mejor para su aplicación.

brianfeucht
fuente
1
Este es un buen comentario sobre nuestras prácticas de bajo rendimiento, pero no responde a mi pregunta sobre si las llamadas a DB son algo de qué preocuparse cuando ya tengo una llamada de red.
cenizas999
1
En general, he descubierto que hacer múltiples llamadas a la base de datos no es un problema. Esto se debe principalmente a la agrupación de conexiones y la pequeña latencia entre la base de datos y el servidor web. Hay un punto en el que hacer un montón de llamadas db diferentes afectará negativamente el rendimiento, pero no tengo un número difícil para usted. Todo depende del entorno y la aplicación. Solo medir le dará la respuesta que busca.
brianfeucht
No debería (necesariamente) depender de detalles específicos, porque estoy hablando de un orden de magnitud.
cenizas999
Solo conjeturas aproximadas (debe medir): Tiempo promedio para conectarse a la base de datos desde el servidor web: 2 ms Tiempo promedio para conectarse al servidor web desde el cliente: 20 ms Entonces, suponiendo que esos números que saqué al azar del aire son correctos, podría hacer 10 llamadas a la base de datos en el tiempo que lleva hacer una llamada al servicio web. Asumiendo que las consultas de la base de datos toman la misma cantidad de tiempo. Esos números dependen extremadamente del medio ambiente. Si el cliente que realiza la llamada al servicio web es local, puede disminuirlo en varios órdenes de magnitud.
brianfeucht
2

No podemos decirte

No sabemos cómo son sus consultas. No sabemos cuánto tardan en completarse. No sabemos cuántos gastos generales implica cada solicitud a su servidor API. No sabemos cuán geográficamente dispersos están sus clientes. Etc.

Si este es un escenario que requiere optimización y es uno en el que puede decidir si dividir o unir las llamadas, debe compararlo en ambos sentidos : decidir para qué está optimizando (latencia de la interfaz de usuario, carga de CPU del servidor, contención, etc.) y elija el que mejor logre su objetivo de optimización.


Aparte de eso, la única una cosa que puedo añadir con relativa certeza es la siguiente:

Dentro de una sola solicitud, debe realizar todas las consultas que necesita realizar para generar una respuesta.

En otras palabras, si la respuesta no se puede generar hasta que se realicen todas las N consultas, generalmente no tiene sentido separarlas. Si puede generar resultados significativos, ya sean intermedios o completos, después de cada consulta, comience la evaluación comparativa.

svidgen
fuente
1

Dos pensamientos:

Primero, para el consumidor que usa la API, está haciendo una llamada para realizar una tarea. Lo que sucede después de que su servidor recibe la llamada para completar la solicitud no debe ser tan rígido. Si esa llamada de un consumidor requiere 10 elementos de subtrabajo para reunir los datos y devolverlos, entonces eso debería ser aceptable.

Segundo: ¿Ve un problema real de rendimiento de la base de datos con el proceso en cuestión? Mi experiencia ha demostrado que, a menudo, tratar de poner todos los aspectos de una solicitud de base de datos en una sola llamada puede resultar en una llamada menos eficiente que simplemente hacer tres o cuatro llamadas de datos. Las bases de datos modernas son muy eficientes en los planes de caché y ejecución. A menudo, cuando intentas hacer demasiado, verás procedimientos con cursores (muy malo para el rendimiento porque los datos se actúan fila por fila, no como un conjunto a la vez) y un código que resulta en un plan menos eficiente que si hubieras roto la llamada en varios pequeños pasos fáciles.

Por simple organización del código, estoy de acuerdo en que cada llamada a la API posiblemente deba llamar a un único procedimiento almacenado (o función db) que a su vez es responsable de completar la solicitud. Puede haber más de un paso en el procedimiento.

Ricardo
fuente
Estoy de acuerdo con usted en medir el rendimiento, que nadie parece estar haciendo. No hay pruebas de que esto sea más rápido, pero sigue apareciendo. El rendimiento surge como un problema cuando tenemos algunas llamadas que pueden hacer, por ejemplo, 1000 DB SELECTs.
cenizas999
@ ashes999 aunque puede ganar velocidad mirando el número de llamadas db, es más probable que se encuentre en la estrategia de indexación, etc., no en el número de llamadas. Como todos han indicado, mire los datos de rendimiento.
Richard
Richard, estoy de acuerdo, y realmente lo sé. Mi pregunta es por qué varias personas siguen sacando a relucir este punto de que "las llamadas múltiples de DB son lentas" cuando hay una llamada de red involucrada. Realmente no veo cómo puede ser significativo.
cenizas999
@ ashes999 Lo sentimos, tal vez deberías entrar en un poco más de detalles sobre la llamada de la red, ya que eso parece obvio, siento que hay un poco más en tu pregunta. Siento que nos falta algo en sus preguntas. Siempre sufrirá una latencia de red, y cada llamada aumenta potencialmente "x" veces por cada llamada (en términos simples). La afirmación en su valor nominal es verdadera, las llamadas de red múltiples serán más lentas que una llamada de red a la base de datos. Es por eso que sugiero una llamada a un procedimiento almacenado, que puede hacer múltiples llamadas a la base de datos sin las llamadas de múltiples redes.
Richard
1

Si la base de datos está en un servidor diferente al servicio REST, cada llamada a la base de datos dará como resultado un viaje de ida y vuelta en la red y eso puede afectar significativamente el rendimiento:

Una vez observé que una sola llamada de servicio web se traducía en aproximadamente 500 consultas de la base de datos; esto no era un problema cuando tanto el servicio web como la base de datos se encuentran en la misma máquina, pero se convirtió en un tiempo de respuesta de 6-7 segundos cuando estaban en diferentes máquinas.

Obviamente, 500 viajes de ida y vuelta a la base de datos es bastante extremo. No estoy seguro de cuáles son sus requisitos de rendimiento, pero como regla general, diría que si se queda con alrededor de 10 consultas de base de datos por llamada REST, no debería experimentar un impacto significativo en el rendimiento.

Astrotrain
fuente
1

Tenemos un par de aplicaciones que son muy, muy conversadoras. Hay una llamada a la base de datos para cada. Soltero. Pequeño. Cosa. Servir datos de referencia una y otra y otra vez es una parte importante de la carga de trabajo en el sistema. Toda esa programación de subprocesos de trabajo, adquisición y caída de bloqueos, planificación de comprobación de caché, etc., se suma incluso si no hay una E / S de disco real. La contención es mayor porque las transacciones tienen que mantener bloqueos en múltiples llamadas a la base de datos y, por lo tanto, el rendimiento es mucho menor de lo que podría ser. Esos equipos ahora están considerando tener que comprar servidores de bases de datos nuevos y muy caros debido a esto.

Por lo tanto, aunque la mayor parte del tiempo transcurrido en la configuración actual de su sistema se toma con llamadas REST API, ignorar el rendimiento en el nivel de base de datos es almacenar problemas para el futuro.

Michael Green
fuente
0

La ruta de optimización presentada es simplemente la forma incorrecta de ver las cosas.

Las llamadas a la API deben ser atómicas. En otras palabras, debería poder hacer 1 llamada a la API web para realizar la acción que quiero. Ya sea para obtener datos, actualizar un registro o lo que sea. NUNCA debe tomar más de 1 llamada para provocar la acción. E intentar aprovechar las transacciones a través de múltiples llamadas debe evitarse como la peste.

A veces una sola acción es bastante compleja. Por ejemplo, obtener datos que se combinan de varias fuentes: nuevamente, esto debería ser una sola llamada. O todo funciona o falla todo.

Ahora, decir que una sola llamada a la API solo debe ejecutar una consulta DB es un poco tonto. Como ha señalado, la sobrecarga para ordenar la llamada a través de la red suele ser mucho más costosa en términos de tiempo total.

De alguna manera puedo entender su afirmación de que una sola consulta se ejecuta más rápido que varias; pero esto da una falsa impresión ya que ignora la DB total y la carga de la red. Solo al perfilar las diversas formas de extraer datos de la base de datos puede descubrir cuál es realmente el problema. Estoy seguro de que todos tienen una historia en la que una consulta en particular ejecutada 100 veces más de lo esperado mató el sistema hasta que se estableció un índice adecuado ...

En última instancia, no podrás convencerlos con solo hablar. Configure un caso de prueba para ambos enfoques y perfílelos. Preste atención al tiempo total para adquirir los datos que necesita, la cantidad de tráfico de red generado, el número y el momento de las llamadas a la base de datos, etc. Adopte un enfoque holístico, lo que significa que mira todo el sistema, y ​​debería terminar con un montón de datos para comer cuervo o mostrarles el camino dorado.

Yo no
fuente