Citymobil - um guia para startups para aumentar a estabilidade em meio ao crescimento. Parte 2. Quais são os tipos de acidentes?



Este é o segundo artigo de uma série sobre como nós da Citymobil aumentamos a estabilidade do serviço (você pode ler o primeiro aqui ). Neste artigo, vou me aprofundar nas especificidades da análise de acidentes. Mas, antes disso, abordarei um ponto em que tive que pensar com antecedência e abordar no primeiro artigo, mas não pensei nisso. E sobre o qual aprendi com o feedback dos leitores. O segundo artigo me dá a chance de eliminar esse defeito irritante.

0. Prólogo


Um dos leitores fez uma pergunta muito justa: "O que é difícil no backend de um serviço de táxi?" A pergunta é boa. Eu me perguntei no verão passado antes de começar a trabalhar na Citymobil. Então pensei "pense em um táxi, em um aplicativo com três botões". O que poderia ser complicado sobre isso? Mas aconteceu que este é um serviço de alta tecnologia e um produto complexo. Para pelo menos esclarecer o que é e o que realmente é um grande colosso tecnológico, falarei sobre várias áreas das atividades de produtos da Citymobil:

  • Preços. A equipe de preços lida com problemas de preços em todos os pontos e a qualquer momento. O preço é determinado pela previsão do balanço de oferta e demanda com base em estatísticas e outros dados. Tudo isso cria um serviço grande, complexo e em constante evolução, baseado no aprendizado de máquina.
  • Preços. A implementação de vários métodos de pagamento, a lógica das sobretaxas após a viagem, reter fundos em cartões bancários, cobrança, interação com parceiros e motoristas.
  • Distribuição de pedidos. Em qual máquina distribuir o pedido de vendas? Por exemplo, a opção de distribuição para a mais próxima não é a melhor em termos de aumento do número de viagens. Uma opção mais correta é comparar clientes e carros de forma a maximizar o número de viagens, dada a probabilidade de cancelamento por esse cliente em particular nessas condições (porque leva muito tempo) e o cancelamento ou sabotagem do pedido por esse motorista (porque leva muito tempo ou muito pouco cheque).
  • Geo. Tudo relacionado à busca e localização de endereços, pontos de aterrissagem, ajuste do tempo de entrega (nossos parceiros, fornecedores de cartões e engarrafamentos nem sempre fornecem informações precisas sobre o ETA, levando em conta os engarrafamentos), melhorando a precisão do geocodificação direta e reversa, melhorando a precisão da máquina. Há muito trabalho com dados, muitas análises, muitos serviços baseados no aprendizado de máquina.
  • Antifraude. A diferença no preço de uma viagem para um passageiro e um motorista (por exemplo, em viagens curtas) cria um incentivo econômico para os fraudadores que estão tentando roubar nosso dinheiro. O combate à fraude é um pouco semelhante ao combate ao spam no serviço de email - a integridade e a precisão são importantes. É necessário bloquear o número máximo de fraudadores (perfeição), mas bons usuários não devem ser confundidos com fraudadores (precisão).
  • Motivação dos motoristas. A equipe de motivação do motorista está envolvida no desenvolvimento de tudo relacionado ao aumento do uso da nossa plataforma pelos motoristas e pela lealdade do motorista devido a vários tipos de motivação. Por exemplo, faça viagens X e obtenha rublos Y adicionais para isso. Ou compre um turno por rublos Z e viaje sem comissão.
  • Aplicativo de driver de back-end. Uma lista de pedidos, um mapa de demanda (uma dica para onde ir ao motorista para maximizar sua receita), alterações de status prokidyvaniya, um sistema de comunicação com drivers e muito mais.
  • O back-end do aplicativo cliente (esta é provavelmente a parte mais óbvia e o que geralmente é entendido pelo back-end de um táxi): fazer pedidos, rolar status sobre a alteração do status do pedido, garantir a circulação de carros no mapa no pedido e na entrega, dicas de back-end e etc.

Esta é toda a ponta do iceberg. Funcionalidade é muito mais. A interface amigável esconde uma enorme parte subaquática do iceberg.

