Menu

چند نکته که باید در هنگام ساختن صف بدانید ۱۳۹۳/۰۶/۳۰

صف queue از مواردی هست که در برنامه نویسی خیلی مورد استفاده قرار میگیره , مثلا از موارد مورد استفاده صف میشه در ارسال ایمیل ، سیستم زمانبندی و اجرای یک مورد خاص ، یا ارسال sms در صورتی که تعداد بالا باشد و نمی خوایم کاربر رو منتظر نگه داریم اشاره کرد.

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

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

userStory :

ما میخواستیم یه سیستمی را بندازیم که بتونه کاربر ارسال sms خودش رو زمانبندی کنه و تو اون زمان خاص ارسالش رو انجام بده . یه مورد دیگه هم ارسال گروهی sms بود . برا همین وقتی کاربر میخواست sms ارسال کنه به حدود ۵۰۰۰ کاربر حدود چهار دقیقه باید منتظر میشد تا همه sms ها ارسال بشه . خب باید چیکار کرد :

راه حل ما صف بود

زمانی که کاربر درخواست خودش رو میداد ما همه شماره هایی که میخواست و زمان ارسالش رو تو دیتابیس ذخیره میکردیم و با استفاده از Cron هر یه دقیقه یه  اسکریپت رو اجرا میکردیم  و اون چک میکرد که تو صف همون دیتابیس ما smsای هست که باید ارسال بشه اونو فچ میکرد و اون رو ارسال میکرد.

همه چی خوب بود و داشت مثل سوایچیم کار میکرد . سوایچیم “کلمه ترکی است ، سوایچیم به معنی این هست که مثل آب خوردن و درست کار  میکرد” .

مشکل کجا بود ، اونجا بود که نزدیک عید همه کاربرا داشتند تبلیغات میکردند و هرکدوم دو سه میلیون شارژ کرده بودند و می خواستند ارسال کنند . دقیق یادم بود اولین کسی که شارژ کرد و ده دقیقه بعد به دو میلیون کاربر ارسال خودش رو انجام داد ، بعد از نیم ساعت زنگ زد نفسش در نمیومد نمیدونست فحش بده یا چی . خلاصه مشکل این بود که به اون شماره هایی که ارسال داشت انجام میشد به هرکدوم داشت هر ثانیه یه sms میرفت 😐

WTF 😐 چه جوری ممکنه ، سریع سرور رو داون کردیم و نام کاربری و پسورد وب سرویسمون رو عوض کردیم تا همه چی بخوابه .

هنگام تست محصول به همه جوانب و شرایط توجه داشته باشید. شرایط production با development خیلی متفاوت هست.

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

مهم ترین مشکل :

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

زمانی که cron اجرا میشد تمام داده هایی که زمان ارسالشون رسیده بود رو ورمی داشتیم و شروع به ارسال می کردیم . تا اینجا خوبه . اون موقع بد میشه که داده هایی که فچ شدند و در حال ارسال هستند بعد از یه دقیقه توسط cron دیگه ای فچ بشه و اونم شروع به ارسال کنه ، حالا در نظر بگیرید که ۱۰۰۰ تا فچ کردند و دارند کارشون رو انجام میدند. خدا بخیر کرد که یه مشتری فقط ارسال انجام داده بود و گرنه همه مشتریهامون از دست می رفتند.

راه حل :

flag

با یه فلگ اگه به سیستم میفهموندیم که داره روش کار میشه و اینو فچ نکن ، راه حل مسیله بود. یعنی هنگامی که cron اولی که اجرا میشد قبل از ارسال flag اونایی که فچ شده بودند به doing تغییر پیدا میکرد و بعد از اتمام اون به done دیگه این مسیله پیش نمیومد . ما فقط حالت do و done رو داشتیم و به doing توجهی نکرده بودیم.

بعد از این اتفاق به مسایلی هم فکر کردیم که شاید در آینده اتفاق بیفته .

یکی php execution time بود که باید زیادش میکردیم تا اگه طول کشید وسط کار از کار نیفته.

چون دیتا هایی که ور میداشتیم فلگ اون رو عوض میکردیم و doing بود وسط کار اگه سرور کرش میکرد اسکریپت نمیفهمید که اینهایی که فلگ هستند هیچ وقت دیگه done نمی شوند. پس یه اسکریپت دیگه نوشتیم که بیاد اونایی که doing هستند و یه ساعت از زمانشون گذشته رو فلگشون رو به do آپدیت بکنه ، ولی اینجا باز یه مشکلی پیش میومد که اگه اون داده هایی که فچ شدند و در حال ارسال هستند بیشتر از یه ساعت طول بکشند باز به مشکل میخوریم . پس یه تعداد معقولی واسه هر اسکریپت گذاشتیم تا به همون تعداد فچ بکنه و ارسالش خیلی کمتر از یه ساعت تموم بشه تا با خیال راحت بتونیم اونایی که ارسال نشدند به دلایلی رو ، تغییر وضعیت بدیم.

اگه واسه شما هم همچین مشکلی پیش اومده یا راه حل بهتری دارید و یا مشکلاتی که من فکرشو نکردم به ذهنتون رسیده ،ممنون میشم تو قسمت کامنت ها به منم بگید.

دیدگاه ها

  1. برای صف ساختن چند تا نکته دیگه هم هست که کار رو بهتر میکنه:
    ۱ – ۲ تا table داشته باشین یکی برای اونایی که ارسال نشده و یکی برای آرشیو اونایی که ارسال شده. item هایی که ارسال شدن رو از table اصلی حذف کنین و بزارین تو table آرشیو … در این صورت چون با table آیتم های جدید بیشتر سروکار دارین select و update زمان کمتری میبره
    ۲ – cron رو طوری بسازین که از طریق وب هم قابل دسترسی باشه، آیتم هایی که برای send انتخاب میکنین مه بگبربن مثلا ۱۰ یا ۲۰ تا و بعد ارسال اینا دوباره اسکریپت cron رو restart کنین (صفحه رو redirect کنین به همون صفحه cron) و یه flag هم جایی بزارین که تعداد کرون هایی که همزمان دارن اجرا میشن از یه حدی بالاتر نره (چون ممکنه که زمان اجرای کرون جدید رسیده)
    ۳ – اگه دیتاتون خلی زیاده و سرور هم کشش اون رو داره میتونین گزینه ۲ رو تغییر بدین، بعد از اینکه آیتم ها رو select کردین و flag اشون رو ست کردین قبل از ارسالشون یه کرون جدید شروع کنین یه صورت async http://stackoverflow.com/questions/124462/asynchronous-php-calls ولی باز هم یه flag داشته باشین که تعداد کرون هایی که دارن اجرا میشن رو نگه داره تا از یه حدی بالاتر نره
    فعلا اینا به ذهنم میرسید بازم چیزی یادم اومد مینویسم D:

    پاسخ دادن

پاسخ دهید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *