Π˜ΡΡ‚ΠΎΡ€ΠΈΡ нашСго open source: ΠΊΠ°ΠΊ ΠΌΡ‹ сдСлали сСрвис Π°Π½Π°Π»ΠΈΡ‚ΠΈΠΊΠΈ Π½Π° Go ΠΈ Π²Ρ‹Π»ΠΎΠΆΠΈΠ»ΠΈ Π΅Π³ΠΎ Π² ΠΎΡ‚ΠΊΡ€Ρ‹Ρ‚Ρ‹ΠΉ доступ

Π’ настоящСС врСмя практичСски каТдая компания Π² ΠΌΠΈΡ€Π΅ собираСт статистику ΠΎ дСйствиях ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»Ρ Π½Π° web рСсурсС. ΠœΠΎΡ‚ΠΈΠ²Π°Ρ†ΠΈΡ понятна β€” ΠΊΠΎΠΌΠΏΠ°Π½ΠΈΠΈ хотят Π·Π½Π°Ρ‚ΡŒ ΠΊΠ°ΠΊ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅Ρ‚ΡΡ ΠΈΡ… ΠΏΡ€ΠΎΠ΄ΡƒΠΊΡ‚/Π²Π΅Π± сайт ΠΈ Π»ΡƒΡ‡ΡˆΠ΅ ΠΏΠΎΠ½ΠΈΠΌΠ°Ρ‚ΡŒ своих ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»Π΅ΠΉ. ΠšΠΎΠ½Π΅Ρ‡Π½ΠΎ Π½Π° Ρ€Ρ‹Π½ΠΊΠ΅ сущСствуСт большоС количСство инструмСнтов для Ρ€Π΅ΡˆΠ΅Π½ΠΈΡ Π΄Π°Π½Π½ΠΎΠΉ ΠΏΡ€ΠΎΠ±Π»Π΅ΠΌΡ‹ β€” ΠΎΡ‚ систСм Π°Π½Π°Π»ΠΈΡ‚ΠΈΠΊΠΈ, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ ΠΏΡ€Π΅Π΄ΠΎΡΡ‚Π°Π²Π»ΡΡŽΡ‚ Π΄Π°Π½Π½Ρ‹Π΅ Π² Π²ΠΈΠ΄Π΅ Π΄Π°ΡˆΠ±ΠΎΡ€Π΄ΠΎΠ² ΠΈ Π³Ρ€Π°Ρ„ΠΈΠΊΠΎΠ² (Π½Π°ΠΏΡ€ΠΈΠΌΠ΅Ρ€ Google Analytics) Π΄ΠΎ Customer Data Platform, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ ΠΏΠΎΠ·Π²ΠΎΠ»ΡΡŽΡ‚ ΡΠΎΠ±ΠΈΡ€Π°Ρ‚ΡŒ ΠΈ Π°Π³Ρ€Π΅Π³ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ Π΄Π°Π½Π½Ρ‹Π΅ ΠΈΠ· Ρ€Π°Π·Π½Ρ‹Ρ… источников Π² любом Ρ…Ρ€Π°Π½ΠΈΠ»ΠΈΡ‰Π΅ (Π½Π°ΠΏΡ€ΠΈΠΌΠ΅Ρ€ Segment).

Но ΠΌΡ‹ нашли ΠΏΡ€ΠΎΠ±Π»Π΅ΠΌΡƒ, которая Π΅Ρ‰Π΅ Π½Π΅ Π±Ρ‹Π»Π° Ρ€Π΅ΡˆΠ΅Π½Π°. Π’Π°ΠΊ родился EventNative β€” open-source сСрвис Π°Π½Π°Π»ΠΈΡ‚ΠΈΠΊΠΈ. O Ρ‚ΠΎΠΌ, ΠΏΠΎΡ‡Π΅ΠΌΡƒ ΠΌΡ‹ пошли Π½Π° Ρ€Π°Π·Ρ€Π°Π±ΠΎΡ‚ΠΊΡƒ собствСнного сСрвиса, Ρ‡Ρ‚ΠΎ Π½Π°ΠΌ это Π΄Π°Π»ΠΎ ΠΈ Ρ‡Ρ‚ΠΎ Π² ΠΈΡ‚ΠΎΠ³Π΅ ΠΏΠΎΠ»ΡƒΡ‡ΠΈΠ»ΠΎΡΡŒ (с кусками ΠΊΠΎΠ΄Π°), Ρ‡ΠΈΡ‚Π°ΠΉΡ‚Π΅ ΠΏΠΎΠ΄ ΠΊΠ°Ρ‚ΠΎΠΌ.

Π˜ΡΡ‚ΠΎΡ€ΠΈΡ нашСго open source: ΠΊΠ°ΠΊ ΠΌΡ‹ сдСлали сСрвис Π°Π½Π°Π»ΠΈΡ‚ΠΈΠΊΠΈ Π½Π° Go ΠΈ Π²Ρ‹Π»ΠΎΠΆΠΈΠ»ΠΈ Π΅Π³ΠΎ Π² ΠΎΡ‚ΠΊΡ€Ρ‹Ρ‚Ρ‹ΠΉ доступ

