Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Designing Data-Intensive Applications: 1. Reliable, Scalable, and Maintainable Applications #2

Open
guilleiguaran opened this issue Apr 5, 2019 · 5 comments
Labels

Comments

@guilleiguaran
Copy link
Collaborator

guilleiguaran commented Apr 5, 2019

1. Reliable, Scalable, and Maintainable Applications

Esta semana a cargo: @elba
Siguiente semana: @sescobb27

EDIT:

El overview de @elba: #2 (comment)

@guilleiguaran
Copy link
Collaborator Author

guilleiguaran commented Apr 17, 2019

Algunas ideas relacionadas con el primer cap de las que queria hacer anotación:

  1. Un error muy comun que cometemos frecuentemente es hacer performance tests para ver cuanta carga puede "manejar" nuestro sistema sin definir antes que es "manejar".
    Al hacer performance tests es muy importante definir previamente SLI/SLA que se enfoquen principalmente en las latencias (ej. p50, p75, p95, p99) y en las tasas de error, y luego medir exhautivamente el sistema. Mas sobre esto en [1][2][3]

  2. Algo en lo que hace enfasis el autor y otros [4][5] es que los promedios muchas veces suelen ser engañosos y los percentiles nos dan un mejor overview sobre como los usuarios perciben el sistema en un momento dado, pero es importante tener en cuenta tambien que los percentiles NO pueden ser promediados [6][7], asi que no podemos por ejemplo calcular algo como el p99 a lo largo de un mes sumando los p99 de cada dia. Almacenar absolutamente todos los puntos de las metricas durante un largo periodo de tiempo para calcular los porcentiles es impractico por lo que muchas veces es recomendable calcular percentiles aproximados usando histogramas [8][9]

[1] https://www.oreilly.com/library/view/site-reliability-engineering/9781491929117/ch04.html
[2] https://content.pivotal.io/blog/slis-and-error-budgets-what-these-terms-mean-and-how-they-apply-to-your-platform-monitoring-strategy
[3] https://www.datadoghq.com/blog/set-and-monitor-slas/
[4] https://signalvnoise.com/posts/1836-the-problem-with-averages
[5] https://blog.optimizely.com/2013/12/11/why-cdn-balancing/
[6] https://twitter.com/heinrichhartman/status/748355170040352768
[7] https://www.circonus.com/2015/02/problem-math/
[8] https://www.circonus.com/2018/11/the-problem-with-percentiles-aggregation-brings-aggravation/
[9] https://www.vividcortex.com/blog/why-percentiles-dont-work-the-way-you-think

@simon0191
Copy link

simon0191 commented Apr 17, 2019

My raw notes:

  • 3 principles: reliability, scalability and maintainability


  • Standard building blocks:


    • databases

    • caches

    • search indexes

    • stream processing

    • batch processing

  • Reliability


    • one study of large internet services found that configuration errors by operators were the leading cause of outages, whereas hardware faults (servers or network) played a role in only 10–25% of outages
    • Then, maintainability and specially operability is crucial to avoid those outages caused by operational errors. i.e. APIs, and admin interfaces make it easy to do “the right thing” and discourage “the wrong thing.”

    • detailed and clear monitoring, such as performance metrics and error rates

  • Scalability


    • There's no silver bullet. Sometimes you should go with a hybrid approach. Twitter case:

      • Global collection of tweets for tweets of popular users which are followed by many people

      • home timeline caches for tweets of "regular" users, whose tweets are followed by few people.

      • A tweet is delivered in AVG to 75 followers. In this case the AVG hides the long tail, where the most popular users are, whose tweets will need to be delivered to 100s of 1000s or even millions of users

    • Response time vs latency:

      • response time is what the client sees. i.e. network delays + queueing delays + actual processing of request

      • Latency is the duration that a request is waiting to be handled—during which it is latent, awaiting service

    • Describing performance:

      • SLO: Service level objetive

        • Internal goal
      • SLA: Service level agreement

        • Agreement with clients

      • The mean/average is misleading. It doesn't tells you how many users are experiencing that response time

      • Percentiles are better because they tell you how many users are having certain experience

        • p50/median: half of the requests

        • p95, p99, p99.9: Almost all of the requests

      • It's important to note that those are metrics per request, not per user. If the final experience of a user requires multiple requests, the probability that at least one of those requests is slower than the median is much greater than 50%.

      • When performing load tests, it's important to keep sending requests without waiting for a response. If the load testing program is waiting for a response, it's basically waiting for the server to be free for more requests which doesn't reflect a real scenario. In a real scenario multiple users are going to make concurrent requests.

  • Metrics and percentiles


    • The author makes emphasis on avoiding aggregating percentiles. i.e. averaging percentiles of time windows.

    • Normally, time series DBs, calculate aggregated metrics for a fixed time window. i.e. They aggregate the data for every 10 seconds window. Therefore, you'll get p95 for a 10 secs window and the author says that you should not aggregate those metrics because averaging percentiles has no mathematical significance.

    • The author suggest instead using histograms which can be aggregated

    • Even though in theory they may not have mathematical significance, Can those aggregations give you a good approximation? 🤔 🤔 🤔

