História nášho open source: ako sme vytvorili analytickú službu v Go a sprístupnili ju verejnosti

V súčasnosti takmer každá spoločnosť na svete zhromažďuje štatistiky o akciách používateľov na webovom zdroji. Motivácia je jasná – spoločnosti chcú vedieť, ako sa ich produkt/webová stránka používa, a lepšie porozumieť svojim používateľom. Samozrejme, na trhu existuje veľké množstvo nástrojov na vyriešenie tohto problému – od analytických systémov, ktoré poskytujú dáta vo forme dashboardov a grafov (napr. Google Analytics) na platformu zákazníckych údajov, ktorá vám umožňuje zhromažďovať a agregovať údaje z rôznych zdrojov v akomkoľvek úložisku (napr. Segment).

Našli sme však problém, ktorý zatiaľ nebol vyriešený. Tak narodený EventNative — analytická služba s otvoreným zdrojom. O tom, prečo sme išli vyvinúť vlastnú službu, čo nám to dalo a čo sa nakoniec stalo (s kúskami kódu), si prečítajte pod strihom.

História nášho open source: ako sme vytvorili analytickú službu v Go a sprístupnili ju verejnosti

Prečo by sme mali rozvíjať našu vlastnú službu?

Boli deväťdesiate roky, prežili sme, ako sa dalo. 2019 sme vyvinuli rozhranie API platformy First Customer Data Platform kSense, ktorá umožnila agregovať údaje z rôznych zdrojov (reklamy na Facebooku, Stripe, Salesforce, Google play, Google Analytics atď.) pre pohodlnejšiu analýzu údajov, identifikáciu závislostí atď. Všimli sme si, že veľa používateľov používa našu platformu na analýzu údajov, konkrétne Google Analytics (ďalej len GA). Hovorili sme s niektorými používateľmi a zistili sme, že potrebujú svoje analytické údaje o produktoch, ktoré dostávajú pomocou GA, ale Google vzorky údajov a pre mnohých nie je používateľské rozhranie GA štandardom pohodlia. Mali sme dosť rozhovorov s našimi používateľmi a uvedomili sme si, že mnohí používali aj platformu Segment (ktorá, mimochodom, bola len pred pár dňami predal za 3.2 miliardy dolárov).

Na svoj webový zdroj nainštalovali javascriptový pixel Segment a údaje o ich správaní používateľov sa načítali do špecifikovanej databázy (napr. Postgres). Segment má ale aj svoje mínus – cenu. Napríklad, ak má webový zdroj 90,000 1,000 MTU (mesačne sledovaní používatelia), musíte pokladníkovi zaplatiť ~ XNUMX XNUMX USD mesačne. Vyskytol sa aj tretí problém – niektoré rozšírenia prehliadača (napríklad AdBlock) blokovali zber analytiky. Žiadosti http z prehliadača boli odoslané do domén GA a Segment. Na základe želania našich klientov sme vytvorili analytickú službu, ktorá zhromažďuje celý súbor údajov (bez vzorkovania), bezplatne a môže pracovať na našej vlastnej infraštruktúre.

Ako služba funguje

Služba sa skladá z troch častí: javascriptový pixel (ktorý sme neskôr prepísali na strojopis), serverová časť implementovaná v jazyku GO a plánovalo sa použiť Redshift a BigQuery ako internú databázu (neskôr pridali podporu pre Postgres , ClickHouse a Snowflake).

Štruktúru podujatí GA a Segment sa rozhodli ponechať nezmenenú. Všetko, čo bolo potrebné, bolo duplikovať všetky udalosti z webového zdroja, kde je pixel nainštalovaný, do nášho backendu. Ako sa ukázalo, je to jednoduché. Pixel Javascript prepísal pôvodnú metódu knižnice GA novou, ktorá duplikovala udalosť v našom systéme.

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

S pixelom Segment je všetko jednoduchšie, má middleware metódy a jednu z nich sme použili.


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

Okrem kopírovania udalostí sme pridali možnosť odosielať ľubovoľný súbor 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'
});

Ďalej sa bavme o strane servera. Backend by mal akceptovať požiadavky http, vyplniť ich ďalšími informáciami, napríklad geoúdajmi (vďaka maximálna myseľ za to) a zapíšte do databázy. Chceli sme, aby bola služba čo najpohodlnejšia, aby sa dala používať s minimálnou konfiguráciou. Implementovali sme funkcionalitu určenia dátovej schémy na základe štruktúry json prichádzajúcej udalosti. Dátové typy sú definované hodnotami. Vnorené objekty sa rozložia a zredukujú na plochú štruktúru:

//входящий 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"
}

