تاريخ مصدرنا المفتوح: كيف قدمنا ​​خدمة تحليلات في Go وجعلناها متاحة للجمهور

في الوقت الحالي ، تقوم كل شركة تقريبًا في العالم بجمع إحصائيات حول إجراءات المستخدم على مورد الويب. الدافع واضح - الشركات تريد معرفة كيفية استخدام منتجها / موقعها الإلكتروني وفهم مستخدميها بشكل أفضل. بالطبع ، هناك عدد كبير من الأدوات في السوق لحل هذه المشكلة - من أنظمة التحليلات التي توفر البيانات في شكل لوحات معلومات ورسوم بيانية (على سبيل المثال Google Analytics) إلى منصة بيانات العملاء ، والتي تتيح لك جمع البيانات وتجميعها من مصادر مختلفة في أي تخزين (على سبيل المثال ، قطعة).

لكننا وجدنا مشكلة لم يتم حلها بعد. ولد هكذا حدث - خدمة تحليلات مفتوحة المصدر. حول سبب ذهابنا لتطوير خدمتنا الخاصة ، وما الذي قدمته لنا وما حدث في النهاية (مع أجزاء من التعليمات البرمجية) ، اقرأ أسفل الخفض.

تاريخ مصدرنا المفتوح: كيف قدمنا ​​خدمة تحليلات في Go وجعلناها متاحة للجمهور

لماذا يجب علينا تطوير خدمتنا الخاصة؟

كان ذلك في التسعينيات ، وكنا على قيد الحياة بأفضل ما نستطيع. في عام 2019 ، قمنا بتطوير First Customer Data Platform API كسينس، مما سمح بتجميع البيانات من مصادر مختلفة (إعلانات Facebook ، و Stripe ، و Salesforce ، و Google play ، و Google Analytics ، وما إلى ذلك) لتحليل البيانات بشكل أكثر ملاءمة ، وتحديد التبعيات ، وما إلى ذلك. لقد لاحظنا أن العديد من المستخدمين يستخدمون منصة تحليل البيانات الخاصة بنا ، وتحديداً Google Analytics (المشار إليها فيما يلي باسم GA). تحدثنا مع بعض المستخدمين واكتشفنا أنهم بحاجة إلى بيانات تحليلات المنتج الخاصة بهم ، والتي يتلقونها باستخدام GA ، ولكن جوجل عينات البيانات وبالنسبة للعديد من واجهة مستخدم GA ، فهي ليست معيارًا للراحة. لقد أجرينا محادثات كافية مع مستخدمينا وأدركنا أن الكثيرين استخدموا أيضًا النظام الأساسي Segment (والذي ، بالمناسبة ، كان قبل أيام قليلة فقط بيعت بمبلغ 3.2 مليار دولار).

قاموا بتثبيت جزء جافا سكريبت بكسل على مورد الويب الخاص بهم وتم تحميل بيانات سلوك المستخدم الخاصة بهم في قاعدة بيانات محددة (مثل Postgres). لكن Segment لها أيضًا ناقصها - السعر. على سبيل المثال ، إذا كان مورد الويب يحتوي على 90,000 MTU (المستخدمون المتتبعون شهريًا) ، فأنت بحاجة إلى دفع حوالي 1,000 دولار شهريًا إلى أمين الصندوق. كانت هناك أيضًا مشكلة ثالثة - بعض امتدادات المتصفح (مثل AdBlock) منعت جمع التحليلات. تم إرسال طلبات http من المتصفح إلى نطاقي GA و Segment. بناءً على رغبة عملائنا ، أنشأنا خدمة تحليلات تجمع مجموعة كاملة من البيانات (بدون أخذ عينات) مجانًا ويمكن أن تعمل على بنيتنا التحتية الخاصة.

كيف تعمل الخدمة

تتكون الخدمة من ثلاثة أجزاء: بكسل جافا سكريبت (والذي قمنا بإعادة كتابته لاحقًا إلى نص مكتوب) ، وجزء خادم تم تنفيذه بلغة GO ، وكان من المخطط استخدام Redshift و BigQuery كقاعدة بيانات داخلية (قاموا لاحقًا بإضافة دعم لـ Postgres و ClickHouse و Snowflake).

قرر هيكل الأحداث GA و Segment عدم تغيير. كل ما كان مطلوبًا هو تكرار جميع الأحداث من مورد الويب حيث تم تثبيت البكسل على الواجهة الخلفية لدينا. كما اتضح ، من السهل القيام بذلك. تجاوز بكسل جافا سكريبت طريقة مكتبة 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);
        });
    });
}

باستخدام بكسل المقطع ، يكون كل شيء أبسط ، ولديه طرق وسيطة ، وقد استخدمنا واحدة منها.


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

بعد ذلك ، دعنا نتحدث عن جانب الخادم. يجب أن تقبل الواجهة الخلفية طلبات http ، وتعبئتها بمعلومات إضافية ، على سبيل المثال ، البيانات الجغرافية (شكرًا com.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"
}

