Una guía para comprender los patrones de escala de la base de datos

Hay muchos artículos en línea que describen patrones de escalabilidad de bases de datos, pero en su mayoría son artículos dispersos, solo técnicas que se definen al azar sin mucho contexto. Encuentro que no se definen paso a paso, y no discuto cuándo elegir qué opción de escala, qué opciones de escala son factibles en la práctica y por qué.

Por lo tanto, planeo discutir algunas de las técnicas en detalle en artículos futuros. Para empezar, creo que es mejor si hablo de técnicas paso a paso con algo de contexto a mi manera. Este artículo es un artículo de alto nivel; no discutiré las técnicas de escala en detalle aquí, pero proporcionaré una descripción general. Entonces empecemos.

Un caso de estudio

Suponga que ha creado una startup que ofrece viajes compartidos a un precio económico. Inicialmente, cuando comienza, se dirige a una ciudad y apenas tiene decenas de clientes después de su anuncio inicial.

Guarde todos los clientes, viajes, ubicaciones, datos de reservas e historial de viajes de clientes en la misma base de datos o, muy probablemente, en una sola máquina física. No hay un almacenamiento en caché sofisticado o una canalización de big data para resolver problemas, ya que su aplicación es muy nueva. Esto es perfecto para su caso de uso en este momento, ya que hay muy pocos clientes y su sistema apenas reserva 1 viaje en 5 minutos, por ejemplo.

Pero a medida que pasa el tiempo, más personas comienzan a registrarse en tu sistema ya que eres el servicio más barato del mercado y gracias a tu promoción y anuncios. Comienzas a reservar, digamos, 10 reservas por minuto, y poco a poco el número aumenta a 20, 30 reservas por minuto.

En este momento, se da cuenta de que el sistema ha comenzado a funcionar mal: la latencia de la API ha aumentado mucho y algunas transacciones se bloquean o mueren de hambre y, finalmente, fallan. Su aplicación está tardando más en responder, lo que provoca la insatisfacción del cliente. ¿Qué puedes hacer para solucionar el problema?

Patrón 1: optimización de consultas e implementación del grupo de conexiones:

La primera solución que viene a la mente es que la caché utiliza con frecuencia datos no dinámicos como el historial de reservas, el historial de pagos, los perfiles de usuario, etc. Pero después de este almacenamiento en caché de la capa de aplicación, no puede resolver el problema de latencia de las API que exponen datos dinámicos como la ubicación del conductor actual o los taxis más cercanos para un cliente determinado o el costo del viaje actual en un momento determinado después de que comienza el viaje.

Usted identifica que su base de datos probablemente está muy normalizada, por lo que introduce algunas columnas redundantes (estas columnas aparecen con frecuencia en la cláusula WHEREo JOIN ONen las consultas) en tablas muy utilizadas por el bien de la desnormalización. Esto reduce las consultas de combinación, divide una consulta grande en varias consultas más pequeñas y agrega sus resultados en la capa de aplicación.

Otra optimización paralela que puede hacer es ajustar las conexiones de la base de datos. Las bibliotecas cliente de bases de datos y las bibliotecas externas están disponibles en casi todos los lenguajes de programación. Puede utilizar bibliotecas de grupos de conexiones para almacenar en caché las conexiones de la base de datos o puede configurar el tamaño del grupo de conexiones en el propio sistema de administración de bases de datos.

Crear cualquier conexión de red es costoso ya que requiere cierta comunicación entre el cliente y el servidor. La agrupación de conexiones puede ayudarlo a optimizar la cantidad de conexiones. Las bibliotecas de grupos de conexiones pueden ayudarlo a multiplexar conexiones: varios subprocesos de aplicaciones pueden usar la misma conexión de base de datos. Veré si puedo explicar la agrupación de conexiones en detalle en un artículo separado más adelante.

Mide la latencia de tus API y encuentra probablemente entre un 20% y un 50% o más de latencia reducida. Esta es una buena optimización en este momento.

Ahora ha escalado su negocio a una ciudad más, se registran más clientes y poco a poco comienza a hacer entre 80 y 100 reservas por minuto. Su sistema no puede manejar esta báscula. Una vez más, verá que la latencia de la API ha aumentado, la capa de la base de datos se ha rendido, pero esta vez, ninguna optimización de consultas le brinda una ganancia significativa de rendimiento. Verifica la métrica del sistema, encuentra que el espacio en disco está casi lleno, la CPU está ocupada el 80% del tiempo, la RAM se llena muy rápidamente.

Patrón 2: escala vertical o escala ascendente:

Después de examinar todas las métricas del sistema, sabrá que no hay otra solución fácil que actualizar el hardware del sistema. Actualiza el tamaño de su RAM 2 veces, aumenta el espacio en disco, digamos, 3 veces o más. A esto se le llama escalado vertical o escalado de su sistema. Usted informa a su equipo de infraestructura o equipo de devops o agentes del centro de datos de terceros para actualizar su máquina.

Pero, ¿cómo se configura la máquina para el escalado vertical?

