از ویرگول ‌MySqlای به ویرگول ‌Elasticsearchای - قسمت ۲ (آمار)

تو قسمت قبل گفتم که چی شد و چجوری شد که سرچ ویرگول رو بردیم روی الستیک. اما فقط سرچ نیست که داره با الستیک کار می‌کنه. بلکه بخش آمار هم داره از الستیک استفاده می‌کنه و این قابلیت‌های خوب و جدیدی که بهش اضافه شده به لطف الستیکه 🙂 چون خیلی‌ها هم گفتند که فنی‌تر باشه، سعی کردم بیشتر از لحاظ فنی صحبت کنم.

ماجرای اینکه آمار رفت روی الستیک از اینجا شروع شد که تعداد کاربرهای ویرگول داشت زیاد می‌شد و به همین خاطر سرعت سایت خیلی کم شده بود و سیستم‌های مانیتورینگ بهمون می‌گفتن که مشکل از دیتابیسیه که برای آمار استفاده می‌کنیم 🤦‍♂️. دیتابیس آمار MySQL بود و از دیتابیس اصلی جدا بود ولی تعداد نوشتن‌‌ها، خوندن‌ها و عملیات‌های آماری مثل جمع‌بندی(aggregation) و دسته‌بندی(grouping) زیاد و سنگینی داشت. خودتون می‌تونید حساب کنید که با تعداد بازدیدی که هر روز داشتیم و مقدار باری که هر کاربر صفحه آمارش رو باز می‌کرد، چقدر این عملیات‌ها زیاد می‌شدند. برای همین سرعت سایت خیلی پایین اومده بود و باید یه فکر جدی می‌کردیم. این‌جا بود که من (که شدیدا داشتم مبهوت الستیک و قابلیت‌هاش می‌شدم 🤩) دوباره اومدم جلو و گفتم بذارید لاگ رو ببریم روی الستیک. علی که خیلی سر سرچ با الستیک حال کرده‌بود بهم اجازه داد و منم شروع کردم به تحقیق و طراحی و کد زدن و …

اولین مشکلی که همون اول به نظرم اومد این بود که چطوری اون حجم از دیتا رو، که تقریبا ۲۰ میلیون رکورد بود، ببریم روی الستیک. عملیات خیلی سنگینی حساب می‌شد و باید حتما دسته‌ دسته‌شون می‌کردم و طی چند روز توسط کرون‌جاب‌ها انجام می‌شد، چون نمی‌خواستم بار سینگینی روی الستیک باشه و کلی رم و سی‌پی‌یو مصرف کنه. همچنین اندپوینت _bulk توی الستیک، که برای ریختن دسته‌ای دیتاست، گفته‌شده بود که بهتره در لحظه تا یه حد خاصی دیتا از طریقش توی الستیک ریخته بشه و من با تست‌هایی که کردم به این نتیجه رسیدم که ۱۰۰۰ عدد خوبیه و خب برای ۲۰ میلیون رکورد کم بود. با خودم گفتم اول این قسمت رو درست می‌کنم و می‌ذارم به حال خودش تا تموم شه و همزمان کد‌های MySQL رو با کدهای الستیک عوض می‌کنم که دوتا کار با هم تقریبا تموم بشن اما هنوز نمی‌دونستم قراره چه اشتباهاتی بکنم و سر همین‌ها چه بلاهایی سرم بیاد 🤦‍♂️.

