Ochiq manba tarixi: Go-da qanday qilib tahliliy xizmatni yaratdik va uni hammaga ochiq qildik

Hozirgi vaqtda dunyodagi deyarli har bir kompaniya veb-resursda foydalanuvchi harakatlari haqida statistik ma'lumotlarni to'playdi. Motivatsiya aniq - kompaniyalar o'z mahsuloti/veb-sayti qanday ishlatilishini bilishni va foydalanuvchilarini yaxshiroq tushunishni xohlaydi. Albatta, bozorda ushbu muammoni hal qilish uchun juda ko'p vositalar mavjud - asboblar paneli va grafiklar ko'rinishidagi ma'lumotlarni taqdim etadigan analitik tizimlardan (masalan, Google Analytics) har qanday ombordagi turli manbalardan ma'lumotlarni to'plash va jamlash imkonini beruvchi Mijoz ma'lumotlari platformasiga (masalan, Segment).

Ammo biz haligacha hal qilinmagan muammoni topdik. Shunday qilib tug'ildi EventNative — ochiq manbali tahlil xizmati. Nima uchun biz o'z xizmatimizni ishlab chiqishga qaror qilganimiz, u bizga nima berdi va yakuniy natija qanday bo'lganligi (kod qismlari bilan) haqida o'qing.

Ochiq manba tarixi: Go-da qanday qilib tahliliy xizmatni yaratdik va uni hammaga ochiq qildik

Nima uchun biz o'z xizmatimizni rivojlantirishimiz kerak?

To‘qsoninchi yillar edi, biz imkon qadar omon qoldik. 2019 yilda biz API Birinchi Mijoz ma'lumotlari platformasini ishlab chiqdik kSense, bu esa turli manbalardan (Facebook reklamalari, Stripe, Salesforce, Google play, Google Analytics va boshqalar) maʼlumotlarni yanada qulayroq tahlil qilish, bogʻliqliklarni aniqlash va h.k.larni jamlash imkonini berdi. Ko'p foydalanuvchilar bizning platformamizdan ma'lumotlarni tahlil qilish uchun, xususan Google Analytics (keyingi o'rinlarda GA) foydalanishini payqadik. Biz ba'zi foydalanuvchilar bilan suhbatlashdik va ularga GA-dan foydalangan holda o'z mahsuloti uchun analitik ma'lumotlar kerakligini aniqladik, ammo Google ma'lumotlar namunalari va ko'pchilik uchun GA foydalanuvchi interfeysi qulaylik standarti emas. Biz foydalanuvchilarimiz bilan etarlicha suhbatlashdik va ko'pchilik Segment platformasidan ham foydalanishayotganini angladik (bu, aytmoqchi, bir kun oldin edi. 3.2 milliard dollarga sotilgan).

Ular o'zlarining veb-resurslariga Segment javascript pikselini o'rnatdilar va foydalanuvchilarining xatti-harakatlari haqidagi ma'lumotlar belgilangan ma'lumotlar bazasiga yuklandi (masalan, Postgres). Lekin Segmentning ham salbiy tomoni bor - narx. Misol uchun, agar veb-resursda 90,000 1,000 MTU (oylik kuzatilgan foydalanuvchilar) bo'lsa, siz kassirga oyiga ~ XNUMX dollar to'lashingiz kerak. Uchinchi muammo ham bor edi - ba'zi brauzer kengaytmalari (masalan, AdBlock) tahlillar to'plamini blokladi, chunki... Brauzerdan http so'rovlari GA va Segment domenlariga yuborildi. Mijozlarimizning xohish-istaklaridan kelib chiqib, biz maʼlumotlarning toʻliq toʻplamini (namuna olishsiz) toʻplaydigan, bepul va oʻz infratuzilmamizda ishlashi mumkin boʻlgan tahliliy xizmatni yaratdik.

Xizmat qanday ishlaydi

