Nem GA nem YM. Como criamos nosso próprio fluxo de cliques

Coletamos mais de dois bilhões de eventos analíticos por dia. Graças a isso, podemos descobrir um monte de coisas necessárias: elas clicam mais nos corações do que nas estrelas, em que horas escrevem descrições mais detalhadas, em quais regiões geralmente perdem os botões verdes.


O sistema de coleta e análise de eventos pode ser chamado genericamente de fluxo de cliques. Vou falar sobre o lado técnico do fluxo de cliques no Avito: a organização dos eventos, o envio e a entrega, análises, relatórios. Por que você quer o seu próprio, se existe o Google Analytics e o Yandex.Metrica, a quem os desenvolvedores de fluxo de cliques estragam a vida e por que os codificadores go não podem esquecer o php.



Sobre mim


Dmitry Khasanov, dez anos em desenvolvimento web, três anos em Avito. Trabalho em equipe de plataforma, desenvolvo ferramentas comuns de infraestrutura. Eu amo hackathons .


Desafio


Os negócios exigem uma profunda compreensão dos processos que ocorrem no site. Por exemplo, ao registrar um usuário, quero saber de qual região, de qual dispositivo e através de qual navegador o usuário efetuou login. Como os campos do formulário são preenchidos, se foram enviados ou se o usuário desistiu. E se você desistiu, em que etapa. E quanto tempo levou.


Gostaria de saber se eles clicam no botão com mais frequência se ele for repintado em verde. O botão verde será pressionado com mais frequência em Murmansk ou em Vladivostok, dia ou noite, pelos usuários de aplicativos móveis ou do site; usuários que vieram do principal ou da pesquisa; que compraram antes no Avito ou que vieram pela primeira vez.


Todos esses sinais: sistema operacional, ID do usuário, hora da solicitação, dispositivo, navegador, valores nos campos - devem ser disponibilizados para análise. Colete, estruture, dê acesso rápido aos dados.


Além disso, geralmente é necessário dividir o fluxo de eventos. Os projetos precisam agir quando certos eventos ocorrem. Por exemplo, dessa maneira, é obtido feedback para treinar novamente o modelo para reconhecimento de padrões e auto-moderação, e estatísticas em tempo real são compiladas.


Com a ajuda do fluxo de cliques como um produto, deve ser fácil para os programadores enviar eventos de um projeto e para analistas gerenciar eventos coletados e criar uma variedade de relatórios mostrando tendências e hipóteses de suporte.


Relatórios com base no fluxo de eventos.
Exemplo 1


Exemplo 2


Ferramentas acabadas


Conhecemos o Yandex Metric e o Google Analytics, usamos-o para algumas tarefas. Com a ajuda deles, é bom e rápido coletar dados analíticos dos front-ends. Mas para exportar dados de back-end para sistemas analíticos externos, é necessário fazer integrações complicadas.


Com ferramentas externas, é necessário resolver independentemente o problema de dividir o fluxo de eventos.


A informação analítica é muito valiosa. Há anos que o colecionamos, ele nos permite saber em detalhes como os usuários se comportam. Não quero compartilhar esse conhecimento com o mundo exterior.


A legislação obriga a armazenar dados no território da Rússia.


Esses motivos foram suficientes para desenvolver nossa própria solução como a principal ferramenta para coletar e processar dados analíticos.


Solução


Os eventos são despachados através de transporte de alto desempenho (Event Streaming Processing, ESP) no armazenamento (Data Warehouse, DWH). Com base nos dados do repositório, são elaborados relatórios analíticos.


Evento


Entidade central. Em si, significa fato. Algo concreto aconteceu na unidade de tempo designada.


É necessário distinguir um evento de outro. Este é o identificador exclusivo do evento.


Também interessado no tempo de ocorrência de eventos. Nós o transmitimos em todos os eventos com uma precisão de microssegundos. Nos eventos que chegam dos front-ends, também corrigimos o tempo no dispositivo do cliente para restaurar com mais precisão a sequência de ações.


O campo


Um evento consiste em campos. O campo é a menor unidade semântica do sistema analítico. No parágrafo anterior, existem exemplos de campos: identificador de evento, hora do envio.


Atributos do campo: tipo (sequência, número, matriz), obrigatório.


O meio ambiente


O mesmo evento pode ocorrer em diferentes partes do sistema: por exemplo, a autorização é possível no site ou em um aplicativo móvel. Nesse caso, enviamos o mesmo evento, mas sempre adicionamos o identificador exclusivo da origem do evento.


As fontes são visivelmente diferentes uma da outra. Pode ser demônios e coroas internas, um serviço de front-end ou back-end, um aplicativo móvel. Parte dos campos deve ser enviada com cada evento de uma fonte específica.


Existe o conceito de "ambiente". Este é um agrupamento lógico de eventos por origem, com a capacidade de definir campos comuns para todos os eventos de origem.


Exemplos de ambientes: “back-end do serviço A”, “front-end do serviço A”, “aplicação iOS do serviço A”.


