Historie našeho open source: jak jsme vytvořili analytickou službu v Go a zpřístupnili ji veřejnosti

V současné době téměř každá společnost na světě shromažďuje statistiky o akcích uživatelů na webovém zdroji. Motivace je jasná – firmy chtějí vědět, jak se jejich produkt/web používá a lépe rozumět svým uživatelům. Na trhu je samozřejmě velké množství nástrojů k řešení tohoto problému – od analytických systémů, které poskytují data ve formě dashboardů a grafů (např. Google Analytics) na Customer Data Platform, která vám umožní shromažďovat a agregovat data z různých zdrojů v jakémkoli skladu (např Segment).

Našli jsme ale problém, který dosud nebyl vyřešen. Tak se zrodilo EventNative — open-source analytická služba. Přečtěte si, proč jsme se rozhodli vyvinout vlastní službu, co nám dala a jaký byl konečný výsledek (s kousky kódu).

Historie našeho open source: jak jsme vytvořili analytickou službu v Go a zpřístupnili ji veřejnosti

Proč bychom měli rozvíjet vlastní službu?

Byla devadesátá léta, přežili jsme, jak se dalo. 2019 jsme vyvinuli API First Customer Data Platform kSense, což umožnilo agregovat data z různých zdrojů (reklamy na Facebooku, Stripe, Salesforce, Google play, Google Analytics atd.) pro pohodlnější analýzu dat, identifikaci závislostí atd. Všimli jsme si, že mnoho uživatelů používá naši platformu pro analýzu dat, konkrétně Google Analytics (dále jen GA). Mluvili jsme s některými uživateli a zjistili jsme, že potřebují analytická data pro svůj produkt, která dostávají pomocí GA, ale Google vzorová data a pro mnohé není uživatelské rozhraní GA standardem pohodlí. Měli jsme dost konverzací s našimi uživateli a uvědomili jsme si, že mnozí také používají platformu Segment (což mimochodem bylo nedávno prodal za 3.2 miliardy dolarů).

Na svůj webový zdroj nainstalovali javascriptový pixel Segment a data o chování jejich uživatelů se načetla do zadané databáze (například Postgres). Segment má ale i svou nevýhodu – cenu. Pokud má například webový zdroj 90,000 1,000 MTU (měsíčně sledovaných uživatelů), musíte pokladníkovi platit ~ XNUMX XNUMX $ měsíčně. Vyskytl se také třetí problém – některá rozšíření prohlížeče (například AdBlock) blokovala shromažďování analýz, protože... Požadavky http z prohlížeče byly odeslány do domén GA a Segment. Na základě přání našich klientů jsme vytvořili analytickou službu, která shromažďuje kompletní sadu dat (bez vzorkování), je bezplatná a může fungovat na naší vlastní infrastruktuře.

Jak služba funguje

Služba se skládá ze tří částí: javascriptový pixel (který jsme později přepsali do strojopisu), serverová část je implementována v jazyce GO a bylo plánováno použití Redshift a BigQuery jako interní databáze (později přidali podporu pro Postgres, ClickHouse a Snowflake).

Bylo rozhodnuto ponechat strukturu událostí GA a segmentů beze změny. Vše, co bylo potřeba, bylo duplikovat všechny události z webového zdroje, kde je pixel nainstalován, do našeho backendu. Jak se ukazuje, není to těžké. Pixel JavaScript přepsal původní metodu knihovny GA novou, která událost duplikovala do našeho systému.

//'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 pixelem segmentu je vše jednodušší, má middlewarové metody, z nichž jednu jsme 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.');
}

Kromě kopírování událostí jsme přidali možnost odesílat libovolný 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'
});

Dále si promluvme o serverové části. Backend by měl přijímat požadavky http, naplnit je dalšími informacemi, například geografickými daty (díky maximální mysl za tímto účelem) a zaznamenejte jej do databáze. Chtěli jsme, aby služba byla co nejpohodlnější, aby ji bylo možné používat s minimální konfigurací. Implementovali jsme funkci určování datového schématu na základě struktury příchozí události json. Datové typy jsou definovány hodnotami. Vnořené objekty se rozloží a zredukují na plochou strukturu:

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