@simon0191
Copy link

Regarding the aggregation of percentile measurements, I asked in an observability chat and someone told me:

regarding whether its a good approximation, thats kind of the crux of the problem, there's no error bounds for the approximation, so in many cases, yes it probably is, but there may be pathological cases (especially where the number of samples in each windows varies wildly) where it may not be a good approximation

@epsanchezma
Copy link

Disculpen por el resumen tardío, estas fueron mis anotaciones con respecto al primer capítulo del libro:

Parte 1: Fundamentos de los Data Systems (sistemas enfocados a datos)

El primer capítulo se enfoca en 3 principios:

  • Reliability (confiabilidad): El sistema debería tolerar errores y fallas humanas, de software y de hardware.
  • Scalability (escalabilidad): El sistema puede ser medido bajo ciertos parámetros que permiten planear las maneras de hacer el sistema crecer para la correcta manipulación del tráfico.
  • Maintainability (mantenibilidad): La habilidad para hacer cambios fácilmente al sistema.

Como introducción se mencionan los sistemas de antes que solían ser computer-intensive versus los de ahora que son data-i, al enfocarse más en la intensidad y cantidad de los datos, llegan nuevos problemas para estos sistemas:

  • manejo de la cantidad de datos
  • complejidad de los datos
  • velocidad en la que cambian los datos

Un sistema data-intesive podría tener las siguientes partes en común, pero se necesitaría saber que combinación de herramientas + enfoque va mejor con cada solución de software:

  • databases
  • cache
  • search indexes
  • stream processing
  • batch processing

Pensando sobre los Data Systems

¿Por qué poner colas y bases de datos bajo el mismo término "Data Systems"?, si tienen sus similitudes pero diferentes patrones de acceso, implementación y rendimiento. Entonces estas herramientas de almacenamiento de datos están diseñadas para diferentes soluciones y además se puede decir que no encajan bajo un modelo en específico.
Con esto dicho, y viendo el ejemplo de la página 5, se pueden combinar varios de estos componentes para crear un Data i que nos puede garantizar:

  • resultados consistentes ya que en el ejemplo se puede ver como la cache es actualizada o queda invalidada bajos ciertas circunstancias
  • resultados de búsquedas mas rápidos gracias al motor de índices
  • asincronía entre procesos gracias al diseño enfocado en eventos

A partir de esto surgen las siguientes preguntas cuando el sistema, aunque completo, todavía es propenso a fallas y errores:

  • ¿Como asegurarse que los datos permanezcan correctos y completos después de un error en el sistema?
  • ¿Como proveer un buen rendimiento cuando partes del sistema están degradadas?
  • ¿Cómo escalar el sistema cuando se incrementa la carga de datos?

Aquí entran los 3 principios en los que se enfoca este capítulo.

RELIABILITY

