Historien om vår öppen källkod: hur vi skapade en analystjänst i Go och gjorde den offentligt tillgänglig

För närvarande samlar nästan alla företag i världen in statistik om användaråtgärder på en webbresurs. Motivationen är tydlig – företag vill veta hur deras produkt/webbplats används och bättre förstå sina användare. Naturligtvis finns det ett stort antal verktyg på marknaden för att lösa detta problem - från analyssystem som tillhandahåller data i form av instrumentpaneler och grafer (till exempel, Google Analytics) till kunddataplattformen, som låter dig samla in och aggregera data från olika källor i valfri lagring (t.ex. Segmentet).

Men vi hittade ett problem som inte är löst än. Så född EventNative — analystjänst med öppen källkod. Om varför vi gick för att utveckla vår egen tjänst, vad den gav oss och vad som hände till slut (med kodbitar), läs under klippet.

Historien om vår öppen källkod: hur vi skapade en analystjänst i Go och gjorde den offentligt tillgänglig

Varför ska vi utveckla vår egen tjänst?

Det var nittiotalet, vi överlevde så gott vi kunde. 2019 utvecklade vi First Customer Data Platform API kSense, som gjorde det möjligt att samla data från olika källor (Facebook-annonser, Stripe, Salesforce, Google play, Google Analytics, etc.) för mer bekväm dataanalys, identifiera beroenden, etc. Vi har märkt att många användare använder vår dataanalysplattform, specifikt Google Analytics (nedan kallat GA). Vi pratade med några användare och fick reda på att de behöver deras produktanalysdata, som de får med hjälp av GA, men Google tar provdata och för många GA är användargränssnitt inte en standard för bekvämlighet. Vi hade tillräckligt med samtal med våra användare och insåg att många också använde Segment-plattformen (vilket för övrigt var för bara några dagar sedan såldes för 3.2 miljarder dollar).

De installerade en Segment javascript-pixel på sin webbresurs och deras användarbeteendedata laddades in i en specificerad databas (t.ex. Postgres). Men Segment har också sitt minus – priset. Till exempel, om en webbresurs har 90,000 1,000 MTU (månadsspårade användare), måste du betala ~ $ XNUMX XNUMX per månad till kassan. Det fanns också ett tredje problem - vissa webbläsartillägg (som AdBlock) blockerade insamlingen av analyser. http-förfrågningar från webbläsaren skickades till GA- och segmentdomänerna. Utifrån våra kunders önskemål har vi skapat en analystjänst som samlar in en komplett uppsättning data (utan provtagning), kostnadsfritt och kan köras på vår egen infrastruktur.

Hur tjänsten fungerar

Tjänsten består av tre delar: en javascript-pixel (som vi senare skrev om till typescript), en serverdel implementerad i GO-språket, och det var planerat att använda Redshift och BigQuery som en intern databas (senare lade de till stöd för Postgres , ClickHouse och Snowflake).

Händelsestrukturen GA och Segment beslutade att lämna oförändrade. Allt som behövdes var att duplicera alla händelser från webbresursen där pixeln är installerad till vår backend. Som det visar sig är detta lätt att göra. Javascript-pixeln åsidosatte den ursprungliga GA-biblioteksmetoden med en ny som duplicerade händelsen i vårt 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-pixeln är allt enklare, det har middleware-metoder, och vi använde en av dem.


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

Förutom att kopiera händelser har vi lagt till möjligheten att skicka godtyckliga 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'
});

Låt oss sedan prata om serversidan. Backend bör acceptera http-förfrågningar, fyll dem med ytterligare information, till exempel geodata (tack maxmind för det) och skriv till databasen. Vi ville göra tjänsten så bekväm som möjligt så att den kan användas med minimal konfiguration. Vi har implementerat funktionen för att bestämma dataschemat baserat på strukturen för den inkommande händelsen json. Datatyper definieras av värden. Kapslade föremål sönderdelas och reduceras till en platt 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"
}