E agora de volta aos acidentes. Nos seis meses de histórico de acidentes, compilamos a seguinte categorização:

  • versão ruim, 500 erros;
  • liberação ruim, código abaixo do ideal, carga na base;
  • intervenção manual malsucedida no sistema;
  • ovo de páscoa;
  • causas externas;
  • versão ruim, funcionalidade corrompida.

Abaixo, anotarei as conclusões que tiramos sobre os tipos mais comuns de acidentes.

1. Versão ruim, 500º erros


Quase todo o nosso back-end é escrito em PHP, uma linguagem interpretada com digitação fraca. Acontece que você lança o código e ele falha devido a um erro no nome da classe ou função. E este é apenas um exemplo quando o 500º erro aparece. Também pode aparecer no caso de um erro lógico no código; lambeu o ramo errado; acidentalmente excluiu a pasta com o código; deixado no código artefatos temporários necessários para teste; não alterou a estrutura das tabelas de acordo com o novo código; não reiniciou ou parou os scripts cron necessários.

Lutamos com esse problema sequencialmente em várias etapas. As viagens perdidas devido a baixa liberação são obviamente proporcionais ao tempo em que foram usadas. Ou seja, devemos fazer o possível para garantir que uma versão ruim esteja em operação o mínimo possível. Qualquer alteração no processo de desenvolvimento que reduz o tempo médio necessário para obter uma versão ruim em uso por pelo menos 1 segundo é positiva para os negócios e precisa ser implementada.

Uma versão ruim ou qualquer acidente de produção geralmente passa por dois estados, que chamamos de "estágio passivo" e "estágio ativo". O estágio passivo é quando ainda não estamos cientes do acidente. O estágio ativo é quando já estamos sabendo. O acidente começa na fase passiva e, com o tempo, quando descobrimos, o acidente entra na fase ativa - começamos a combatê-lo: primeiro diagnosticamos e depois reparamos.

Para reduzir a duração de qualquer acidente na produção, é necessário reduzir a duração média dos estágios passivo e ativo. O mesmo vale para uma versão ruim, porque é em si um tipo de acidente.

Começamos a analisar nosso processo atual de reparação de acidentes. As versões ruins que encontramos no momento do início da análise resultaram em uma média ociosa (total ou parcial) de 20 a 25 minutos. O estágio passivo geralmente levava 15 minutos, o ativo 10 minutos. Durante a fase passiva, as reclamações dos usuários começaram a ser processadas pelo contact center e, após algum limiar, o contact center se queixou de chats gerais no Slack. Às vezes, um dos funcionários reclamava quando ele não podia pedir um táxi. Uma reclamação de funcionário foi um sinal para nós sobre um problema sério. Após a transição de uma versão ruim para o estágio ativo, começamos a diagnosticar o problema, analisamos as versões mais recentes, vários gráficos e logs para determinar a causa do acidente. Após descobrir o motivo, revertemos o código se a versão ruim foi lançada por último ou fizemos uma nova reversão com o reverso da confirmação da versão ruim.

Aqui está um processo para lidar com lançamentos ruins, tivemos que melhorar.

1.1 Redução passiva do estágio


Antes de tudo, percebemos que, se uma versão ruim é acompanhada por 500 erros, podemos entender sem queixa que ocorreu um problema. Felizmente, todos os 500 erros foram registrados na New Relic (este é um dos sistemas de monitoramento que usamos), e restava apenas enviar notificações por SMS e URA sobre o excesso de uma certa frequência de "quinhentos" (com o tempo, o limite era constantemente reduzido).

Isso levou ao fato de que a fase ativa do acidente, como "Versão ruim, 500º erro" começou quase imediatamente após a versão. O processo em caso de acidente começou a ter a seguinte aparência:

  1. O programador implementa o código.
  2. O lançamento leva a um acidente (enormes 500s).
  3. O SMS chega.
  4. Programadores e administradores começam a entender (às vezes não imediatamente, mas após 2-3 minutos: o SMS pode atrasar, o som do telefone pode ser desligado e a cultura de ações imediatas após o SMS não pode aparecer em um dia).
  5. A fase ativa do acidente começa, que dura os mesmos 10 minutos de antes.

