
Este es el segundo artículo de una serie sobre cómo nosotros en Citymobil aumentamos la estabilidad del servicio (puede leer el primero
aquí ). En este artículo, profundizaré en los detalles del análisis de accidentes. Pero antes de eso, cubriré un punto que tenía que pensar de antemano y cubrir en el primer artículo, pero no lo pensé. Y sobre lo que aprendí de los comentarios de los lectores. El segundo artículo me da la oportunidad de eliminar este molesto defecto.
0. Prólogo
Uno de los lectores hizo una pregunta muy justa: "¿Qué es difícil en el backend de un servicio de taxi?" La pregunta es buena. Me pregunté a mí mismo el verano pasado antes de comenzar a trabajar en Citymobil. Entonces pensé "pensar, un taxi, una aplicación con tres botones". ¿Qué podría ser complicado al respecto? Pero resultó que este es un servicio de muy alta tecnología y un producto complejo. Para al menos dejar en claro de qué se trata y qué es realmente un gran coloso tecnológico, hablaré sobre varias áreas de las actividades de productos de Citymobil:
- Precios. El equipo de fijación de precios se ocupa de los problemas de precios en cada punto y en cualquier momento. El precio se determina prediciendo el equilibrio de la oferta y la demanda en base a estadísticas y otros datos. Todo esto hace un servicio grande, complejo y en constante evolución basado en el aprendizaje automático.
- Precios. La implementación de varios métodos de pago, la lógica de los recargos después del viaje, la retención de fondos en tarjetas bancarias, facturación, interacción con socios y conductores.
- Distribución de pedidos. ¿A qué máquina distribuir el pedido de ventas? Por ejemplo, la opción de distribución para el más cercano no es la mejor en términos de aumentar el número de viajes. Una opción más correcta es comparar clientes y automóviles de tal manera que se maximice el número de viajes, dada la probabilidad de cancelación por parte de este cliente en particular en estas condiciones (porque lleva mucho tiempo) y la cancelación o sabotaje del pedido por parte de este conductor (porque toma demasiado tiempo o demasiado bajo verificar).
- Geo. Todo lo relacionado con la búsqueda y recepción de direcciones, puntos de aterrizaje, ajuste del tiempo de entrega (nuestros socios, proveedores de tarjetas y atascos de tráfico no siempre brindan información precisa sobre ETA, teniendo en cuenta los atascos de tráfico), mejorando la precisión de la geocodificación directa e inversa, mejorando la precisión de la máquina. Hay mucho trabajo con datos, muchos análisis, muchos servicios basados en aprendizaje automático.
- Antifraude La diferencia en el precio de un viaje para un pasajero y para un conductor (por ejemplo, en viajes cortos) crea un incentivo económico para los estafadores que intentan robar nuestro dinero. Combatir el fraude es algo similar a combatir el spam en el servicio de correo electrónico: la integridad y la precisión son importantes. Es necesario bloquear el número máximo de estafadores (integridad), pero los buenos usuarios no deben confundirse con los estafadores (precisión).
- Motivación de los conductores. El equipo de motivación del conductor se dedica al desarrollo de todo lo relacionado con aumentar el uso de nuestra plataforma por parte de los conductores y la lealtad del conductor debido a varios tipos de motivación. Por ejemplo, haz viajes X y obtén rublos Y adicionales para esto. O compre un turno por Z rublos y viaje sin comisión.
- Aplicación de controlador de fondo. Una lista de pedidos, un mapa de demanda (una pista de dónde ir al conductor para maximizar sus ingresos), cambios de estado de prokidyvaniya, un sistema de comunicación con conductores y mucho más.
- El backend de la aplicación del cliente (esta es probablemente la parte más obvia y lo que generalmente se entiende por el backend de un taxi): hacer pedidos, desplazarse por los estados sobre cambiar el estado del pedido, garantizar el movimiento de los automóviles en el mapa en el pedido y en la entrega, consejos de back-end y etc.
Esta es toda la punta del iceberg. La funcionalidad es mucho más. La interfaz fácil de usar oculta una gran parte submarina del iceberg.
Y ahora volviendo a los accidentes. Durante los seis meses de historia de accidentes, hemos compilado la siguiente categorización:
- lanzamiento pobre, errores 500;
- lanzamiento deficiente, código subóptimo, carga en la base;
- intervención manual fallida en el sistema;
- huevo de pascua
- causas externas;
- lanzamiento deficiente, funcionalidad rota.
A continuación, escribiré qué conclusiones hicimos sobre los tipos más comunes de accidentes.
1. Mala versión, errores 500
Casi todo nuestro backend está escrito en PHP, un lenguaje interpretado con escritura débil. Sucede que despliega el código y se bloquea debido a un error en el nombre de la clase o función. Y este es solo un ejemplo cuando aparece el error número 500. También puede aparecer en caso de un error lógico en el código; lamí la rama equivocada; borró accidentalmente la carpeta con el código; dejó en el código los artefactos temporales necesarios para la prueba; no cambió la estructura de las tablas de acuerdo con el nuevo código; no reinició ni detuvo los scripts cron necesarios.
Luchamos con este problema secuencialmente en varias etapas. Los viajes perdidos debido a una mala liberación son obviamente proporcionales al tiempo que estuvo en uso. Es decir, debemos hacer todo lo posible para garantizar que una versión deficiente funcione lo menos posible. Cualquier cambio en el proceso de desarrollo que reduzca el tiempo promedio que se tarda en utilizar una versión incorrecta en al menos 1 segundo es positivo para la empresa y debe implementarse.
Una mala liberación o cualquier accidente de producción generalmente pasa por dos estados, que llamamos "etapa pasiva" y "etapa activa". La etapa pasiva es cuando aún no nos damos cuenta del accidente. La etapa activa es cuando ya estamos en el saber. El accidente comienza en la etapa pasiva y, con el tiempo, cuando nos damos cuenta, el accidente pasa a la etapa activa: comenzamos a combatirlo: primero lo diagnosticamos y luego lo reparamos.
Para reducir la duración de cualquier accidente en la producción, es necesario reducir la duración promedio de las etapas pasiva y activa. Lo mismo ocurre con un mal lanzamiento, porque es en sí mismo una especie de accidente.
Comenzamos a analizar nuestro proceso actual de reparación de accidentes. Los lanzamientos incorrectos que encontramos en el momento del inicio del análisis dieron como resultado un promedio inactivo (total o parcial) de 20-25 minutos. La etapa pasiva usualmente toma 15 minutos, la activa 10 minutos. Durante la fase pasiva, las quejas de los usuarios comenzaron a ser procesadas por el centro de contacto, y después de cierto umbral, el centro de contacto se quejó de chats generales en Slack. A veces, uno de los empleados se quejaba cuando no podía pedir un taxi. Una queja de los empleados fue una señal para nosotros sobre un problema grave. Después de la transición de una mala versión a la etapa activa, comenzamos a diagnosticar el problema, analizamos las últimas versiones, varios gráficos y registros para determinar la causa del accidente. Después de descubrir la razón, revertimos el código si la versión incorrecta se bombeó por última vez, o hicimos una nueva reversión con una confirmación de lanzamiento incorrecta inversa.
Aquí hay un proceso para lidiar con lanzamientos malos, tuvimos que mejorar.
1.1. Reducción de etapa pasiva
En primer lugar, notamos que si una versión deficiente está acompañada de 500 errores, entonces podemos entender sin quejas que ha ocurrido un problema. Afortunadamente, todos los errores número 500 se registraron en New Relic (este es uno de los sistemas de monitoreo que usamos), y solo quedaba para atornillar las notificaciones de SMS e IVR sobre el exceso de una cierta frecuencia de "quinientos" (con el tiempo, el umbral se redujo constantemente).
Esto llevó al hecho de que la etapa activa del accidente, como "Mala versión, errores número 500", comenzó casi inmediatamente después de la liberación. El proceso en caso de accidente comenzó a verse así:
- El programador implementa el código.
- El lanzamiento lleva a un accidente (500 masivos).
- SMS llega.
- Los programadores y administradores comienzan a entender (a veces no de inmediato, pero después de 2-3 minutos: los SMS pueden retrasarse, el sonido en el teléfono puede apagarse y la cultura de acciones inmediatas después de SMS no puede aparecer en un día).
- Comienza la fase activa del accidente, que dura los mismos 10 minutos que antes.
Por lo tanto, la etapa pasiva se redujo de 15 minutos a 3.
1.2. Reducción adicional de la etapa pasiva.
A pesar de la reducción de la etapa pasiva a 3 minutos, incluso una etapa pasiva tan corta nos molestó más que la activa, porque durante la etapa activa ya hacemos algo para resolver el problema, y durante la etapa pasiva el servicio no funciona en su totalidad o en parte, pero " los hombres no lo saben ".
Para reducir aún más la etapa pasiva, decidimos sacrificar tres minutos de tiempo de desarrollador después de cada lanzamiento. La idea era muy simple: despliega el código y mira New Relic, Sentry, Kibana durante tres minutos para ver si hay 500 errores. Tan pronto como vea un problema allí, a priori asume que está relacionado con su código y comienza a comprender.
Elegimos tres minutos en función de las estadísticas: a veces aparecían problemas en los gráficos con un retraso de 1-2 minutos, pero nunca había más de tres minutos.
Esta regla se registró en lo que se debe y no se debe hacer. Al principio no siempre se ejecutó, pero gradualmente los desarrolladores se acostumbraron a la regla como higiene elemental: cepillarse los dientes por la mañana también es una pérdida de tiempo, pero debe hacerlo.
Como resultado, la etapa pasiva se redujo a 1 minuto (los horarios todavía llegaban tarde a veces). Como sorpresa agradable, esto simultáneamente redujo la etapa activa. Después de todo, el desarrollador encuentra un problema en buena forma y está listo para deshacer inmediatamente su código. Aunque esto no siempre ayuda, porque El problema podría haber surgido debido al código de otra persona que se estaba implementando en paralelo. Pero, sin embargo, la etapa activa en promedio se redujo a 5 minutos.
1.3. Reducción adicional en la etapa activa
Más o menos satisfechos con un minuto de la etapa pasiva, comenzamos a pensar en una reducción adicional en la etapa activa. En primer lugar, prestamos atención a la historia de los problemas (¡es la piedra angular en la construcción de nuestra estabilidad!) Y descubrimos que en muchos casos no retrocedemos inmediatamente porque no entendemos a qué versión retroceder, porque hay muchas versiones paralelas. Para resolver este problema, presentamos la siguiente regla (y la registramos en lo que se debe y no se debe hacer): antes del lanzamiento, escribes en el chat en Slack, para qué estás rodando y qué, y en caso de accidente, escribes en el chat "¡accidente, no ruedes!". Además, comenzamos a informar automáticamente por SMS sobre los hechos de la publicación para notificar a aquellos que no entran al chat.
Esta simple regla redujo drásticamente el número de liberaciones ya durante los accidentes y redujo la etapa activa, de 5 minutos a 3.
1.4. Una reducción aún mayor en la etapa activa
A pesar del hecho de que advertimos en el chat sobre todos los lanzamientos y bloqueos, a veces aparecían condiciones de carrera: uno escribió sobre el lanzamiento y el otro ya se lanzó en ese momento; o cuando comenzó el accidente, escribieron sobre eso en el chat, y alguien acaba de lanzar un nuevo código. Estas circunstancias alargaron el diagnóstico. Para resolver este problema, implementamos una prohibición automática de versiones paralelas. La idea es muy simple: después de cada versión, el sistema CI / CD prohíbe que todos se lancen durante los próximos 5 minutos, excepto el autor de la última versión (para que pueda lanzar o hacer hotfix si es necesario) y varios desarrolladores especialmente experimentados (en caso de emergencia). Además, el sistema CI / CD prohíbe el despliegue durante un accidente (es decir, desde el momento de la recepción de la notificación del comienzo del accidente hasta el momento de la recepción de la notificación de su finalización).
Por lo tanto, el proceso se hizo así: el desarrollador implementa, monitorea los gráficos durante tres minutos, y después de eso durante dos minutos más, nadie puede implementar nada. Si hay un problema, entonces el desarrollador revierte la versión. Esta regla simplificó radicalmente el diagnóstico, y la duración total de las etapas activa y pasiva disminuyó de 3 + 1 = 4 minutos a 1 + 1 = 2 minutos.
Pero dos minutos del accidente son muchos. Por lo tanto, continuamos optimizando el proceso.
1.5. Detección automática de fallas y reversión
Hemos estado pensando durante mucho tiempo cómo reducir la duración del accidente debido a las bajas emisiones. Incluso intentaron obligarse a mirar en la
tail -f error_log | grep 500
tail -f error_log | grep 500
. Pero al final, todos se decidieron por una solución cardinal automática.
En resumen, este es un retroceso automático. Configuramos un servidor web separado, en el que cargamos 10 veces menos carga del equilibrador que en otros servidores web. Cada versión fue implementada automáticamente por el sistema CI / CD en este servidor separado (lo llamamos preprod, aunque, a pesar del nombre, la carga real de los usuarios reales fue allí). Y luego la automatización hizo
tail -f error_log | grep 500
tail -f error_log | grep 500
. Si no se produjo el error número 500 en un minuto, el CI / CD desplegó el nuevo código en producción. Si aparecieron errores, el sistema inmediatamente revierte todo. Al mismo tiempo, en el nivel de equilibrador, todas las solicitudes completadas con 500 errores en el preprod se duplicaron en uno de los servidores de producción.
Esta medida redujo el efecto de las quinientas versiones a cero. Al mismo tiempo, en caso de errores en la automatización, no cancelamos la regla durante tres minutos para monitorear los gráficos. Eso se trata de malas versiones y errores número 500. Pasamos al siguiente tipo de accidente.
2. Lanzamiento incorrecto, código subóptimo, carga base
Comenzaré de inmediato con un ejemplo concreto de un accidente de este tipo. Implementamos la optimización: agregamos
USE INDEX
a la consulta SQL, durante la prueba de estas consultas cortas aceleradas, como en la producción, pero las consultas largas se ralentizaron. La desaceleración de las consultas largas solo se notó en la producción. Como resultado, el flujo de solicitudes largas puso a toda la base maestra durante una hora. Entendimos completamente cómo funciona
USE INDEX
, lo describimos en el archivo de hacer y no hacer, y advertimos a los desarrolladores contra el mal uso. También analizamos la consulta y nos dimos cuenta de que devuelve principalmente datos históricos, lo que significa que se puede ejecutar en una réplica separada para consultas históricas. Incluso si esta réplica se encuentra bajo carga, el negocio no se detendrá.
Después de este incidente, todavía nos encontramos con problemas similares, y en algún momento decidimos abordar el problema sistemáticamente. Escaneamos todo el código con un peine frecuente y realizamos a la réplica todas las solicitudes que se pueden realizar allí sin comprometer la calidad del servicio. Al mismo tiempo, dividimos las réplicas de acuerdo con los niveles de criticidad para que la caída de cualquiera de ellas no detuviera el servicio. Como resultado, llegamos a una arquitectura que tiene las siguientes bases:
- base maestra (para operaciones de escritura y para consultas que son supercríticas para la actualización de datos);
- réplica de producción (para consultas cortas que son un poco menos críticas para la actualización de datos);
- réplica para calcular las relaciones de precios, el llamado aumento de precios. Esta réplica puede retrasarse entre 30 y 60 segundos: esto no es crítico, los coeficientes cambian con poca frecuencia y si esta réplica cae, el servicio no se detendrá, solo los precios no coincidirán con el equilibrio de la oferta y la demanda;
- réplica para el panel de administración de usuarios comerciales y el centro de contacto (si cae, el negocio principal no aumentará, pero el soporte no funcionará y no podremos ver ni cambiar la configuración temporalmente);
- muchas réplicas para análisis;
- Base de datos MPP para análisis pesados con cortes completos según datos históricos.
Esta arquitectura nos dio más espacio para el crecimiento y redujo el número de bloqueos en un orden de magnitud debido a consultas SQL subóptimas. Pero ella todavía está lejos de ser ideal. Planea hacer sharding para que puedas escalar actualizaciones y eliminaciones, así como consultas cortas supercríticas para la actualización de estos datos. El margen de seguridad de MySQL no es infinito. Pronto necesitaremos artillería pesada en forma de Tarantool. ¡Sobre esto será necesario en los siguientes artículos!
En el proceso de la prueba con código y solicitudes no óptimos, nos dimos cuenta de lo siguiente: es mejor eliminar cualquier falta de optimización antes del lanzamiento, y no después. Esto reduce el riesgo de un accidente y el tiempo dedicado por los desarrolladores a la optimización. Porque si el código ya se ha descargado y hay nuevas versiones además, es mucho más difícil de optimizar. Como resultado, introdujimos una verificación de código obligatoria para la optimización. Lo llevan a cabo los desarrolladores más experimentados, de hecho, nuestras fuerzas especiales.
Además, comenzamos a recopilar en do's & dont's los mejores métodos de optimización de código que funcionan en nuestras realidades, se enumeran a continuación. Por favor, no perciban estas prácticas como una verdad absoluta y no intenten repetirlas ciegamente en ustedes mismos. Cada método tiene sentido solo para una situación específica y un negocio específico. Aquí se dan solo por ejemplo, para que los detalles sean claros:
- Si la consulta SQL no depende del usuario actual (por ejemplo, un mapa de demanda de controladores que indique las tasas de viajes mínimos y coeficientes para polígonos), entonces esta consulta debe ser realizada por cron con cierta frecuencia (en nuestro caso, una vez por minuto es suficiente). Escriba el resultado en el caché (Memcached o Redis), que ya se usa en el código de producción.
- Si la consulta SQL funciona con datos cuya acumulación no es crítica para el negocio, entonces su resultado debe almacenarse en caché con algunos TTL (por ejemplo, 30 segundos). Y luego, en solicitudes posteriores, leer desde el caché.
- Si en el contexto del procesamiento de una solicitud en la web (en nuestro caso, en el contexto de la implementación de un método de servidor específico en PHP) desea realizar una consulta SQL, debe asegurarse de que estos datos no hayan "llegado" con ninguna otra consulta SQL (y si llegarán más lejos por código). Lo mismo se aplica al acceso a la memoria caché: también se puede inundar con solicitudes si lo desea, por lo tanto, si los datos ya han "llegado" de la memoria caché, entonces no es necesario que vaya a la memoria caché como a su hogar y la retire, que ya está quitada.
- Si en el contexto del procesamiento de consultas en la web desea llamar a alguna función, debe asegurarse de que no se realizarán consultas SQL adicionales ni acceso a la caché en sus menudillos. Si llamar a una función de este tipo es inevitable, debe asegurarse de que no se pueda modificar o que su lógica se rompa para no realizar consultas innecesarias en las bases de datos / cachés.
- Si aún necesita ingresar a SQL, debe asegurarse de que no puede agregar los campos necesarios más altos o más bajos en el código a las consultas que ya existen en el código.
3. Intervención manual fallida en el sistema
Ejemplos de tales accidentes: un ALTER sin éxito (que sobrecargó la base de datos o provocó un retraso de la réplica) o DROP sin éxito (se encontró con un error en MySQL, bloqueó la base de datos cuando se dejó caer una nueva tabla); fuerte solicitud de un maestro hecho por error a mano; Realizamos trabajo en el servidor bajo carga, aunque pensamos que no tenía trabajo.
Para minimizar las caídas por estos motivos, es necesario, desafortunadamente, comprender la naturaleza del accidente cada vez. Todavía no hemos encontrado la regla general. De nuevo, prueba los ejemplos. Digamos que, en algún momento, los coeficientes de sobretensión dejaron de funcionar (multiplican el precio del viaje en el lugar y momento de mayor demanda). La razón fue que en la réplica de la base de datos, de donde provienen los datos para calcular los coeficientes, el script Python funcionó, que se comió toda la memoria, y la réplica se cayó. El script se ha estado ejecutando durante mucho tiempo, funcionó en una réplica solo por conveniencia. El problema se resolvió reiniciando el script. Las conclusiones fueron las siguientes: no ejecute scripts de terceros en una máquina con una base de datos (grabada en hacer y no hacer, de lo contrario, es un tiro en blanco!), Monitoree el final de la memoria en una máquina con una réplica y alerta por SMS si la memoria se agota pronto.
Es muy importante sacar siempre conclusiones y no caer en una situación cómoda "vieron un problema, lo solucionaron y lo olvidaron". Un servicio de calidad solo se puede construir si se extraen conclusiones. Además, las alertas por SMS son muy importantes: establecen la calidad del servicio en un nivel superior al que tenían, evitan que se caiga y mejoran aún más la confiabilidad. Como escalador de cada estado estable, se levanta y queda fijo en otro estado estable, pero a mayor altitud.
Monitorear y alertar con ganchos de hierro invisibles pero rígidos cortan la roca de la incertidumbre y nunca nos dejan caer por debajo del nivel de estabilidad que establecemos, que constantemente elevamos solo.
4. huevo de pascua
Lo que llamamos el "huevo de Pascua" es una bomba de tiempo que ha existido durante mucho tiempo, pero que no hemos encontrado. Fuera de este artículo, este término se refiere a una característica no documentada hecha a propósito. En nuestro caso, esto no es una característica en absoluto, sino más bien un error, pero que funciona como una bomba de tiempo y que es un efecto secundario de las buenas intenciones.
Por ejemplo: desbordamiento de 32 bits
auto_increment
; no optimidad en el código / configuración, "disparo" debido a la carga; réplica retrasada (generalmente debido a una solicitud subóptima de una réplica que se activó por un nuevo patrón de uso, o una carga más alta, o debido a una ACTUALIZACIÓN subóptima en el maestro que fue llamado por un nuevo patrón de carga y cargó la réplica).
Otro tipo popular de huevo de Pascua es el código no óptimo y, más específicamente, la consulta SQL no óptima. Anteriormente, la tabla era más pequeña y la carga era menor: la consulta funcionó bien. Y con el aumento de la tabla, lineal en el tiempo y el crecimiento de la carga, lineal en el tiempo, el consumo de recursos DBMS creció de forma cuadrática. Por lo general, esto lleva a un efecto negativo agudo: todo estaba "bien" y explosión.
Los escenarios más raros son una combinación de insectos y huevos de pascua. Un lanzamiento con un error provocó un aumento en el tamaño de la tabla o un aumento en el número de registros en una tabla de cierto tipo, y un huevo de Pascua ya existente causó una carga excesiva en la base de datos debido a consultas más lentas a esta tabla demasiado grande.
Aunque, también tuvimos huevos de Pascua, no relacionados con la carga. Por ejemplo,
auto increment
32 bits: después de dos y algunos miles de millones de registros en la tabla, las inserciones dejan de realizarse. Por lo tanto, el campo de
auto increment
en el mundo moderno debe hacerse de 64 bits. Aprendimos bien esta lección.
¿Cómo lidiar con los huevos de Pascua? La respuesta es simple: a) busque "huevos" viejos yb) evite que aparezcan nuevos. Intentamos cumplir ambos puntos. La búsqueda de viejos "huevos" en nuestro país está asociada con la optimización constante del código. Identificamos a dos de los desarrolladores más experimentados para la optimización casi a tiempo completo. Encuentran en slow.log consultas que consumen la mayoría de los recursos de la base de datos, optimizan estas consultas y el código que las rodea. Reducimos la probabilidad de nuevos huevos al verificar el código de optimización de cada confirmación por parte del sensei rezrabotchiki mencionado anteriormente. Su tarea es señalar errores que afectan el rendimiento; decirle cómo hacerlo mejor y transferir conocimientos a otros desarrolladores.
En algún momento después del siguiente huevo de pascua que encontramos, nos dimos cuenta de que buscar consultas lentas es bueno, pero valdría la pena buscar consultas que parezcan lentas pero que funcionen rápido. Estos son solo los próximos candidatos para poner todo en caso de un crecimiento explosivo de la siguiente tabla.
5. Causas externas
Estas son razones que creemos que están mal controladas por nosotros. Por ejemplo:
- Trote por Google Maps. Puede evitarlo monitoreando el uso de este servicio, observando un cierto nivel de carga, planificando el crecimiento de la carga por adelantado y comprando la expansión del servicio.
- La caída de la red en el centro de datos. Puede moverse colocando una copia del servicio en el centro de datos de respaldo.
- Accidente de servicio de pago. Puede omitir la reserva de servicios de pago.
- Bloqueo de tráfico erróneo por parte del servicio de protección DDoS. Puede moverse deshabilitando el servicio de protección DDoS predeterminado y habilitándolo solo en caso de un ataque DDoS.
Dado que eliminar una causa externa es una tarea larga y costosa (por definición), acabamos de comenzar a recopilar estadísticas sobre accidentes debido a causas externas y esperar la acumulación de masa crítica. No existe una receta para determinar la masa crítica. Simplemente funciona la intuición. Por ejemplo, si estuviéramos 5 veces en tiempo de inactividad completo debido a problemas, por ejemplo, del servicio de control DDoS, entonces con cada próxima caída se volverá cada vez más agudo para plantear la cuestión de una alternativa.
Por otro lado, si de alguna manera puede hacer que funcione con un servicio externo inaccesible, entonces definitivamente lo hacemos. Y esto nos ayuda a realizar análisis post-mortem de cada otoño. Siempre debe haber una conclusión. Eso significa que siempre quieres-no-quieres, pero puedes encontrar una solución alternativa.
6. Mala versión, funcionalidad rota
Este es el tipo de accidente más desagradable. El único tipo de accidente que no es visible por ningún síntoma que no sean las quejas de usuarios / negocios. Por lo tanto, tal accidente, especialmente si no es grande, puede pasar desapercibido en la producción durante mucho tiempo.
Todos los otros tipos de accidentes son más o menos similares a "mala liberación, errores número 500". Es solo que el disparador no es una liberación, sino una carga, una operación manual o un problema del lado de un servicio externo.
Para describir el método de tratar este tipo de accidente, es suficiente recordar una anécdota barbuda:
A las matemáticas y la física se les ofreció la misma tarea: hervir una tetera. Se entregan herramientas auxiliares: estufa, hervidor de agua, grifo con agua, fósforos. Ambos vierten agua alternativamente en el hervidor, encienden el gas, lo encienden y encienden el hervidor. Luego la tarea se simplificó: se propuso una tetera llena de agua y una estufa con gas ardiente. El objetivo es el mismo: hervir agua. El físico prende fuego a la tetera. El matemático vierte agua de la tetera, apaga el gas y dice: "La tarea se ha reducido a la anterior". anekdotov.net
Este tipo de accidente debe reducirse por todos los medios a "mala liberación, errores número 500". Idealmente, si los errores en el código se guardaron en el registro como un error. Bueno, o al menos dejó rastros en la base de datos. A partir de estos rastros, puede comprender que se ha producido un error e inmediatamente alertar. ¿Cómo contribuir a esto? Comenzamos a analizar cada error importante y ofrecer soluciones, qué tipo de monitoreo / alerta de SMS se puede hacer para que este error se manifieste inmediatamente de la misma manera que el error número 500.
6.1. Ejemplo
Hubo quejas masivas: los pedidos pagados a través de Apple Pay no se cierran. Comenzaron a entender, el problema se repitió. Encontramos la razón: realizamos mejoras en el formato de
expire date
de las tarjetas bancarias al interactuar con la adquisición, como resultado de lo cual comenzaron a transferirlo específicamente para pagos a través de Apple Pay en el formato que se esperaba del servicio de procesamiento de pagos (de hecho, uno es tratable, mutilar algo más), por lo que todos los pagos a través de Apple Pay comenzaron a declinar. Rápidamente arreglado, desplegado, el problema desapareció. Pero "vivieron" con el problema durante 45 minutos.
Siguiendo los rastros de este problema, monitoreamos el número de pagos fallidos a través de Apple Pay, y también realizamos una alerta SMS / IVR con un umbral distinto de cero (porque los pagos fallidos son la norma desde el punto de vista del servicio, por ejemplo, el cliente no tiene dinero en la tarjeta o la tarjeta está bloqueada) . A partir de este momento, cuando se supera el umbral, aprendemos instantáneamente sobre el problema. Si la nueva versión presenta CUALQUIER problema en el procesamiento de Apple Pay, lo que conducirá a la inoperancia del servicio, incluso parcial, lo aprenderemos de inmediato a partir del monitoreo y revertiremos la versión en tres minutos (se describe anteriormente cómo funciona el proceso de laminación manual). Fueron 45 minutos de tiempo de inactividad parcial, se convirtieron en 3 minutos. Ganancia
6.2. Otros ejemplos
Lanzamos la optimización de la lista de pedidos ofrecidos a los conductores. Un error se deslizó en el código. Como resultado, los conductores en algunos casos no vieron la lista de pedidos (estaba vacía). Descubrieron el error por accidente: uno de los empleados examinó la solicitud del conductor. Retrocedió rápidamente. Como conclusión del accidente, hicimos un gráfico del número promedio de pedidos en la lista de controladores de acuerdo con la base de datos, observamos el gráfico retroactivamente durante un mes, vimos una falla allí e hicimos una alerta por SMS para la consulta SQL, que forma este gráfico cuando el número promedio de pedidos en la lista debajo del umbral seleccionado en función del mínimo histórico del mes.
Cambió la lógica de dar devolución de dinero a los usuarios para los viajes. Incluido distribuido al grupo de usuarios incorrecto. Solucionamos el problema, construimos un calendario de devoluciones de efectivo entregados, vimos un fuerte aumento allí, también vimos que nunca había habido tal crecimiento, hicimos una alerta por SMS.
Con el lanzamiento, se rompió la funcionalidad de cerrar las órdenes (la orden se cerró para siempre, el pago con tarjetas no funcionó, los conductores exigieron el pago en efectivo de los clientes). El problema fue de 1,5 horas (etapas total pasiva y activa). Aprendimos sobre el problema del centro de contacto de quejas. Hicieron una corrección, monitorearon y alertaron sobre el tiempo de cierre de las órdenes con umbrales encontrados en el estudio de gráficos históricos.
Como puede ver, el enfoque para este tipo de accidente es siempre el mismo:
- Lanza el lanzamiento.
- Aprende sobre el problema.
- Arreglarlo
- Determinamos qué rastros (en la base de datos, registros, Kiban) puede encontrar los signos del problema.
- Trazamos estos signos.
- Lo rebobinamos hacia el pasado y observamos las explosiones / caídas.
- Seleccionamos el umbral correcto para la alerta.
- Cuando surge un problema nuevamente, nos enteramos de inmediato a través de una alerta.
Lo bueno de este método: una gran clase de problemas se cierra de inmediato con un gráfico y una alerta (ejemplos de clases de problemas: no cierre de pedidos, bonos adicionales, falta de pago a través de Apple Pay, etc.).
Con el tiempo, hemos creado alertas y monitoreo para cada error importante como parte de la cultura de desarrollo. Para evitar que esta cultura se pierda, la formalizamos un poco. Para cada accidente, comenzaron a exigir un informe de ellos mismos. Un informe es un formulario completo con respuestas a las siguientes preguntas: causa raíz, método de eliminación, impacto en el negocio, conclusiones. Todos los artículos son obligatorios. Por lo tanto, si lo quieres o no, escribirás las conclusiones. Este cambio de proceso, por supuesto, fue escrito por do's & dont's.
7. Kotan
, , -, . - ( , ) «». «». :-)
«» :
. — , . , ( ), ( ) , . ( , ).
. , . , : — , — . , « 500- 1 %» — . « 500- 1 %, - , - , - » — . , . ( ). , : , «», , , , . — . ( , ). .
. . , ( , , ), , : , , , .
. , , ( , ).
8. ?
— . . : , . , , . , , , .. — , — ! , . , , ? , , .. , , .
. . ( , ), , : , , , . , , . . . -, , . , , , — : .
9.
, .
? | ? |
---|
.
| .
|
( ) post-mortem.
| .
|
do's & dont's.
| , , .
|
, 5 .
| .
|
, .
| .
|
.
| .
|
| .
|
.
| .
|
.
| .
|
SMS/IVR- .
| .
|
( ) .
| .
|
.
| - .
|
( — slow.log).
| - « ».
|
.
| .
|
.
| .
|
.
| , , .
|
«» — .
| , .
|
.
| .
|
, ! , , , , !