Asignas una máquina más grande. Un enfoque es no migrar los datos manualmente desde la máquina antigua, sino configurar la nueva máquina como si fuera replicala máquina existente ( primary), hacer una primary replicaconfiguración temporal . Deje que la replicación ocurra de forma natural. Una vez que se realiza la replicación, promueva la nueva máquina a primaria y desconecte la máquina anterior. Dado que se espera que la máquina más grande atienda todas las solicitudes, todas las operaciones de lectura / escritura se realizarán en esta máquina.

Frio. Su sistema está en funcionamiento nuevamente con mayor rendimiento.

Su negocio está funcionando muy bien y decide escalar a 3 ciudades más; ahora está operativo en 5 ciudades en total. El tráfico es 3 veces mayor que antes, se espera que haga alrededor de 300 reservas por minuto. Antes incluso de lograr esta reserva de destino, vuelve a golpear la contracción del rendimiento, el tamaño del índice de la base de datos está aumentando considerablemente en la memoria, necesita un mantenimiento constante, el escaneo de tablas con índice se está volviendo más lento que nunca. Calcula el costo de ampliar aún más la máquina, pero no está convencido del costo. ¿Qué haces ahora?

Patrón 3 - Segregación de responsabilidad de consultas de comando (CQRS):

Identifica que la máquina grande no puede manejar todas las read/writesolicitudes. Además, en la mayoría de los casos, cualquier empresa necesita capacidad transaccional en las operaciones, writepero no en ellas read. También está bien con un poco de readoperaciones inconsistentes o demoradas y su negocio tampoco tiene problemas con eso. Usted ve una oportunidad en la que podría ser una buena opción para separar el ready writeoperaciones de máquina física sabia. Creará un margen para que las máquinas individuales manejen más read/writeoperaciones.

Ahora toma dos máquinas grandes más y configúralas como replicala máquina actual. La replicación de la base de datos se encargará de distribuir los datos de una primarymáquina a otra replica. Navega por todas las consultas de lectura (Query ( Q) in CQRS) a las réplicas; cualquiera replicapuede atender cualquier solicitud de lectura, navega por todas las consultas de escritura (Command ( C) in CQRS) al archivo primary. Puede haber un pequeño retraso en la replicación, pero de acuerdo con su caso de uso comercial, eso está bien.

La mayoría de las startups de mediana escala que atienden unos cientos de miles de solicitudes todos los días pueden sobrevivir con la configuración de réplicas primarias siempre que archiven periódicamente datos más antiguos.

Ahora que escala a 2 ciudades más, ve que primaryno puede manejar todas las writesolicitudes. Muchas writesolicitudes tienen latencia. Además, el retraso entre primaryy a replicaveces afecta a los clientes y conductores, por ejemplo, cuando el viaje finaliza, el cliente le paga al conductor correctamente, pero el conductor no puede ver el pago ya que la actividad del cliente es una writesolicitud que se dirige al primary, mientras que la actividad del conductor es una readsolicitud. que va a una de las réplicas. Su sistema general es tan lento que el conductor no puede ver el pago durante al menos medio minuto, lo que resulta frustrante tanto para el conductor como para el cliente. ¿Cómo lo resuelves?

Patrón 4: replicación primaria múltiple

Escalaste muy bien con la primary-replicaconfiguración, pero ahora necesitas más rendimiento de escritura. Es posible que esté listo para comprometer un poco el readrendimiento de la solicitud. ¿Por qué no distribuir la solicitud de escritura replicatambién?

En una multi-primaryconfiguración, todas las máquinas pueden funcionar como primary& replica. Puedes pensar en multi-primarycomo dicen un círculo de máquinas A->B->C->D->A. Bpuede replicar datos de A, Cpuede replicar datos de B, Dpuede replicar datos de C, Apuede replicar datos de D. Puede escribir datos en cualquier nodo, mientras lee datos, puede transmitir la consulta a todos los nodos, quien responda devolverá eso. Todos los nodos tendrán el mismo esquema de base de datos, el mismo conjunto de tablas, índice, etc. Por lo tanto, debe asegurarse de que no haya colisiones identre los nodos de la misma tabla; de lo contrario, durante la transmisión, varios nodos devolverían datos diferentes para el mismo id.

Generalmente es mejor usar UUIDo GUIDpara id. Una desventaja más de esta técnica es que las readconsultas pueden ser ineficaces ya que implican la transmisión de consultas y la obtención del resultado correcto, básicamente un enfoque de recopilación de dispersión.

Ahora escalas a 5 ciudades más y tu sistema vuelve a tener problemas. Se espera que maneje aproximadamente 50 solicitudes por segundo. Tiene una necesidad desesperada de manejar una gran cantidad de solicitudes simultáneas. ¿Cómo logras eso?

Patrón 5 - Partición:

Usted sabe que su locationbase de datos es algo que cada vez es alta writey readel tráfico. Probablemente la write:readproporción sea 7:3. Esto está ejerciendo mucha presión sobre las bases de datos existentes. Las locationtablas contienen pocos datos primarios como longitude, latitude, timestamp, driver id, trip idetc no tiene mucho que ver con viajes usuario, datos de usuario, datos de pago, etc. ¿Qué pasa con la separación de las locationtablas en un esquema de base de datos independiente? ¿Qué hay de poner esa base de datos en máquinas separadas con el adecuado primary-replicao multi-primaryconfiguración?

