Mūsų atvirojo kodo istorija: kaip sukūrėme analizės paslaugą Go ir padarėme ją viešai prieinamą

Šiuo metu beveik kiekviena pasaulio įmonė renka statistiką apie vartotojų veiksmus žiniatinklio šaltinyje. Motyvacija aiški – įmonės nori žinoti, kaip naudojamas jų produktas/svetainė ir geriau suprasti savo vartotojus. Žinoma, rinkoje yra daug įrankių šiai problemai išspręsti – iš analizės sistemų, kurios teikia duomenis prietaisų skydelių ir grafikų pavidalu (pvz. "Google Analytics") į Klientų duomenų platformą, kuri leidžia rinkti ir kaupti duomenis iš įvairių šaltinių bet kuriame sandėlyje (pvz. Segmentas).

Tačiau radome problemą, kuri dar nebuvo išspręsta. Taip gimė ĮvykisNative — atvirojo kodo analizės paslauga. Skaitykite apie tai, kodėl nusprendėme kurti savo paslaugą, ką ji mums davė ir koks buvo galutinis rezultatas (su kodo dalimis).

Mūsų atvirojo kodo istorija: kaip sukūrėme analizės paslaugą Go ir padarėme ją viešai prieinamą

Kodėl turėtume kurti savo paslaugą?

Buvo 2019 dešimtmetis, išgyvenome kaip galėjome. XNUMX m. sukūrėme API First Customer Data Platform kSense, kuri leido apibendrinti duomenis iš skirtingų šaltinių (Facebook reklamų, Stripe, Salesforce, Google play, Google Analytics ir kt.), kad būtų galima patogiau analizuoti duomenis, nustatyti priklausomybes ir pan. Pastebėjome, kad daugelis vartotojų naudoja mūsų platformą duomenų analizei, būtent Google Analytics (toliau GA). Kalbėjomės su kai kuriais naudotojais ir išsiaiškinome, kad jiems reikia produkto analizės duomenų, kuriuos jie gauna naudodami GA, bet Google paima duomenų pavyzdžius ir daugeliui GA vartotojo sąsaja nėra patogumo standartas. Turėjome pakankamai pokalbių su savo vartotojais ir supratome, kad daugelis taip pat naudojasi segmentų platforma (kuri, beje, buvo tik kitą dieną parduota už 3.2 mlrd).

Jie įdiegė Segment JavaScript pikselį savo žiniatinklio šaltinyje ir duomenys apie jų vartotojų elgesį buvo įkelti į nurodytą duomenų bazę (pvz., Postgres). Tačiau Segmentas turi ir minusą – kainą. Pavyzdžiui, jei žiniatinklio resursas turi 90,000 1,000 MTU (mėnesio stebimi vartotojai), tuomet kasininkui reikia mokėti ~XNUMX XNUMX USD per mėnesį. Iškilo ir trečia problema – kai kurie naršyklės plėtiniai (pvz., AdBlock) blokavo analizės rinkimą, nes... http užklausos iš naršyklės buvo išsiųstos į GA ir Segment domenus. Atsižvelgdami į klientų pageidavimus, sukūrėme analitikos paslaugą, kuri renka visą duomenų rinkinį (be atrankos), yra nemokama ir gali dirbti savo infrastruktūroje.

Kaip paslauga veikia

Paslauga susideda iš trijų dalių: javascript pikselio (kurį vėliau perrašėme mašinraščiu), serverio dalis yra įdiegta GO kalba, taip pat buvo numatyta naudoti Redshift ir BigQuery kaip vidinę duomenų bazę (vėliau jie papildė palaikymą Postgres, ClickHouse ir Snowflake).

Buvo nuspręsta GA ir Segmento įvykių struktūrą palikti nepakeistą. Viskas, ko reikėjo, buvo dubliuoti visus įvykius iš žiniatinklio šaltinio, kuriame yra įdiegtas pikselis, į mūsų užpakalinę programą. Kaip paaiškėjo, tai padaryti nėra sunku. „Javascript“ pikselis pakeitė pradinį GA bibliotekos metodą nauju, kuris dubliavo įvykį mūsų sistemoje.

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

Su Segment pikseliu viskas yra paprasčiau, jame yra tarpinės programinės įrangos metodų, iš kurių vieną naudojome.


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

Be įvykių kopijavimo, pridėjome galimybę siųsti savavališką 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'
});

Toliau pakalbėkime apie serverio dalį. Užpakalinė programa turėtų priimti http užklausas, užpildyti jas papildoma informacija, pavyzdžiui, geografiniais duomenimis (ačiū maxmind už tai) ir įrašykite jį į duomenų bazę. Norėjome, kad paslauga būtų kuo patogesnė, kad ja būtų galima naudotis su minimalia konfigūracija. Įdiegėme duomenų schemos nustatymo pagal gaunamo json įvykio struktūrą funkciją. Duomenų tipai apibrėžiami reikšmėmis. Įdėti objektai suskaidomi ir paverčiami plokščia struktūra:

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

