Historien om vores open source: hvordan vi lavede en analysetjeneste i Go og gjorde den offentlig tilgængelig

I øjeblikket indsamler næsten alle virksomheder i verden statistik om brugerhandlinger på en webressource. Motivationen er klar – virksomheder vil gerne vide, hvordan deres produkt/hjemmeside bruges og bedre forstå deres brugere. Der findes naturligvis en lang række værktøjer på markedet til at løse dette problem - lige fra analysesystemer, der leverer data i form af dashboards og grafer (f.eks. Google Analytics) til kundedataplatform, som giver dig mulighed for at indsamle og aggregere data fra forskellige kilder i ethvert lager (f.eks. Segment).

Men vi har fundet et problem, der ikke er løst endnu. Således blev født EventNative — open source-analysetjeneste. Læs om, hvorfor vi besluttede at udvikle vores egen service, hvad det gav os, og hvad slutresultatet blev (med stykker kode).

Historien om vores open source: hvordan vi lavede en analysetjeneste i Go og gjorde den offentlig tilgængelig

Hvorfor skal vi udvikle vores egen service?

Det var halvfemserne, vi overlevede så godt vi kunne. 2019 udviklede vi API First Customer Data Platform kSense, som gjorde det muligt at aggregere data fra forskellige kilder (Facebook-annoncer, Stripe, Salesforce, Google play, Google Analytics osv.) for mere bekvem dataanalyse, identifikation af afhængigheder mv. Vi har bemærket, at mange brugere bruger vores platform til dataanalyse specifikt Google Analytics (herefter GA). Vi talte med nogle brugere og fandt ud af, at de har brug for analysedata for deres produkt, som de modtager ved hjælp af GA, men Google prøver data og for mange er GA-brugergrænsefladen ikke standarden for bekvemmelighed. Vi havde nok samtaler med vores brugere og indså, at mange også brugte Segment-platformen (som i øvrigt var den anden dag solgt for 3.2 mia).

De installerede en Segment-javascript-pixel på deres webressource, og data om deres brugeres adfærd blev indlæst i den angivne database (for eksempel Postgres). Men Segment har også sin bagside – prisen. For eksempel, hvis en webressource har 90,000 MTU (månedligt sporede brugere), så skal du betale ~1,000 $ om måneden til kassereren. Der var også et tredje problem - nogle browserudvidelser (såsom AdBlock) blokerede indsamlingen af ​​analyser, fordi... http-anmodninger fra browseren blev sendt til GA- og Segment-domænerne. Baseret på vores kunders ønsker har vi skabt en analyseservice, der indsamler et komplet sæt data (uden stikprøver), er gratis og kan arbejde på vores egen infrastruktur.

Sådan fungerer tjenesten

Tjenesten består af tre dele: en javascript-pixel (som vi senere omskrev i typescript), serverdelen er implementeret i GO-sproget, og det var planlagt at bruge Redshift og BigQuery som en intern database (senere tilføjede de support til Postgres, ClickHouse og Snowflake).

Det blev besluttet at lade strukturen af ​​GA- og segmentbegivenhederne være uændret. Det eneste, der skulle til, var at duplikere alle hændelser fra webressourcen, hvor pixlen er installeret, til vores backend. Som det viser sig, er dette ikke svært at gøre. Javascript-pixlen tilsidesatte den originale GA-biblioteksmetode med en ny, som duplikerede hændelsen i vores system.

//'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-pixlen er alt enklere; den har middleware-metoder, hvoraf vi brugte en.


//'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.');
}

Ud over at kopiere hændelser har vi tilføjet muligheden for at 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'
});