Assim, o estágio passivo foi reduzido de 15 minutos para 3.

1.2 Redução adicional do estágio passivo


Apesar da redução do estágio passivo para 3 minutos, mesmo um estágio passivo tão curto nos incomodou mais do que o ativo, porque durante o estágio ativo já fazemos algo para resolver o problema e, durante o estágio passivo, o serviço não funciona no todo ou em parte, mas “ os homens não sabem. "

Para reduzir ainda mais o estágio passivo, decidimos sacrificar três minutos de tempo do desenvolvedor após cada versão. A idéia era muito simples: você lança o código e olha para New Relic, Sentry, Kibana por três minutos para ver se há 500 erros. Assim que você encontrar um problema, a priori, você assume que está relacionado ao seu código e começa a entender.

Escolhemos três minutos com base nas estatísticas: às vezes os problemas apareciam nas paradas com um atraso de 1-2 minutos, mas nunca havia mais de três minutos.

Esta regra foi registrada em fazer e não fazer. No começo, nem sempre era executado, mas gradualmente os desenvolvedores se acostumavam à regra como higiene básica: escovar os dentes pela manhã também é uma perda de tempo, mas é preciso fazer isso.

Como resultado, o estágio passivo foi reduzido para 1 minuto (os horários ainda estavam atrasados ​​às vezes). Como uma surpresa agradável, isso reduziu simultaneamente o estágio ativo. Afinal, o desenvolvedor encontra um problema em boa forma e está pronto para reverter imediatamente seu código. Embora isso nem sempre ajude, porque o problema poderia ter surgido devido ao código de outra pessoa que estava sendo implementado em paralelo. Mas, no entanto, o estágio ativo foi reduzido em média para 5 minutos.

1.3 Redução adicional no estágio ativo


Mais ou menos satisfeitos com um minuto do estágio passivo, começamos a pensar em uma redução adicional no estágio ativo. Antes de tudo, prestamos atenção ao histórico de problemas (é a pedra angular na construção de nossa estabilidade!) E descobrimos que, em muitos casos, não retrocedemos imediatamente porque não entendemos para qual versão retroceder, porque existem muitas versões paralelas. Para resolver esse problema, introduzimos a seguinte regra (e a registramos em faça e não faça): antes do lançamento, você escreve para o bate-papo no Slack, para o que está rolando e para quê e, no caso de um acidente, escreve para o bate-papo "acidente, não role!". Além disso, começamos a relatar automaticamente via SMS sobre os fatos da versão para notificar quem não entra no bate-papo.

Essa regra simples reduziu drasticamente o número de lançamentos já ocorridos durante acidentes e reduziu o estágio ativo - de 5 minutos para 3.

1.4 Uma redução ainda maior no estágio ativo


Apesar de termos alertado no bate-papo sobre todos os lançamentos e falhas, algumas vezes as condições da corrida apareceram - uma escreveu sobre a liberação e a outra já foi lançada naquele momento; ou o acidente começou, eles escreveram sobre isso no bate-papo e alguém acabou de lançar um novo código. Essas circunstâncias prolongaram o diagnóstico. Para resolver esse problema, implementamos uma proibição automática de versões paralelas. A ideia é muito simples: após cada versão, o sistema de CI / CD proíbe que todos os lançamentos sejam lançados pelos próximos 5 minutos, exceto o autor do último lançamento (para que ele possa lançar ou lançar hotfix, se necessário) e vários desenvolvedores especialmente experientes (em caso de emergência). Além disso, o sistema de CI / CD proíbe a implantação durante um acidente (ou seja, desde o momento em que a notificação foi recebida no início do acidente até o momento em que a notificação foi concluída).

Assim, o processo ficou assim: o desenvolvedor lança, monitora os gráficos por três minutos e, depois disso, por mais dois minutos, ninguém pode lançar nada. Se houver algum problema, o desenvolvedor reverte o release. Essa regra simplificou radicalmente o diagnóstico e a duração total dos estágios ativo e passivo diminuiu de 3 + 1 = 4 minutos para 1 + 1 = 2 minutos.