Diretório de Eventos


Todos os eventos existentes são descritos em um diretório que desenvolvedores e analistas podem editar. Os eventos são agrupados logicamente por ambiente, cada evento possui um proprietário e um log de alterações no diretório é mantido.


No momento, o diretório descreve várias centenas de campos, várias dezenas de ambientes e mais de mil eventos.


Langpack


Recusamos a tortura e não forçamos mais os desenvolvedores a escreverem manualmente o código de envio de eventos. Em vez disso, com base no diretório, geramos um conjunto de arquivos para cada um dos idiomas de servidor suportados pela empresa: php, go ou python. Esse código gerado é chamado de "langpack".


Os arquivos no langpack são o mais simples possível, eles não conhecem a lógica de negócios dos projetos. Este é um conjunto de getters e setters de campo para cada um dos eventos e um código para enviar o evento.


Um langpack é criado para cada ambiente. Ele se decompõe em um repositório de pacotes (satisf para php, pypi para python). Ele é atualizado automaticamente quando são feitas alterações no diretório.


Você não pode parar de escrever em PHP. O código para o serviço que gera os langpacks está escrito em Go. A empresa tem projetos PHP suficientes, então tive que me lembrar da minha linguagem de programação favorita de três letras e gerar código PHP no Go. Se você se deixar levar um pouco, também poderá gerar testes para testar o código gerado com esses testes.


Versionamento


A referência pode ser editada. O código na batalha não pode ser quebrado. Geramos o código de combate com base no diretório Perigosamente.


Após cada alteração do evento, uma nova versão é criada no diretório Todas as versões de eventos já criadas vivem para sempre no diretório. Então resolvemos o problema da imutabilidade de eventos específicos. Os projetos sempre indicam com qual versão do evento estamos trabalhando.


Se o código do langpack mudar (por exemplo, havia apenas setters, mas agora também decidimos adicionar getters), crie uma nova versão do langpack. Ela também viverá para sempre. Os projetos sempre solicitam uma versão específica do langpack para seu ambiente. Então resolvemos o problema de invariância da interface langpack.


Nós usamos sempre. A versão de cada langpack consiste em três números. O primeiro é sempre zero, o segundo é a versão do código langpack e o terceiro é o incremento. O terceiro dígito muda com mais frequência, após cada alteração de eventos.


O controle de versão em dois níveis permite editar o diretório sem quebrar o código na batalha. É baseado em dois princípios: você não pode excluir nada; Você não pode editar entidades criadas, apenas crie cópias modificadas lado a lado.


Transporte


Ao contrário dos caras do Badoo no LSD , nunca aprendemos a escrever arquivos lindamente . E acreditamos que o NSQ não é apenas um servidor de filas , mas também um transporte para eventos.


Eles ocultaram o NSQ atrás de uma pequena camada de código go, organizaram coletores para cada nó no cluster Kubernetes usando conjuntos de daemon e escreveram consumidores que podem adicionar eventos a diferentes fontes.


No momento, o transporte entrega cerca de dois bilhões de eventos por dia. Sob essa carga, trinta colecionadores trabalham com alguma margem. Cada um consome um pouco mais de núcleo do processador e um pouco mais de um gigabyte de memória.


Roteamento de Eventos


Os remetentes de eventos podem ser projetos que residem dentro ou fora do cluster. Dentro de clusters, esses são back-end de serviços, coroas, daemons, projetos de infraestrutura e uma intranet. Lá fora, os eventos vêm da interface de projetos públicos, de aplicativos móveis e projetos de parceiros.


Para receber eventos fora do cluster, usamos um proxy. Um ponto de entrada comum com uma pequena filtragem do fluxo de eventos, com a possibilidade de seu enriquecimento. Envio adicional para transporte de acordo com o esquema geral.


Esquema geral de roteamento: cada evento pode ter um conjunto de destinatários. Os possíveis destinatários incluem um repositório analítico compartilhado (DWH), rebbits ou projetos monga interessados ​​em determinados eventos. O último caso, por exemplo, é usado para treinar novamente os modelos de moderação automática de anúncios. Os modelos ouvem determinados eventos, obtendo o feedback necessário.


Do lado dos projetos, não há conhecimento sobre roteamento. Eles enviam eventos usando langpacks nos quais são costurados endereços de coletores comuns.


Armazenamento


O principal repositório de eventos é o HP Vertica, com algumas dezenas de terabytes. Uma base de coluna com recursos adequados para nossos analistas. Interface - Tableau para geração de relatórios.


É mais eficiente registrar eventos em nosso armazenamento em grandes lotes. Na frente do armazenamento, há um buffer na forma de Mongo. Coleções de exclusão automática criadas automaticamente a cada hora. As coleções são armazenadas por vários dias para poder reiniciar a revisão no Vertica se algo der errado.


Leitura do buffer Mongo em scripts de estimação. Os scripts são guiados por uma referência, tentamos não manter a lógica de negócios aqui. Nesta fase, o enriquecimento do evento é possível.


