سلام خدمت همه ی دوستان راکتی
من تازه اومدم سمت لاراول و به قولی نوب هستم
در رابطه با فروشگاه در لاراول داشتم فکر میکردم و سبد خریدش
خب ما توی دوره پروژه محور لاراول ، سبد خرید خیلی خوبی رو پیاده سازیش رو دیدیم.
مسئله ای که هست توی بحث خرید محصولات فیزیکی توی یک فروشگاه پر بازدید وقتی چند نفر همزمان میخوان از یک محصول خریداری کنن و موجودی انبار اون محصول یکی هست مثلا چطور این موضوع رو هندل کنیم؟
و در کل مسائلی مثل رزرو کردن و اینا؟
آیا پکیج های آماده ای براشون هست؟
آیا راه کار مناسبی هست که بشه ازش استفاده کرد یا باید خودمون پیاده سازی کنیمش از صفر که خب کار واقعا وقت گیر و سختیه
در رابطه با پکیج های لاراولی هم بحث و گفتو گویی رو مشاهده کردم که لینکش رو میزارم
بحث و گفتو گو فروشگاه برای لاراول
و همینطور در رابطه با درخواست های همزمان مطلبی رو دیدم که لینک اونم میزارم
پاسخ به درخواست های همزمان
نگاه کنید
راه حل، استفاده از تکنیکی به نام lock در دیتابیسه.
این سوالی که مطرح کردی خیلی جاها ممکنه برامون دردسر ساز شه
مثلا 100 تا کد تخفیف ارائه کردی و در صورت درخواست مکرر و همزمان ممکنه 110 بار هم ازش استفاده شه
برای جلوگیری از وقوع این موضوع از چیزی به نام lock استفاده میکنیم تا
از داده ها برای جلوگیری ویرایش همزمان محافظت بشه
اوومم جواب من برای اون سوالیه که پرسیدین اگر تعداد محصول یکی باشه و چند نفر هم زمان اون رو بخرن چ اتفاقی میوفته ! یا چطوری هندلش کنیم
اولا اینکه تو فروشگاه های بزرگ موجودی رو زیر 5 تا میزنن نا موجود یا محدود ، و وقتی تعداد به زیر 5 تا رسید با یک اعلان به مدیر اعلام میکنه ک محصولت کمه و باید موجودی بزنی ، حالا بر فرض ک ما این سیستم رو نداریم
وقتی که کاربر سبد خریدش رو پر کرده و میخواد کار های پایانی خرید رو انجام بده و در زمان کلیک بر روی پرداخت شما باید جوری تنظیم کنید که در همون لحضه موجودی محصولات توی سبد تصدیق بشه و بعدش به سمت پرداخت بره و محصول میشه برای اونی که زودتر خرید کرده ،
و نفر بعدی ک میخواد دکمه پرداخت رو بزنه متوجه میشه که محصولی ک تو سبد خریدش هست نا موجود شده
من خودم از اکثرا این روش استفاده کردم ولی ممکنه اساتید عزیز روش هایی بهتر و بهینه تری داشته باشن
مرسی از دوست عزیزمون و راهنماییشون خیلی خوب بود
ولی مسئله ی اصلی میتونه هزار جا ب کار بره و شما فرض بر این بگیر که دارید بلیط هواپیما یا یه سایت فروش ماشین یا رزرو هتل رو داری که هزار نفر برا ثبت نام یا خرید یا رزرو وارد اون میشن توی خرید بلیط و یا رزرو اتاق هتل ک موجودی یکسانه تعداد اتاق و صندلی که زیر پنج تا و اینا نداره
داریم شرایط خیلی خاص و حاد رو مورد بررسی قرار میدیم
بالاخره یک روزی یک جایی پیش میاد دو نفر یا چند نفر یک محصول رو با موجودی یکی داخل سبد خریدشون داشته باشن و به طور همزمان درخواست پرداخت رو بدن
نمیتونیم بگیم همچین حالت همزمانی ای وجود نداره اصلا
توی اون حالت خاص چه کاری میشه انجام داد
ببینین شما میتونین یکاری کنین
اینطوری عمل کنین
زمانی که کاربر محصول را به سبد خرید اضافه میکنه مشخصات موجودی اون محصول را در یک جدول جداگانه به صورت queue ذخیره کنید و بهش زمان expire بدید مثلا 48 ساعت
خب اینطوری اگر در این مدت زمان 48 ساعت پرداخت کاربر نهایی شد که هیچی
اگر نشد محصول از سبد خرید اون کاربر حذف میشه و موجودی اون محصول به محصولات اضافه میشه و قاعدتا queue محصول مورد نظر از جدول مربوطه پاک میشه
حالا فرض بر این میگیریم که یک محصول موجودیش 1 دونه هست و 2 کاربر به صورت همزمان میان و اون محصول را به سبد خرید اضافه میکنن
اینجا همون queue به کمکت میاد و زمان اضافه شدن محصول به سبد خرید هرکاربر که سریعتر بود اون کاربر تا 48 ساعت میتونه اون محصول را خرید نهایی کنه و اگر همون زمان کاربر دوم خواست بره برای پرداخت ، قبل از رفتن به درگاه بانک موجودی دوباره بررسی میشه و اگر 0 بود بهش خطا میده که موجودی 0 شده
فکر نمیکردم همچین موضوع رو مخی باشه ، بعد از خوندن چندتا issue که عمرشون بشتر از سن من بود 😂😂😂متوجه شدم که واقعا یک راه حل منطقی برای این وجود نداره ، ولی چیز هایی که دستگیرم شد رو بهتون میگم :
البته این سوال سوال خیلییی ها بود و یک معادله حل نشدس تقریبا ولی میشه یه کار هایی کرد که احتمالش خیلی پایین بیاد
1- شما میتونید از قفل محصول استفاده کنید ، به این شکل که اگر محصول شما دارای موجودی 1 است (فقط و فقط اگر 1 باشد ) بیاید با افزوده شدن این محصول به سبد خرید کاربر موجوددی رو 0 کنید و اگر تا یک تایم خاصی (خودتون تعیین میکنید ) خرید انجام نشد اون محصول رو از سبد خرید کاربر حذف کنید و موجودی رو به 1 برگردونید ، میتونید این محصول هارو به کاربر به شکلی خاص نشون بدید (مثلا محصولات محدود ) که باعث تجربه کاربری بدی نشه : میشه بهشون گفت اینا محصولات محدودن و در زمان اضافه به سبد در صورت خرید نکردن تا فلان ساعت از سبد خرید شما حذف میشن
2- پس از خوندن کلی مطلب به این نتیجه رسیدم که در واقعیت این عمل ممکن نیست ولی اگر پایبند به سناریو باشیم شما میتونید موجودی محصول رو زمانی که موجودیش 2 است 1 در نظر بگیرید و یک رو به عنوان ذخیره حفظ کنید که در شرایط مشابه مجبور به کنسل کردن خرید فرد دوم نشید
3- برخی از سایت های فروش بلیط بلیط هایی که محدود میشن رو تا 5 نفر (به انتخاب خودشون ) اجازه میدن که به سبد خرید اضافه کنن و بعدش قفل میکنن خرید رو و اگر در چند دقیقه فرد اول خرید نکرد حذف بشه و بره برای نفر دوم و همینطور تا نفر 5 م و دوباره موجودی رو برگردونه اگر هیچکدوم خرید نکردن
لپ کلام رو اینطوری بهتون بگم که این مشکل الان نیست و تو لینک زیر تاپیکی که میبینید برای 9 سال پیشه
https://www.drupal.org/project/ucoutofstock/issues/1536576
و این اتفاق خیلی خیلی به ندرت میوفته ، البته این تاپیک برای یه پکیجه
ممنون میشم اگه مفید بود لایک کنید
اینم یه راه حل بود ولی برای سبد خرید اینکه موقع افزودن اون محصول به سبد خرید موجودیش کم بشه از سبد یکم درد سر ساز نیست؟
با دونستن این موضوع خیلی راحت میشه چند تا اکانت فیک ساختو همیشه محصولات سایت رو الکی از دسترس خارج کرد
و یه سایتی مثل دیجیکالا اگر بررسی کرده باشید ممکنه نیم ساعت از قرار دادن یه محصول توی سبد خرید نگذشته باشه اما پیغام مبنی بر اتمام موجودی اون محصول رو ببینیم و از سبد حذف بشه خیلی از محصولات هست که با عنوان تنها یک عدد در انبار باقیست رو هم میتونیم مشاهده کنیم. اگر در لحظه ی پرداخت بخواییم موجودی انبار کم بشه و درخواست همزمان برای خرید یک محصول داشته باشیم چه کنیم واقعا؟
کلا مسئله همزمانی استفاده از یک منبع اشتراکی در لاراول باید بررسی بشه که چه ساختاری براش پیشبینی شده
سلام دوست عزیز رو عجب موضوعی هم دست گذاشتید
نکته اول دوست عزیز خوب همیشه قبل از پرداخت نهایی که باید موجودی چک بشه به هر طوری هم که بقیه کار رو پیاده کرده باشید .(میتونید یه بار کلا قبل از اینکه به صفحه پرداخت بریم چک کنید یه بار با کلیک روی دکمه پرداخت اول موجودی چک بشه اگه اوکی نبود همونجا بگه متاسفیم تموم شد)
نکته دوم خوب بعد از این اگه اگه سایت شما اونقد واقعن بزرگ باشه که همزمان یعنی بعد از چک شدن موجودی بازم به مشکل بوخورید که واقعا دیگه عجیب میشه باید چند نکته رو در نظر بگیرید
یه فکر دیگه هم که به ذهنم میاد اینه که اگه فقط یکی از محصول مونده اگه کاربری که محصول تو سبد خریدشه انلاینه دکمه افزودن به سبد خرید برا دیگران قفل بشه ( که واقعا عجیبه بخواید از این روش استفاده کنید چون هم باید بدونید کی انلاینه هم بدونید چی تو سبد خریدشه واقعا مسخرست که بخواید از این روش استفاده کنید )
بهترینش از نظر خودم چک کردن موجودی با کلیک شدن دکمه پرداخت بعد ادامه کار (همون نکته اول )
بعدش اگه بازم به مشکل خوردید که واقعا عجیبه اینه که بلاخره یه کاریش میکنی یا به کاربر پولشو بر میگردونی یا زودی محصول رو موجود میکنی (حتی شده از یکی دیگه بگیری , همکارت مثلا )
ولی فک نکنم چیزی بشه چون به هر حال سرعت سرور بالا تر از ادماست و واقعا عجیب میشه دقیقا تو یه ثانیه دو نفر درجا رو پرداخت بزن ( تازه ما با همون دکمه پرداخت هم موجودی رو چک میکردیم )
ساختار دکمه پرداختمونم در نهایت میشه یه چنین چیزی
اگه پرداخت هم موفق نبود دوباره موجودی رو زیاد میکنیم
مرسی از همه دوستان واقعا راه حل های جذابی پیشنهاد شد و چالش واقعا خوبیه همچنان مشتاق شنیدن نظرات دوستان هستن
تا اینجای کار میشه گفت باید محصول یا موجودی پشتیبان داشته باشی یا هزینه مشتری رو پس بدی ولی از بحثایی که توی سیستم عامل برای مدیریت منبع اشتراکی مثل انتظار مشغولو راه حل پیترسون هیچکدوم جایی ازش حرفی زده نمیشه و انگار فقط واسه تئوری هستن و عملی کسی استفاده نمیکنه😂😂🤣🤣
لینک زیر میتونید پنج راه حلی که در این رابطه مطرح شده توی سیستم عامل ببینید.
عنوان لینک مورد نظر
@ali.agk25
@salar.mohammad2013
سلام
شما به نکته ی زیبا و کاربردی در اکثر سایت های فروشگاهی اشاره فرمودید به نظرم.
موارد زیر امکان داره در طرح شما کارساز باشه :
شما نمی تونید موقعی که کاربر کالا رو به سبد خرید اضافه میکنه موجودی رو کم کنید ، پس به این مورد فکر هم نکنید چون اشتباهه.
در صورتی که پرداخت کاربر به صورت آنلاین هست ( که پرداخت آنلاین این معنی رو میرسونه که کاربر قصد خرید 100 درصدی این کالا رو داره برای همین پرداخت انجام میده ) در این صورت در لحظه آخر قبل از ورود به درگاه پرداخت موجودی محصول به تعداد سفارش کم میشه و سبد خرید اون کاربر به سفارش تبدیل میشه دیگه و معنی دیگری داره - خب اگر سفارش رو کاربر در مدت زمان مثلا یک ساعت پرداخت کرد ، که موجودی مال ایشونه و اگر نکرد با یک کران که ست شده موجودی به محصول بر میگرده و این مورد اجتناب ناپذیر هست که اگر چند نفر هم برن به درگاه پرداخت باز هم مجبورید که موجودی رو کم کنید چون شاید قصد خرید داشته باشند.
در صورتی که پرداخت در محل باشه ، هم میشه شرایط مشابه پرداخت در محل رو اجرا کرد و هم میشه کم کردن موجودی رو با تایید سفارش توسط یک ناظر انجام داد
مورد مهم در این فرایند این هست که یک middleware داشته باشید که در هنگام بازشدن تمامی صفحات قبل از پرداخت سفارش ( مانند سبد خرید و shipping و ... ) همواره موجودی محصولات سبد رو چک کنه که اگر تا اون لحظه ناموجود شده بودند از سبد حذف کنه و یا اخطار کم بودن موجودی و حتی تغییر قیمت رو به مشتری بده .
من هنوز دست از سر این موصوع برنداشتم و هنگامی که در عالم ملکوت بودم این به ذهنم رسید که برای محصولاتی که موجودی 1 دارن میشه تو میدلور کاری کرد که همزمان 2 نفر نتونن وارد درگاه بشن اگ یکی محصول رو انتخاب کرده باشه و روی دکمه پرداخت بزنه و در لحضه ورود به پرداخت باشه میشه با استفاده از میدل ور موجودی رو از دسترس خارج کرد
من دیدم که سایت ها برای فروش خودشون گزارش میزارن مثل :
کاربر x وارد درگاه شد
کاربر y از پرداخت صرف نظر کرد
و ...
از این حالت میشه استفاده کرد و یک صف ایجاد کرد (این خیلی خوب نی خریدارارو منتظر بزارید ولی میشه فقط برای محصولات با موجودی 1 این کارو کرد
پسر عجب لا ینحلیه این موضوع😂😂😂
😂😂🤣🤣 آره برای خودمم خیلی جذابه
این که موجودی از دسترس خارج بشه در لحظه ی زدن دکمه ی پرداخت اتفاق میفته که موجودی کم میشه و چک هم میشه
باز هم اگر در همین لحظه دو نفر بخوان براشون چک بشه و از دسترس خارج بشه همون مشکل رو داریم ولی این که یک صف خاص یکسان داشته باشیم و بعد از چک شدن این موضوع که موجودی یکی هست اون رو وارد صف کنیم خب باز هم ممکنه دو نفر وارد صف بشن
اگر چک کنیم ک با تعداد دو نفر یا بیش از یک نفر به درگاه پرداخت نره و فقط یکی رو به صورت رندوم یا اونی که ابتدای صف هست به صفحه پرداخت انتقال بده ممکنه مشکل بگیم حل شده
ولی اگر سه نفر بخوان محصولی با موجودی دو تا رو خریداری کنن باز هم مشکل رو داریم باز هم دو نفر برای خرید یک محصول دعواشونه
حتی اگر محصولی با موجودی پنج تا باشه و دو نفر بخوان از اون محصول هر یک به تعداد سه تا خریداری کنن و در لحظه پرداخت چک کنیم میبینیم مشکل و محدودیتی نداریم ولی بازم یکی کم میاد
همیشه روی موجودی یک مشکلمون نیست که فقط در حالت یک بودن چک بشه با توجه به مثالی که زدم گاهی به خرید با تعداد بالا تر و یا همزمانی تعداد بیشتر هم هست
همچنان راه حل نشد براش😐😐
نگاه کنید
راه حل، استفاده از تکنیکی به نام lock در دیتابیسه.
این سوالی که مطرح کردی خیلی جاها ممکنه برامون دردسر ساز شه
مثلا 100 تا کد تخفیف ارائه کردی و در صورت درخواست مکرر و همزمان ممکنه 110 بار هم ازش استفاده شه
برای جلوگیری از وقوع این موضوع از چیزی به نام lock استفاده میکنیم تا
از داده ها برای جلوگیری ویرایش همزمان محافظت بشه
به نظرم زیادی درگیر شدی 😅
چون در اخر همون طور همین مقاله ای که گذاشتی هم در اخر گفت هر کاری هم کنیم بازم منابعمون مصرفش بیشتر میشه
The sad truth
The thing is, no matter how perfect these algorithms are, they still create some busy waiting processes. Some processes aside from the one inside the critical region will have to wait and check and wait and check until they can enter. This wastes CPU resources because instead of actually working on other important tasks, it just waits and checks indefinitely.
به نظر من باید از ساده ترین روش استفاده کنی
مثلا ساده ترین راه حل برای کد تخفیف تعداد محدود این میشه که مثلا اگه کلا 100 تا کاربر میتونن استفاده کنن تو مثلا 90 تا بزاری بعد حالا اینا که مصرف شد اگه خواستی بازم یه 5 تا اضاف میکنی (معمولا کد تخفیف خودش باعث تحریک مشتری و شلوغ شدنه)
حالا کد تخفیف که انچان مهم نیست مثلا از 100 تا فقط به 95 تا بدی یا 5 تا بیشتر بدی ( کی به کیه )
اما سر موجودی محصول ساده ترین راه برای اینکه هیچ کی شاکی نشه اینه که موجودی انبارمون رو درست مدیریت کنیم
اقا تقاضا زیاده زیاد تر سفارش بده
اما اگه بخوایم سر برنامه نویسیش بگیم
ساده ترین راه همون چک کردن موجودی به محض فشرده شدن کلیک پرداخته
یا اینکه وقتی موجودی کم میشه رو روتت محدودیت بزار ( ولی بازم میشه همون مقاله )
بلاخره اگه اونقد شلوغ شه بازم تو جلو پرداخت رو بگیری مشتری شاکی میشه ( کل پروسه سفارش رو رفته دم پرداخت یهو محصول ناموجود میشه 😖🙁) البته بازم بهتر اینه پرداخت کنی بگی ندارم
بقیه اش خاطرست
من یه بار از یه سایتی یه لپ تاپ سفارش دادم خیر سرم سفارش انجام شد
دیدیم اقا چند روز گذشت حتی نگفتن مرسوله ارسال شد زنگ زدم گفتن موجودی نداریم ( ماشالله نوسان دلار که کم نداریم)
گفت اگه بخوای خودم باید بریم گرون تر بخریم بدم بهت ( البته از منم میخواست پول بیشتر بگیره )
منم سفارش رو لغو کردم بعد چند روز پول رو ریخت رفتم بازار کامپیوتر گرون تر خریدم 😂
البته یه کار تئوری هم میشه کرد
مثلا 3 ثانیه زمان بزاری تو این 3 ثانیه هر چند نفر که ثبت سفارش کردن ( یعنی میخوان پرداخت کنن )
خود میای از بین اینا محصول رو میدی به یکیشون
حالا یا مثلا از رو امتیاز کاربر ( اگه پروژه ات یه چنین چیزی داره)
یا رندوم یکی رو انتخاب میکنی و تمام
حالا 10 نفر دقیق هم زمان دکمه پرداخت رو زده باشن حالا اینا میرن تا بینشون انتخاب شه حالا مثلا تو اون 3 ثانیه که داره پردازش انجام میشه پرداخت هم قفل میشه یعنی یه گروه دیگه نمیتون دوباره رو پرداخت بزنن
حالا اگه بزنن کار اینا انجام شده دیگه یعنی یکیشون انتخاب شده و از موجودی کم شده
حالا نمیدونم چند درصد عملی باشه ولی گفتم شاید برای کسی مفید باشه
و باز هم اصل موضوع تغییر کرد
درسته میشه کلک زدو چارتا محصول اضاف کرد مدیریت کرد و هرچی
ولی بازم موضوع اصلی ما حل نشد
طرح سوال رو خیلی پیچیده تر و مهم تر میکنم
فرض کنیم سایت فروشگاه بزرگی مثل آمازون داریم توی ایران حالا از سایتای ایرانی نام نبریم مثلا
اصلا شرکت فروشگاه هرچی
موجودی بانکشو در نظر بگیر
درسته میگیم ی محصول کم پیش میاد همچین حالتی رو شامل شه
ولی برای مثلا حساب این سایت یا شرکت توی بانک
الگوریتم پرداخت خود بانک چیکار میکنه؟
شاید در یک لحظه ی خاص هزار تراکنش همزمان داشته باشه سایت
اگر فرض بگیریم وقتی یه سفارشی پرداخت میشه موجودی چک شه مثلا یک میلیارد
هزار تراکنش هم زمان داریم ک خرید مثلا یم میلیونیه یا هرچی مهم نی
وقتی مقدار قبلی موجودی حساب بخواد با یک میلیون جمع شه
در لحظه چک کردن برای هر هزار تراکنش موجودی یک میلیارده و یک میلیون اضاف میشه و موجودی نهایی میشه یک میلیارد و یک میلیون
اگر دو نفر همزمان باشه و موجودی همزمان بررسی بشه هر کی دیرتر ثبت کنه فقط میزان اون نوی دیتابیس ذخیره میشه
باز هم لینکی که در ابتدای این بحث قرار دادم رو میزارم موضوعی شبیه ب چیزی ک الان حرفشو زدم مطرح کرده برای دو نفر
اینجا نمیتونیم بگیم محصولی تهیه میکنیم یا انباری رو مدیریت میکنیم
توی اون گفت گو از همون lock که دوست عزیزمون گفتن استفاده شده البته با عنوان database transactions
DB::beginTransaction(); try { $result = Db::table(DB_T_TEST.' as s') ->select('s.money') ->where('id',1)->sharedLock()->first();
@ali.agk25 در رابطه با پیام اخرتون که بین سه نفر بود
مسئله اینه ک تشخیص داده نمیشه که چند نفرن
وقتی همزمان اتفاق میفته در همون لحظه برای هر سه کاربر هیچ کسی درخواستی نداده و و خودشون تنها نفر درخواست دهنده هستن چون در یک لحظه چک شده این موضوع
پس کارساز نیست ب نظرم
آیا مایل به ارسال نوتیفیکیشن و اخبار از طرف راکت هستید ؟