Tačiau masyvai šiuo metu tiesiog konvertuojami į eilutes, nes Ne visos reliacinės duomenų bazės palaiko pasikartojančius laukus. Taip pat galima keisti laukų pavadinimus arba juos ištrinti naudojant pasirenkamas susiejimo taisykles. Jie leidžia keisti duomenų schemą, jei reikia, arba konvertuoti vieną duomenų tipą į kitą. Pavyzdžiui, jei json lauke yra eilutė su laiko žyma (field_3_sub_field_1_sub_sub_field_1 iš aukščiau pateikto pavyzdžio), tada norėdami duomenų bazėje sukurti lauką su laiko žymos tipu, konfigūracijoje turite parašyti susiejimo taisyklę. Kitaip tariant, lauko duomenų tipas pirmiausia nustatomas pagal json reikšmę, o tada taikoma tipo perdavimo taisyklė (jei sukonfigūruota). Mes nustatėme 4 pagrindinius duomenų tipus: STRING, FLOAT64, INT64 ir TIMESTAMP. Susiejimo ir tipo liejimo taisyklės atrodo taip:

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

Duomenų tipo nustatymo algoritmas:

  • konvertuoti json struktūrą į plokščią struktūrą
  • pagal reikšmes nustatant laukų duomenų tipą
  • taikant kartografavimo ir tipo liejimo taisykles

Tada iš gaunamos json struktūros:

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

bus gauta duomenų schema:

"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

Taip pat pagalvojome, kad vartotojas turi turėti galimybę sukonfigūruoti skaidymą arba dalyti duomenis duomenų bazėje pagal kitus kriterijus ir įdiegėme galimybę lentelės pavadinimą nustatyti su konstanta arba išraiška konfigūracijoje. Toliau pateiktame pavyzdyje įvykis bus įrašytas į lentelę su pavadinimu, apskaičiuotu pagal laukų product_type ir _timestamp reikšmes (pvz. reikmenys_2020_10):

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

Tačiau gaunamų įvykių struktūra gali pasikeisti vykdymo metu. Įdiegėme algoritmą, skirtą patikrinti esamos lentelės ir gaunamo įvykio struktūros skirtumą. Jei randamas skirtumas, lentelė bus atnaujinta naujais laukais. Norėdami tai padaryti, naudokite pataisos SQL užklausą:

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

Architektūra

Mūsų atvirojo kodo istorija: kaip sukūrėme analizės paslaugą Go ir padarėme ją viešai prieinamą

Kodėl įvykius reikia įrašyti į failų sistemą, o ne tiesiog rašyti į duomenų bazę? Duomenų bazės ne visada gerai veikia, kai dirbama su daugybe įterpimų („Postgres“ rekomendacijos). Norėdami tai padaryti, Logger įrašo įeinančius įvykius į failą ir atskiroje gorutinoje (gijoje) Failų skaitytuvas nuskaito failą, tada duomenys konvertuojami ir nustatomi. Lentelių tvarkytuvui įsitikinus, kad lentelės schema yra atnaujinta, duomenys į duomenų bazę bus įrašomi viena pakete. Vėliau įtraukėme galimybę įrašyti duomenis tiesiai į duomenų bazę, tačiau šį režimą naudojame įvykiams, kurių nėra daug – pavyzdžiui, konversijoms.

Atvirasis šaltinis ir ateities planai

Tam tikru momentu paslauga pradėjo atrodyti kaip visavertis produktas, ir mes nusprendėme ją išleisti į atvirąjį kodą. Šiuo metu įdiegtos integracijos su Postgres, ClickHouse, BigQuery, Redshift, S3, Snowflake. Visos integracijos palaiko tiek paketinio, tiek srautinio duomenų įkėlimo režimus. Pridėtas užklausų per API palaikymas.

Dabartinė integravimo schema atrodo taip:

Mūsų atvirojo kodo istorija: kaip sukūrėme analizės paslaugą Go ir padarėme ją viešai prieinamą

Nors paslauga gali būti naudojama savarankiškai (pavyzdžiui, naudojant Docker), mes taip pat turime priglobta versija, kuriame galite nustatyti integraciją su duomenų saugykla, pridėti CNAME į savo domeną ir peržiūrėti įvykių skaičiaus statistiką. Mūsų artimiausi planai yra pridėti galimybę kaupti ne tik statistiką iš žiniatinklio išteklių, bet ir duomenis iš išorinių duomenų šaltinių ir išsaugoti juos bet kurioje jūsų pasirinktoje saugykloje!

→ GitHub
→ Įrašai
→ Palaidas

Mes džiaugsimės, jei EventNative padės išspręsti jūsų problemas!

Apklausoje gali dalyvauti tik registruoti vartotojai. Prisijungti, Prašau.

Kokia statistikos rinkimo sistema naudojama jūsų įmonėje?

  • 48,0%Google Analytics 12

  • 4,0%1 segmentas

  • 16,0%Kitas (rašyk komentaruose)4

  • 32,0%Įgyvendino jūsų paslaugą8

Balsavo 25 vartotojų. 6 vartotojai susilaikė.

Šaltinis: www.habr.com

Добавить комментарий