Açık kaynağımızın geçmişi: Go'da bir analiz hizmetini nasıl oluşturduk ve bunu kamuya açık hale getirdik

Şu anda dünyadaki hemen hemen her şirket, bir web kaynağındaki kullanıcı eylemlerine ilişkin istatistikler toplamaktadır. Motivasyon açık; şirketler ürünlerinin/web sitelerinin nasıl kullanıldığını bilmek ve kullanıcılarını daha iyi anlamak istiyor. Elbette piyasada bu sorunu çözmeye yönelik çok sayıda araç var; gösterge tabloları ve grafikler biçiminde veri sağlayan analitik sistemlerinden (örneğin, Google Analytics) herhangi bir depodaki farklı kaynaklardan veri toplamanıza ve birleştirmenize olanak tanıyan Müşteri Veri Platformuna (örneğin Bölüm).

Ancak henüz çözülmemiş bir sorun bulduk. Böylece doğdu Etkinlik Yerel — açık kaynaklı analiz hizmeti. Neden kendi hizmetimizi geliştirmeye karar verdiğimizi, bunun bize neler kazandırdığını ve nihai sonucun (kod parçalarıyla birlikte) ne olduğunu okuyun.

Açık kaynağımızın geçmişi: Go'da bir analiz hizmetini nasıl oluşturduk ve bunu kamuya açık hale getirdik

Neden kendi hizmetimizi geliştirmeliyiz?

Doksanlı yıllardı, elimizden geldiğince hayatta kaldık. 2019'da API Birinci Müşteri Veri Platformunu geliştirdik kSense, daha uygun veri analizi, bağımlılıkların belirlenmesi vb. için farklı kaynaklardan (Facebook reklamları, Stripe, Salesforce, Google play, Google Analytics vb.) veri toplamayı mümkün kıldı. Pek çok kullanıcının platformumuzu, özellikle de Google Analytics'i (bundan sonra GA olarak anılacaktır) veri analizi için kullandığını fark ettik. Bazı kullanıcılarla konuştuk ve ürünlerine ilişkin GA kullanarak aldıkları analiz verilerine ihtiyaç duyduklarını öğrendik, ancak Google verileri örnekliyor ve çoğu kişi için GA Kullanıcı arayüzü kolaylık standardı değildir. Kullanıcılarımızla yeterince sohbet ettik ve birçoğunun Segment platformunu da kullandığını fark ettik (bu arada, bu da geçen gün oldu) 3.2 milyar dolara satıldı).

Web kaynaklarına bir Segment javascript pikseli yüklediler ve kullanıcılarının davranışlarına ilişkin veriler belirtilen veritabanına (örneğin Postgres) yüklendi. Ancak Segment'in bir dezavantajı da var: fiyat. Örneğin, bir web kaynağının 90,000 MTU'su (aylık izlenen kullanıcılar) varsa, o zaman kasiyere ayda ~1,000 $ ödemeniz gerekir. Ayrıca üçüncü bir sorun daha vardı; bazı tarayıcı uzantıları (AdBlock gibi) analizlerin toplanmasını engelliyordu çünkü... Tarayıcıdan gelen http istekleri GA ve Segment alanlarına gönderildi. Müşterilerimizin istekleri doğrultusunda eksiksiz veri seti toplayan (örnekleme yapmadan), ücretsiz ve kendi altyapımız üzerinde çalışabilen bir analitik hizmeti oluşturduk.

Hizmet nasıl çalışır?

Hizmet üç bölümden oluşur: bir javascript pikseli (daha sonra typescript'te yeniden yazdık), sunucu kısmı GO dilinde uygulandı ve Redshift ve BigQuery'nin şirket içi veritabanı olarak kullanılması planlandı (daha sonra destek eklendi) Postgres, ClickHouse ve Snowflake).

GA ve Segment olaylarının yapısının değiştirilmeden bırakılmasına karar verildi. Gereken tek şey, pikselin kurulu olduğu web kaynağındaki tüm olayları arka uçumuza kopyalamaktı. Görünüşe göre bunu yapmak zor değil. Javascript pikseli, orijinal GA kitaplık yöntemini yenisiyle geçersiz kıldı ve bu da olayı sistemimize kopyaladı.

//'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 ile her şey daha basit; ara yazılım yöntemleri var, biz de bunlardan birini kullandık.


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

Olayları kopyalamanın yanı sıra isteğe bağlı json gönderme özelliğini de ekledik:


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

Şimdi sunucu kısmından bahsedelim. Arka uç http isteklerini kabul etmeli, bunları coğrafi veriler gibi ek bilgilerle doldurmalıdır (teşekkürler) maksimum akıl bunun için) ve veritabanına kaydedin. Hizmeti minimum konfigürasyonla kullanılabilmesi için mümkün olduğunca kullanışlı hale getirmek istedik. Gelen json olayının yapısına göre veri şeması belirleme işlevselliğini hayata geçirdik. Veri türleri değerlerle tanımlanır. İç içe geçmiş nesneler ayrıştırılır ve düz bir yapıya indirgenir:

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