Para resumir, confiabilidad significa que el sistema debe seguir funcionando correctamente cuando las cosas se ponen difíciles en términos de fallas y errores. Resiliencia.

El sistema debería:

  • desempeñarse como es esperado
  • tolerar más que el camino feliz (happy path)
  • funcionar correctamente bajo cierta carga y volumen de datos
  • prevenir acceso malicioso

El autor hace una diferenciación importante, menciona que "fault" no es lo mismo que "failure":

  • Fault: Un componente se desvía de sus especificaciones
  • Failure: El sistema entero como tal deja de proveer lo que se espera

"Es imposible reducir la probabilidad de una falla a 0, así que es mejor diseñar mecanismos tolerantes a estas que previenen que estas fallas (faults) causen fracasos (failures)"[cita]
Así que de cierta manera es preferible que deliberadamente se induzcan estas fallas (como parar procesos) y construir el sistema para que sea tolerante a ellas.

Fallas de Hardware

El cuarto de servidores podría sufrir un apagón o un rack podría ser desconectado, para evitar tener un major outage a causa de esto, una de las prevenciones mencionadas es usar Redundancia/RAID configuration como un enfoque para prevenir problemas de hardware. Esto además tendría que ser combinado con técnicas de tolerancia a fallas del lado el software.

Errores de Software

Una falla sistemática en un componente puede causar que otras partes del sistema fallen, esto puede ser debido a dependencias internas entre los componentes. En los ejemplos que se muestran en las páginas 8 y 9 podemos concluir que no hay manera para prevenir al 100% las fallas de software pero se podrían prevenir usando ciertas técnicas:

  • pensar sobre las interacciones
  • todo tipo de testing
  • aislamiento de procesos
  • crashes/reinicio de procesos
  • monitoreo

Errores Humanos

Los errores de configuración son la causa No. 1 de las fallas en los sistemas cuando se mide las fallas que son únicamente operacionales. Para evitar tener estos errores hay que pensar en:

  • minimizar las oportunidades para cometer errores de operación
  • tener ambientes experimentales (sandboxes) con usuarios reales antes de salir a producción
  • todo tipo de testing
  • tener un plan fácil para hacer rollbacks
  • métricas y monitoreo
  • buen entrenamiento a las partes que usan el sistema

SCALABILITY

El incremento en la carga de datos puede perjudicar el rendimiento del sistema. La habilidad de de atender el incremental número de usuarios concurrentes o la carga de datos en un sistema, la llamamos escalabilidad.

Según el autor, lo más importante para poder trabajar sobre la escalabilidad de un sistema, es saber describir los puntos sobre los cuales es medido el rendimiento de este. En el texto se mencionan como "load parameters" (parámetros de carga), los cuales dependen de la arquitectura del sistema y podrían ser:

  • número de peticiones por segundo a un servidor
  • proporción de escritura en la base de datos
  • usuarios activos simultáneos en un chat
  • tasa de acceso a la cache

Describiendo el rendimiento

Después de describir la carga y los puntos para medir el rendimiento del sistema, se puede determinar cómo manejar el rendimiento. Para esto se deben responder los siguientes interrogantes:

  • Se debe incrementar la carga usando los mismos recursos del sistema (hardware, CPU, memory) y ver como se afecta el rendimiento.
  • Se debe incrementar la carga y ver que incremento en recursos hay que hacer si se quiere mantener el mismo rendimiento.

Los valores que hayan escogido para medir el rendimiento del sistema pueden variar rápidamente, por eso usar la media/promedio no dice en concreto cuantos usuarios están percibiendo los tiempos de respuesta reflejados. A partir de esto el autor recomienda usar percentiles para las medidas de rendimiento. Entre más alto sea el percentil sobre el que se está evaluando, mejor información se va a obtener; aunque calcular sobre los percentiles más altos es más costoso.

Enfoques para hacer frente a la carga