Π—Π°Ρ‡Π΅ΠΌ Π½Π°ΠΌ Ρ€Π°Π·Ρ€Π°Π±Π°Ρ‚Ρ‹Π²Π°Ρ‚ΡŒ собствСнный сСрвис?

Π­Ρ‚ΠΎ Π±Ρ‹Π»ΠΈ дСвяностыС, ΠΌΡ‹ Π²Ρ‹ΠΆΠΈΠ²Π°Π»ΠΈ ΠΊΠ°ΠΊ ΠΌΠΎΠ³Π»ΠΈ. 2019 Π³ΠΎΠ΄, ΠΌΡ‹ Ρ€Π°Π·Ρ€Π°Π±Π°Ρ‚Ρ‹Π²Π°Π»ΠΈ API First Customer Data Platform kSense, которая позволяла Π°Π³Ρ€Π΅Π³ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ Π΄Π°Π½Π½Ρ‹Π΅ ΠΈΠ· Ρ€Π°Π·Π½Ρ‹Ρ… источников (Facebook ads, Stripe, Salesforce, Google play, Google Analytics ΠΈ Π΄Ρ€) для Π±ΠΎΠ»Π΅Π΅ ΡƒΠ΄ΠΎΠ±Π½ΠΎΠ³ΠΎ Π°Π½Π°Π»ΠΈΠ·Π° Π΄Π°Π½Π½Ρ‹Ρ…, выявлСния зависимостСй ΠΈ Ρ‚.Π΄. ΠœΡ‹ Π·Π°ΠΌΠ΅Ρ‚ΠΈΠ»ΠΈ, Ρ‡Ρ‚ΠΎ ΠΌΠ½ΠΎΠ³ΠΈΠ΅ ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»ΠΈ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΡŽΡ‚ Π½Π°ΡˆΡƒ ΠΏΠ»Π°Ρ‚Ρ„ΠΎΡ€ΠΌΡƒ для Π°Π½Π°Π»ΠΈΠ·Π° Π΄Π°Π½Π½Ρ‹Ρ… ΠΈΠΌΠ΅Π½Π½ΠΎ Google Analytics (Π΄Π°Π»Π΅Π΅ GA). Π‘ Π½Π΅ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΌΠΈ ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»ΡΠΌΠΈ ΠΌΡ‹ ΠΏΠΎΠ³ΠΎΠ²ΠΎΡ€ΠΈΠ»ΠΈ ΠΈ выяснили, Ρ‡Ρ‚ΠΎ ΠΈΠΌ Π½ΡƒΠΆΠ½Ρ‹ Π΄Π°Π½Π½Ρ‹Π΅ Π°Π½Π°Π»ΠΈΡ‚ΠΈΠΊΠΈ ΠΈΡ… ΠΏΡ€ΠΎΠ΄ΡƒΠΊΡ‚Π°, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ ΠΎΠ½ΠΈ ΠΏΠΎΠ»ΡƒΡ‡Π°ΡŽΡ‚ с ΠΏΠΎΠΌΠΎΡ‰ΡŒΡŽ GA, Π½ΠΎ Google сэмплируСт Π΄Π°Π½Π½Ρ‹Π΅ ΠΈ для ΠΌΠ½ΠΎΠ³ΠΈΡ… GA User interface Π½Π΅ являСтся эталоном удобства. ΠœΡ‹ ΠΏΡ€ΠΎΠ²Π΅Π»ΠΈ достаточноС количСство бСсСд с нашими ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»ΡΠΌΠΈ ΠΈ поняли, Ρ‡Ρ‚ΠΎ ΠΌΠ½ΠΎΠ³ΠΈΠ΅ Ρ‚Π°ΠΊΠΆΠ΅ использовали ΠΏΠ»Π°Ρ‚Ρ„ΠΎΡ€ΠΌΡƒ Segment (которая, кстати, Π±ΡƒΠΊΠ²Π°Π»ΡŒΠ½ΠΎ Π½Π° днях Π±Ρ‹Π»Π° ΠΏΡ€ΠΎΠ΄Π°Π½Π° Π·Π° 3.2 ΠΌΠ»Ρ€Π΄$).

Они устанавливали Segment javascript пиксСль Π½Π° свой web рСсурс ΠΈ Π΄Π°Π½Π½Ρ‹Π΅ ΠΎ ΠΏΠΎΠ²Π΅Π΄Π΅Π½ΠΈΠΈ ΠΈΡ… ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»Π΅ΠΉ Π·Π°Π³Ρ€ΡƒΠΆΠ°Π»ΠΈΡΡŒ Π² ΡƒΠΊΠ°Π·Π°Π½Π½ΡƒΡŽ Π±Π°Π·Ρƒ Π΄Π°Π½Π½Ρ‹Ρ… (Π½Π°ΠΏΡ€ΠΈΠΌΠ΅Ρ€ Postgres). Но ΠΈ Ρƒ Segment Π΅ΡΡ‚ΡŒ свой минус β€” Ρ†Π΅Π½Π°. К ΠΏΡ€ΠΈΠΌΠ΅Ρ€Ρƒ, Ссли Ρƒ Π²Π΅Π± рСсурса 90,000 MTU (monthly tracked users) Ρ‚ΠΎ Π½Π΅ΠΎΠ±Ρ…ΠΎΠ΄ΠΈΠΌΠΎ ΠΎΠΏΠ»Π°Ρ‚ΠΈΡ‚ΡŒ Π² кассу ~1,000 $ Π² мСсяц. Π’Π°ΠΊΠΆΠ΅ Π±Ρ‹Π»Π° ΠΈ Ρ‚Ρ€Π΅Ρ‚ΡŒΡ ΠΏΡ€ΠΎΠ±Π»Π΅ΠΌΠ° β€” Π½Π΅ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ Ρ€Π°ΡΡˆΠΈΡ€Π΅Π½ΠΈΡ для Π±Ρ€Π°ΡƒΠ·Π΅Ρ€Π° (Ρ‚Π°ΠΊΠΈΠ΅ ΠΊΠ°ΠΊ AdBlock) Π±Π»ΠΎΠΊΠΈΡ€ΠΎΠ²Π°Π»ΠΈ сбор Π°Π½Π°Π»ΠΈΡ‚ΠΈΠΊΠΈ Ρ‚.ΠΊ. http запросы ΠΈΠ· Π±Ρ€Π°ΡƒΠ·Π΅Ρ€Π° ΠΎΡ‚ΠΏΡ€Π°Π²Π»ΡΠ»ΠΈΡΡŒ Π½Π° Π΄ΠΎΠΌΠ΅Π½Ρ‹ GA ΠΈ Segment. Π˜ΡΡ…ΠΎΠ΄Ρ ΠΈΠ· ТСлания Π½Π°ΡˆΠΈΡ… ΠΊΠ»ΠΈΠ΅Π½Ρ‚ΠΎΠ², ΠΌΡ‹ сдСлали сСрвис Π°Π½Π°Π»ΠΈΡ‚ΠΈΠΊΠΈ, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ собираСт ΠΏΠΎΠ»Π½Ρ‹ΠΉ Π½Π°Π±ΠΎΡ€ Π΄Π°Π½Π½Ρ‹Ρ… (Π±Π΅Π· сэмплинга), бСсплатный ΠΈ ΠΌΠΎΠΆΠ΅Ρ‚ Ρ€Π°Π±ΠΎΡ‚Π°Ρ‚ΡŒ Π½Π° собствСнной инфраструктурС.

Как устроСн сСрвис

БСрвис состоит ΠΈΠ· Ρ‚Ρ€Π΅Ρ… частСй: javascript пиксСль (ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ ΠΌΡ‹ впослСдствии пСрСписали Π½Π° typescript), сСрвСрная Ρ‡Π°ΡΡ‚ΡŒ Ρ€Π΅Π°Π»ΠΈΠ·ΠΎΠ²Π°Π½Π° Π½Π° языкС GO ΠΈ Π² качСствС in-house Π±Π°Π·Ρ‹ Π΄Π°Π½Π½Ρ‹Ρ… ΠΏΠ»Π°Π½ΠΈΡ€ΠΎΠ²Π°Π»ΠΎΡΡŒ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ Redshift ΠΈ BigQuery (ΠΏΠΎΠ·ΠΆΠ΅ Π΄ΠΎΠ±Π°Π²ΠΈΠ»ΠΈ ΠΏΠΎΠ΄Π΄Π΅Ρ€ΠΆΠΊΡƒ Postgres, ClickHouse ΠΈ Snowflake).

Π‘Ρ‚Ρ€ΡƒΠΊΡ‚ΡƒΡ€Ρƒ событий GA ΠΈ Segment Ρ€Π΅ΡˆΠΈΠ»ΠΈ ΠΎΡΡ‚Π°Π²ΠΈΡ‚ΡŒ Π±Π΅Π· измСнСния. ВсС, Ρ‡Ρ‚ΠΎ Π±Ρ‹Π»ΠΎ Π½ΡƒΠΆΠ½ΠΎ, это Π΄ΡƒΠ±Π»ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ всС события с web рСсурса, Π³Π΄Π΅ установлСн пиксСль, Π² наш Π±Π΅ΠΊΠ΅Π½Π΄. Как оказалось, это ΡΠ΄Π΅Π»Π°Ρ‚ΡŒ нСслоТно. Javascript пиксСль пСрСопрСдСлял ΠΎΡ€ΠΈΠ³ΠΈΠ½Π°Π»ΡŒΠ½Ρ‹ΠΉ ΠΌΠ΅Ρ‚ΠΎΠ΄ Π±ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊΠΈ GA Π½Π° Π½ΠΎΠ²Ρ‹ΠΉ, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ Π΄ΡƒΠ±Π»ΠΈΡ€ΠΎΠ²Π°Π» событиС Π² Π½Π°ΡˆΡƒ систСму.

//'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 всС ΠΏΡ€ΠΎΡ‰Π΅, ΠΎΠ½ ΠΈΠΌΠ΅Π΅Ρ‚ middleware ΠΌΠ΅Ρ‚ΠΎΠ΄Ρ‹, ΠΎΠ΄Π½ΠΈΠΌ ΠΈΠ· Π½ΠΈΡ… ΠΌΡ‹ ΠΈ воспользовались.


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

Помимо копирования событий ΠΌΡ‹ Π΄ΠΎΠ±Π°Π²ΠΈΠ»ΠΈ Π²ΠΎΠ·ΠΌΠΎΠΆΠ½ΠΎΡΡ‚ΡŒ ΠΎΡ‚ΠΏΡ€Π°Π²Π»ΡΡ‚ΡŒ ΠΏΡ€ΠΎΠΈΠ·Π²ΠΎΠ»ΡŒΠ½Ρ‹ΠΉ 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'
});

Π”Π°Π»Π΅Π΅ ΠΏΠΎΠ³ΠΎΠ²ΠΎΡ€ΠΈΠΌ ΠΏΡ€ΠΎ ΡΠ΅Ρ€Π²Π΅Ρ€Π½ΡƒΡŽ Ρ‡Π°ΡΡ‚ΡŒ. Backend Π΄ΠΎΠ»ΠΆΠ΅Π½ ΠΏΡ€ΠΈΠ½ΠΈΠΌΠ°Ρ‚ΡŒ http запросы, Π½Π°ΠΏΠΎΠ»Π½ΡΡ‚ΡŒ ΠΈΡ… Π΄ΠΎΠΏΠΎΠ»Π½ΠΈΡ‚Π΅Π»ΡŒΠ½ΠΎΠΉ ΠΈΠ½Ρ„ΠΎΡ€ΠΌΠ°Ρ†ΠΈΠ΅ΠΉ, ΠΊ ΠΏΡ€ΠΈΠΌΠ΅Ρ€Ρƒ, Π³Π΅ΠΎ Π΄Π°Π½Π½Ρ‹ΠΌΠΈ (спасибо maxmind Π·Π° это) ΠΈ Π·Π°ΠΏΠΈΡΡ‹Π²Π°Ρ‚ΡŒ Π² Π±Π°Π·Ρƒ Π΄Π°Π½Π½Ρ‹Ρ…. ΠœΡ‹ Ρ…ΠΎΡ‚Π΅Π»ΠΈ ΡΠ΄Π΅Π»Π°Ρ‚ΡŒ сСрвис максимально ΡƒΠ΄ΠΎΠ±Π½Ρ‹ΠΌ, Ρ‡Ρ‚ΠΎΠ±Ρ‹ Π΅Π³ΠΎ ΠΌΠΎΠΆΠ½ΠΎ Π±Ρ‹Π»ΠΎ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ с минимальной ΠΊΠΎΠ½Ρ„ΠΈΠ³ΡƒΡ€Π°Ρ†ΠΈΠ΅ΠΉ. ΠœΡ‹ Ρ€Π΅Π°Π»ΠΈΠ·ΠΎΠ²Π°Π»ΠΈ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΎΠ½Π°Π» опрСдСлСния схСмы Π΄Π°Π½Π½Ρ‹Ρ… Π½Π° основС структуры входящСго json события. Π’ΠΈΠΏΡ‹ Π΄Π°Π½Π½Ρ‹Ρ… ΠΎΠΏΡ€Π΅Π΄Π΅Π»ΡΡŽΡ‚ΡΡ ΠΏΠΎ значСниям. Π’Π»ΠΎΠΆΠ΅Π½Π½Ρ‹Π΅ ΠΎΠ±ΡŠΠ΅ΠΊΡ‚Ρ‹ Ρ€Π°ΡΠΊΠ»Π°Π΄Ρ‹Π²Π°ΡŽΡ‚ΡΡ ΠΈ приводятся ΠΊ плоской структурС:

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