Esto se denomina partición de datos por funcionalidad. Diferentes bases de datos pueden albergar datos categorizados por diferentes funcionalidades; si es necesario, el resultado se puede agregar en la capa de back-end. Con esta técnica, puede concentrarse en escalar bien aquellas funcionalidades que exigen grandes read/writesolicitudes. Aunque el back-end o la capa de aplicación tiene que asumir la responsabilidad de unir los resultados cuando sea necesario, probablemente se produzcan más cambios en el código.

Ahora imagine que ha expandido su negocio a un total de 20 ciudades en su país y planea expandirse pronto a Australia. Su creciente demanda de aplicaciones requiere una respuesta más rápida y rápida. Ninguno de los métodos anteriores puede ayudarlo al extremo ahora. Debe escalar su sistema de tal manera que la expansión a otros países / regiones no siempre requiera que realice cambios frecuentes de ingeniería o arquitectura. ¿Cómo haces eso?

Patrón 6 - Escala horizontal:

Buscas mucho en Google, lees mucho sobre cómo otras empresas han resuelto el problema y llegas a la conclusión de que necesitas escalar horizontalmente. Usted asigna, digamos, 50 máquinas, todas tienen el mismo esquema de base de datos que a su vez contiene el mismo conjunto de tablas. Todas las máquinas solo contienen una parte de los datos.

Dado que todas las bases de datos contienen el mismo conjunto de tablas, puede diseñar el sistema de tal manera que la localidad de los datos esté allí, es decir; todos los datos relacionados aterrizan en la misma máquina. Cada máquina puede tener sus propias réplicas, las réplicas se pueden utilizar en la recuperación de fallos. Cada una de las bases de datos se llama shard. Una máquina física puede tener una o varias shards; depende de su diseño cómo lo desee. Debe decidir de sharding keytal manera que un solo sharding keysiempre se refiera a la misma máquina. Por lo tanto, puede imaginar muchas máquinas que contienen datos relacionados en el mismo conjunto de tablas, read/writesolicitudes para la misma fila o el mismo conjunto de recursos aterrizan en la misma máquina de base de datos.

La fragmentación es en general difícil, al menos los ingenieros de diferentes empresas dicen eso. Pero cuando atiende millones o miles de millones de solicitudes, tiene que tomar una decisión tan difícil.

Lo discutiré shardingcon más detalle en mi próximo artículo, por lo que reprimiré mi tentación de discutir más en este artículo.

Ahora que tiene la fragmentación en su lugar, está seguro de que puede escalar a muchos países. Su negocio ha crecido tanto que los inversores lo están presionando para escalar el negocio en todos los continentes. Vuelve a ver algún problema aquí. Latencia de API de nuevo. Su servicio está alojado en EE. UU. Y la gente de Vietnam está teniendo dificultades para reservar viajes. ¿Por qué? ¿Qué haces al respecto?

Patrón 7 - Partición inteligente del centro de datos:

Su negocio está creciendo en América, el sur de Asia y en algunos países de Europa. Realiza millones de reservas al día y miles de millones de solicitudes llegan a su servidor. Felicitaciones, este es un momento pico para su negocio.

Pero dado que las solicitudes de la aplicación tienen que viajar a través de continentes a través de cientos o miles de servidores en Internet, surge la latencia. ¿Qué pasa con la distribución del tráfico en los centros de datos? Puede configurar un centro de datos en Singapur que maneje todas las solicitudes del sur de Asia, el centro de datos en Alemania puede manejar todas las solicitudes de países europeos y un centro de datos de California puede manejar todas las solicitudes de EE. UU.

También habilita la replicación entre centros de datos, lo que ayuda a la recuperación ante desastres. Entonces, si el centro de datos de California se replica en el centro de datos de Singapur, en caso de que el centro de datos de California se bloquee debido a un problema de electricidad o una catástrofe natural, todas las solicitudes de EE. UU. Pueden recurrir al centro de datos de Singapur, etc.

Esta técnica de escalado es útil cuando tiene millones de clientes para atender en todos los países y no puede adaptarse a ninguna pérdida de datos, debe mantener siempre la disponibilidad del sistema.

Estas son algunas técnicas generales paso a paso para escalar bases de datos. Aunque la mayoría de los ingenieros no tienen la oportunidad de implementar estas técnicas, en general es mejor tener una idea más amplia sobre dicho sistema que en el futuro puede ayudarlo a hacer un mejor diseño de sistemas y arquitectura.

En mis próximos artículos, intentaré discutir algunos de los conceptos en detalle. Por favor, siéntase libre de dar los comentarios apropiados para esta publicación, si corresponde.

El artículo se publicó originalmente en la cuenta del medio del autor: //medium.com/@kousiknath/understanding-database-scaling-patterns-ac24e5223522