¿Cómo mantener un buen rendimiento cuando nuestros parámetros de carga de datos se incrementan?

  • Escalar hacia arriba (vertical): más maquinas potentes
  • Escalar hacia los lados (horizontal): distribuir la carga en múltiples maquinas pequeñas

Algunos sistemas son elásticos, significa que pueden automáticamente añadir recursos computacionales cuando detectan que la carga de datos se incrementa, otros sistemas escalan manualmente. Es importante tener en cuenta que los sistemas sin estados internos pueden escalar de manera distribuida fácilmente entre varias máquinas, pero los sistemas que usan estados internos y que quieren escalar de un nodo a múltiples es más complejo.

MAINTAINABILITY

"Cuesta más mantener un software que construirlo"
Debemos tener en cuenta al construir sistemas que debemos minimizar el dolor que puede causar la mantención de este, pero como no hay una solución fácil para alcanzar esta meta, intentemos pensar en los siguientes principios:

  • Operabilidad: un equipo de operaciones debería ser capaz de mantener los sistemas corriendo correctamente
  • Simplicidad: hacer un sistema legible, evitar complejidad en el código
  • Evolucionalidad(?)(Evolvability): la habilidad de hacer cambios facilmente y sin romper otros componentes del sistema

Operabilidad - Hacerle la vida fácil al equipo de operaciones

Un buen equipo de operaciones puede buscar soluciones alternativas con respecto a las limitaciones de un software incompleto, pero un buen software usualmente no puede correr confiando en un mal equipo de operaciones.
Los equipos de operaciones son vitales para mantener el software, un buen equipo de operaciones es responsable de:

  • monitorear el sistema y ser capaz de restaurarlo si llega a un mal estado
  • rastrear la causa de los problemas, errores y mal rendimiento
  • tener la plataforma al dia con la última versión
  • saber sobre los cambios venideros y ayudar a evitar posibles problemas
  • establecer buenas prácticas y herramientas para configuración y despliegue
  • conocimiento en tareas complejas de mantenimiento
  • mantener la seguridad de los sistemas
  • definir procesos para mantener el sistema y su ambiente estable
  • documentar para que toda la organización sepa del uso y estado de los sistemas

Y los sistemas pueden hacerle la vida fácil al equipo de operaciones de la siguiente manera:

  • proveer visibilidad sobre los internals del sistema con un buen monitoreo
  • proveer buen soporte
  • evitar dependencias de todo tipo
  • proveer buena documentación
  • proveer un buen comportamiento por defecto (happy path)
  • habilidad de autocuración
  • minimizar sorpresas

Simplicidad: Gestionar la complejidad

Sistemas grandes se vuelven mas dificiles de entender, pueden tener mucho legacy code y se hace mas dificil para personas nuevas hacer cambios. Los sistemas que se hacen más dificiles de entender es usualmente por dependencia entre modules, acoplamiento, hacks al resolver problemas (o como decimos en la costa: "EMPANADAS") e inconsistencias en terminología. Estos problemas de complejidad pueden llevar a gastar mucho dinero en mantención. Por estas y otras razones, reducir la complejidad del sistema, mantenerlo simple, hace más fácil mantenerlo.

Una buena herramienta para eliminar complejidad es la abstracción que puede esconder implementación bajo una simple fachada y además hace mas simple usar ciertos módulos en diferentes partes del sistema. El autor menciona que a lo largo del libro explicará buenas prácticas de abstracción para mejorar la mantenabilidad del sistema.

Evolucionalidad (Evolvability): Hacer cambios fácilmente

Todos estamos conscientes que es muy probable que un sistema deba sufrir cambios, ya sea por cambios en el negocio o añadiduras necesarias para mejorarlo. Usar procedimientos ágiles o técnicas como TDD pueden ayudar a hacer mas faciles la implementación de cambios.

@glrodasz
Copy link

El termino Percentil puede ser un poco desconocido para los que no sabemos mucho de estadistica. Aquí dejo un articulo es español que explica y muestra ejemplos generales: https://www.matematicas10.net/2017/02/ejemplos-de-percentiles.html

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

4 participants