Mas dois minutos do acidente são muitos. Portanto, continuamos a otimizar o processo.

1.5 Detecção e reversão automáticas de falhas


Temos pensado há muito tempo em como reduzir a duração do acidente devido a lançamentos ruins. Eles até tentaram se forçar a olhar na tail -f error_log | grep 500 tail -f error_log | grep 500 . Mas no final, todos eles decidiram por uma solução cardinal automática.

Em resumo, isso é uma reversão automática. Configuramos um servidor da web separado, no qual carregamos 10 vezes menos carga do balanceador do que em outros servidores da web. Cada versão foi implantada automaticamente pelo sistema CI / CD neste servidor separado (chamamos de pré-produção, embora, apesar do nome, a carga real de usuários reais tenha ido para lá). E então a automação seguiu tail -f error_log | grep 500 tail -f error_log | grep 500 . Se nenhum erro 500 ocorrer dentro de um minuto, o CI / CD implantou o novo código em produção. Se erros aparecessem, o sistema imediatamente revertia tudo. Ao mesmo tempo, no nível do balanceador, todas as solicitações concluídas com 500 erros no pré-produto foram duplicadas em um dos servidores de produção.

Essa medida reduziu o efeito das quinhentas liberações para zero. Ao mesmo tempo, no caso de erros na automação, não cancelamos a regra por três minutos para monitorar os gráficos. Isso é tudo sobre lançamentos ruins e 500º bugs. Prosseguimos para o próximo tipo de acidente.

2. Versão ruim, código abaixo do ideal, carga básica


Começarei imediatamente com um exemplo concreto de um acidente desse tipo. Implementamos a otimização: adicionamos USE INDEX à consulta SQL, durante o teste dessas consultas curtas aceleradas, como na produção, mas as consultas longas diminuíram. A desaceleração de consultas longas foi notada apenas na produção. Como resultado, o fluxo de solicitações longas coloca toda a base principal por uma hora. Compreendemos perfeitamente como o USE INDEX funciona, o descrevemos no arquivo do's & dont e alertamos os desenvolvedores contra o uso indevido. Também analisamos a consulta e percebemos que ela retorna principalmente dados históricos, o que significa que ela pode ser executada em uma réplica separada para consultas históricas. Mesmo se essa réplica estiver sob carga, os negócios não serão interrompidos.

Após esse incidente, ainda enfrentamos problemas semelhantes e, em algum momento, decidimos abordar o problema sistematicamente. Analisamos todo o código com um pente frequente e realizamos até a réplica todos os pedidos que podem ser feitos lá, sem comprometer a qualidade do serviço. Ao mesmo tempo, dividimos as próprias réplicas de acordo com os níveis de criticidade, para que a queda de qualquer uma delas não parasse o serviço. Como resultado, chegamos a uma arquitetura que possui as seguintes bases:

  • base mestre (para operações de gravação e para consultas que são supercríticas à atualização de dados);
  • réplica de produção (para consultas curtas que são um pouco menos críticas para a atualização dos dados);
  • réplica para o cálculo de índices de preços, os chamados preços de aumento. Essa réplica pode demorar entre 30 a 60 segundos - isso não é crítico, os coeficientes mudam com tanta frequência e, se essa réplica cair, o serviço não será interrompido, apenas os preços não corresponderão exatamente ao equilíbrio de oferta e demanda;
  • réplica para o painel de administração de usuários de negócios e o contact center (se cair, o negócio principal não aumentará, mas o suporte não funcionará e não poderemos exibir e alterar temporariamente as configurações);
  • muitas réplicas para análises;
  • Banco de dados MPP para análises pesadas com fatias completas de acordo com dados históricos.