Однако массивы Π½Π° Π΄Π°Π½Π½Ρ‹ΠΉ ΠΌΠΎΠΌΠ΅Π½Ρ‚ просто ΠΊΠΎΠ½Π²Π΅Ρ€Ρ‚ΠΈΡ€ΡƒΡŽΡ‚ΡΡ Π² строку Ρ‚.ΠΊ. Π½Π΅ всС рСляционныС Π±Π°Π·Ρ‹ Π΄Π°Π½Π½Ρ‹Ρ… ΠΏΠΎΠ΄Π΄Π΅Ρ€ΠΆΠΈΠ²Π°ΡŽΡ‚ ΠΏΠΎΠ²Ρ‚ΠΎΡ€ΡΡŽΡ‰ΠΈΠ΅ΡΡ поля (repeated fields). Π’Π°ΠΊΠΆΠ΅ Π΅ΡΡ‚ΡŒ Π²ΠΎΠ·ΠΌΠΎΠΆΠ½ΠΎΡΡ‚ΡŒ ΠΈΠ·ΠΌΠ΅Π½ΡΡ‚ΡŒ названия ΠΏΠΎΠ»Π΅ΠΉ ΠΈΠ»ΠΈ ΡƒΠ΄Π°Π»ΡΡ‚ΡŒ ΠΈΡ… с ΠΏΠΎΠΌΠΎΡ‰ΡŒΡŽ ΠΎΠΏΡ†ΠΈΠΎΠ½Π°Π»ΡŒΠ½Ρ‹Ρ… ΠΏΡ€Π°Π²ΠΈΠ» ΠΌΠ°ΠΏΠΏΠΈΠ½Π³Π°. Они ΠΏΠΎΠ·Π²ΠΎΠ»ΡΡŽΡ‚ ΠΌΠ΅Π½ΡΡ‚ΡŒ схСму Π΄Π°Π½Π½Ρ‹Ρ…, Ссли это потрСбуСтся ΠΈΠ»ΠΈ ΠΏΡ€ΠΈΠ²ΠΎΠ΄ΠΈΡ‚ΡŒ ΠΎΠ΄ΠΈΠ½ Ρ‚ΠΈΠΏ Π΄Π°Π½Π½Ρ‹Ρ… ΠΊ Π΄Ρ€ΡƒΠ³ΠΎΠΌΡƒ. К ΠΏΡ€ΠΈΠΌΠ΅Ρ€Ρƒ, Ссли Π² json ΠΏΠΎΠ»Π΅ находится строка с timestamp (field_3_sub_field_1_sub_sub_field_1 ΠΈΠ· ΠΏΡ€ΠΈΠΌΠ΅Ρ€Π° Π²Ρ‹ΡˆΠ΅) Ρ‚ΠΎ для Ρ‚ΠΎΠ³ΠΎ Ρ‡Ρ‚ΠΎΠ±Ρ‹ ΡΠΎΠ·Π΄Π°Ρ‚ΡŒ ΠΏΠΎΠ»Π΅ Π² Π±Π°Π·Π΅ Π΄Π°Π½Π½Ρ‹Ρ… с Ρ‚ΠΈΠΏΠΎΠΌ timestamp, Π½Π΅ΠΎΠ±Ρ…ΠΎΠ΄ΠΈΠΌΠΎ Π½Π°ΠΏΠΈΡΠ°Ρ‚ΡŒ ΠΏΡ€Π°Π²ΠΈΠ»ΠΎ ΠΌΠ°ΠΏΠΏΠΈΠ½Π³Π° Π² ΠΊΠΎΠ½Ρ„ΠΈΠ³ΡƒΡ€Π°Ρ†ΠΈΠΈ. Π”Ρ€ΡƒΠ³ΠΈΠΌΠΈ словами, Ρ‚ΠΈΠΏ Π΄Π°Π½Π½Ρ‹Ρ… поля опрСдСляСтся сначала ΠΏΠΎ json Π·Π½Π°Ρ‡Π΅Π½ΠΈΡŽ, Π° Π·Π°Ρ‚Π΅ΠΌ примСняСтся ΠΏΡ€Π°Π²ΠΈΠ»ΠΎ привСдСния Ρ‚ΠΈΠΏΠΎΠ² (Ссли ΠΎΠ½ΠΎ сконфигурировано). ΠœΡ‹ Π²Ρ‹Π΄Π΅Π»ΠΈΠ»ΠΈ 4 основных Ρ‚ΠΈΠΏΠ° Π΄Π°Π½Π½Ρ‹Ρ…: STRING, FLOAT64, INT64 ΠΈ TIMESTAMP. ΠŸΡ€Π°Π²ΠΈΠ»Π° ΠΌΠ°ΠΏΠΏΠΈΠ½Π³Π° ΠΈ привСдСния Ρ‚ΠΈΠΏΠΎΠ² выглядят ΡΠ»Π΅Π΄ΡƒΡŽΡ‰ΠΈΠΌ ΠΎΠ±Ρ€Π°Π·ΠΎΠΌ:

rules:
  - "/field_1/subfield_1 -> " #ΠΏΡ€Π°Π²ΠΈΠ»ΠΎ удалСния поля
  - "/field_2/subfield_1 -> /field_10/subfield_1" #ΠΏΡ€Π°Π²ΠΈΠ»ΠΎ пСрСноса поля
  - "/field_3/subfield_1/subsubfield_1 -> (timestamp) /field_20" #ΠΏΡ€Π°Π²ΠΈΠ»ΠΎ пСрСноса поля ΠΈ привСдСния Ρ‚ΠΈΠΏΠ°

Алгоритм опрСдСлСния Ρ‚ΠΈΠΏΠ° Π΄Π°Π½Π½Ρ‹Ρ…:

  • ΠΏΡ€Π΅ΠΎΠ±Ρ€Π°Π·ΠΎΠ²Π°Π½ΠΈΠ΅ json структуры Π² ΠΏΠ»ΠΎΡΠΊΡƒΡŽ структуру
  • ΠΎΠΏΡ€Π΅Π΄Π΅Π»Π΅Π½ΠΈΠ΅ Ρ‚ΠΈΠΏΠ° Π΄Π°Π½Π½Ρ‹Ρ… ΠΏΠΎΠ»Π΅ΠΉ ΠΏΠΎ значСниям
  • ΠΏΡ€ΠΈΠΌΠ΅Π½Π΅Π½ΠΈΠ΅ ΠΏΡ€Π°Π²ΠΈΠ» ΠΌΠ°ΠΏΠΏΠΈΠ½Π³Π° ΠΈ привСдСния Ρ‚ΠΈΠΏΠΎΠ²

Π’ΠΎΠ³Π΄Π° ΠΈΠ· входящСй 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"
    }
}

Π±ΡƒΠ΄Π΅Ρ‚ ΠΏΠΎΠ»ΡƒΡ‡Π΅Π½Π° схСма Π΄Π°Π½Π½Ρ‹Ρ…:

"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

