Otimização de carga em um projeto Highload com ElasticSearch

Olá Habr! Meu nome é Maxim Vasiliev, trabalho como analista e gerente de projetos na FINCH. Hoje gostaria de contar como, usando o ElasticSearch, conseguimos processar 15 milhões de solicitações em 6 minutos e otimizar as cargas diárias no site de um de nossos clientes. Infelizmente teremos que ficar sem nomes, já que temos um NDA, esperamos que o conteúdo do artigo não sofra com isso. Vamos.

Como funciona o projeto

Em nosso backend, criamos serviços que garantem o desempenho dos sites e aplicativos mobile de nossos clientes. A estrutura geral pode ser vista no diagrama:

Otimização de carga em um projeto Highload com ElasticSearch

No processo de trabalho, processamos um grande número de transações: compras, pagamentos, operações com saldos de usuários, para as quais armazenamos muitos logs, bem como importamos e exportamos esses dados para sistemas externos.

Existem também processos inversos quando recebemos dados do cliente e os transferimos para o usuário. Além disso, ainda existem processos para trabalhar com pagamentos e programas de bônus.

Breve histórico

Inicialmente, usamos o PostgreSQL como único armazenamento de dados. Suas vantagens padrão para um SGBD: presença de transações, linguagem de amostragem de dados desenvolvida, ampla gama de ferramentas de integração; combinado com um bom desempenho satisfez nossas necessidades por um bom tempo.

Armazenamos absolutamente todos os dados no Postgres: de transações a notícias. Mas o número de usuários cresceu e com ele o número de solicitações.

Para entender, o número anual de sessões em 2017 apenas no site para desktop é de 131 milhões. Em 2018 - 125 milhões. Em 2019 novamente 130 milhões. Adicione outros 100-200 milhões da versão móvel do site e do aplicativo móvel, e você receberá um grande número de solicitações.

Com o crescimento do projeto, o Postgres deixou de dar conta da carga, não tivemos tempo - surgiram um grande número de consultas diversas, para as quais não conseguíamos criar um número suficiente de índices.

Entendemos que havia necessidade de outros armazenamentos de dados que atendessem às nossas necessidades e aliviassem a carga do PostgreSQL. Elasticsearch e MongoDB foram considerados opções possíveis. Este último perdeu nos seguintes pontos:

  1. Velocidade de indexação lenta à medida que a quantidade de dados nos índices aumenta. Com o Elastic, a velocidade não depende da quantidade de dados.
  2. Nenhuma pesquisa de texto completo

Então escolhemos a Elastic para nós e nos preparamos para a transição.

Transição para Elástico

1. Iniciamos a transição do serviço de busca no ponto de venda. Nosso cliente possui um total de cerca de 70 mil pontos de venda, e isso exige diversos tipos de pesquisas no site e no aplicativo:

  • Pesquisa de texto por nome da cidade
  • Pesquisa geográfica dentro de um determinado raio a partir de algum ponto. Por exemplo, se o usuário quiser ver quais pontos de venda estão mais próximos de sua casa.
  • Pesquise por um determinado quadrado - o usuário desenha um quadrado no mapa e todos os pontos desse raio são mostrados a ele.
  • Pesquise por filtros adicionais. Os pontos de venda diferem entre si no sortimento

Se falamos de organização, então no Postgres temos uma fonte de dados tanto para o mapa quanto para as notícias, e no Elastic Snapshots são retirados dos dados originais. O fato é que inicialmente o Postgres não conseguiu dar conta da busca por todos os critérios. Além de haver muitos índices, eles também poderiam se sobrepor, então o agendador do Postgres se perdeu e não entendeu qual índice usar.

2. O próximo da fila era a seção de notícias. As publicações aparecem no site todos os dias para que o usuário não se perca no fluxo de informações, os dados devem ser ordenados antes da emissão. É para isso que serve a busca: você pode pesquisar o site por correspondência de texto, e ao mesmo tempo conectar filtros adicionais, já que eles também são feitos através do Elastic.

3. Em seguida, movemos o processamento da transação. Os usuários podem comprar determinado produto no site e participar de um sorteio. Após essas compras, processamos uma grande quantidade de dados, principalmente nos finais de semana e feriados. Para efeito de comparação, se em dias normais o número de compras fica entre 1,5 e 2 milhões, nos feriados o número pode chegar a 53 milhões.

Ao mesmo tempo, os dados devem ser processados ​​​​no menor tempo possível - os usuários não gostam de esperar vários dias pelo resultado. Não há como cumprir esses prazos por meio do Postgres - muitas vezes recebíamos bloqueios e, enquanto processávamos todas as solicitações, os usuários não conseguiam verificar se receberam prêmios ou não. Isso não é muito agradável para os negócios, por isso migramos o processamento para o Elasticsearch.