Essa arquitetura nos deu mais espaço para crescimento e reduziu o número de falhas em uma ordem de magnitude devido a consultas SQL abaixo do ideal. Mas ela ainda está longe do ideal. Planeja fazer sharding para que você possa dimensionar atualizações e exclusões, bem como consultas curtas, supercríticas à atualização desses dados. A margem de segurança do MySQL não é infinita. Em breve, precisaremos de artilharia pesada na forma de um Tarantool. Sobre isso será necessário nos seguintes artigos!

No processo do teste com códigos e solicitações não ideais, percebemos o seguinte: é melhor eliminar qualquer não otimização antes do lançamento e não depois. Isso reduz o risco de um acidente e reduz o tempo gasto pelos desenvolvedores na otimização. Porque, se o código já foi baixado e há novas versões, é muito mais difícil otimizar. Como resultado, introduzimos uma verificação de código obrigatória para otimizar. É conduzido pelos desenvolvedores mais experientes, de fato, nossas forças especiais.

Além disso, começamos a coletar no melhor e no não os melhores métodos de otimização de código que funcionam em nossas realidades, eles estão listados abaixo. Por favor, não percebam essas práticas como verdade absoluta e não tente repeti-las cegamente em si mesmos. Cada método faz sentido apenas para uma situação específica e um negócio específico. Eles são fornecidos aqui apenas por exemplo, para que os detalhes sejam claros:

  • Se a consulta SQL não depender do usuário atual (por exemplo, um mapa de demanda por drivers indicando as taxas de viagens mínimas e coeficientes para polígonos), essa consulta deverá ser feita pelo cron com uma certa frequência (no nosso caso, uma vez a cada minuto). Escreva o resultado no cache (Memcached ou Redis), que já é usado no código de produção.
  • Se a consulta SQL operar com dados cuja lista não processada não seja crítica para os negócios, seu resultado deverá ser armazenado em cache com algum TTL (por exemplo, 30 segundos). E, em solicitações subseqüentes, leia do cache.
  • Se, no contexto do processamento de uma solicitação na Web (no nosso caso, no contexto da implementação de um método de servidor específico em PHP), você desejar fazer uma consulta SQL, precisará garantir que esses dados não "cheguem" a nenhuma outra consulta SQL (e se eles chegarão mais longe por código). O mesmo se aplica ao acesso ao cache: ele também pode ser inundado com solicitações, se você desejar, portanto, se os dados já "chegaram" do cache, você não precisa ir ao cache como em sua casa e retirá-lo, o que já foi retirado.
  • Se, no contexto do processamento de consultas na Web, você desejar chamar alguma função, precisará garantir que nenhuma consulta SQL ou acesso a cache extra seja feito em seus giblets. Se a chamada de uma função for inevitável, você precisará garantir que ela não possa ser modificada ou que sua lógica seja desfeita para não fazer consultas desnecessárias aos bancos de dados / caches.
  • Se você ainda precisar acessar o SQL, verifique se não é possível adicionar os campos necessários mais alto ou mais baixo no código às consultas que já existem no código.

3. Intervenção manual malsucedida no sistema


Exemplos desses acidentes: um ALTER malsucedido (que sobrecarregou o banco de dados ou provocou um atraso na réplica) ou DROP malsucedido (encontrou um bug no MySQL, bloqueou o banco de dados quando uma nova tabela foi descartada); pedido pesado de mestre feito por engano à mão; Realizamos um trabalho no servidor sob carga, embora pensássemos que estava sem trabalho.

Para minimizar quedas por esses motivos, é necessário, infelizmente, entender a natureza do acidente a cada vez. Ainda não encontramos a regra geral. Mais uma vez, tente os exemplos. Digamos que, em algum momento, os coeficientes de pico pararam de funcionar (eles multiplicam o preço da viagem no local e no horário de maior demanda). O motivo foi que, na réplica do banco de dados, de onde vieram os dados para calcular os coeficientes, o script Python funcionou, que consumiu toda a memória, e a réplica caiu. O script está em execução há muito tempo, funcionou em uma réplica apenas por conveniência. O problema foi resolvido reiniciando o script. As conclusões foram as seguintes: não execute scripts de terceiros em uma máquina com um banco de dados (gravado em do's & dont's; caso contrário, isso é um tiro em branco!), Monitore o fim da memória em uma máquina com uma réplica e alerta por SMS se a memória acabar rapidamente.