با توجه به حجم دیتا، تخمین من این بود که اگر روزی یک میلیون و خورده‌ای دیتا توی الستیک بره، کمتر از دو هفته تموم می‌شه؛ همه هم خوشحال و فلان بودن که چقدر خوب و بالاخره دوران tracker (دیتابیس آمار) به سر میاد. از همون اول که عملیات رو شروع کردم، دونه دونه با باگ‌های یکی از یکی بدتر رو‌به‌رو می‌شدم و مجبور می‌شدم هی بزنم از اول دیتا توی الستیک ریخته‌بشه. یه بار می‌دیدم حواسم به نافرمی بعضی دیتاها نبوده(مثلا فرمت تاریخ چیزی نبود که تو mapping مشخص شده بود) و کرون‌جاب‌ها دارن به ارور می‌خورن. یه بار می‌دیدم حواسم به خطاهای زیرساختی و شبکه‌ای نبوده و ریکوئستی که به سمت الستیک می‌ره ارور می‌ده (که خب تو این مواقع باید جاب از اول اجرا می‌شد). حتی یه سری بخاطر مشکلات زیرساخت و storage دو سه روز عملیات متوقف شد (این یکی دیگه واقعا تقصیر من نبود 😤). خلاصه که کاری که می‌گفتم کمتر از دو هفته تموم می‌شه، بعد از یک ماه تموم شد. این وسط، دیتاهای جدید هم تو tracker ریخته می‌شدن هم تو الستیک. بخاطر همین فقط دیتاهایی که تا یک تاریخ خاص بودن (زمانی که مطمئن بودیم دیتایی که تو الستیک هست سالم و درسته) رو سعی می‌کردیم جابجا کنیم، چون از بعد از اون دیگه تو الستیک بود.

حالا که همه دیتاها یه جا جمع شده بودن، وقت تست رسید. بچه‌ها شروع کردن به تست کردن و یهو دیدیم اطلاعات با چیزی که توی trackerـه فرق می‌کنه؛ آماری که باید مثلا ۲۰۰ می‌بود، الستیک می‌گفت ۹۰ 😵!! اون‌جا بود که من نمی‌دونستم چه خاکی به سرم بزنم و مونده بودم که چیکار باید بکنم. بعد از یک ماه دیتاها ناقصن. با گوگل هم چک کردیم و دیدیم خیلی فرق داره. اون موقع دیگه متوجه‌ شدم که یه چیزی رو خراب کردم. کلی گشتم تا ببینم مشکل از چیه. آمار چندین پست و کاربر رو چک کردم، کدها رو بارها و بارها خوندم و منطقش رو روی کاغذ نوشتم و بررسی کردم تا بتونم مشکل رو پیدا کنم. کلی وقت گذاشتم تا اینکه فهمیدم وقتی داشتم query گرفتن دیتاها از tracker رو ‌می‌نوشتم حواسم به این نبوده که یکی از جدول‌ها رو باید بجای join زدن left join می‌زدم 🤦‍♂️ چون لزوما برای هر سطر دیتا توی جدول اصلی، تو این جدول دیتا نداشتیم (رابطشون یک به صفر یا یک بود). از ترس اینکه الان اگه علی بفهمه کلی عصبانی می‌شه، با خودم گفتم تا اومد تو، مسخره بازی در میارم تا خنده‌ش بگیره و عصبی نشه برای همین تا اومد تو رفتم زیر میز که یعنی یه کار بدی کردم و خجالت‌زدم 🙈 و این جوری خنده‌اش گرفت و همه چی به خوبی گذشت(البته بنده‌خدا انقدری هم که تو ذهنم خشنه نیست 😅، فقط چون ویرگول واسش مهمه، خیلی حرص می‌خوره پیش خودش ولی می‌شه متوجه شد).

