چگونه از چندین میلیون رکورد به تنها دو رکورد رسیدم!

سلام

این اولین پست ویرگولی من و در واقع بلاگ پست هست پس اگر ایراداتی داشت به بزرگی خودتون ببخشید.

خب بریم سر اصل مطلب :‌

من به عنوان یک برنامه نویس (یجورایی مهندس نرم افزار) روی یکی از اپ های موبایل بانک کشور کار میکنم. بخاطر همون مسایلی که میدونید نمیتونم اسم کارفرمامون طبیعتا بانک رو نام ببرم.

بواسطه اینکه اپ بانکی هست تعداد یوزر هاش خیلی کم نیست(آخرین اطلاعاتم حدود ۱ میلیون نفر).

مشکلی که ما داشتیم سر ارسال پوش نوتیفیکیشن به کاربرای نرم افزار بود.

بخاطر معماری کد قدیمی و نحوه طراحی راه حل شون ما تو هربار ارسال پیام، باید حدود ۲-۱.۵ میلیون رکورد به یک جدول insert می کردیم و به مرور ۱ میلیون رکورد دیگه هم به یک جدول دیگه.

این عملیات طی یک batch insert query با جوین ۵ لایه ای و یه سری مسایل دیگه باعث میشد سرور ها یکم اذیت شن.

میشه گفت یه جدول با حدود ۵۰-۶۰ میلیون رکورد و بیشتر که با آرشیو و … رسونده بودنش به ۳۰ میلیون رکورد.

اینطور شد که مجبور شدم بیل رو بردارم و یکم کد رو زیر و رو کنم.

برای ارسال نوتیف به کاربرا روال اینطور بود که برنامه میومد فیلتر رو چک می کرد و در صورت پس شدن یوزر تو شروط فیلتر کاربر رو به یه لیست اضافه میکرد. بر اساس فیلتر و اون لیست push notification api رو فراخوانی می کرد و بعدا به ازای هر آیتم از اون لیست یه رکورد به جدول insert میکرد . البته چند حالت برای pass کردن شروط فیلتر وجود داشت که تو هر کدوم با یه همچین مکانیزمی که تو عکس زیر معلومه به اون جدول اضافه میشد.

یه نیتیو کوری به شدت کثیف با ۵ لایه جوین
یه نیتیو کوری به شدت کثیف با ۵ لایه جوین

حالا فرض کنید چندین تیکه کد شبیه عکس بالا برای insert کردن به اون جدول وجود داشت.

در اینصورت به ازای هر کاربر حداقل یک رکورد و بعضا تا چهار رکورد تو دیتابیس اضافه می شد که یه فاجعه بود و اون جدول رو هی بزرگ و بزرگ تر می کرد.یه جدول این چنینی هم بود که پیام هایی که کاربر دیده بودتشون رو توش اضافه می کردیم.

از طرفی کاربر باید این پیام ها رو در برنامه که تو یه لیست می دید . برای نمایش دادن پیام ها بکند میرفت یه select رو این جدول اولی برای دریافت لیست پیام های کاربر میزد و یک select دیگه می زد برای دریافت لیست پیام های خونده شده. و نتایج دومی رو از اولی خارج میکرد و نتیجه رو به به کاربر ارسال میکرد.

چون فراخوانی سرویس تو بک گراند اتفاق می افتاد زیاد تو چشم کاربر نمی زد ولی هزینه به شدت بالایی داشت برامون.

برای شما

از طرفی با یک کد legacy و به شدت سخت و شکننده طرف بودیم که برای تغییر دادن یه متد باید تمام استفاده هاش و خلاصه بالا و پایینش رو در می اوردیم. لذا اینکار ریسک بسیار زیادی داشت ولی رفتم و دست به کد شدم.

اول تو این فکر بودم که جدول message_user رو که پیام های کاربر توش بود رو کامل حذف کنم و کد جدید رو بنویسم و مکررا smoke test کنم و برم جلو. ولی بعدش نظرم عوض شد و با ساختار خودم رفتم جلو و از ساختار های بزرگ شروع کردم و هی کد های جدید رو تزریق کردم و کد های قدیمی رو حذف کردم. خوش بختانه با این روال در انتهای کار حدود ۸۰% کد قدیمی حذف شده بود.

تو قدم اول من اومدم و جدول پیام ها رو کاملا مستقل کردم و یه موجودیت برای یک ریچ فیلتر اون پیام ساختم. و یه رابطه ۱-۱ بین پیام و فیلترش برقرار کردم.

اینجوری فقط و فقط ۲ رکورد داشتیم. یکی برای پیام و یکی هم برای فیلترش.

حالا سوال این پیش میاد که یه ریچ فیلتر چجوری میتونه فقط یه رکورد باشه؟

فیلتر ما شامل لیستی از پلتفورم ها، لیستی از نوع یوزر ها (بانکی و غیر بانکی و …)، لیستی از اپراتورهای موبایل، لیستی از پیش شماره های موبایل و لیستی از ورژن های برنامه است.

که طبعا برای هر کدوم از اینا یه جدول دیگه و یه رابطه 1-n نیازه ولی اشتباه نکنید !

ما برای نگهداری و ذخیره این قسمت از برنامه از postgres استفاده میکنیم واین دیتابیس یه امکان باحال داره که میتونید داخل یک ستون، یک آرایه چند بعدی ذخیره کنید.درست شنیدید. یک آرایه چند بعدی که من با یک بعد کارم راه می افتاد. به نظرم خیلی امکان جالب و باحالیه :))

حالا یه جدول دیگه میمونه که اون هم برای پیام های خوانده شده کاربر بود. اون جدول هم به همین شکل ایجاد کردم و ماکسیموم به ازای هر نفر یک رکورد ایجاد میشه که توش لیستی از id پیام های خونده شده رو می ریزیم.

ازین قابلیت برای ذخیره فیلتر ها و پیام های خوانده شده استفاده کردم و به نظرم تمیز شد.

نتیجه نهایی به این شکل شد که یه select ساده روی message ها میزنیم و خودش و فیلترش رو دریافت میکنیم. یه select هم روی جدول پیام های خوانده شده میزنیم. بعد به ازای هر پیام چک میکنیم که تو شرط فیلتر صدق میکنه یا نه و خروجی رو با لیست پیام های خوانده شده مقایسه کرده و نتیجه رو به کاربر ارسال می کنیم.

با این راه‌حل جدید حجم دیتای ذخیره شده میلیون ها بار کاهش پیدا کرد و حجم پردازش هم به حد خوبی کاهش پیدا کرد.

سعی کردم خوب شرح بدم ماجرا رو. امیدوارم براتون مفید باشه.

نویسنده مطلب: Seyyed Mahdiyar Zerehpoush- سید مهدیار زره پوش

منبع مطلب

به فکر سرمایه‌گذاری هستی؟

با هر سطحی از دانش در سریع‌ترین زمان با آموزش گام به گام، سرمایه گذاری را تجربه کن. همین الان میتونی با لینک زیر ثبت نام کنی و ۱۰ درصد تخفیف در کارمزد معاملاتی داشته باشی

ثبت نام و دریافت جایزه
ممکن است شما بپسندید
نظر شما درباره این مطلب

آدرس ایمیل شما منتشر نخواهد شد.