Π’Π°ΠΊΠΆΠ΅ ΠΌΡ‹ ΠΏΠΎΠ΄ΡƒΠΌΠ°Π»ΠΈ, Ρ‡Ρ‚ΠΎ ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»ΡŒ Π΄ΠΎΠ»ΠΆΠ΅Π½ ΠΈΠΌΠ΅Ρ‚ΡŒ Π²ΠΎΠ·ΠΌΠΎΠΆΠ½ΠΎΡΡ‚ΡŒ Π½Π°ΡΡ‚Ρ€ΠΎΠΈΡ‚ΡŒ ΠΏΠ°Ρ€Ρ‚ΠΈΡ†ΠΈΠΎΠ½ΠΈΡ€ΠΎΠ²Π°Π½ΠΈΠ΅ ΠΈΠ»ΠΈ Ρ€Π°Π·Π΄Π΅Π»ΡΡ‚ΡŒ Π΄Π°Π½Π½Ρ‹Π΅ Π² Π‘Π” ΠΏΠΎ Π΄Ρ€ΡƒΠ³ΠΈΠΌ критСриям ΠΈ Ρ€Π΅Π°Π»ΠΈΠ·ΠΎΠ²Π°Π»ΠΈ Π²ΠΎΠ·ΠΌΠΎΠΆΠ½ΠΎΡΡ‚ΡŒ Π·Π°Π΄Π°Π²Π°Ρ‚ΡŒ имя Ρ‚Π°Π±Π»ΠΈΡ†Ρ‹ константой ΠΈΠ»ΠΈ Π²Ρ‹Ρ€Π°ΠΆΠ΅Π½ΠΈΠ΅ΠΌ Π² ΠΊΠΎΠ½Ρ„ΠΈΠ³ΡƒΡ€Π°Ρ†ΠΈΠΈ. Π’ ΠΏΡ€ΠΈΠΌΠ΅Ρ€Π΅ Π½ΠΈΠΆΠ΅ событиС Π±ΡƒΠ΄Π΅Ρ‚ сохранСно Π² Ρ‚Π°Π±Π»ΠΈΡ†Ρƒ с ΠΈΠΌΠ΅Π½Π΅ΠΌ, вычислСнным Π½Π° основС Π·Π½Π°Ρ‡Π΅Π½ΠΈΠΉ ΠΏΠΎΠ»Π΅ΠΉ product_type ΠΈ _timestamp (Π½Π°ΠΏΡ€ΠΈΠΌΠ΅Ρ€ supplies_2020_10):

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

Однако структура входящих событий ΠΌΠΎΠΆΠ΅Ρ‚ ΠΈΠ·ΠΌΠ΅Π½ΡΡ‚ΡŒΡΡ Π² runtime. ΠœΡ‹ Ρ€Π΅Π°Π»ΠΈΠ·ΠΎΠ²Π°Π»ΠΈ Π°Π»Π³ΠΎΡ€ΠΈΡ‚ΠΌ ΠΏΡ€ΠΎΠ²Π΅Ρ€ΠΊΠΈ Ρ€Π°Π·Π½ΠΈΡ†Ρ‹ ΠΌΠ΅ΠΆΠ΄Ρƒ структурой ΡΡƒΡ‰Π΅ΡΡ‚Π²ΡƒΡŽΡ‰Π΅ΠΉ Ρ‚Π°Π±Π»ΠΈΡ†Ρ‹ ΠΈ структурой входящСго события. Если Ρ€Π°Π·Π½ΠΈΡ†Π° Π½Π°ΠΉΠ΄Π΅Π½Π° β€” Ρ‚Π°Π±Π»ΠΈΡ†Π° Π±ΡƒΠ΄Π΅Ρ‚ ΠΎΠ±Π½ΠΎΠ²Π»Π΅Π½Π° Π½ΠΎΠ²Ρ‹ΠΌΠΈ полями. Для этого ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅Ρ‚ΡΡ patch SQL запрос:

#ΠŸΡ€ΠΈΠΌΠ΅Ρ€ для Postgres
ALTER TABLE "schema"."table" ADD COLUMN new_column character varying

АрхитСктура

Π˜ΡΡ‚ΠΎΡ€ΠΈΡ нашСго open source: ΠΊΠ°ΠΊ ΠΌΡ‹ сдСлали сСрвис Π°Π½Π°Π»ΠΈΡ‚ΠΈΠΊΠΈ Π½Π° Go ΠΈ Π²Ρ‹Π»ΠΎΠΆΠΈΠ»ΠΈ Π΅Π³ΠΎ Π² ΠΎΡ‚ΠΊΡ€Ρ‹Ρ‚Ρ‹ΠΉ доступ

