معماری داده وب سایت دیوار – بخش مدیریت رفتار کاربران
چگونه تیم دیتای دیوار زیرساخت لازم برای پردازش اکشنلاگ های کاربران را فراهم میکند.
این مقاله در وبلاگ تخصصی دیوار منتشر شده است و وب سایت مهندسی داده با هدف بازنشر مطالب مفید در حوزه پردازش داده به انتشار آن بدون هیچ گونه دخل و تصرفی در محتوا اقدام کرده است . به امید اینکه شاهد اشتراک تجربیاتی از این قبیل توسط تیمهای داده شرکتهای بزرگ ایرانی باشیم .
جمله معروفی درباره شرکتهای نرمافزاری وجود دارد: «اگر آن شرکت پروژههایش را میکرو سرویس نکند، نمیتواند رشد و توسعه پیدا کند». اما به جز این مورد، توصیه مهم دیگری هم وجود دارد: «اگر شرکتی تصمیمهای محصولی مبتنی بر دیتا را مد نظر قرار ندهد، نمیتواند رشد کند.» برای همین نقش data engineer برای شرکتهای بزرگ با دیتاهای بزرگ و متنوع به شدت اهمیت پیدا میکند.
دیوار هم از این قاعده مستثنی نیست و با داشتن بیشتر از ۳۵ میلیون کاربر فعال، این موضوع برایش اهمیت ویژهای پیدا میکند.
متخصصین data engineer، تیم زیرساخت دیتای دیوار رو شکل میدهند و هدفشان این است که تصمیمگیریهای محصولی مبتنی بر دیتا را دقیقتر، سریعتر و راحتتر کنند.
اصلیترین استفاده کنندههای دیتا در دیوار data scientist ها، data analyst ها، business intelligenceها هستند که به طور مستقیم خروجی کارها و تحلیلهای آنها، در تصمیمگیریهای محصولی تاثیر میگذارد. هر چهقدر این تحلیلها دقیقتر باشند و سریعتر انجام شوند، تصمیمهای بهتری در سطح محصول گرفته شده و به رشد شرکت کمک خواهد کرد.
متخصصین data engineer معمولاً چه کارهایی انجام میدهند و چه مسئولیتهایی دارند؟
وظیفه اصلی یک data engineer طراحی و پیادهسازی پایپلاینهای بیگ دیتاست؛ تا تمرکز استفاده کنندههای دیتا تا حد ممکن فقط روی خود دیتا باشد و وقت و تمرکزشان را برای جمعآوری نگهداری، تمیزسازی و کارهایی از این دست روی دیتا صرف نکنند.
از طرفی هم با حجیم و متنوع شدن دیتا، کارهای مربوط به جمع آوری و نگهداری و در کل آمادهسازی داده خام به شکل مناسب، پیچیده و تخصصی میشود.
پایپلاین دیتا هم به طور خلاصه به تمام مراحل از تولید دیتا تا ذخیرهسازی و خواندن نهایی آن گفته میشود. در شکل زیر یک شِمای کلی و بدون جزئیات از پایپلاینهای دیتا را مشاهده میکنید.
از وقتی که دیتا تولید میشود تا وقتی که به دست استفادهکننده برسد، تغییرات زیادی بر روی آن انجام میشود که همه این تغییرات، جزئی از پایپلاین دیتای مورد نظر به حساب میآید.
شاید اسم بیگ دیتا را زیاد شنیده باشیم، اما به چه چیزی بیگ دیتا گفته میشود؟
به دیتایی که یکی از سه ویژگی زیر را داشته باشد، بیگ دیتا میگوییم:
- حجم بسیار زیادی داشته باشد.
- تنوع بسیار زیادی داشته باشد.
- با rate خیلی زیادی دریافت شود.
اگر دیتا در هر کدام از زمینههای بالا پیچیدگی داشته باشد، با روشهای معمول نمیتوان با آن کار کرد و به ابزار و دانش خاصی برای کار کردن با آن نیاز داریم؛ دانشی که گاهی اوقات به آن «دانش بیگ دیتا » میگوییم.
در ادامه یکی از پایپلاینهای مهم و پر چالش دیتای دیوار را بررسی میکنیم.
یکی از مهمترین دیتاها در دیوار اکشنلاگ کاربرهای دیوار است. این دیتا شامل تمام رفتار کاربرها روی اپلیکیشن (و سایت) دیوار از وقتی است که برنامه را باز میکنند. قسمتهایی که کاربران به آن سر میزنند و بخشهایی که بر روی آن کلیک میکنند. در کل با هر حرکت کاربر در برنامه دیوار یک request اکشن لاگ برای ما ارسال میشود که به آن یک اکشن میگوییم. این اکشنها به صورت بستههای ۵ تایی برای ما ارسال میشوند. فایده این کار این است که باعث میشود تعداد request های اکشن لاگ خیلی پایینتر بیاید. بنابراین هم دریافت آن برای ما سادهتر است و هم باتری گوشیهای کاربرهای دیوار دیرتر تمام میشوند 🙂
برای اینکه یک دید کلی از میزان بزرگی این دیتا بدست بیاورید، به نمودار زیر دقت کنید:
همانطور که میبینید در ساعات اوج مصرف تعداد request های اکشن لاگی که سمت ما میآید نزدیک ۶k بر ثانیهست . یعنی ۳۰ هزار تا اکشن در هر ثانیه.
چهطور این دیتا با این وسعت را جمعآوری و ذخیره میکنیم؟
اولین و مهمترین چالش این دیتا، rate و حجم بسیار بالای آن است. در گام اول ما سرویسی طراحی کردیم که request های اکشن لاگ کاربرها را دریافت میکند، batch ها را باز میکند (جدا کردن ۵ اکشن) و برای سرویس دیگری میفرستد (که در ادامه درباره آن صحبت میکنیم). به سرویسی که اکشنلاگها را دریافت میکند actionlogger میگوییم. ویژگی مهم این سرویس stateless بودن آن است. بنابراین ما میتوانیم به راحتی instance های مختلف آن را بالا بیاوریم که در کنار هم به طور موازی این کار را انجام دهند و فشار بین آنها تقسیم شود. actionlogger را بر روی کلاستر kubernetes بالا آوردیم که بالا نگه داشتن تعداد instance مورد نظر را انجام داده و اگه یکی از دست رفت، instance دیگری جایگزین کند. بعد از آن actionlogger این اکشنها را برای سرویس دیگری به نام fluentd میفرستد که مثل یه صف عمل خواهد کرد. fluentd یک ابزار log collector و opensource هست که ما برای جمعآوری و ارسال اکشنها از آن استفاده میکنیم. اگر تمایل به آشنایی بیشتر با آن دارید میتوانید اینجا را ببینید. علت اینکه fluentd را به پایپلاین اضافه کردیم این بود که دیتا را بر روی هارد و مموری بافر کند و اگر مقصد مشکلی برای دریافت دیتا داشت به actionlogger فشار نیاید و دیتا هم از دست نرود. fluentd هم مثل actionlogger چون stateless هست تعدادی instance آوردیم بالا و یه کلاستر تشکیل دادیم. تعداد ریکوئستهای سمت fluentd در ساعت اوج که بر اساس اکشن جدا شده اند به ۳۰k بر ثانیه میرسد.
مسئلهای که در این مرحله مطرح میشود، شیوه و محل ذخیره سازی دیتاست. حجم این دیتا در روز به حدود ۳ الی ۴ ترابایت میرسد. پیش از هرچیز به فشردهسازی دیتا فکر کردیم. fluentd چنین قابلیتی را در اختیارمان میگذارد که دیتای خروجی را به صورت فشردهشده تحویل دهد. دیتای اکشن لاگ به صورت فشردهشده از ۳ الی ۴ ترابایت در روز به ۳۰۰ الی ۴۰۰ گیگ کاهش پیدا میکند و شرایط را بهبود میدهد؛ ولی همچنان اگر روزی ۴۰۰ گیگ دیتا (دقت کنید فقط دیتای خام) را ذخیره کنیم در یک سال حدود ۱۴۰ ترابایت فضا لازم داریم. این موجود ایجاب میکند تا برای ذخیره این حجم داده روشهای دیگری را امتحان کنیم. در دانش بیگ دیتا سیستمی رایج و مشهور برای ذخیره سازی دیتا وجود دارد به نام Hadoop Distributed File System یا HDFS.
همانطور که از نام آن مشخص است، hdfs یک فایل سیستم توزیع شده است که به جای ذخیرهسازی دیتا بر روی یک سرور، میتواند دیتا را به صورت توزیعشده روی مجموعهای از سرورها ذخیره کند. برای آشنایی بیشتر با هدوپ میتوانید به این لینک سر بزنید.
با توجه به نکاتی که گفته شد، تا این مرحله پایپلاین اکشن لاگ دیوار به این شکل رسیده است:
این دیتا را چطور برای استفاده تحلیلگرها آماده کنیم؟
تا این مرحله دیتا را به صورت خام ذخیره کردیم. ولی این دیتا هنوز قابل استفاده نیست. دیتا باید تغییر کند، تمیز شود و فرمت آن هم متناسب با نیازها باشد. حجم این دیتا زیاد است و کوئری اجرا کردن روی این دیتا کار آسانی نیست.
برای تمیز کردن دیتا نیاز به یک ابزار محاسباتی قوی داریم که بتواند این حجم دیتا را بخواند، محاسبات لازم را بر روی آن انجام دهد و تمیزش کند. یک ابزار رایج و مشهور در دانش بیگ دیتا Apache Spark است. Spark یک موتور محاسباتی توزیع شده مبتنی بر map reduce است. (مفهوم map reduce از ظرفیت این مقاله خارج است اما اگر علاقهمند بودید میتوانید این لینک را ببینید).
حالا که ابزار مناسب برای خواندن دیتا و محاسبه بر روی آن را در اختیار داریم، این دیتا را میخوانیم، با spark تمیزش میکنیم و خروجی را با فرمت apache parquet که روی روز / ساعت / اکشن پارتیشن شده و به صورت snappy فشرده شده است ذخیره میکنیم. شاید این بخش از مطلب به توضیح بیشتری نیاز داشته باشد؛ فرمت parqeut یک فرمت ذخیره سازی ستونی است ( Column-oriented_DBMS ) که به جای ذخیره سطر به سطر، دیتا را ستون به ستون ذخیره میکند. به زبان ساده، این قابلیت کمک میکند تا وقتی یک نفر به ستونهای خاصی از دیتا نیاز دارد (که معمولا دیتاساینتیستها به همین شکل از دیتا استفاده میکنند) فقط هزینهی خواندن ستونهای مورد نیازش را بپردازد و هزینهای برای بقیه ستونها پرداخت نکند. مساله بعدی پارتیشن کردن دیتا با توجه به روز و ساعت و اکشن است. با پارتیشن کردن به این شکل، هزینه فیلتر کردنهای متداول کمتر شده و در کل میزان خواندن دیتا برای رسیدن به دیتای مورد نظر کاهش پیدا میکند.
مطلب بعدی ذخیره سازی با فرمت snappy است. تمرکز فشردهسازی snappy بر مصرف کم cpu و سرعت است و هدف آن این است که با مصرف کم cpu بتوان فشردهسازی یا خارج کردن از حالت فشرده را سریع انجام داد. این موضوع به ما کمک میکند تا بتوانیم دیتا را با سرعت بیشتری بخوانیم، علاوه بر آن spark هم با این فرمت به خوبی سازگار است. در کل نسبت به gzip فشرده سازی کمتری ارائه میدهد، اما از آن جایی که برای ما سرعت و سی پی یو اهمیت بیشتری داشت، snappy را انتخاب کردیم.
در تیم دیتا جابهای تمیزسازی اکشن لاگ را به صورت ساعتی اجرا میکنیم. برای زمانبندی کردن این جابها از ابزاری به اسم Apache Airflow استفاده میکنیم که امکانات خوبی برای ما فراهم میکند. Airflow تسکها رو به ترتیب و با زمانبندی مشخص بر روی spark اجرا میکند، مانیتورینگ راحتی ارائه میدهد تا اگر تسکهایمان به مشکل برخوردند سریعا متوجه شویم.
این گراف تسکهای تمیزسازی اکشن لاگمان را نشان میدهد که به صورت ساعتی اجرا میشوند. ابتدا fluentdها flush میشوند که دیتای باقی مانده در بافرها خالی شده و بعد از آن تمیزسازی آغاز میشود.
تحلیلگرها چطور با این دیتا کار میکنند؟
تا اینجا دیتا آماده شده و قابل استفاده است. در این مرحله تنها باید ابزارهای مناسب را در اختیار بچهها قرار دهیم تا کار تحلیل را شروع کنند. ما ابزار Apache zeppelin را برای بچه ها فراهم کردیم. مهمترین ویژگی زپلین این است که راحت به spark وصل میشود و میتواند از موتور spark برای انجام محاسبات استفاده کند.
علاوه بر ابزار زپلین، تابعهایی برای خواندن و کار کردن با دیتا که اصطلاحا ETL نامیده میشوند توسط تیم ما به بچهها ارائه میشود تا بتوانند راحتتر با دیتاها کار کنند.
پس در نهایت پایپلاین دیتای اکشن لاگ دیوار به این شکل است:
پایپلاینهای دیگری هم وجود دارد که طراحی، پیادهسازی و نگهداری آنها در تیم زیرساخت داده انجام میشود تا تحلیلکنندههای
دیتا بتوانند راحتتر با آن کار کنند.
این مقاله، خلاصهای از فعالیتهای تیم زیرساخت داده دیوار بود. این تیم تلاش میکند تا با استفاده از بهروزترین ابزارها، راه حلهای اثربخشی برای چالشها ارائه دهد و با بررسی مستمر فرآیندها، روشهای انجام کار را بهبود دهد.
در نتیجه بهبود عملکرد تیم زیرساخت داده، استفاده کنندههای دیتا سریعتر و راحتتر به خروجیهای مورد نظر خود دست پیدا میکنند و این موضوع، به افزایش کیفیت تصمیماتی که در سطح محصول و بیزنس گرفته میشود، کمک زیادی میکند.