Polia sa však v súčasnosti jednoducho konvertujú na reťazce. nie všetky relačné databázy podporujú opakované polia. Je tiež možné zmeniť názvy polí alebo ich odstrániť pomocou voliteľných pravidiel mapovania. Umožňujú vám v prípade potreby zmeniť dátovú schému alebo pretypovať jeden dátový typ na iný. Ak napríklad pole json obsahuje reťazec s časovou pečiatkou (field_3_sub_field_1_sub_sub_field_1 z vyššie uvedeného príkladu), potom, aby ste vytvorili pole v databáze s typom časovej pečiatky, musíte v konfigurácii napísať pravidlo mapovania. Inými slovami, typ údajov poľa je určený najskôr hodnotou json a potom sa použije pravidlo pretypovania (ak je nakonfigurované). Identifikovali sme 4 hlavné typy údajov: STRING, FLOAT64, INT64 a TIMESTAMP. Pravidlá mapovania a prenášania vyzerajú takto:

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

Algoritmus na určenie typu údajov:

  • previesť štruktúru json na plochú štruktúru
  • určenie dátového typu polí podľa hodnôt
  • uplatňovanie pravidiel mapovania a typového vrhania

Potom z prichádzajúcej štruktúry json:

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

získa sa dátová schéma:

"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

Mysleli sme aj na to, že používateľ by mal mať možnosť nastaviť rozdelenie alebo rozdeliť dáta v databáze podľa iných kritérií a implementovali sme možnosť nastaviť názov tabuľky ako konštantný resp. výraz v konfigurácii. V príklade nižšie sa udalosť uloží do tabuľky s názvom vypočítaným na základe hodnôt polí product_type a _timestamp (napr. zásoby_2020_10):

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

Štruktúra prichádzajúcich udalostí sa však môže počas behu meniť. Implementovali sme algoritmus na kontrolu rozdielu medzi štruktúrou existujúcej tabuľky a štruktúrou prichádzajúcej udalosti. Ak sa nájde rozdiel, tabuľka sa aktualizuje o nové polia. Ak to chcete urobiť, použite opravný SQL dotaz:

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

architektúra

História nášho open source: ako sme vytvorili analytickú službu v Go a sprístupnili ju verejnosti

Prečo potrebujete zapisovať udalosti do súborového systému a nielen ich zapisovať priamo do databázy? Databázy nie vždy vykazujú vysoký výkon s veľkým počtom vložiek (postgres odporúčania). Za týmto účelom Logger zapíše prichádzajúce udalosti do súboru a už v samostatnom goroutine (vlákne) Čítačka súborov načíta súbor, potom prebehne transformácia a definícia dátovej schémy. Keď sa správca tabuliek uistí, že schéma tabuľky je aktuálna, údaje sa zapíšu do databázy v jednej dávke. Následne sme pridali možnosť zapisovať dáta priamo do databázy, no tento režim využívame pri udalostiach, ktorých nie je veľa – napríklad konverzie.

Open Source a plány do budúcnosti

V určitom okamihu sa služba stala plnohodnotným produktom a rozhodli sme sa dať ju do Open Source. V súčasnosti boli implementované integrácie s Postgres, ClickHouse, BigQuery, Redshift, S3, Snowflake. Všetky integrácie podporujú dávkový aj streamingový režim načítania dát. Pridaná podpora pre požiadavky cez API.

Súčasná integračná schéma vyzerá takto:

História nášho open source: ako sme vytvorili analytickú službu v Go a sprístupnili ju verejnosti

Hoci službu možno používať samostatne (napríklad pomocou Docker), máme tiež hosťovaná verzia, kde si môžete nastaviť integráciu s dátovým skladom, pridať CNAME do svojej domény a zobraziť štatistiky o počte udalostí. Naše najbližšie plány sú pridať možnosť agregovať nielen štatistiky z webového zdroja, ale aj údaje z externých zdrojov údajov a uložiť ich na ľubovoľné úložisko podľa vášho výberu!

→ GitHub
→ Záznamy
→ Voľný

Budeme radi, ak vám EventNative pomôže vyriešiť vaše problémy!

Do prieskumu sa môžu zapojiť iba registrovaní užívatelia. Prihlásiť saProsím.

Aký systém zberu štatistík sa používa vo vašej spoločnosti

  • 48,0%Google Analytics12

  • 4,0%Segment1

  • 16,0%Iné (napíšte do komentárov) 4

  • 32,0%Implementovali ste vašu službu8

Hlasovalo 25 užívateľov. 6 užívateľov sa zdržalo hlasovania.

Zdroj: hab.com

Pridať komentár