É muito importante sempre tirar conclusões e não cair em uma situação confortável "eles viram um problema, consertaram e esqueceram". Um serviço de qualidade só pode ser construído se forem tiradas conclusões. Além disso, os alertas por SMS são muito importantes - eles definem a qualidade do serviço em um nível mais alto do que o fizeram, impedem que caiam e melhoram ainda mais a confiabilidade. Como escalador de cada estado estável, ele se levanta e é fixado em outro estado estável, mas a uma altitude mais alta.

Monitorar e alertar com ganchos de ferro invisíveis, porém rígidos, cortam a rocha da incerteza e nunca nos deixam abaixo do nível de estabilidade que estabelecemos, que constantemente aumentamos apenas.

4. ovo de pascoa


O que chamamos de "Ovo de Páscoa" é uma bomba-relógio que existe há muito tempo, mas que não encontramos. Fora deste artigo, este termo refere-se a um recurso não documentado feito de propósito. No nosso caso, isso não é um recurso, mas um bug, mas que funciona como uma bomba-relógio e que é um efeito colateral de boas intenções.

Por exemplo: estouro auto_increment 32 bits; não otimização no código / configuração, "tiro" devido à carga; réplica atrasada (geralmente devido a uma solicitação subótima de uma réplica que foi acionada por um novo padrão de uso ou uma carga mais alta ou por uma UPDATE subótima no mestre que foi chamada por um novo padrão de carga e carregou a réplica).

Outro tipo popular de ovo de Páscoa é o código não ideal e, mais especificamente, a consulta SQL não ideal. Anteriormente, a tabela era menor e a carga era menor - a consulta funcionava bem. E com o aumento da tabela, linear no tempo e no crescimento da carga, linear no tempo, o consumo de recursos do DBMS cresceu quadraticamente. Normalmente, isso leva a um forte efeito negativo: tudo estava "ok" e bang.

Cenários mais raros são uma combinação de insetos e ovos de páscoa. Uma versão com um bug levou a um aumento no tamanho da tabela ou no número de registros em uma tabela de um determinado tipo, e um ovo de Páscoa já existente causou uma carga excessiva no banco de dados devido a consultas mais lentas nessa tabela de crescimento excessivo.

Embora também tivéssemos ovos de Páscoa, não relacionados à carga. Por exemplo, auto increment 32 bits: após dois e alguns bilhões de registros na tabela, as inserções deixam de ser executadas. Portanto, o campo do auto increment no mundo moderno deve ser feito de 64 bits. Aprendemos bem esta lição.

Como lidar com ovos de Páscoa? A resposta é simples: a) procure por "ovos" velhos eb) evite que novos ovos apareçam. Tentamos cumprir os dois pontos. A busca por "ovos" antigos em nosso país está associada à otimização constante do código. Identificamos dois dos desenvolvedores mais experientes para otimização em tempo integral. Eles encontram em consultas slow.log que consomem mais recursos do banco de dados, otimizam essas consultas e o código ao seu redor. Reduzimos a probabilidade de novos ovos, verificando o código de otimização de cada confirmação pelo sensei rezrabotchiki mencionado acima. A tarefa deles é apontar erros que afetam o desempenho; dizer como fazer melhor e transferir conhecimento para outros desenvolvedores.

Em algum momento após o próximo ovo de páscoa que encontramos, percebemos que pesquisar consultas lentas é bom, mas vale a pena pesquisar adicionalmente consultas que parecem lentas, mas funcionam rapidamente. Esses são apenas os próximos candidatos a colocar tudo no caso de um crescimento explosivo da próxima tabela.

5. Causas externas