Periodicidade

Agora as atualizações são configuradas com base em eventos, de acordo com as seguintes condições:

  1. Pontos de vendas. Assim que recebemos dados de uma fonte externa, iniciamos imediatamente a atualização.
  2. Notícias. Assim que alguma notícia é editada no site, ela é enviada automaticamente para a Elastic.

Aqui novamente vale ressaltar as vantagens do Elastic. No Postgres, ao enviar uma solicitação, é necessário aguardar até que ele processe honestamente todos os registros. Você pode enviar 10 registros para a Elastic e começar a trabalhar imediatamente, sem esperar que os registros sejam distribuídos por todos os Shards. Claro, alguns Shard ou Replica podem não ver os dados imediatamente, mas tudo estará disponível em breve.

Métodos de integração

Existem 2 maneiras de integração com o Elastic:

  1. Através de um cliente nativo sobre TCP. O driver nativo está desaparecendo gradativamente: não é mais suportado, tem uma sintaxe muito inconveniente. Portanto, praticamente não o utilizamos e tentamos abandoná-lo completamente.
  2. Através de uma interface HTTP que pode usar solicitações JSON e sintaxe Lucene. O último é um mecanismo de texto que usa Elastic. Nesta versão, temos a capacidade de enviar em lote por meio de solicitações JSON por HTTP. Esta é a opção que estamos tentando usar.

Graças à interface HTTP, podemos usar bibliotecas que fornecem uma implementação assíncrona do cliente HTTP. Podemos aproveitar o Batch e a API assíncrona, que resulta em alto desempenho, o que ajudou muito nos dias da grande promoção (mais sobre isso abaixo)

Alguns números para comparação:

  • Salvando usuários de recompensa do Postgres em 20 threads sem agrupamento: 460713 registros em 42 segundos
  • Cliente elástico + reativo para 10 threads + lote para 1000 elementos: 596749 registros em 11 segundos
  • Cliente elástico + reativo para 10 threads + lote para 1000 elementos: 23801684 entradas em 4 minutos

Agora escrevemos um gerenciador de solicitações HTTP que cria JSON como Lote/não Lote e o envia por meio de qualquer cliente HTTP, independentemente da biblioteca. Você também pode optar por enviar solicitações de forma síncrona ou assíncrona.

Em algumas integrações, ainda utilizamos o cliente de transporte oficial, mas isso é apenas questão da próxima refatoração. Nesse caso, um cliente customizado construído com base no Spring WebClient é usado para processamento.

Otimização de carga em um projeto Highload com ElasticSearch

grande promoção

Uma vez por ano, o projeto realiza uma grande promoção para os usuários - este é o mesmo Highload, já que neste momento trabalhamos com dezenas de milhões de usuários ao mesmo tempo.

Normalmente os picos de carga ocorrem durante as férias, mas esta promoção está num patamar completamente diferente. No ano retrasado, no dia da promoção, vendemos 27 unidades da mercadoria. Os dados foram processados ​​por mais de meia hora, o que causou transtornos aos usuários. Os usuários receberam prêmios pela participação, mas ficou claro que o processo precisava ser acelerado.

No início de 2019, decidimos que precisávamos do ElasticSearch. Durante um ano inteiro organizamos o processamento dos dados recebidos no Elastic e sua emissão na API do aplicativo mobile e site. Como resultado, no ano seguinte durante a campanha, processamos 15 entradas em 131 minutos.

Como temos muita gente querendo comprar mercadorias e participar de sorteios de prêmios em promoções, esta é uma medida temporária. Agora estamos enviando informações atualizadas para a Elastic, mas no futuro planejamos transferir as informações arquivadas dos últimos meses para o Postgres como armazenamento permanente. Para não entupir o índice Elastic, que também tem suas limitações.

Conclusão/Conclusões

No momento, transferimos todos os serviços que queríamos para a Elastic e pausamos isso por enquanto. Agora estamos construindo um índice no Elastic sobre o armazenamento persistente principal no Postgres, que assume a carga do usuário.

No futuro, planejamos transferir serviços se entendermos que a solicitação de dados se torna muito diversificada e é pesquisada em um número ilimitado de colunas. Esta não é mais uma tarefa do Postgres.

Se precisarmos de funcionalidade de pesquisa de texto completo ou se tivermos muitos critérios de pesquisa diferentes, já sabemos que isso precisa ser traduzido para o Elastic.

⌘⌘⌘

Obrigado por ler. Se sua empresa também utiliza ElasticSearch e possui cases de implementação próprios, conte-nos. Será interessante saber como são os outros 🙂

Fonte: habr.com

Adicionar um comentário