در حال حاضر، تقریباً هر شرکتی در جهان آماری در مورد اقدامات کاربر در یک منبع وب جمع آوری می کند. انگیزه واضح است - شرکتها میخواهند بدانند محصول/وبسایتشان چگونه استفاده میشود و کاربران خود را بهتر درک کنند. البته، تعداد زیادی ابزار در بازار برای حل این مشکل وجود دارد - از سیستم های تحلیلی که داده ها را در قالب داشبورد و نمودار ارائه می کنند (به عنوان مثال
اما مشکلی پیدا کردیم که هنوز حل نشده است. بدین ترتیب متولد شد
چرا باید خدمات خود را توسعه دهیم؟
دهه نود بود، ما به بهترین شکل ممکن زنده ماندیم. در سال 2019، پلتفرم دادههای مشتری اول API را توسعه دادیم kSense، که امکان جمع آوری داده ها از منابع مختلف (تبلیغات فیس بوک، Stripe، Salesforce، Google play، Google Analytics و غیره) را برای تجزیه و تحلیل راحت تر داده ها، شناسایی وابستگی ها و غیره فراهم می کند. ما متوجه شده ایم که بسیاری از کاربران از پلتفرم ما برای تجزیه و تحلیل داده ها به ویژه Google Analytics (از این پس GA) استفاده می کنند. ما با برخی از کاربران صحبت کردیم و متوجه شدیم که آنها به داده های تحلیلی محصول خود نیاز دارند که با استفاده از GA دریافت می کنند، اما
آنها یک پیکسل جاوا اسکریپت Segment را بر روی منبع وب خود نصب کردند و داده های مربوط به رفتار کاربران آنها در پایگاه داده مشخص شده بارگذاری شد (به عنوان مثال 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);
});
});
}
با پیکسل Segment همه چیز ساده تر است؛ روش های میان افزاری دارد که ما از یکی از آنها استفاده کردیم.
//'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 را بپذیرد، آنها را با اطلاعات اضافی پر کند، به عنوان مثال، داده های جغرافیایی (با تشکر
//входящий 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 از مثال بالا)، سپس برای ایجاد یک فیلد در پایگاه داده با نوع 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
ما همچنین فکر کردیم که کاربر باید بتواند پارتیشن بندی یا تقسیم داده ها را در پایگاه داده بر اساس معیارهای دیگر پیکربندی کند و قابلیت تنظیم نام جدول را با یک ثابت یا پیاده سازی کرد.
tableName: '{{.product_type}}_{{._timestamp.Format "2006_01"}}'
با این حال، ساختار رویدادهای ورودی می تواند در زمان اجرا تغییر کند. ما یک الگوریتم برای بررسی تفاوت بین ساختار یک جدول موجود و ساختار یک رویداد ورودی پیادهسازی کردهایم. در صورت مشاهده تفاوت، جدول با فیلدهای جدید به روز می شود. برای این کار از پچ SQL Query استفاده کنید:
#Пример для Postgres
ALTER TABLE "schema"."table" ADD COLUMN new_column character varying
معماری
چرا باید رویدادها را در سیستم فایل بنویسید و فقط آنها را مستقیماً در پایگاه داده بنویسید؟ هنگامی که با تعداد زیادی از درج ها سروکار دارید، پایگاه های داده همیشه عملکرد خوبی ندارند (
منبع باز و برنامه هایی برای آینده
در مقطعی، این سرویس مانند یک محصول تمام عیار به نظر می رسید و ما تصمیم گرفتیم آن را به منبع باز عرضه کنیم. در حال حاضر، ادغام با Postgres، ClickHouse، BigQuery، Redshift، S3، Snowflake پیاده سازی شده است. همه ادغام ها از هر دو حالت دسته ای و جریانی بارگذاری داده پشتیبانی می کنند. پشتیبانی از درخواست ها از طریق API اضافه شده است.
طرح ادغام فعلی به این صورت است:
اگرچه می توان از این سرویس به طور مستقل استفاده کرد (به عنوان مثال با استفاده از Docker)، ما نیز داریم
اگر EventNative به حل مشکلات شما کمک کند، خوشحال خواهیم شد!
فقط کاربران ثبت نام شده می توانند در نظرسنجی شرکت کنند.
چه سیستم جمع آوری آمار در شرکت شما استفاده می شود؟
-
٪۱۰۰گوگل آنالیتیکس 12
-
٪۱۰۰بخش 1
-
٪۱۰۰دیگری (در نظرات بنویسید)4
-
٪۱۰۰سرویس شما 8 را پیاده سازی کرد
25 کاربر رای دادند. 6 کاربر رای ممتنع دادند.
منبع: www.habr.com