Lad os derefter tale om serverdelen. Backend bør acceptere http-anmodninger, udfylde dem med yderligere oplysninger, for eksempel geodata (tak maxmind for dette) og optag det i databasen. Vi ønskede at gøre tjenesten så bekvem som muligt, så den kan bruges med minimal konfiguration. Vi har implementeret funktionaliteten til at bestemme dataskemaet baseret på strukturen af ​​den indkommende json-hændelse. Datatyper er defineret af værdier. Indlejrede objekter nedbrydes og reduceres til en flad 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 i øjeblikket simpelthen konverteret til strenge, fordi Ikke alle relationelle databaser understøtter gentagne felter. Det er også muligt at ændre feltnavne eller slette dem ved hjælp af valgfri kortlægningsregler. De giver dig mulighed for at ændre dataskemaet om nødvendigt eller konvertere en datatype til en anden. For eksempel, hvis et json-felt indeholder en streng med tidsstempel (field_3_sub_field_1_sub_sub_field_1 fra eksemplet ovenfor), for at oprette et felt i databasen med tidsstempeltypen, skal du skrive en mapping-regel i konfigurationen. Med andre ord bestemmes feltets datatype først af json-værdien, og derefter anvendes type-casting-reglen (hvis den er konfigureret). Vi har identificeret 4 hoveddatatyper: STRING, FLOAT64, INT64 og TIMESTAMP. Kortlægnings- og typecasting-reglerne ser sådan ud:

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

Algoritme til bestemmelse af datatypen:

  • konverter json-struktur til flad struktur
  • bestemme datatypen for felter ved hjælp af værdier
  • anvendelse af kortlægning og typestøbningsregler

Så fra den indgående json-struktur:

{
    "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"
    }
}

dataskemaet vil blive indhentet:

"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 tænkte også, at brugeren skulle være i stand til at konfigurere partitionering eller opdele data i databasen efter andre kriterier og implementerede muligheden for at sætte tabelnavnet med en konstant eller udtryk i konfigurationen. I eksemplet nedenfor vil hændelsen blive gemt i en tabel med et navn beregnet ud fra værdierne af felterne product_type og _timestamp (f.eks. forsyninger_2020_10):

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

Strukturen af ​​indgående hændelser kan dog ændre sig under kørsel. Vi har implementeret en algoritme til at kontrollere forskellen mellem strukturen af ​​en eksisterende tabel og strukturen af ​​en indkommende begivenhed. Hvis der findes en forskel, vil tabellen blive opdateret med nye felter. For at gøre dette skal du bruge patch SQL-forespørgslen:

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

arkitektur

Historien om vores open source: hvordan vi lavede en analysetjeneste i Go og gjorde den offentlig tilgængelig

Hvorfor skal du skrive hændelser til filsystemet, og ikke bare skrive dem direkte til databasen? Databaser fungerer ikke altid godt, når de håndterer et stort antal indstik (Postgres anbefalinger). For at gøre dette, skriver Logger indgående hændelser til en fil og i en separat goroutine (tråd) læser fillæseren filen, hvorefter dataene konverteres og bestemmes. Efter at Tabelmanageren har sikret sig, at tabelskemaet er opdateret, vil dataene blive skrevet til databasen i én batch. Efterfølgende har vi tilføjet muligheden for at skrive data direkte til databasen, men vi bruger denne tilstand til hændelser, der ikke er talrige - for eksempel konverteringer.

Open Source og planer for fremtiden

På et tidspunkt begyndte tjenesten at ligne et fuldgyldigt produkt, og vi besluttede at frigive den til Open Source. I øjeblikket er integrationer med Postgres, ClickHouse, BigQuery, Redshift, S3, Snowflake blevet implementeret. Alle integrationer understøtter både batch- og streaming-tilstande til dataindlæsning. Tilføjet support til anmodninger via API.

Den nuværende integrationsordning ser således ud:

Historien om vores open source: hvordan vi lavede en analysetjeneste i Go og gjorde den offentlig tilgængelig

Selvom tjenesten kan bruges uafhængigt (for eksempel ved hjælp af Docker), har vi også hostet version, hvor du kan opsætte integration med et datavarehus, tilføje en CNAME til dit domæne og se statistik over antallet af hændelser. Vores umiddelbare planer er at tilføje muligheden for at samle ikke kun statistik fra en webressource, men også data fra eksterne datakilder og gemme dem til ethvert lager efter eget valg!

→ GitHub
→ Records
→ Slack

Vi vil blive glade, hvis EventNative hjælper med at løse dine problemer!

Kun registrerede brugere kan deltage i undersøgelsen. Log ind, Vær venlig.

Hvilket statistikindsamlingssystem bruges i din virksomhed?

  • 48,0 %Google Analytics12

  • 4,0 %Segment 1

  • 16,0 %En anden (skriv i kommentarerne)4

  • 32,0 %Implementeret din service8

25 brugere stemte. 6 brugere undlod at stemme.

Kilde: www.habr.com

Tilføj en kommentar