Essas são as razões que consideramos pouco controladas por nós. Por exemplo:

  • Trote pelo Google Maps. Você pode contornar isso monitorando o uso desse serviço, observando um certo nível de carga, planejando o crescimento da carga com antecedência e comprando a expansão do serviço.
  • A queda da rede no data center. Você pode se locomover colocando uma cópia do serviço no centro de dados de backup.
  • Acidente de serviço de pagamento. Você pode ignorar a reserva de serviços de pagamento.
  • Bloqueio de tráfego incorreto pelo serviço de proteção DDoS. Você pode se deslocar desativando o serviço de proteção DDoS padrão e ativando-o apenas no caso de um ataque DDoS.

Como a eliminação de uma causa externa é uma tarefa longa e cara (por definição), começamos a coletar estatísticas sobre acidentes devido a causas externas e aguardamos o acúmulo de massa crítica. Não há receita para determinar a massa crítica. Simplesmente funciona intuição. Por exemplo, se estivéssemos cinco vezes em tempo de inatividade total devido a problemas, digamos, do serviço de controle DDoS, a cada queda seguinte, ele se tornará cada vez mais nítido para levantar a questão de uma alternativa.

Por outro lado, se você pode, de alguma forma, fazê-lo funcionar com um serviço externo inacessível, nós definitivamente o fazemos. E isso nos ajuda a analisar post-mortem de cada queda. Sempre deve haver uma conclusão. Isso significa que você sempre não quer, mas pode criar uma solução alternativa.

6. Versão ruim, funcionalidade corrompida


Este é o tipo mais desagradável de acidente. O único tipo de acidente que não é visível para sintomas que não sejam reclamações de usuários / negócios. Portanto, esse acidente, especialmente se não for grande, pode existir despercebido na produção por um longo tempo.

Todos os outros tipos de acidentes são mais ou menos parecidos com “má liberação, 500º erro”. Só que o gatilho não é uma liberação, mas uma carga, uma operação manual ou um problema ao lado de um serviço externo.

Para descrever o método de lidar com esse tipo de acidente, basta recordar uma anedota barbada:

A matemática e a física receberam a mesma tarefa: ferver uma chaleira. Ferramentas auxiliares são dadas: fogão, chaleira, torneira de água com água, fósforos. Os dois alternadamente despejam água na chaleira, ligam o gás, acendem e acendem a chaleira. Em seguida, a tarefa foi simplificada: uma chaleira cheia de água e um fogão com gás ardente foram propostos. O objetivo é o mesmo - ferver água. O físico põe fogo na chaleira. O matemático derrama água da chaleira, desliga o gás e diz: "A tarefa foi reduzida à anterior". anekdotov.net

Este tipo de acidente deve ser reduzido por todos os meios para "baixa liberação, 500 erros". Idealmente, se os erros no código foram salvos no log como um erro. Bem, ou pelo menos deixou vestígios no banco de dados. A partir desses rastreamentos, você pode entender que ocorreu um erro e alertar imediatamente. Como contribuir para isso? Começamos a analisar cada bug principal e oferecer soluções, que tipo de alerta de monitoramento / SMS pode ser feito para que esse bug se manifeste imediatamente da mesma maneira que o 500º erro.

6.1 Exemplo


Houve queixas maciças: os pedidos pagos através do Apple Pay não fecham. Eles começaram a entender, o problema foi repetido. Descobrimos o motivo: aprimoramos o formato da expire date dos cartões bancários ao interagir com a aquisição, e eles começaram a transferi-lo especificamente para pagamentos via Apple Pay no formato esperado no serviço de processamento de pagamentos (na verdade, um é tratável, mutilando outra coisa), então todos os pagamentos através do Apple Pay começaram a declinar. Rapidamente corrigido, lançado, o problema desapareceu. Mas eles "viveram" com o problema por 45 minutos.

Seguindo os rastreios desse problema, monitoramos o número de falhas nos pagamentos via Apple Pay e também emitimos um alerta SMS / IVR com um limite diferente de zero (porque falhas nos pagamentos são a norma do ponto de vista do serviço, por exemplo, o cliente não tem dinheiro no cartão ou o cartão está bloqueado) . A partir deste momento, quando o limite é excedido, aprendemos instantaneamente sobre o problema. Se a nova versão introduzir QUALQUER problema no processamento do Apple Pay, o que levará à inoperabilidade do serviço, mesmo parcial, aprenderemos imediatamente sobre isso a partir do monitoramento e reverteremos a versão em três minutos (a descrição acima descreve como o processo de rolagem manual funciona). Foram 45 minutos de inatividade parcial e 3 minutos. Lucro