Xizmat uch qismdan iborat: javascript pikseli (keyinchalik uni matn terishda qayta yozdik), server qismi GO tilida amalga oshiriladi va Redshift va BigQuery-dan ichki ma'lumotlar bazasi sifatida foydalanish rejalashtirilgan edi (keyinchalik ular qo'llab-quvvatlashni qo'shdilar. Postgres, ClickHouse va Snowflake).

GA va Segment voqealari tuzilishini o'zgarishsiz qoldirishga qaror qilindi. Piksel o'rnatilgan veb-resursdan bizning backendimizga barcha voqealarni takrorlash kerak edi. Ma'lum bo'lishicha, buni qilish qiyin emas. Javascript pikseli asl GA kutubxonasi usulini yangisi bilan bekor qildi, bu hodisani tizimimizga takrorladi.

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

Segment pikseli bilan hamma narsa sodda; unda o'rta dastur usullari mavjud, ulardan biri biz foydalangan.


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

Hodisalarni nusxalashdan tashqari, biz o'zboshimchalik bilan json yuborish imkoniyatini qo'shdik:


//Отправка событий с произвольным 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'
});

Keyinchalik, server qismi haqida gapiraylik. Backend http so'rovlarini qabul qilishi, ularni qo'shimcha ma'lumotlar bilan to'ldirishi kerak, masalan, geoma'lumotlar (rahmat maxmind Buning uchun) va uni ma'lumotlar bazasiga yozib oling. Biz xizmatni minimal konfiguratsiya bilan ishlatish uchun imkon qadar qulay qilishni xohladik. Biz kiruvchi json hodisasining tuzilishi asosida ma'lumotlar sxemasini aniqlash funksiyasini amalga oshirdik. Ma'lumotlar turlari qiymatlar bilan belgilanadi. O'rnatilgan ob'ektlar parchalanadi va tekis tuzilishga aylanadi:

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