دوباره عملیات migrate رو از اول شروع کردم و این بار دیگه چون همه باگ‌ها کشف شده ‌بودند، با سرعت بیشتر کار رو انجام دادم. تعداد کرون‌جاب‌ها رو زیاد کردم و تعداد دیتا رو کردم روزی ۳ میلیون. تخمینم ۵ روز بود که واقعا هم ۵ روزه تموم شد(خدارو شکر🙇‍♂️). صبح که رفتم شرکت، بچه‌ها اومدن و خواستیم دوباره تست کنیم. من دیگه با اعتماد به نفس کامل اومده بودم و می‌دونستم همه چی خوب بوده. تا اینکه یهو علی گفت پست فلان آمارش غلطه. نه در حد ۳ ۴ تا دونه بلکه در حد ۸۰تا 😩!!! تو اون لحظه آن چنان استرسی به من وارد شد که داشتم می‌مردم. داشتم به این فکر می‌کردم که چجوری استعفا بدم و خودم دُمم رو بذارم رو کولم و برم 😰. با این گندی که زدم دیگه آبرو نموند واسم 😓. ولی پیمان که بزنم به تخته (تِق تِق) همیشه تو لحظات بحرانی می‌تونه خوب همه رو جمع کنه و اوضاع رو آروم کنه اومد پیشم و گفت بیا ببینیم چه مشکلی داره که فهمیدیم در واقع مشکلی از طرف کار من نبوده!!!! دیتاهای بازدید که از طرف ربات‌ها بودند، در اوایل کار tracker ثبت می‌شدند و من تو migrate اونا رو نیاوردم، برای همین انقد تفاوت داشت و در اصل کد من خیلی دقیق داشت جواب می‌داد 🕺😊

اون موقع بود که دیگه از درست بودن آمار الستیک مطمئن شدیم و من یک نفس راحت کشیدم(ولی هیچ وقت استرس اون لحظه رو فراموش نمی‌کنم، خییییللللیییی بد بود🥺)

اینایی که تا الان گفتم مال قسمتی بود که باید دیتای قدیمی رو روی سرویس جدید میاوردیم. ولی چالش‌هایی هم سمت پیاده‌سازی کد داشتیم. یکیش این بود که چیکار کنیم که تا حد ممکن، کسی نتونه آمار غلط ثبت بکنه. اون موقع، یه درسی داشتم به اسم مهندسی فناوری اطلاعات. توش یه مبحثی رو درس می‌دادن به اسم MAC و HMAC که برای اطمینان از صحت پیام هست. از این دو مبحث استفاده کردم و مکانیزمی رو طراحی کردم که همراه هر پیام که برای آمار از سمت کلاینت میاد، یک کد هم فرستاده بشه که سمت سرور چک بشه آیا واقعا این کاربر، این پست رو باز کرده یا نه و خب تا حد ممکن کمک کرد که کسی نتونه آمار غلط ثبت بکنه. خیلی نمی‌تونم دقیق بگم چجوری هست ولی کلی بخوام بگم، یه کدی که فقط خودمون داریم با یه سری اطلاعات هش گرفته می‌شن و برای کاربر فرستاده می‌شه و این هش سمت خودمون ذخیره می‌شه و وقتی ریکوئست میاد سمتمون، با صحتش رو می‌تونیم تا حد خوبی بررسی کنیم.

وقتی که سرویس ثبت آمار توی مرحله تست بود، متوجه شدیم حجم زیادی از دیتایی که داره ثبت می‌شه رو ربات‌ها دارن ثبت می‌کنن. یعنی کلی صفحه هست که باز می‌شن، آمار بازدید واسشون ذخیره می‌شه ولی ربات هستن، نه کاربر عادی. تنها چیزی که می‌شد چک کرد، User-Agent بود. با لاگ‌های که ذخیره کردیم، متوجه‌ شدیم که تعداد زیادی از ربات‌ها رو می‌شه با فیلتر کردن کلمه‌هایی مثل bot و crawler و … پیدا کرد اما باز هم، همه ربات‌ها رو نمی‌شد پیدا کرد چون عوض کردن Header که کاری نداره. باید تحلیل رفتاری هم می‌کردیم. متوجه شدیم که خیلی از ربات‌ها، جاوا اسکریپت رو اجرا نمی‌کنن و اینجوری سعی کردیم یه سریشون رو تشخیص بدیم و فیلتر کنیم. البته باز شاید بشه گفت که بعضی از ربات‌ها هنوز از دستمون در می‌رن ولی خب تا حد خوبی اینجوری آمار رو دقیق‌تر کردیم.


برای اینکه سرتون رو درد نیارم، یک سری داستان دیگه مونده که تو قسمت بعدی (و پایانی) می‌گم. امیدوارم براتون جالب باشه :)