Ancak diziler şu anda yalnızca dizelere dönüştürülüyor çünkü İlişkisel veritabanlarının tümü tekrarlanan alanları desteklemez. İsteğe bağlı eşleme kurallarını kullanarak alan adlarını değiştirmek veya silmek de mümkündür. Gerekirse veri şemasını değiştirmenize veya bir veri türünü diğerine dönüştürmenize olanak tanır. Örneğin, bir json alanı zaman damgasına sahip bir dize içeriyorsa (field_3_sub_field_1_sub_sub_field_1 yukarıdaki örnekten) sonra veritabanında zaman damgası tipinde bir alan oluşturmak için konfigürasyonda bir eşleme kuralı yazmanız gerekir. Yani alanın veri tipi öncelikle json değerine göre belirlenir ve ardından tip atama kuralı (eğer yapılandırılmışsa) uygulanır. 4 ana veri türü belirledik: STRING, FLOAT64, INT64 ve TIMESTAMP. Eşleme ve tür belirleme kuralları şuna benzer:

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

Veri türünü belirlemek için algoritma:

  • json yapısını düz yapıya dönüştürün
  • Alanların veri tipinin değerlere göre belirlenmesi
  • eşleme ve tür belirleme kurallarını uygulama

Sonra gelen json yapısından:

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

veri şeması elde edilecektir:

"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

Ayrıca kullanıcının veritabanındaki verileri başka kriterlere göre bölümleme veya bölme işlemi yapabilmesi gerektiğini düşündük ve tablo adını sabit veya bir değerle ayarlama yeteneğini uyguladık. ifade konfigürasyonda. Aşağıdaki örnekte etkinlik,product_type ve _timestamp alanlarının değerlerine göre hesaplanan isimle bir tabloya kaydedilecektir (örneğin sarf malzemeleri_2020_10):

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

Ancak gelen olayların yapısı çalışma zamanında değişebilir. Mevcut bir tablonun yapısı ile gelen bir olayın yapısı arasındaki farkı kontrol etmek için bir algoritma uyguladık. Bir fark bulunursa tablo yeni alanlarla güncellenecektir. Bunu yapmak için yama SQL sorgusunu kullanın:

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

Mimari

Açık kaynağımızın geçmişi: Go'da bir analiz hizmetini nasıl oluşturduk ve bunu kamuya açık hale getirdik

Neden olayları doğrudan veritabanına yazmak yerine dosya sistemine yazmanız gerekiyor? Veritabanları çok sayıda eklemeyle uğraşırken her zaman iyi performans göstermez (Postgres önerileri). Bunu yapmak için Logger gelen olayları bir dosyaya yazar ve ayrı bir goroutine (thread) Dosya okuyucusu dosyayı okur, ardından veriler dönüştürülür ve belirlenir. Tablo yöneticisi tablo şemasının güncel olduğundan emin olduktan sonra veriler tek toplu olarak veritabanına yazılacaktır. Daha sonra, verileri doğrudan veritabanına yazma özelliğini ekledik, ancak bu modu çok sayıda olmayan olaylar (örneğin dönüşümler) için kullanıyoruz.

Açık Kaynak ve geleceğe yönelik planlar

Bir noktada hizmet tam teşekküllü bir ürün gibi görünmeye başladı ve biz de onu Açık Kaynak olarak yayınlamaya karar verdik. Şu anda Postgres, ClickHouse, BigQuery, Redshift, S3, Snowflake ile entegrasyonlar hayata geçirilmiştir. Tüm entegrasyonlar, veri yüklemenin hem toplu hem de akış modlarını destekler. API aracılığıyla istekler için destek eklendi.

Mevcut entegrasyon şeması şuna benzer:

Açık kaynağımızın geçmişi: Go'da bir analiz hizmetini nasıl oluşturduk ve bunu kamuya açık hale getirdik

Hizmet bağımsız olarak kullanılabilse de (örneğin Docker kullanarak), ayrıca barındırılan sürümBir veri ambarıyla entegrasyonu ayarlayabileceğiniz, alanınıza bir CNAME ekleyebileceğiniz ve etkinlik sayısına ilişkin istatistikleri görüntüleyebileceğiniz. Acil planlarımız, yalnızca bir web kaynağından alınan istatistikleri değil, aynı zamanda harici veri kaynaklarından gelen verileri de toplama ve bunları seçtiğiniz herhangi bir depolama birimine kaydetme olanağını eklemektir!

→ GitHub
→ Belgeleme
→ Gevşeklik

EventNative sorunlarınızı çözmeye yardımcı olursa seviniriz!

Ankete sadece kayıtlı kullanıcılar katılabilir. Giriş yapLütfen.

Şirketinizde hangi istatistik toplama sistemi kullanılıyor?

  • %48,0Google Analytics12

  • %4,0Segment1

  • %16,0Başka (yorumlara yazın)4

  • %32,0Hizmetinizi uyguladı8

25 kullanıcı oy kullandı. 6 kişi çekimser kaldı.

Kaynak: habr.com

Yorum ekle