Evolução


Mão dançando no escuro


A necessidade de registrar eventos surgiu muito antes da conscientização da necessidade de manter um diretório. Os desenvolvedores de cada um dos projetos criaram uma maneira de enviar eventos, procurando transporte. Isso gerou muito código em idiomas diferentes, encontrando-se em projetos diferentes, mas resolvendo um problema.


Muitas vezes, dentro do código de despacho de eventos, os bits da lógica de negócios permanecem vivos. Código com esse conhecimento não pode ser portado para outros projetos. Ao refatorar, a lógica de negócios precisa ser retornada ao projeto, deixando no código do evento apenas conformidade com o formato de dados especificado.


Nesta fase, não havia diretório de eventos. Para entender quais eventos já estão sendo registrados, quais campos os eventos tinham, era possível apenas olhando o código. Para saber que o desenvolvedor parou acidentalmente de gravar dados no campo necessário, foi possível ao criar o relatório, se você prestar atenção especificamente nisso.


Não houve muitos eventos. As coleções de buffer nos mongos foram adicionadas conforme necessário. À medida que o número de eventos aumentava, era necessário redirecionar manualmente os eventos para outras coleções, para criar as coleções necessárias. A decisão de colocar o evento em uma coleção de buffer específica foi tomada no momento do envio, no lado do projeto. O transporte era fluente, o cliente era o agente td.


Consciente assíncrono


Foi decidido criar um diretório de todos os eventos existentes. Analisamos o código dos back-ends e retiramos algumas informações de lá. Nós obrigamos os desenvolvedores a anotar isso no diretório com todas as alterações no código do evento.


Os eventos que chegam dos frontends e dos aplicativos móveis foram descritos manualmente, às vezes capturando as informações necessárias no fluxo de eventos no nível de transporte.


Os desenvolvedores sabem como esquecer. Isso levou a uma dessincronização do diretório e código, mas o diretório mostrou a imagem geral.


O número de coleções de buffers aumentou significativamente, o trabalho manual para mantê-las aumentou significativamente. Uma pessoa insubstituível apareceu com um monte de conhecimento secreto sobre o armazenamento em buffer.


Novo transporte


Eles criaram um transporte compartilhado, ESP, ciente de todos os pontos de entrega de eventos. Eles fizeram dele um único ponto de recepção. Isso tornou possível controlar todos os fluxos de eventos. Os projetos pararam diretamente de acessar o armazenamento em buffer.


Clickstreamism iluminado


Com base no diretório, langpacks foram gerados. Eles não permitem a criação de eventos inválidos.


Introduziu verificações automáticas para a correção de eventos que chegam de front-end e aplicativos móveis. Nesse caso, não paramos de gravar eventos para não perder dados, mas registramos erros e sinalizamos para os desenvolvedores.


Eventos raros em back-end difíceis de refatorar e que ainda não são enviados por meio de langpacks são validados por uma biblioteca separada, de acordo com as regras do diretório. Em caso de erros, lance uma exceção que bloqueia a distribuição.


Tem um sistema tendendo a corresponder ao diretório. Bônus: transparência, capacidade de gerenciamento, velocidade de criação e mudança de eventos.


Posfácio


As principais dificuldades e lições foram organizacionais. É difícil vincular iniciativas que envolvam várias equipes. Não é fácil alterar o código de um grande projeto antigo. As habilidades de comunicação com outras equipes, dividindo tarefas em uma integração relativamente independente e pré-pensada, com a possibilidade de implementação independente de ajuda. Os desenvolvedores de fluxo de cliques não adoram mais as equipes de produtos quando a fase de integração de uma nova solução começa. Se as interfaces mudarem, o trabalho será adicionado a todos.


Criar um diretório foi uma ideia muito boa. Ele se tornou a única fonte de verdade, você sempre pode apelar para ele em caso de discrepâncias no código. Muita automação está ligada ao diretório: cheques, roteamento de eventos, geração de código.


A infraestrutura não precisa saber sobre lógica de negócios. Sinais do surgimento da lógica de negócios: os eventos mudam ao longo do caminho do projeto para o repositório; mudar o transporte sem alterar os projetos se torna impossível. No lado da infraestrutura, deve haver conhecimento sobre a composição dos eventos, tipos de campos e sua obrigatoriedade. No lado do produto, o significado lógico desses campos.


Sempre há espaço para crescer. Tecnicamente, é um aumento no número de eventos, uma diminuição no tempo desde a criação do evento até o início da gravação dos dados, eliminação do trabalho manual em todas as etapas.


Existem algumas idéias ousadas. Obter um gráfico detalhado das transições do usuário, configurar eventos em tempo real sem implantar o serviço. Mas mais sobre isso nos seguintes artigos.


PS: Falei sobre esse tópico na reunião nº 1 do Backend United. Vinagrete. Pode ver
apresentação ou vídeo da reunião.

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


All Articles