ومع ذلك ، يتم حاليًا تحويل المصفوفات ببساطة إلى سلاسل. لا تدعم جميع قواعد البيانات العلائقية الحقول المتكررة. من الممكن أيضًا تغيير أسماء الحقول أو إزالتها باستخدام قواعد التعيين الاختيارية. تسمح لك بتغيير مخطط البيانات ، إذا لزم الأمر ، أو تحويل نوع بيانات إلى آخر. على سبيل المثال ، إذا كان حقل json يحتوي على سلسلة ذات طابع زمني (field_3_sub_field_1_sub_sub_field_1 من المثال أعلاه) ، ثم لإنشاء حقل في قاعدة البيانات بنوع الطابع الزمني ، تحتاج إلى كتابة قاعدة تعيين في التكوين. بمعنى آخر ، يتم تحديد نوع بيانات الحقل أولاً بواسطة قيمة 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

اعتقدنا أيضًا أنه يجب أن يكون المستخدم قادرًا على إعداد تقسيم أو تقسيم البيانات في قاعدة البيانات وفقًا لمعايير أخرى وتنفيذ القدرة على تعيين اسم الجدول على أنه ثابت أو التعبير في التكوين. في المثال أدناه ، سيتم حفظ الحدث في جدول باسم محسوب على أساس قيم نوع المنتج وحقول _timestamp (على سبيل المثال اللوازم_2020_10):

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

ومع ذلك ، يمكن تغيير هيكل الأحداث الواردة في وقت التشغيل. لقد قمنا بتنفيذ خوارزمية للتحقق من الفرق بين بنية الجدول الحالي وهيكل الحدث القادم. إذا تم العثور على اختلاف ، فسيتم تحديث الجدول بحقول جديدة. للقيام بذلك ، استخدم استعلام التصحيح SQL:

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

هندسة معمارية

تاريخ مصدرنا المفتوح: كيف قدمنا ​​خدمة تحليلات في Go وجعلناها متاحة للجمهور

لماذا تحتاج إلى كتابة الأحداث في نظام الملفات ، وليس مجرد كتابتها مباشرة إلى قاعدة البيانات؟ لا تظهر قواعد البيانات دائمًا أداءً عاليًا مع عدد كبير من الإدخالات (توصيات postgres). للقيام بذلك ، يكتب المسجل الأحداث الواردة إلى ملف وبالفعل في ملف منفصل (خيط) يقرأ قارئ الملف الملف ، ثم يتم تحويل وتعريف مخطط البيانات. بعد أن يتأكد مدير الجدول من تحديث مخطط الجدول ، ستتم كتابة البيانات في قاعدة البيانات دفعة واحدة. بعد ذلك ، أضفنا القدرة على كتابة البيانات مباشرة إلى قاعدة البيانات ، لكننا نستخدم هذا الوضع للأحداث التي ليست كثيرة - على سبيل المثال ، التحويلات.

المصدر المفتوح والخطط المستقبلية

في مرحلة ما ، أصبحت الخدمة كمنتج كامل وقررنا وضعها في المصدر المفتوح. في الوقت الحالي ، تم تنفيذ عمليات تكامل مع Postgres و ClickHouse و BigQuery و Redshift و S3 و Snowflake. تدعم جميع عمليات الدمج أوضاع تحميل البيانات المجمعة والمتدفقة. دعم إضافي للطلبات عبر API.

يبدو مخطط التكامل الحالي كما يلي:

تاريخ مصدرنا المفتوح: كيف قدمنا ​​خدمة تحليلات في Go وجعلناها متاحة للجمهور

على الرغم من أنه يمكن استخدام الخدمة بشكل مستقل (على سبيل المثال ، باستخدام Docker) ، إلا أننا لدينا أيضًا نسخة مستضافة، حيث يمكنك إعداد التكامل مع مستودع البيانات وإضافة CNAME إلى المجال الخاص بك وعرض إحصائيات حول عدد الأحداث. تتمثل خطتنا الفورية في إضافة القدرة على تجميع ليس فقط الإحصائيات من مورد الويب ، ولكن أيضًا البيانات من مصادر البيانات الخارجية وحفظها في أي مساحة تخزين من اختيارك!

→ GitHub جيثب:
→ توثيق
→ فترة ركود

سنكون سعداء إذا ساعدتك EventNative على حل مشاكلك!

يمكن للمستخدمين المسجلين فقط المشاركة في الاستطلاع. تسجيل الدخول، من فضلك.

ما هو نظام جمع الإحصائيات المستخدم في شركتك

  • 48,0%تحليلات جوجل 12

  • 4,0%الجزء 1

  • 16,0%أخرى (اكتب في التعليقات) 4

  • 32,0%نفذت خدمتك 8

صوت 25 مستخدمين. امتنع 6 مستخدما عن التصويت.

المصدر: www.habr.com

إضافة تعليق