Pole jsou však v současné době jednoduše převedeny na řetězce, protože Ne všechny relační databáze podporují opakovaná pole. Je také možné změnit názvy polí nebo je odstranit pomocí volitelných pravidel mapování. Umožňují v případě potřeby změnit datové schéma nebo převést jeden datový typ na jiný. Pokud například pole json obsahuje řetězec s časovým razítkem (field_3_sub_field_1_sub_sub_field_1 z výše uvedeného příkladu), pak abyste mohli vytvořit pole v databázi s typem časového razítka, musíte v konfiguraci napsat pravidlo mapování. Jinými slovy, datový typ pole je nejprve určen hodnotou json a poté se použije pravidlo přetypování typu (pokud je nakonfigurováno). Identifikovali jsme 4 hlavní datové typy: STRING, FLOAT64, INT64 a TIMESTAMP. Pravidla mapování a přetypování vypadají takto:

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

Algoritmus pro určení datového typu:

  • převést strukturu json na plochou strukturu
  • určení datového typu polí podle hodnot
  • použití pravidel mapování a přelévání typů

Poté z příchozí struktury 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"
    }
}

bude získáno datové 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 jsme také na to, že uživatel by měl mít možnost konfigurovat dělení nebo rozdělovat data v databázi podle jiných kritérií a implementovali jsme možnost nastavit název tabulky s konstantou resp. výraz v konfiguraci. V níže uvedeném příkladu bude událost uložena do tabulky s názvem vypočítaným na základě hodnot polí product_type a _timestamp (např. dodávky_2020_10):

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

Struktura příchozích událostí se však může za běhu měnit. Implementovali jsme algoritmus pro kontrolu rozdílu mezi strukturou existující tabulky a strukturou příchozí události. Pokud je nalezen rozdíl, tabulka bude aktualizována o nová pole. K tomu použijte opravný SQL dotaz:

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

architektura

Historie našeho open source: jak jsme vytvořili analytickou službu v Go a zpřístupnili ji veřejnosti

Proč potřebujete zapisovat události do souborového systému, a nejen je zapisovat přímo do databáze? Databáze nefungují vždy dobře při práci s velkým počtem vložek (Doporučení Postgres). Za tímto účelem Logger zapíše příchozí události do souboru a v samostatné goroutine (vláknu) File reader přečte soubor, poté se data převedou a určí. Poté, co se správce tabulek ujistí, že schéma tabulky je aktuální, budou data zapsána do databáze v jedné dávce. Následně jsme přidali možnost zapisovat data přímo do databáze, ale tento režim používáme pro události, kterých není mnoho – například konverze.

Open Source a plány do budoucna

V určitém okamžiku se služba začala tvářit jako plnohodnotný produkt a rozhodli jsme se ji vydat do Open Source. V současné době byly implementovány integrace s Postgres, ClickHouse, BigQuery, Redshift, S3, Snowflake. Všechny integrace podporují dávkové i streamovací režimy načítání dat. Přidána podpora pro požadavky přes API.

Současné schéma integrace vypadá takto:

Historie našeho open source: jak jsme vytvořili analytickou službu v Go a zpřístupnili ji veřejnosti

I když lze službu používat samostatně (například pomocí Dockeru), máme také hostovaná verze, ve kterém si můžete nastavit integraci s datovým skladem, přidat CNAME do vaší domény a zobrazit statistiky o počtu událostí. Naše nejbližší plány jsou přidat možnost agregovat nejen statistiky z webového zdroje, ale také data z externích zdrojů dat a uložit je na libovolné úložiště podle vašeho výběru!

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

Budeme rádi, když EventNative pomůže vyřešit vaše problémy!

Průzkumu se mohou zúčastnit pouze registrovaní uživatelé. Přihlásit se, prosím.

Jaký systém sběru statistik používáte ve vaší společnosti?

  • 48,0%Google Analytics12

  • 4,0%Segment1

  • 16,0%Další (pište do komentářů)4

  • 32,0%Implementovali vaši službu8

Hlasovalo 25 uživatelů. 6 uživatelů se zdrželo hlasování.

Zdroj: www.habr.com

Přidat komentář