Biroq, massivlar hozirda oddiygina satrlarga aylantiriladi, chunki Barcha relyatsion ma'lumotlar bazalari takroriy maydonlarni qo'llab-quvvatlamaydi. Bundan tashqari, ixtiyoriy xaritalash qoidalaridan foydalanib, maydon nomlarini o'zgartirish yoki ularni o'chirish mumkin. Agar kerak bo'lsa, ular sizga ma'lumotlar sxemasini o'zgartirish yoki bir ma'lumot turini boshqasiga aylantirish imkonini beradi. Misol uchun, agar json maydonida vaqt tamg'asi bo'lgan satr bo'lsa (maydon_3_sub_field_1_sub_sub_field_1 yuqoridagi misoldan), keyin ma'lumotlar bazasida vaqt tamg'asi turi bilan maydon yaratish uchun konfiguratsiyada xaritalash qoidasini yozishingiz kerak. Boshqacha qilib aytadigan bo'lsak, maydonning ma'lumotlar turi birinchi navbatda json qiymati bilan aniqlanadi, so'ngra turdagi quyish qoidasi (agar sozlangan bo'lsa) qo'llaniladi. Biz 4 ta asosiy maʼlumot turini aniqladik: STRING, FLOAT64, INT64 va TIMESTAMP. Xaritalash va turlarni taqsimlash qoidalari quyidagicha ko'rinadi:

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

Ma'lumotlar turini aniqlash algoritmi:

  • json strukturasini tekis tuzilishga aylantirish
  • qiymatlar bo'yicha maydonlarning ma'lumotlar turini aniqlash
  • xaritalash va turlarni quyish qoidalarini qo'llash

Keyin kiruvchi json tuzilishidan:

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

ma'lumotlar sxemasi olinadi:

"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

Shuningdek, biz foydalanuvchi ma'lumotlar bazasidagi ma'lumotlarni boshqa mezonlarga ko'ra qismlarga ajratish yoki ajratish imkoniyatiga ega bo'lishi kerak deb o'yladik va jadval nomini doimiy yoki doimiy bilan belgilash qobiliyatini amalga oshirdik. ifoda konfiguratsiyada. Quyidagi misolda voqea mahsulot_turi va vaqt tamg'asi maydonlarining qiymatlari asosida hisoblangan nom bilan jadvalga saqlanadi (masalan, ta'minot_2020_10):

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

Biroq, kiruvchi hodisalarning tuzilishi ish vaqtida o'zgarishi mumkin. Biz mavjud jadval tuzilishi va kiruvchi hodisaning tuzilishi o'rtasidagi farqni tekshirish uchun algoritmni amalga oshirdik. Agar farq topilsa, jadval yangi maydonlar bilan yangilanadi. Buning uchun yamoq SQL so'rovidan foydalaning:

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

arxitektura

Ochiq manba tarixi: Go-da qanday qilib tahliliy xizmatni yaratdik va uni hammaga ochiq qildik

Nima uchun hodisalarni faqat ma'lumotlar bazasiga yozish emas, balki fayl tizimiga yozish kerak? Ko'p sonli qo'shimchalar bilan ishlashda ma'lumotlar bazalari har doim ham yaxshi ishlamaydi (Postgres tavsiyalari). Buning uchun Logger kiruvchi hodisalarni faylga yozadi va alohida goroutine (ip) Faylni o'quvchi faylni o'qiydi, so'ngra ma'lumotlar o'zgartiriladi va aniqlanadi. Jadval menejeri jadval sxemasining yangilanganligiga ishonch hosil qilgandan so'ng, ma'lumotlar ma'lumotlar bazasiga bir partiyada yoziladi. Keyinchalik, biz ma'lumotlarni to'g'ridan-to'g'ri ma'lumotlar bazasiga yozish imkoniyatini qo'shdik, ammo biz bu rejimdan ko'p bo'lmagan voqealar uchun foydalanamiz - masalan, konversiyalar.

Ochiq manba va kelajak uchun rejalar

Bir nuqtada, xizmat to'liq huquqli mahsulotga o'xshay boshladi va biz uni Open Source-ga chiqarishga qaror qildik. Hozirda Postgres, ClickHouse, BigQuery, Redshift, S3, Snowflake bilan integratsiya amalga oshirildi. Barcha integratsiya ma'lumotlarni yuklashning ham ommaviy, ham oqimli rejimlarini qo'llab-quvvatlaydi. API orqali so'rovlarni qo'llab-quvvatlash qo'shildi.

Joriy integratsiya sxemasi quyidagicha ko'rinadi:

Ochiq manba tarixi: Go-da qanday qilib tahliliy xizmatni yaratdik va uni hammaga ochiq qildik

Xizmatdan mustaqil ravishda foydalanish mumkin bo'lsa-da (masalan, Docker yordamida), bizda ham mavjud joylashtirilgan versiya, unda siz ma'lumotlar ombori bilan integratsiyani o'rnatishingiz, domeningizga CNAME qo'shishingiz va voqealar soni bo'yicha statistikani ko'rishingiz mumkin. Bizning yaqin rejalarimiz nafaqat veb-resursdagi statistik ma'lumotlarni, balki tashqi ma'lumotlar manbalaridan olingan ma'lumotlarni ham jamlash va ularni istalgan xotiraga saqlash qobiliyatini qo'shishdir!

→ GitHub
→ hujjatlar
→ bo'shashmasdan

Agar EventNative muammolaringizni hal qilishda yordam bersa, xursand bo'lamiz!

So'rovda faqat ro'yxatdan o'tgan foydalanuvchilar ishtirok etishlari mumkin. tizimga kirishiltimos.

Sizning kompaniyangizda qanday statistika yig'ish tizimi qo'llaniladi?

  • 48,0%Google Analytics 12

  • 4,0%Segment 1

  • 16,0%Boshqasi (sharhlarda yozing)4

  • 32,0%Sizning xizmatingiz amalga oshirildi8

25 foydalanuvchi ovoz berdi. 6 nafar foydalanuvchi betaraf qolgan.

Manba: www.habr.com

a Izoh qo'shish