Π—Π°Ρ‡Π΅ΠΌ Π½ΡƒΠΆΠ½ΠΎ Π·Π°ΠΏΠΈΡΡ‹Π²Π°Ρ‚ΡŒ события Π½Π° Ρ„Π°ΠΉΠ»ΠΎΠ²ΡƒΡŽ систСму, Π° Π½Π΅ просто ΠΏΠΈΡΠ°Ρ‚ΡŒ ΠΈΡ… сразу Π² Π‘Π”? Π‘Π°Π·Ρ‹ Π΄Π°Π½Π½Ρ‹Ρ… Π½Π΅ всСгда Π΄Π΅ΠΌΠΎΠ½ΡΡ‚Ρ€ΠΈΡ€ΡƒΡŽΡ‚ Π²Ρ‹ΡΠΎΠΊΡƒΡŽ ΠΏΡ€ΠΎΠΈΠ·Π²ΠΎΠ΄ΠΈΡ‚Π΅Π»ΡŒΠ½ΠΎΡΡ‚ΡŒ ΠΏΡ€ΠΈ большом количСствС вставок (Ρ€Π΅ΠΊΠΎΠΌΠ΅Π½Π΄Π°Ρ†ΠΈΠΈ Postgres). Для этого Logger записываСт входящиС события Π² Ρ„Π°ΠΉΠ» ΠΈ ΡƒΠΆΠ΅ Π² ΠΎΡ‚Π΄Π΅Π»ΡŒΠ½ΠΎΠΉ Π³ΠΎΡ€ΡƒΡ‚ΠΈΠ½Π΅ (ΠΏΠΎΡ‚ΠΎΠΊΠ΅) File reader Ρ‡ΠΈΡ‚Π°Π΅Ρ‚ Ρ„Π°ΠΉΠ», Π΄Π°Π»Π΅Π΅ происходит ΠΏΡ€Π΅ΠΎΠ±Ρ€Π°Π·ΠΎΠ²Π°Π½ΠΈΠ΅ ΠΈ ΠΎΠΏΡ€Π΅Π΄Π΅Π»Π΅Π½ΠΈΠ΅ схСмы Π΄Π°Π½Π½Ρ‹Ρ…. ПослС Ρ‚ΠΎΠ³ΠΎ ΠΊΠ°ΠΊ Table manager убСдится, Ρ‡Ρ‚ΠΎ схСма Ρ‚Π°Π±Π»ΠΈΡ†Ρ‹ Π°ΠΊΡ‚ΡƒΠ°Π»ΡŒΠ½Π° β€” Π΄Π°Π½Π½Ρ‹Π΅ Π±ΡƒΠ΄ΡƒΡ‚ записаны Π² Π‘Π” ΠΎΠ΄Π½ΠΈΠΌ Π±Π°Ρ‚Ρ‡Π΅ΠΌ. ВпослСдствии ΠΌΡ‹ Π΄ΠΎΠ±Π°Π²ΠΈΠ»ΠΈ Π²ΠΎΠ·ΠΌΠΎΠΆΠ½ΠΎΡΡ‚ΡŒ Π·Π°ΠΏΠΈΡΡ‹Π²Π°Ρ‚ΡŒ Π΄Π°Π½Π½Ρ‹Π΅ Π½Π°ΠΏΡ€ΡΠΌΡƒΡŽ Π² Π‘Π”, Π½ΠΎ примСняСм Ρ‚Π°ΠΊΠΎΠΉ Ρ€Π΅ΠΆΠΈΠΌ для событий, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Ρ… Π½Π΅ ΠΌΠ½ΠΎΠ³ΠΎ β€” Π½Π°ΠΏΡ€ΠΈΠΌΠ΅Ρ€ конвСрсии.

Open Source ΠΈ ΠΏΠ»Π°Π½Ρ‹ Π½Π° Π±ΡƒΠ΄ΡƒΡ‰Π΅Π΅

Π’ ΠΊΠ°ΠΊΠΎΠΉ-Ρ‚ΠΎ ΠΌΠΎΠΌΠ΅Π½Ρ‚ сСрвис стал ΠΏΠΎΡ…ΠΎΠΆ Π½Π° ΠΏΠΎΠ»Π½ΠΎΡ†Π΅Π½Π½Ρ‹ΠΉ ΠΏΡ€ΠΎΠ΄ΡƒΠΊΡ‚ ΠΈ ΠΌΡ‹ Ρ€Π΅ΡˆΠΈΠ»ΠΈ Π²Ρ‹Π»ΠΎΠΆΠΈΡ‚ΡŒ Π΅Π³ΠΎ Π² Open Source. На Ρ‚Π΅ΠΊΡƒΡ‰ΠΈΠΉ ΠΌΠΎΠΌΠ΅Π½Ρ‚ Ρ€Π΅Π°Π»ΠΈΠ·ΠΎΠ²Π°Π½Ρ‹ ΠΈΠ½Ρ‚Π΅Π³Ρ€Π°Ρ†ΠΈΠΈ с Postgres, ClickHouse, BigQuery, Redshift, S3, Snowflake. ВсС ΠΈΠ½Ρ‚Π΅Π³Ρ€Π°Ρ†ΠΈΠΈ ΠΏΠΎΠ΄Π΄Π΅Ρ€ΠΆΠΈΠ²Π°ΡŽΡ‚ ΠΊΠ°ΠΊ batch, Ρ‚Π°ΠΊ ΠΈ streaming Ρ€Π΅ΠΆΠΈΠΌΡ‹ Π·Π°Π³Ρ€ΡƒΠ·ΠΊΠΈ Π΄Π°Π½Π½Ρ‹Ρ…. Π”ΠΎΠ±Π°Π²Π»Π΅Π½Π° ΠΏΠΎΠ΄Π΄Π΅Ρ€ΠΆΠΊΠ° запросов Ρ‡Π΅Ρ€Π΅Π· API.