Men arrayer konverteras för närvarande helt enkelt till strängar. inte alla relationsdatabaser stöder upprepade fält. Det är också möjligt att ändra fältnamn eller ta bort dem med valfria mappningsregler. De låter dig ändra dataschemat, om det behövs, eller casta en datatyp till en annan. Till exempel, om json-fältet innehåller en sträng med en tidsstämpel (field_3_sub_field_1_sub_sub_field_1 från exemplet ovan), för att skapa ett fält i databasen med tidsstämpeltypen måste du skriva en mappningsregel i konfigurationen. Med andra ord bestäms datatypen för fältet först av json-värdet och sedan tillämpas regeln för typcasting (om den är konfigurerad). Vi har identifierat fyra huvuddatatyper: STRING, FLOAT4, INT64 och TIMESTAMP. Mappnings- och castingreglerna ser ut så här:

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

Algoritm för att bestämma datatypen:

  • konvertera json-strukturen till platt struktur
  • bestämma datatypen för fält genom värden
  • tillämpa kartläggning och typgjutningsregler

Sedan från den inkommande 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"
    }
}

dataschema kommer att erhållas:

"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 också att användaren skulle kunna ställa in partitionering eller dela data i databasen enligt andra kriterier och implementerade möjligheten att ställa in tabellnamnet som en konstant eller uttryck i konfiguration. I exemplet nedan kommer händelsen att sparas i en tabell med ett namn som beräknas baserat på värdena i fälten product_type och _timestamp (till exempel supplies_2020_10):

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

Strukturen för inkommande händelser kan dock ändras under körning. Vi har implementerat en algoritm för att kontrollera skillnaden mellan strukturen för en befintlig tabell och strukturen för en inkommande händelse. Om en skillnad hittas kommer tabellen att uppdateras med nya fält. För att göra detta, använd patch SQL-frågan:

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

Arkitektur

Historien om vår öppen källkod: hur vi skapade en analystjänst i Go och gjorde den offentligt tillgänglig

Varför behöver du skriva händelser till filsystemet, och inte bara skriva dem direkt till databasen? Databaser visar inte alltid hög prestanda med ett stort antal inlägg (postgres rekommendationer). För att göra detta skriver Logger inkommande händelser till en fil och redan i en separat goroutine (tråd) läser Filläsaren filen, sedan sker transformationen och definitionen av dataschemat. Efter att tabellhanteraren försäkrat sig om att tabellschemat är uppdaterat kommer data att skrivas till databasen i en batch. Därefter lade vi till möjligheten att skriva data direkt till databasen, men vi använder det här läget för händelser som inte är många - till exempel konverteringar.

Öppen källkod och framtidsplaner

Vid något tillfälle blev tjänsten som en fullfjädrad produkt och vi bestämde oss för att lägga den i Open Source. För tillfället har integrationer med Postgres, ClickHouse, BigQuery, Redshift, S3, Snowflake implementerats. Alla integrationer stöder både batch- och strömmande dataladdningslägen. Lade till stöd för förfrågningar via API.

Det nuvarande integrationsschemat ser ut så här:

Historien om vår öppen källkod: hur vi skapade en analystjänst i Go och gjorde den offentligt tillgänglig

Även om tjänsten kan användas oberoende (till exempel med Docker), har vi också värdversion, där du kan ställa in integration med datalagret, lägga till en CNAME till din domän och se statistik över antalet händelser. Våra omedelbara planer är att lägga till möjligheten att samla inte bara statistik från en webbresurs utan även data från externa datakällor och spara dem till valfri lagring!

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

Vi blir glada om EventNative hjälper dig att lösa dina problem!

Endast registrerade användare kan delta i undersökningen. Logga in, Snälla du.

Vilket statistikinsamlingssystem som används i ditt företag

  • 48,0%Google Analytics12

  • 4,0%Segment1

  • 16,0%Annat (skriv i kommentarerna) 4

  • 32,0%Implementerade din tjänst8

25 användare röstade. 6 användare avstod från att rösta.

Källa: will.com

Lägg en kommentar