6.2 Outros exemplos


Implementamos a otimização da lista de pedidos oferecidos aos motoristas. Um bug entrou no código. Como resultado, em alguns casos, os motoristas não viram a lista de pedidos (estava vazia). Eles descobriram o bug por acidente - um dos funcionários examinou o aplicativo do motorista. Revertido rapidamente. Como conclusão do acidente, fizemos um gráfico do número médio de pedidos na lista de drivers de acordo com o banco de dados, analisamos o gráfico retroativamente por um mês, observamos uma falha lá e fizemos um alerta por SMS para a consulta SQL, que forma esse gráfico quando o número médio de pedidos em a lista abaixo do limite selecionado com base no mínimo histórico do mês.

Mudou a lógica de devolver os usuários para viagens. Incluindo distribuído para o grupo errado de usuários. Corrigimos o problema, construímos um cronograma de reembolso, vimos um aumento acentuado lá, também vimos que nunca houve esse crescimento, fizemos um alerta por SMS.

Com o lançamento, a funcionalidade de fechamento de pedidos foi interrompida (o pedido foi encerrado para sempre, o pagamento com cartões não funcionou, os motoristas exigiram pagamento em dinheiro dos clientes). O problema foi de 1,5 horas (estágios totais passivos e ativos). Aprendemos sobre o problema no contact center de reclamações. Eles fizeram uma correção, fizeram monitoramento e alertas sobre o horário de fechamento de pedidos com limiares encontrados no estudo de gráficos históricos.

Como você pode ver, a abordagem para esse tipo de acidente é sempre a mesma:

  1. Abra a versão.
  2. Aprenda sobre o problema.
  3. Corrija.
  4. Determinamos por quais rastreamentos (no banco de dados, logs, Kiban) você pode descobrir os sinais do problema.
  5. Traçamos esses sinais.
  6. Retrocedemos no passado e olhamos para as explosões / quedas.
  7. Selecionamos o limite correto para o alerta.
  8. Quando um problema surge novamente, aprendemos imediatamente por meio de um alerta.

O que é legal nesse método: uma enorme classe de problemas é fechada imediatamente com um gráfico e um alerta (exemplos de classes de problemas: não fechamento de pedidos, bônus extras, não pagamento via Apple Pay, etc.).

Com o tempo, tornamos a criação de alertas e o monitoramento de todos os principais erros uma parte da cultura de desenvolvimento. Para evitar que essa cultura se perca, formalizamos um pouco. Para cada acidente, eles começaram a exigir um relatório de si mesmos. Um relatório é um formulário preenchido com respostas para as seguintes perguntas: causa raiz, método de eliminação, impacto nos negócios, conclusões. Todos os itens são obrigatórios. Portanto, se você quiser ou não, você escreverá as conclusões. Essa mudança de processo, é claro, foi escrita por do's & dont's.

7. Kotan


, , -, . - ( , ) «». «». :-)

«» :

. — , . , ( ), ( ) , . ( , ).

. , . , : — , — . , « 500- 1 %» — . « 500- 1 %, - , - , - » — . , . ( ). , : , «», , , , . — . ( , ). .

. . , ( , , ), , : , , , .

. , , ( , ).

8. ?


— . . : , . , , . , , , .. — , — ! , . , , ? , , .. , , .

. . ( , ), , : , , , . , , . . . -, , . , , , — : .

9.


, .

??
.
.
( ) post-mortem.
.
do's & dont's.
, , .
, 5 .
.
, .
.
.
.

.
.
.
.
.
SMS/IVR- .
.
( ) .
.
.
- .
( — slow.log).
- « ».
.
.
.
.
.
, , .
«» — .
, .
.
.

, ! , , , , !

Source: https://habr.com/ru/post/pt445704/


All Articles