ВСкущая интСграционная схСма выглядит ΡΠ»Π΅Π΄ΡƒΡŽΡ‰ΠΈΠΌ ΠΎΠ±Ρ€Π°Π·ΠΎΠΌ:

Π˜ΡΡ‚ΠΎΡ€ΠΈΡ нашСго open source: ΠΊΠ°ΠΊ ΠΌΡ‹ сдСлали сСрвис Π°Π½Π°Π»ΠΈΡ‚ΠΈΠΊΠΈ Π½Π° Go ΠΈ Π²Ρ‹Π»ΠΎΠΆΠΈΠ»ΠΈ Π΅Π³ΠΎ Π² ΠΎΡ‚ΠΊΡ€Ρ‹Ρ‚Ρ‹ΠΉ доступ

НСсмотря Π½Π° Ρ‚ΠΎ Ρ‡Ρ‚ΠΎ сСрвис ΠΌΠΎΠΆΠ½ΠΎ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ ΡΠ°ΠΌΠΎΡΡ‚ΠΎΡΡ‚Π΅Π»ΡŒΠ½ΠΎ (Π½Π°ΠΏΡ€ΠΈΠΌΠ΅Ρ€ с ΠΏΠΎΠΌΠΎΡ‰ΡŒΡŽ Docker), Ρƒ нас Ρ‚Π°ΠΊΠΆΠ΅ Π΅ΡΡ‚ΡŒ hosted вСрсия, Π² ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠΉ ΠΌΠΎΠΆΠ½ΠΎ Π½Π°ΡΡ‚Ρ€ΠΎΠΈΡ‚ΡŒ ΠΈΠ½Ρ‚Π΅Π³Ρ€Π°Ρ†ΠΈΡŽ с Ρ…Ρ€Π°Π½ΠΈΠ»ΠΈΡ‰Π΅ΠΌ Π΄Π°Π½Π½Ρ‹Ρ…, Π΄ΠΎΠ±Π°Π²ΠΈΡ‚ΡŒ CNAME Π½Π° свой Π΄ΠΎΠΌΠ΅Π½ ΠΈ ΠΏΠΎΡΠΌΠΎΡ‚Ρ€Π΅Ρ‚ΡŒ статистику ΠΏΠΎ количСству событий. Наши блиТайшиС ΠΏΠ»Π°Π½Ρ‹ β€” Π΄ΠΎΠ±Π°Π²Π»Π΅Π½ΠΈΠ΅ возмоТности Π°Π³Ρ€Π΅Π³ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ Π½Π΅ Ρ‚ΠΎΠ»ΡŒΠΊΠΎ статистику с Π²Π΅Π± рСсурса, Π½ΠΎ ΠΈ Π΄Π°Π½Π½Ρ‹Π΅ ΠΈΠ· Π²Π½Π΅ΡˆΠ½ΠΈΡ… источников Π΄Π°Π½Π½Ρ‹Ρ… ΠΈ ΡΠΎΡ…Ρ€Π°Π½ΡΡ‚ΡŒ ΠΈΡ… Π² любоС Ρ…Ρ€Π°Π½ΠΈΠ»ΠΈΡ‰Π΅ Π½Π° Π²Ρ‹Π±ΠΎΡ€!

β†’Β GitHub
→ ДокумСнтация
β†’Β Slack

Π‘ΡƒΠ΄Π΅ΠΌ Ρ€Π°Π΄Ρ‹ Ссли EventNative ΠΏΠΎΠΌΠΎΠΆΠ΅Ρ‚ Ρ€Π΅ΡˆΠΈΡ‚ΡŒ ваши Π·Π°Π΄Π°Ρ‡ΠΈ!

Волько зарСгистрированныС ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»ΠΈ ΠΌΠΎΠ³ΡƒΡ‚ ΡƒΡ‡Π°ΡΡ‚Π²ΠΎΠ²Π°Ρ‚ΡŒ Π² опросС. Π’ΠΎΠΉΠ΄ΠΈΡ‚Π΅, поТалуйста.

Какая систСма сбора статистики ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅Ρ‚ΡΡ Π² вашСй ΠΊΠΎΠΌΠΏΠ°Π½ΠΈΠΈ

  • 48,0%Google Analytics12

  • 4,0%Segment1

  • 16,0%Π”Ρ€ΡƒΠ³ΡƒΡŽ (Π½Π°ΠΏΠΈΡˆΠΈΡ‚Π΅ Π² коммСнтариях)4

  • 32,0%Π Π΅Π°Π»ΠΈΠ·ΠΎΠ²Π°Π»ΠΈ свой сСрвис8

ΠŸΡ€ΠΎΠ³ΠΎΠ»ΠΎΡΠΎΠ²Π°Π»ΠΈ 25 ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»Π΅ΠΉ. Π’ΠΎΠ·Π΄Π΅Ρ€ΠΆΠ°Π»ΠΈΡΡŒ 6 ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»Π΅ΠΉ.

Π˜ΡΡ‚ΠΎΡ‡Π½ΠΈΠΊ: habr.com

Π”ΠΎΠ±Π°Π²ΠΈΡ‚ΡŒ ΠΊΠΎΠΌΠΌΠ΅Π½Ρ‚Π°Ρ€ΠΈΠΉ