Historien til vår åpne kildekode: hvordan vi laget en analysetjeneste i Go og gjorde den offentlig tilgjengelig

For tiden samler nesten alle selskaper i verden inn statistikk om brukerhandlinger på en nettressurs. Motivasjonen er klar – bedrifter ønsker å vite hvordan deres produkt/nettside brukes og bedre forstå brukerne sine. Selvfølgelig finnes det et stort antall verktøy på markedet for å løse dette problemet - fra analysesystemer som gir data i form av dashboards og grafer (f.eks. Google Analytics) til Customer Data Platform, som lar deg samle inn og samle data fra forskjellige kilder i ethvert lager (f.eks. Segment).

Men vi fant et problem som ikke er løst ennå. Slik ble født EventNative — analysetjeneste med åpen kildekode. Les om hvorfor vi bestemte oss for å utvikle vår egen tjeneste, hva den ga oss, og hva sluttresultatet ble (med biter av kode).

Historien til vår åpne kildekode: hvordan vi laget en analysetjeneste i Go og gjorde den offentlig tilgjengelig

Hvorfor skal vi utvikle vår egen tjeneste?

Det var nittitallet, vi overlevde så godt vi kunne. I 2019 utviklet vi API First Customer Data Platform kSense, som gjorde det mulig å samle data fra forskjellige kilder (Facebook-annonser, Stripe, Salesforce, Google play, Google Analytics, etc.) for mer praktisk dataanalyse, identifisering av avhengigheter osv. Vi har lagt merke til at mange brukere bruker vår plattform for dataanalyse spesifikt Google Analytics (heretter GA). Vi snakket med noen brukere og fant ut at de trenger analysedataene for produktet deres som de mottar ved hjelp av GA, men Google prøver data og for mange er ikke GA-brukergrensesnittet standarden for bekvemmelighet. Vi hadde nok samtaler med brukerne våre og innså at mange også brukte Segment-plattformen (som forresten var her om dagen solgt for 3.2 milliarder dollar).

De installerte en Segment-javascript-piksel på nettressursen deres, og data om oppførselen til brukerne deres ble lastet inn i den spesifiserte databasen (for eksempel Postgres). Men Segment har også sin bakside – prisen. For eksempel, hvis en nettressurs har 90,000 1,000 MTU (månedlig sporede brukere), må du betale ~XNUMX XNUMX $ per måned til kassereren. Det var også et tredje problem - noen nettleserutvidelser (som AdBlock) blokkerte innsamlingen av analyser fordi... http-forespørsler fra nettleseren ble sendt til GA- og Segment-domenene. Basert på ønsker fra våre kunder har vi laget en analysetjeneste som samler inn et komplett sett med data (uten prøvetaking), er gratis og kan jobbe på vår egen infrastruktur.

Hvordan tjenesten fungerer

Tjenesten består av tre deler: en javascript-piksel (som vi senere skrev om i typescript), serverdelen er implementert i GO-språket, og det var planlagt å bruke Redshift og BigQuery som en intern database (senere la de til støtte for Postgres, ClickHouse og Snowflake).

Det ble besluttet å forlate strukturen til GA- og segmenthendelsene uendret. Alt som var nødvendig var å duplisere alle hendelser fra nettressursen der pikselen er installert til vår backend. Som det viser seg, er dette ikke vanskelig å gjøre. Javascript-pikselen overstyrte den originale GA-bibliotekmetoden med en ny, som dupliserte hendelsen inn i systemet vårt.

//'ga' - стандартное название переменной Google Analytics
if (window.ga) {
    ga(tracker => {
        var originalSendHitTask = tracker.get('sendHitTask');
        tracker.set('sendHitTask', (model) => {
            var payLoad = model.get('hitPayload');
            //отправка оригинального события в GA
            originalSendHitTask(model);
            let jsonPayload = this.parseQuery(payLoad);
            //отправка события в наш сервис
            this.send3p('ga', jsonPayload);
        });
    });
}

Med Segment-pikselen er alt enklere; den har mellomvaremetoder, hvorav en vi brukte.


//'analytics' - стандартное название переменной Segment
if (window.analytics) {
    if (window.analytics.addSourceMiddleware) {
        window.analytics.addSourceMiddleware(chain => {
            try {
		//дублирование события в наш сервис
                this.send3p('ajs', chain.payload);
            } catch (e) {
                LOG.warn('Failed to send an event', e)
            }
	    //отправка оригинального события в Segment
            chain.next(chain.payload);
        });
    } else {
        LOG.warn("Invalid interceptor state. Analytics js initialized, but not completely");
    }
} else {
    LOG.warn('Analytics.js listener is not set.');
}

I tillegg til å kopiere hendelser, har vi lagt til muligheten til å sende vilkårlig json:


//Отправка событий с произвольным json объектом
eventN.track('product_page_view', {
    product_id: '1e48fb70-ef12-4ea9-ab10-fd0b910c49ce',
    product_price: 399.99,
    price_currency: 'USD'
    product_release_start: '2020-09-25T12:38:27.763000Z'
});

La oss deretter snakke om serverdelen. Backend bør godta http-forespørsler, fylle dem med tilleggsinformasjon, for eksempel geodata (takk maxmind for dette) og registrere det i databasen. Vi ønsket å gjøre tjenesten så praktisk som mulig slik at den kan brukes med minimal konfigurasjon. Vi har implementert funksjonaliteten for å bestemme dataskjemaet basert på strukturen til den innkommende json-hendelsen. Datatyper er definert av verdier. Nestede gjenstander dekomponeres og reduseres til en flat struktur:

//входящий json
{
  "field_1":  {
    "sub_field_1": "text1",
    "sub_field_2": 100
  },
  "field_2": "text2",
  "field_3": {
    "sub_field_1": {
      "sub_sub_field_1": "2020-09-25T12:38:27.763000Z"
    }
  }
}

//результат
{
  "field_1_sub_field_1":  "text1",
  "field_1_sub_field_2":  100,
  "field_2": "text2",
  "field_3_sub_field_1_sub_sub_field_1": "2020-09-25T12:38:27.763000Z"
}

Imidlertid er arrays for øyeblikket ganske enkelt konvertert til strenger fordi Ikke alle relasjonsdatabaser støtter gjentatte felt. Det er også mulig å endre feltnavn eller slette dem ved hjelp av valgfrie kartleggingsregler. De lar deg endre dataskjemaet om nødvendig eller konvertere en datatype til en annen. For eksempel, hvis et json-felt inneholder en streng med tidsstempel (field_3_sub_field_1_sub_sub_field_1 fra eksempelet ovenfor), så for å lage et felt i databasen med tidsstempeltypen, må du skrive en tilordningsregel i konfigurasjonen. Med andre ord, datatypen til feltet bestemmes først av json-verdien, og deretter brukes type-casting-regelen (hvis konfigurert). Vi har identifisert 4 hoveddatatyper: STRING, FLOAT64, INT64 og TIMESTAMP. Kartleggings- og typecasting-reglene ser slik ut:

rules:
  - "/field_1/subfield_1 -> " #правило удаления поля
  - "/field_2/subfield_1 -> /field_10/subfield_1" #правило переноса поля
  - "/field_3/subfield_1/subsubfield_1 -> (timestamp) /field_20" #правило переноса поля и приведения типа

Algoritme for å bestemme datatypen:

  • konverter json-struktur til flat struktur
  • bestemme datatypen for felt ved hjelp av verdier
  • anvendelse av kartleggings- og typestøpingsregler

Så fra den innkommende json-strukturen:

{
    "product_id":  "1e48fb70-ef12-4ea9-ab10-fd0b910c49ce",
    "product_price": 399.99,
    "price_currency": "USD",
    "product_type": "supplies",
    "product_release_start": "2020-09-25T12:38:27.763000Z",
    "images": {
      "main": "picture1",
      "sub":  "picture2"
    }
}

dataskjemaet vil bli innhentet:

"product_id" character varying,
"product_price" numeric (38,18),
"price_currency" character varying,
"product_type" character varying,
"product_release_start" timestamp,
"images_main" character varying,
"images_sub" character varying

Vi tenkte også at brukeren skulle kunne konfigurere partisjonering eller dele data i databasen i henhold til andre kriterier og implementerte muligheten til å sette tabellnavnet med en konstant eller uttrykk i konfigurasjonen. I eksemplet nedenfor vil hendelsen lagres i en tabell med et navn beregnet basert på verdiene i feltene product_type og _timestamp (for eksempel rekvisita_2020_10):

tableName: '{{.product_type}}_{{._timestamp.Format "2006_01"}}'

Strukturen til innkommende hendelser kan imidlertid endres under kjøring. Vi har implementert en algoritme for å sjekke forskjellen mellom strukturen til en eksisterende tabell og strukturen til en innkommende hendelse. Hvis en forskjell blir funnet, vil tabellen bli oppdatert med nye felt. For å gjøre dette, bruk patch SQL-spørringen:

#Пример для Postgres
ALTER TABLE "schema"."table" ADD COLUMN new_column character varying

arkitektur

Historien til vår åpne kildekode: hvordan vi laget en analysetjeneste i Go og gjorde den offentlig tilgjengelig

Hvorfor trenger du å skrive hendelser til filsystemet, og ikke bare skrive dem direkte til databasen? Databaser gir ikke alltid gode resultater når de håndterer et stort antall innlegg (Postgres anbefalinger). For å gjøre dette, skriver Logger innkommende hendelser til en fil og i en egen goroutine (tråd) leser Filleser filen, deretter blir dataene konvertert og bestemt. Etter at tabellbehandleren har sørget for at tabellskjemaet er oppdatert, vil dataene bli skrevet til databasen i én batch. Deretter la vi til muligheten til å skrive data direkte til databasen, men vi bruker denne modusen for hendelser som ikke er mange - for eksempel konverteringer.

Åpen kildekode og planer for fremtiden

På et tidspunkt begynte tjenesten å se ut som et fullverdig produkt, og vi bestemte oss for å gi den ut til åpen kildekode. For tiden er integrasjoner med Postgres, ClickHouse, BigQuery, Redshift, S3, Snowflake implementert. Alle integrasjoner støtter både batch- og streamingmoduser for datalasting. Lagt til støtte for forespørsler via API.

Dagens integreringsordning ser slik ut:

Historien til vår åpne kildekode: hvordan vi laget en analysetjeneste i Go og gjorde den offentlig tilgjengelig

Selv om tjenesten kan brukes uavhengig (for eksempel ved hjelp av Docker), har vi også vertsbasert versjon, der du kan sette opp integrasjon med et datavarehus, legge til en CNAME på domenet ditt og se statistikk over antall hendelser. Våre umiddelbare planer er å legge til muligheten til å samle ikke bare statistikk fra en nettressurs, men også data fra eksterne datakilder og lagre dem til et valgfritt lager!

→ GitHub
→ Документация
→ Slack

Vi vil være glade hvis EventNative hjelper deg med å løse dine problemer!

Kun registrerte brukere kan delta i undersøkelsen. Logg inn, vær så snill.

Hvilket statistikkinnsamlingssystem brukes i din bedrift?

  • 48,0%Google Analytics12

  • 4,0%Segment 1

  • 16,0%En annen (skriv i kommentarfeltet)4

  • 32,0%Implementerte tjenesten din8

25 brukere stemte. 6 brukere avsto.

Kilde: www.habr.com

Legg til en kommentar