PDA

View Full Version : سوال: بهترین روش اتصال بین لوکال و اینترنت بدون استفاده از وب سرویس ؟



imanitc
شنبه 11 آبان 1392, 20:45 عصر
با سلام خدمت مهندسین عزیز
من 2 تا برنامه جداگانه دارم هردو php و mysql استفاده میکنن یکی لوکال و یکی روی اینترنت هست میخاستم اطلاعات روی وب بصورت همزمان یا با فراخوانی از طرف لوکال به اون منتقل بشه.برای مثال شما برنامه ای دارید که نوبت حضوری و اینترنتی میده حالا میخاهیم نوبت های آنلاین و لوکال با هم هماهنگ باشن و تکراری نشن بهترین کار چیه یا چه روشی میتوان استفاده کرد؟لطفا وب سرویس یا انتقال برنامه لوکال به وب رو پیشنهاد ندین ممنون :لبخندساده:

AliRezaPro
شنبه 11 آبان 1392, 22:47 عصر
چرا پیشنهاد ندیم ؟
امکان استفاده از برنامه های ویندوزی نیست ؟ چرا با خود اسکریپت از لوکال به mysql هاست وصل نمیشید ؟

imanitc
یک شنبه 12 آبان 1392, 06:34 صبح
چون اگر امکان اين کار بود خودم انجام ميدادم ولي اونجا اينترنت وصل هست.اين راه قبلا تست کردم بد نيست ولي به نظرم بهينه نيست اگر پيشنهاد خاص يا کدي در اين رابطه دارين خوشحال ميشم بذارين :لبخندساده:

eshpilen
یک شنبه 12 آبان 1392, 10:19 صبح
به نظرم بهينه نيست
چطور؟ چرا؟

imanitc
یک شنبه 12 آبان 1392, 10:41 صبح
من قبلا يه صفحه ساخته بودم که يه کدي رو با گت به اون ميفرستادم اگر کد درست بود يه سري اطلاعات بصورت کد شده بر ميگردوند به سمت من حالا نميدونم اين کار درست بوده يا نه ؟راه ديگه اي يا استانداردي چيزي هست براي اين کار؟اين روش خودم و جايي نديدم

eshpilen
یک شنبه 12 آبان 1392, 11:05 صبح
این که گفتی جواب من بود؟ :متفکر:


من قبلا يه صفحه ساخته بودم که يه کدي رو با گت به اون ميفرستادم اگر کد درست بود يه سري اطلاعات بصورت کد شده بر ميگردوند به سمت من حالا نميدونم اين کار درست بوده يا نه ؟راه ديگه اي يا استانداردي چيزي هست براي اين کار؟اين روش خودم و جايي نديدم
خیلی کلی و مبهم هست؛ نمیشه چیزی گفت.
بستگی داره دقیقا چه کدی چطوری چه روش کدی چه اطلاعاتی برای چه کاری از چه نظر...

imanitc
یک شنبه 12 آبان 1392, 13:09 عصر
آقا کد من و نظر من ول کن .شما اگر خودت کدي يا نظري داري اعلام کن استفاده کنيم :لبخندساده:

eshpilen
یک شنبه 12 آبان 1392, 13:19 عصر
ارسال اطلاعات که امروزه به ده ها روش ممکنه. امکاناتش هم راحت و همه جاییه تقریبا.
تا جزییات دونسته نشه نمیشه گفت کدوم روش و نمیشه از جزییات صحبت کرد.
مسائل امنیتی و غیره هم که جداگانه هستن.
اما خب آدم بطور کلی امروزه روشی رو انتخاب میکنه که از نظر کدنویسی راحتتر و سریعتر باشه، مگر اینکه شرایط طوری باشه و در عمل مشکلات/محدودیت های فنی وجود داشته باشن. مثلا شما گفتی بنظرت بهینه نیست. واسه همین پرسیدم چرا! چون این بنظر نشانهء اینه که ممکنه کم و بیش دچار وسواس در بهینه سازی شده باشه (این یه بیماری نسبتا شایع بین برنامه نویسان است که قبلا راجع بهش زیاد بحث کردم). بنظر منظر نداره! یا هست یا نیست. در عمل باید وجود داشته باشه، نه بنظر! باید دلیل و سند معتبر داشته باشه حداقل اگر ذهنی هم هست.
در درجهء بعد آدم اگر به هر دلیلی استاندارد بودن و امکان تعامل با برنامه ها و سرویسهای دیگران براش مهم باشه، میره دنبال استاندارد بودن روش (مثلا وب سرویس یا روشهای استاندارد دیگر). وگرنه که خودش شده یه پروتکل و روشی اختراع میکنه!! کاری نداره که!!
البته بازم مسائل امنیتی نیاز به تخصص دارن. مثلا اطلاعات رو طوری بفرستی که دیگران نتونن دسترسی داشته باشن یا دستکاری کنن در مسیر.

حالا از این بیشتر چی میخوای الان؟ بیایم کد و برنامه هم بنویسیم بذاریم؟ اونم وقتی اطلاعات و شرایطش دقیقا معلوم نیست چطوریه؟

imanitc
دوشنبه 13 آبان 1392, 08:35 صبح
با تشکر از شما دوست عزيز من مشکلم همون که توي سوال اول تاپيک مطرح کردم نوبت دهي آنلاين و لوکالي همزمان، ذخيره سازي در هر دو ديتا بيس يعني لوکال و آنلاين حالا مشکل سينک کردن اين 2 تاس حالا چيکار کنم ؟

eshpilen
دوشنبه 13 آبان 1392, 09:11 صبح
سینک کردن که میگید، با مشکلات همزمانی فرق داره بنظرم.
سینک کردن یعنی یکسان کردن دو منبع.
ولی سینک کردن ارتباطی به مشکلات همزمانی نداره و نمیتونه این مشکل رو حل کنه.
مثلا اگر یک صندلی در هر دو دیتابیس به افراد مختلفی اختصاص داده شده باشه، سینک کردن اینجا معنایی نمیده و قابل انجام نیست.

درمورد مشکل همزمانی هم خب چرا دو دیتابیس؟ نمیشه از یک دیتابیس مشترک استفاده کرد؟
نهایت باید یه ارتباطی بین هر دو برنامه (لوکال و آنلاین) برقرار بشه، حداقل در مواقعی که رکوردی میخواد درج بشه؛ حالا دیتابیس رو مشترک نکردید، ولی حداقل یک تبادل اطلاعات و چک بین دو سیستم باید صورت بگیره یا نه؟
مثلا سیستم آنلاین میخواد یک صندلی رو رزو کنه، باید اول با سیستم لوکال تماس بگیره ببینه این صندلی رزو شده یا نه، بعد رکورد رو درج کنه در دیتابیس خودش. تازه باید یک قفل هم بذارید روی سیستم لوکال که در همین زمان کوتاه، اون صندلی رو رزرو نکنه. سیستم لوکال هم باید برای رزور صندلی، با سیستم آنلاین تماس بگیره، اما اصولی و دقیق و بی نقص بخواد باشه فقط این کافی نیست. فرض کنید دو سیستم همزمان برای یک صندلی همدیگر رو کوئری میکنن، هر دو جواب میگیرن که صندلی رزور نشده، بعد هر دو اون صندلی رو اختصاص میدن! اینطوری مشکل پیش میاد؛ نه؟ پس نیاز به قفل و فراینده پیچیده تری هست.

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

colors
دوشنبه 13 آبان 1392, 10:55 صبح
سینک کردن که میگید، با مشکلات همزمانی فرق داره بنظرم.
سینک کردن یعنی یکسان کردن دو منبع.
ولی سینک کردن ارتباطی به مشکلات همزمانی نداره و نمیتونه این مشکل رو حل کنه.
مثلا اگر یک صندلی در هر دو دیتابیس به افراد مختلفی اختصاص داده شده باشه، سینک کردن اینجا معنایی نمیده و قابل انجام نیست.

درمورد مشکل همزمانی هم خب چرا دو دیتابیس؟ نمیشه از یک دیتابیس مشترک استفاده کرد؟
نهایت باید یه ارتباطی بین هر دو برنامه (لوکال و آنلاین) برقرار بشه، حداقل در مواقعی که رکوردی میخواد درج بشه؛ حالا دیتابیس رو مشترک نکردید، ولی حداقل یک تبادل اطلاعات و چک بین دو سیستم باید صورت بگیره یا نه؟
مثلا سیستم آنلاین میخواد یک صندلی رو رزو کنه، باید اول با سیستم لوکال تماس بگیره ببینه این صندلی رزو شده یا نه، بعد رکورد رو درج کنه در دیتابیس خودش. تازه باید یک قفل هم بذارید روی سیستم لوکال که در همین زمان کوتاه، اون صندلی رو رزرو نکنه. سیستم لوکال هم باید برای رزور صندلی، با سیستم آنلاین تماس بگیره، اما اصولی و دقیق و بی نقص بخواد باشه فقط این کافی نیست. فرض کنید دو سیستم همزمان برای یک صندلی همدیگر رو کوئری میکنن، هر دو جواب میگیرن که صندلی رزور نشده، بعد هر دو اون صندلی رو اختصاص میدن! اینطوری مشکل پیش میاد؛ نه؟ پس نیاز به قفل و فراینده پیچیده تری هست.

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

سلام جناب eshpilen :لبخند:, نیستی آقا؟

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

eshpilen
دوشنبه 13 آبان 1392, 11:09 صبح
البته فقط دیتابیش مشترک لزوما همهء مشکلات همزمانی رو حل نمیکنه.
این قضیهء دسترسی همزمان در خیلی از برنامه ها درنظر گرفته نشده.
یعنی حتی دو درخواستی که به یک سرور وارد میشن، و کوئری هایی که هرکدام اجرا میکنن، ترتیب اجرای اینها میتونه هرچیزی باشه، مثلا اول کوئری 1 از درخواست A اجرا بشه بعد کوئری 1 از درخواست B بعد کوئری 2 درخواست A و ... . اینطوری نیست که چون درخواست A قبل از درخواست B به سرور وارد یا حتی اول شروع به اجرا شده، ترتیب اجرای کدهای درخواست ها هم به همین شکل باشه. ترتیب اجرای کدها در سیستم عامل و برنامه های مربوطه تضمین نشده.
اینا میتونه موجب خطا در داده های ثبت شده بشه.
هرکجا که منبع مشترکی توسط چند فرایند مورد استفاده قرار میگیره این مسائل دسترسی همزمان میتونن بروز کنن.

یه مثال:
یه فیلد داریم که مقدار اعتبار مالی رو ذخیره میکنه.
فرضا مقدار اولیه 1000 تومن.
درخواست A میخواد این مقدار رو بخونه (و فرضا ممکنه میخواد یکسری عملیات محاسبهء مالیاتی چیزی هم روش انجام بده) و 500 تومن بهش اضافه کنه.
درخواست B هم میخواد 500 تومن دیگه بهش اضافه کنه.
درخواست A با اجرای یک کوئری مقدار 1000 رو از این فیلد میخونه، در این بین درخواست B هم 1000 رو میخونه، درخواست A مقدار 1500 رو در فیلد مینویسه، بعدش درخواست B هم میاد همین مقدار رو مینویسه!
اینجا مشاهده میکنیم که بجای 1000 تومن در مجموع، 500 تومن به اعتبار اضافه شده.
این یه نمونه خیلی ساده از مشکل دسترسی همزمان!

SlowCode
دوشنبه 13 آبان 1392, 11:19 صبح
خب اومدم یه کلیدی تو برنامه لوکال تعبیه کردم و یه دیتابیس جدا در لوکال ساختم که وقتی این کلید رو میزدی آخرین اطلاعات هاست آنلاین رو دریافت و دیتابیسشو آپدیت میکرد. در این صورت فقط میتونستی از برنامه و اطلاعات فعلیش استفاده کنی و قابلیت ویرایش, حذف و اضافه کردن اینا نداشت و جز اینهم راهی نداره.

فکر نکنم نیازی به دریافت آخرین اطلاعات هاست آنلاین باشه!
کافیه شما مواردی رو که زمان آفلاین ثبت میشن رو داخل یه جدول ثبت کنی بعد هر وقت که اینترنت فعال شد اون موارد رو به سایت اصلی میفرسته و در صورت دریافت پاسخ success اون رکورد رو حذف میکنه.
البته به نظرم بهتره واسه لوکال یه برنامه تحت دسکتاپ مستقل نوشت. اینطوری راحت تر میشه کا رو انجام داد.
اینطوری میتونی مستقیما به دیتابیس هاست اصلی وصل بشی و اطلعات رو درج کنی.(البته اینجا مسئله امنیت پیش میاد چون اگه راهکاری انجام ندی پسوردت 3 سوت لو رفته:لبخند:)

colors
دوشنبه 13 آبان 1392, 11:25 صبح
یه مثال:
یه فیلد داریم که مقدار اعتبار مالی رو ذخیره میکنه.
فرضا مقدار اولیه 1000 تومن.
درخواست A میخواد این مقدار رو بخونه (و فرضا ممکنه میخواد یکسری عملیات محاسبهء مالیاتی چیزی هم روش انجام بده) و 500 تومن بهش اضافه کنه.
درخواست B هم میخواد 500 تومن دیگه بهش اضافه کنه.
درخواست A با اجرای یک کوئری مقدار 1000 رو از این فیلد میخونه، در این بین درخواست B هم 1000 رو میخونه، درخواست A مقدار 1500 رو در فیلد مینویسه، بعدش درخواست B هم میاد همین مقدار رو مینویسه!
اینجا مشاهده میکنیم که بجای 1000 تومن در مجموع، 500 تومن به اعتبار اضافه شده.
این یه نمونه خیلی ساده از مشکل دسترسی همزمان!

بله موافقم.
البته رو این هم فکر کردم. راه و روشهای مختلفی به ذهنم رسید ولی نهایتا هیچکدوم رو اجرا نکردم.
مثلا میخواستم درخواستهای که از برنامه لوکال ارسال میشه رو فقط در ثانیه های فرد اجراش کنم و درخواستهای سایت رو فقط در ثانیه های زوج. اینطوری احتمال درصد خطاش 0 میشه. نظرتون چیه؟
یا مثلا درخواستهای که ارسال میشن یه آی دی یونیک بهشون بدیم و بریزیم تو یه لیست انتظار و 100 هزارم ثانیه یه درخواست رو اجرا کرد. این روش کمی پیچیدگی بالای و احتمال اشتباه داره, ولی بلاخره روشه دیگه

colors
دوشنبه 13 آبان 1392, 11:32 صبح
کافیه شما مواردی رو که زمان آفلاین ثبت میشن رو داخل یه جدول ثبت کنی بعد هر وقت که اینترنت فعال شد اون موارد رو به سایت اصلی میفرسته و در صورت دریافت پاسخ success اون رکورد رو حذف میکنه.

فکر کنم اشتباه متوجه شدین.
برنامه آفلاین عملا نمیتونه رکوردی رو حذف اضاف یا ... کنه مگر اینکه سیستم پایه برنامه آفلاین به اینترنت وصل بوده باشه که بتونه با دیتابیس آنلاین ارتباط برقرار کنه.
اگر بخوای خود برنامه آفلاین زمان وصل نبودن به اینترنت قادر به ویرایش اطلاعات باشه و هر وقت وصل شدی آپدیت کنه, این مشکل داره. چند پست بالاتر دوستان گفتن که مثلا همون بحث رزرو صندلی تو اینجور مواقع پر از مشکل میشه.
مثلا یه اتوبوس VIP 30 نفره واسه 185 نفر رزرو میشه :قهقهه:

eshpilen
دوشنبه 13 آبان 1392, 11:44 صبح
درخواستهای که از برنامه لوکال ارسال میشه رو فقط در ثانیه های فرد اجراش کنم و درخواستهای سایت رو فقط در ثانیه های زوج. اینطوری احتمال درصد خطاش 0 میشه. نظرتون چیه؟
شما به خیال خودت در زمان خاصی چیزی رو اجرا میکنی، ولی زمانبندی دقیق هیچوقت دست شما نیست و به هزارتا پارامتر در محیط سخت افزاری و نرم افزار و ارتباطات سرور و رایانه بستگی داره.
یعنی چی در ثانیه های فرد و زوج؟
مثلا تایم رو میگیری توی حلقهء while هروقت زوج بود دستور رو اجرا میکنی؟
اصلا شما نمیتونی به هیچ صورتی مطمئن باشی که زمانی که دستور رو به خیال خودت اجرا کردی اجرای واقعی اون چه زمانی در کامپیوتر شروع میشه و با چه سرعتی اجرا میشه و کی تموم میشه.
اینا هیچکدام تضمین و قاعدهء قابل اتکایی ندارن. سیستم بر اساس الگوریتم و اولویت و پارامترهای زیادی این کارها رو انجام میده.
ضمنا مگه فکر کردی اجرای هر دستور و درخواست و عملیاتی بیشتر از یک ثانیه طول نمیکشه؟
اینم تضمین نداره.
شاید برنامهء شما خیلی سبک باشه اما سرور به علت خاصی خیلی کندتر میشه و اجراش خیلی بیشتر طول میکشه.



یا مثلا درخواستهای که ارسال میشن یه آی دی یونیک بهشون بدیم و بریزیم تو یه لیست انتظار و 100 هزارم ثانیه یه درخواست رو اجرا کرد. این روش کمی پیچیدگی بالای و احتمال اشتباه داره, ولی بلاخره روشه دیگه
متوجه نشدم چی میگی. ولی فکر کنم اینم مثل قبلی روی فرضهای اشتباهی استواره.

colors
دوشنبه 13 آبان 1392, 11:47 صبح
شما به خیال خودت در زمان خاصی چیزی رو اجرا میکنی، ولی زمانبندی دقیق هیچوقت دست شما نیست و به هزارتا پارامتر در محیط سخت افزاری و نرم افزار و ارتباطات سرور و رایانه بستگی داره.
یعنی چی در ثانیه های فرد و زوج؟
مثلا تایم رو میگیری توی حلقهء while هروقت زوج بود دستور رو اجرا میکنی؟
اصلا شما نمیتونی به هیچ صورتی مطمئن باشی که زمانی که دستور رو به خیال خودت اجرا کردی اجرای واقعی اون چه زمانی در کامپیوتر شروع میشه و با چه سرعتی اجرا میشه و کی تموم میشه.
اینا هیچکدام تضمین و قاعدهء قابل اتکایی ندارن. سیستم بر اساس الگوریتم و اولویت و پارامترهای زیادی این کارها رو انجام میده.
ضمنا مگه فکر کردی اجرای هر دستور و درخواست و عملیاتی بیشتر از یک ثانیه طول نمیکشه؟
اینم تضمین نداره.
شاید برنامهء شما خیلی سبک باشه اما سرور به علت خاصی خیلی کندتر میشه و اجراش خیلی بیشتر طول میکشه.

متوجه نشدم چی میگی. ولی فکر کنم اینم مثل قبلی روی فرضهای اشتباهی استواره.

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

eshpilen
دوشنبه 13 آبان 1392, 11:48 صبح
بهرحال واسه این دسترسی همزمان روشهای اصولی تر خودش هست.
مثلا قفل. مکانیزم های قفل رو واسه همین چیزا گذاشتن دیگه!
فکر کنم از ترنزکشن هم میشه استفاده کرد (چون خودم تاحالا استفاده نکردم زیاد مطمئن نیستم).

SlowCode
دوشنبه 13 آبان 1392, 11:49 صبح
فکر کنم اشتباه متوجه شدین.
برنامه آفلاین عملا نمیتونه رکوردی رو حذف اضاف یا ... کنه مگر اینکه سیستم پایه برنامه آفلاین به اینترنت وصل بوده باشه که بتونه با دیتابیس آنلاین ارتباط برقرار کنه.
اگر بخوای خود برنامه آفلاین زمان وصل نبودن به اینترنت قادر به ویرایش اطلاعات باشه و هر وقت وصل شدی آپدیت کنه, این مشکل داره. چند پست بالاتر دوستان گفتن که مثلا همون بحث رزرو صندلی تو اینجور مواقع پر از مشکل میشه.
مثلا یه اتوبوس VIP 30 نفره واسه 185 نفر رزرو میشه :قهقهه:
نخیر فکر نکنم اشتباه متوجه شده باشم:لبخند:
چیزی که گفتم اصلا به صندلی و اوتوبوس ربط نداره! لطفا با دقت بخونین.
بله سیستم آفلاین نمیتونه رکوردی رو حذف کنه منم اون حرفها رو بر پایه پست قبلی شما نوشتم.
اگه بخوام کامل بگم...
فرض کنیم کاربر به اینترنت وصل نیست و میخواد یه رکورد ثبت کنه، تو دیتابیسی که تو لوکال درست کردیم اون رکورد رو ثبت میکنیم پس قطعا کاربر نمیتونه رکورد هایی که تو دیتابیس اصلی هستن رو ویرایش یا حذف کنه چون لیست رکوردها رو نداریم و فقط یه جدول موقت داریم.
بعد تو یه بازه زمانی مشخص با تایمر چک میکنیم که سیستم به اینترنت وصله یا نه؟(یا هوک:لبخند: میکنیم هر وقت سیستم به اینترنت وصل شد انتقال شروع میشه) اگه وصل بود شروع میکنه اطلعات رو میفرسته به هاست و اونا رو ذخیره میکنه بعد از جدول موقت حذفشون میکنه.
حالا به نظرتون اشتباه فهمیدم؟:لبخند:

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

colors
دوشنبه 13 آبان 1392, 12:01 عصر
نخیر فکر نکنم اشتباه متوجه شده باشم:لبخند:
چیزی که گفتم اصلا به صندلی و اوتوبوس ربط نداره! لطفا با دقت بخونین.
بله سیستم آفلاین نمیتونه رکوردی رو حذف کنه منم اون حرفها رو بر پایه پست قبلی شما نوشتم.
اگه بخوام کامل بگم...


حالا به نظرتون اشتباه فهمیدم؟:لبخند:

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

بازم نقهمیدم.

فرض کنیم کاربر به اینترنت وصل نیست و میخواد یه رکورد ثبت کنه
بله مشکلی نیست

تو دیتابیسی که تو لوکال درست کردیم اون رکورد رو ثبت میکنیم
بله درسته

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

بعد تو یه بازه زمانی مشخص با تایمر چک میکنیم که سیستم به اینترنت وصله یا نه؟ (یا هوک:لبخند: میکنیم هر وقت سیستم به اینترنت وصل شد انتقال شروع میشه)
بسیار عالی

اگه وصل بود شروع میکنه اطلعات رو میفرسته به هاست و اونا رو ذخیره میکنه بعد از جدول موقت حذفشون میکنه.
اینجارو خراب کردی.
خب در این صورت اگر سیستم آفلاین در طول روز بلیط های شماره 1 تا 10 رو رزرو کنه و کاربر سیستمش رو ساعت 20 به اینترنت وصل کنه که اطلاعات رو بفرسته به هاست, و همه بیلط های اتوبوس(حتی بلیط های 1 تا 10) تا قبل از ساعت 19 توسط سایت رزرو شده باشه, میخوای چیکار کنی؟
وقتی که کاربر ساعت 20 وصل شد و اطلاعات به هاست رفت میبینه که اون رکوردها قبلا تو دینابیس درج شدن و دعوا شروع میشه.

SlowCode
دوشنبه 13 آبان 1392, 13:30 عصر
خب در این صورت اگر سیستم آفلاین در طول روز بلیط های شماره 1 تا 10 رو رزرو کنه و کاربر سیستمش رو ساعت 20 به اینترنت وصل کنه که اطلاعات رو بفرسته به هاست, و همه بیلط های اتوبوس(حتی بلیط های 1 تا 10) تا قبل از ساعت 19 توسط سایت رزرو شده باشه, میخوای چیکار کنی؟
وقتی که کاربر ساعت 20 وصل شد و اطلاعات به هاست رفت میبینه که اون رکوردها قبلا تو دینابیس درج شدن و دعوا شروع میشه.
خب بدیهیه که قبل از ثبت رکورد باید یه بررسی هایی انجام بشه!
اونم بستگی داره به سیستم شما. خیلی بدیهیه!

colors
دوشنبه 13 آبان 1392, 17:48 عصر
خب بدیهیه که قبل از ثبت رکورد باید یه بررسی هایی انجام بشه!
اونم بستگی داره به سیستم شما. خیلی بدیهیه!

مثلا چه بررسی های ؟

SlowCode
دوشنبه 13 آبان 1392, 19:57 عصر
آقا سامان گیر دادیا:لبخند:

خب مثلا واسه رزرو بلیط وقتی که اطلاعات به سرور ارسال شد بررسی بشه آیا این صندلی رزو شده یا نه؟ آیا زمان حرکت اتوبوس گذشته یا نه؟
اگه مشکلی بود به کاربر خطا بده اگه نبود هم که هیچی!
من با سیستم رزرو بلیط آشنا نیستم وگرنه دقیق تر جواب میدادم. اینا به جزئیات پروژه مربوط میشه نه روش انجام کار. ما روی روشها بحث میکنیم الان.

colors
دوشنبه 13 آبان 1392, 20:24 عصر
آقا سامان گیر دادیا:لبخند:

خب مثلا واسه رزرو بلیط وقتی که اطلاعات به سرور ارسال شد بررسی بشه آیا این صندلی رزو شده یا نه؟ آیا زمان حرکت اتوبوس گذشته یا نه؟
اگه مشکلی بود به کاربر خطا بده اگه نبود هم که هیچی!
من با سیستم رزرو بلیط آشنا نیستم وگرنه دقیق تر جواب میدادم. اینا به جزئیات پروژه مربوط میشه نه روش انجام کار. ما روی روشها بحث میکنیم الان.

:لبخند:
خب دقیق مشکل همینجاست که اگه سیستم بخواد به هاست کوئری بفرسته که ببینه این صندلی رزرو شده یا خیر, باید به اینترنت متصل باشه, درسته؟ پس اگه قرار به اینترنت وصل بشی که اینارو چک کنی همون اطلاعات رو به دیتابیس آنلاین(هاست) میفرستی راحت. این همه پیچیدگی و دردسرهم نداره. درسته؟

SlowCode
دوشنبه 13 آبان 1392, 22:10 عصر
:عصبانی++:
آقا! برنامه چک میکنه که آیا سیستم به اینترنت وصله یا نه؟ بعد شروع میکنه به سینک کردن و بعد موقع سینک کردن بررسی میکنه که آیا صندلی رزو شده یا نه؟ بعد اگه ثبت شده باشه به کاربر خطا میده که این صندلی که شما موقع افلاین بودن ثبت کردین قبلا ثبت شده!




خب دقیق مشکل همینجاست که اگه سیستم بخواد به هاست کوئری بفرسته که ببینه این صندلی رزرو شده یا خیر, باید به اینترنت متصل باشه, درسته؟
هم بله هم خیر. شما گفتین سیستم مثلا ساعت 8 به اینترنت وصل میشه برنامه هم به طور خودکار اون زمان عملیات رو شروع میکنه. تو پست 13 و 19 به این نکته اشاره کردم:چشمک:
اصلا به جای این همه بحث کردن یه اشتراک adsl براش بگیر تا همون راحت بشیم!

بهتره دیگه بحث رو کشش ندیم دیگه. من توضیحاتی که تو نظرم بود رو دادم:لبخندساده:

colors
سه شنبه 14 آبان 1392, 00:37 صبح
:عصبانی++:
آقا! برنامه چک میکنه که آیا سیستم به اینترنت وصله یا نه؟ بعد شروع میکنه به سینک کردن و بعد موقع سینک کردن بررسی میکنه که آیا صندلی رزو شده یا نه؟ بعد اگه ثبت شده باشه به کاربر خطا میده که این صندلی که شما موقع افلاین بودن ثبت کردین قبلا ثبت شده!

هم بله هم خیر. شما گفتین سیستم مثلا ساعت 8 به اینترنت وصل میشه برنامه هم به طور خودکار اون زمان عملیات رو شروع میکنه. تو پست 13 و 19 به این نکته اشاره کردم:چشمک:
اصلا به جای این همه بحث کردن یه اشتراک adsl براش بگیر تا همون راحت بشیم!

بهتره دیگه بحث رو کشش ندیم دیگه. من توضیحاتی که تو نظرم بود رو دادم:لبخندساده:

باشه :لبخند:

AliRezaPro
سه شنبه 14 آبان 1392, 11:08 صبح
با سلام خدمت مهندسین عزیز
من 2 تا برنامه جداگانه دارم هردو php و mysql استفاده میکنن یکی لوکال و یکی روی اینترنت هست میخاستم اطلاعات روی وب بصورت همزمان یا با فراخوانی از طرف لوکال به اون منتقل بشه.برای مثال شما برنامه ای دارید که نوبت حضوری و اینترنتی میده حالا میخاهیم نوبت های آنلاین و لوکال با هم هماهنگ باشن و تکراری نشن بهترین کار چیه یا چه روشی میتوان استفاده کرد؟لطفا وب سرویس یا انتقال برنامه لوکال به وب رو پیشنهاد ندین ممنون :لبخندساده:

احساس میکنم استارتر تاپیک به شدت سردرگم شدند .استارتر محترم سعی کنید اول سناریو رو کامل کنید و سپس به دنبال کد و امنیت و با قیه ماجرا باشید .
سناریو ی بنده :
دو بانک اطلاعاتی دارید یکی در هاست یکی در لوکال . بانک اطلاعاتی در لوکال فقط برای دخیره است و نه برای پردازش . بانک اطلاعاتی در هاست برای پردازش و دخیره است . ساختار هر بانک کاملا شبیه به هم هستند با ایت تفاوت که بانک موجود در هاست دارای فیلد اضافه ایی به نام check دارد .هر رکوئستی از هر جایی به بانک اطلاعاتی هاست امد برای رزرور مقدار چک را به 1 اپدیت میکند.اگر رکوئست از هاست آمد مقدار check را 1 میکند وپردازش ها را جهت رزرور انجام می دهد و اول داده ها رابه بانک موجود در لوکال (با static ip) انتقال می دهد و سپس داده ها را در بانک هاست اینسرت میکند.
وقتی درخواست رزرور از لوکال آمد (به هاست) اول مقدار چک را پردازش و ست میکند و سپس بعد از پردازش رزرواسیون اول داده ها را در هاسیت اینسرت و سپس در لوکال اینسرت میکنند .
با این روزش وقتی از هر طرفی رکوئستی آمد بانک فقط برای همان سمت قفل می شود و مشکل isolate را حل میکند.
پیشنهاد بنده : با دوتا یانک اطلاعاتی فکر نکنم به مشکل برسید . بانک اطلاعاتی در هاست یا لوکال میتواند به راحتی جا رزرو کند . فیلدی در بانک اطلاعاتی قرار بدید به نام Check. هنگام رزرو در لوکال یا هاست چک کنید اگر مقدار آن 1 بود یعنی از سمت لوکال یا هاست در حال چک کردن رزروها و انجام رزرو است . هنگام رزرو کردن در لوکال یا هاست یک کوئری بزنید اگر مقدار check برابر یا 0 بود آن را 1 کنید که در هیچ سمتی رزرو انجام نشود . بعد از پردازش هاتون میتونید رزرو رو انجام بدید و مقدار check را به 0 تغییر دهید و یعد از ثبت در هاست مقادیر رو لوکال اینسرت کنید.

در صورت داشتن شرایط اینترنتی normal فکر میکنم سناریوی بدی نباشه

colors
سه شنبه 14 آبان 1392, 11:18 صبح
در صورت داشتن شرایط اینترنتی normal فکر میکنم سناریوی بدی نباشه

راه حل خوبیه ولی در هرصورت محدودیت بیشتر ما در پستهای بالا, ارسال دو درخواست به صورت همزمان بود.



یه مثال:
یه فیلد داریم که مقدار اعتبار مالی رو ذخیره میکنه.
فرضا مقدار اولیه 1000 تومن.
درخواست A میخواد این مقدار رو بخونه (و فرضا ممکنه میخواد یکسری عملیات محاسبهء مالیاتی چیزی هم روش انجام بده) و 500 تومن بهش اضافه کنه.
درخواست B هم میخواد 500 تومن دیگه بهش اضافه کنه.
درخواست A با اجرای یک کوئری مقدار 1000 رو از این فیلد میخونه، در این بین درخواست B هم 1000 رو میخونه، درخواست A مقدار 1500 رو در فیلد مینویسه، بعدش درخواست B هم میاد همین مقدار رو مینویسه!
اینجا مشاهده میکنیم که بجای 1000 تومن در مجموع، 500 تومن به اعتبار اضافه شده.
این یه نمونه خیلی ساده از مشکل دسترسی همزمان!

AliRezaPro
سه شنبه 14 آبان 1392, 11:31 صبح
بله مشکل Isolation , ولی برای این مشکل بنده فیلد check را در بانک هاست پیشنهاد دادم. یعنی زمانی که رکوئستی از هر طرفی آمد این فیلد به مقدار 1 اپدیت میشود که از هیچ سمتی کسی بانک را در دست نگیرد . و مشکل همزمانی هم به مراتب به وجود نمی آید . بعد از پردازش ها و اینسرت در آخر این مقدار check به 0 تغییر میکند تا بانک را برای رکوئست های بعدی اماده کند . انشالله متوجه شماتیک کلی کار شده باشید

colors
سه شنبه 14 آبان 1392, 11:40 صبح
بله مشکل Isolation , ولی برای این مشکل بنده فیلد check را در بانک هاست پیشنهاد دادم. یعنی زمانی که رکوئستی از هر طرفی آمد این فیلد به مقدار 1 اپدیت میشود که از هیچ سمتی کسی بانک را در دست نگیرد . و مشکل همزمانی هم به مراتب به وجود نمی آید . بعد از پردازش ها و اینسرت در آخر این مقدار check به 0 تغییر میکند تا بانک را برای رکوئست های بعدی اماده کند . انشالله متوجه شماتیک کلی کار شده باشید

آقای علی رضا خب اگر دو درخواست همزمان از سایت و لوکال بیاد و هر دو مقدار فیلد check رو 0 کنن, پس هر دو میتونن عملیاتشونو انجام بدن درسته؟
نقل قول پست بالای از آقای eshpilen رو ببینید.

eshpilen
سه شنبه 14 آبان 1392, 12:06 عصر
بله مشکل Isolation , ولی برای این مشکل بنده فیلد check را در بانک هاست پیشنهاد دادم. یعنی زمانی که رکوئستی از هر طرفی آمد این فیلد به مقدار 1 اپدیت میشود که از هیچ سمتی کسی بانک را در دست نگیرد . و مشکل همزمانی هم به مراتب به وجود نمی آید . بعد از پردازش ها و اینسرت در آخر این مقدار check به 0 تغییر میکند تا بانک را برای رکوئست های بعدی اماده کند . انشالله متوجه شماتیک کلی کار شده باشید
بنظرت ممکن نیست دو درخواست بصورت همزمان مقدار این فیلد رو بخونن و ببینن مقدارش صفر است و بعد هر دو کوئری بدن برای 1 شدنش؟
اینطوری بازم هر دو درخواست همزمان اجرا میشن.

AliRezaPro
سه شنبه 14 آبان 1392, 12:06 عصر
این مشکل خیلی وقت پیش در سیستم های بانک اطلاعاتی رابطه ایی حل شده است .تمامیه درخواست ها در یک صف قرار میگیرند و تک تک اجرا میشوند . فرض کنید برنامه ایی نوشتید که در شبکه باید داده ها را دست کاری و مدیریت کند . در این صورت چه باید کرد ؟ تمامیه درخواست ها بصورت صف تک تک اجرا میشوند که مشکل به وجود نیاید .

بدانید که:
--
اگر از انجین myisam استفاده میکنید از تکنیک تیبل لاک استفاده میکند یعنی موقعه ی دست کاری کل تیبل لاک میشود . اگر از inodb استفاده میکنید سطر مورد نظر لاک میشود(row lock).به همین خاطر است که inodb میتواند از ترنزکشن پیشتیبانی کند
--
دیدن این لینک هم خالی از لطف نیست

http://dev.mysql.com/doc/refman/5.0/en/lock-tables.html

eshpilen
سه شنبه 14 آبان 1392, 14:23 عصر
این مشکل خیلی وقت پیش در سیستم های بانک اطلاعاتی رابطه ایی حل شده است .تمامیه درخواست ها در یک صف قرار میگیرند و تک تک اجرا میشوند.فکر میکنم اشتباه میکنی و چیزی رو با مسئلهء دیگری اشتباه گرفتی.
تمام کوئری های صادر شده از یک درخواست/کانکشن بنظر بنده هم در صف قرار میگیرن بقول شما.
ولی مسئلهء چند درخواست جداگانه، چند پراسس جداگانه، چند درخواست جداگانه است.
اصولا از نظر پرفورمنس هم بخوای درنظر بگیری این معنا نمیده. چون اگر DBMS بخواد در هر زمان فقط یک کوئری رو اجرا کنه (ولو روی یک جدول یا رکورد خاص)، پرفورمنس نمیتونه برای مقیاس های بزرگ و کوئری های سنگین کافی باشه. مثلا هزارتا کوئری read تقریبا همزمان میرسن برای یک جدولی یا رکوردی، اونوقت کوئری ای که آخر از همه وارد شده باید صبر کنه تا تمام کوئری های قبلی به ترتیب اجرا و تموم بشن؟ اگر کوئری ها نسبتا سنگین باشن اونوقت که زمان بیشتر هم میشه. اگر یک کوئری سنگین باشه یا بعلت کمبود موقتی منابع یا شرایط دیگری (مثلا انتظار برای I/O یا عملیاتی که به یک منبع خارجی وابسته است) دچار تاخیر بشه، کوئری های دیگر هم که اون شرایط رو ندارن باید منتظر بمونن؟
فکر نمیکنم اینطور باشه.
بعد لازم باشه میشه با نمونه کد هم تست کرد، که من از حالا شک چندانی ندارم که خلاف حرف شما رو نشان خواهد داد.
اصولا عملیات خواندن بطور معمول هیچ محدودیت و قفلی ندارن. یعنی همزمان هر تعدادی که سیستم جواب بده میتونن یک منبعی رو بخونن.
این تنها عملیات write هست که بطور موقت درخواستهای دیگر رو بلاک میکنه، چون اگر اینطور نباشه ممکنه اطلاعات ناقص آپدیت شده ای خونده بشن.
بخاطر همینه که به قفلی که موقع read ایجاد میشه shared lock گفته میشه، چون تمام درخواستهای خواندن میتونن این قفل رو بصورت همزمان در اختیار بگیرن (و فقط درخواستهای write باید صبر کنن تا تمام قفل های read آزاد بشن).
و به قفلی که موقع write ایجاد میشه exclusive lock گفته میشه چون در موقع نوشته شدن اطلاعات در رکورد/جدول هیچ کوئری دیگری نمیتونه به اطلاعات دسترسی پیدا کنه.


فرض کنید برنامه ایی نوشتید که در شبکه باید داده ها را دست کاری و مدیریت کند . در این صورت چه باید کرد ؟ تمامیه درخواست ها بصورت صف تک تک اجرا میشوند که مشکل به وجود نیاید .شما فکر میکنید مکانیزمهای مخصوص قفل کردن توسط برنامه نویس (مثل این (http://dev.mysql.com/doc/refman/5.0/en/miscellaneous-functions.html#function_get-lock) یا همونی که خودت آوردی (http://dev.mysql.com/doc/refman/5.0/en/lock-tables.html)) و ترنزکشن و اینها برای چی بوجود آمدن؟
قفل که کاربرد اصلیش همینه. ترنزکشن هم یکی از کاربردهاش همینه بنظرم!
اینها رو برنامه نویس میتونه و باید استفاده کنه؛ دیتابیس خودش بصورت خودکار تشخیص و انجام نمیده.

eshpilen
سه شنبه 14 آبان 1392, 14:29 عصر
با کد هم میشه براحتی تست کرد که کوئری های دو درخواست جداگانه میتونن با هر ترتیبی اجرا بشن.
خواستی بگو نمونه برنامهء تستش رو برات بذارم.

H:Shojaei
سه شنبه 14 آبان 1392, 16:19 عصر
با سلام خدمت دوستان...
به نظر من ارسال داده ها در يك زمان به سرور كه اين وسط واسه كوئري ها پيش مياد و دوستان ميگن كه شايد هر دو در يك زمان دقيقا پيش بياد اصلا منطقي نيست الآن اينجا مثلا روي لوكال و آنلاين بحث شده حالا بيايم تراكنشهايي كه از سمت لوكال مياد رو هم فرض كنيم يه تراكنش از سمت آنلاينه كه اين هم منطقيه و هيچ فرقي به حال بانكمون نميكنه (البته با اين فرض كه يه بانك داريم و اون هم روي سروره) چون قراره مجموعه اي از تراكنشها بيان و انجام بشن.
خب پس ميشه گفت اگر لوكال رو هم در نظر نگيريم با اين تفاصيل كه هست بايد روي درخواستهايي هم كه در سمت آنلاين داريم مشكل داشته باشيم ديگه مثلا همين مثال جناب eshpilen مگه نميشه كه رو دوتا درخواست از سمت كاربران آنلاين پيش بياد؟
مگه ميشه كه نشه، ميشه ولي چرا اينجا هيچ مشكلي نداريم و هر كسي در هر زماني هر تراكنشي ايجاد ميكنه هيچ مشكلي پيش نمياد؟
از زماني كه يادمه دبيرستان بوديم اين طور مثائل تو كتابهاي ما بود و حل شده هم بود و به ما ياد ميدادنشون (كه هيچ وقتم چيزي ازشون ياد نگرفتم به شخصه ولي حل شده بود :لبخند: ) كه همون مبحث قفل هاي اشتراكي و انحصاري هست كه جناب eshpilen بهتر هم ميدونن چطور پيش مياد (راستش اينا رو كه گفتن منم يه چيزايي يادم اومد :لبخند: )
حالا فكرشم نميشه كرد كه رو بانكهاي اطلاعاتي كه مهمترين نمونه بارز همين مثئله هست پياده سازي نشده باشه.
در كل ميخوام اينو بگم كه هيچ وقت نميشه 2 تا كوئري مربوط به يه كار كه حتي 1% احتمالش بره تو كار هم اختلال ايجاد ميكنن در يك زمان اجرا نميشه و 100% خود پيكر بندي اين سيستم ها طوريه كه صف انتظار انجام تراكنش دارن دقيقا براي جلوگيري از همين برخورد 2 كوئري مثل هم با هم.
----
حالا اگر اين مورد قبول واقع بشه كه صف انتظار داريم و تمام تراكنش ها همزمان اجرا نميشن (كه بازم شايد من اشتباه ميكنم تو اين قضيه) قسمت دوم هم يعني تراكنشهاي لوكال هاست در صورتي كه حتي دو تا بانك باشه هم قابل حله كه برخورد نداشته باشن.

colors
سه شنبه 14 آبان 1392, 16:51 عصر
در كل ميخوام اينو بگم كه هيچ وقت نميشه 2 تا كوئري مربوط به يه كار كه حتي 1% احتمالش بره تو كار هم اختلال ايجاد ميكنن در يك زمان اجرا نميشه و 100% خود پيكر بندي اين سيستم ها طوريه كه صف انتظار انجام تراكنش دارن دقيقا براي جلوگيري از همين برخورد 2 كوئري مثل هم با هم.
این صف انتظاری که چند پست بالاتر و اینجا بهش اشاره شد رو, میخواستم خودم پیاده سازی کنم ولی ...

حالا اگر اين مورد قبول واقع بشه كه صف انتظار داريم و تمام تراكنش ها همزمان اجرا نميشن (كه بازم شايد من اشتباه ميكنم تو اين قضيه) قسمت دوم هم يعني تراكنشهاي لوكال هاست در صورتي كه حتي دو تا بانك باشه هم قابل حله كه برخورد نداشته باشن.
اینجا متوجه نشدم چی گفتی, چطوری قابله حله؟

eshpilen
سه شنبه 14 آبان 1392, 18:41 عصر
به نظر من ارسال داده ها در يك زمان به سرور كه اين وسط واسه كوئري ها پيش مياد و دوستان ميگن كه شايد هر دو در يك زمان دقيقا پيش بياد
برای اینکه کوئری های چند درخواست با هم تداخل کنن نیازی نیست که دقیقا همزمان باشن.
من اکثرا میگم همزمان یا تقریبا همزمان، که افراد راحتتر درک کنن، ولی درواقع بحث زمانهای کوچک هست که در شرایط خاص میتونه تا چندین ثانیه هم برسه.
هیچ لزومی نیست که دقیقا همزمان باشن.


اصلا منطقي نيست الآن اينجا مثلا روي لوكال و آنلاين بحث شده حالا بيايم تراكنشهايي كه از سمت لوكال مياد رو هم فرض كنيم يه تراكنش از سمت آنلاينه كه اين هم منطقيه و هيچ فرقي به حال بانكمون نميكنه (البته با اين فرض كه يه بانك داريم و اون هم روي سروره) چون قراره مجموعه اي از تراكنشها بيان و انجام بشن.منکه نفهمیدم چی گفتی.


خب پس ميشه گفت اگر لوكال رو هم در نظر نگيريم با اين تفاصيل كه هست بايد روي درخواستهايي هم كه در سمت آنلاين داريم مشكل داشته باشيم ديگه مثلا همين مثال جناب eshpilen مگه نميشه كه رو دوتا درخواست از سمت كاربران آنلاين پيش بياد؟چرا میشه.


مگه ميشه كه نشه، ميشه ولي چرا اينجا هيچ مشكلي نداريم و هر كسي در هر زماني هر تراكنشي ايجاد ميكنه هيچ مشكلي پيش نمياد؟خب بستگی داره به برنامه، میزان ترافیک، نوع عملیات کاربران،و شانس و غیره.
مشکلات همزمانی چیزی نیست که هرجایی پیش بیاد یا هر زمانی پیش بیاد.
یه مواقع خاصی که همهء شرایط تصادفا (یا عمدا!) فراهم بشه، اونوقت تداخل پیش میاد.
از بین این تداخل هایی هم که پیش میاد، بعلت آمار پایین اونا، و اینکه در خیلی کاربردها مشکل و خسارت مهمی ایجاد نمیکنن، افراد کمی ممکنه متوجه تعداد کمی از اونا بشن. تازه افرادی که دقت و حوصلهء کافی داشته باشن و علت مسئله رو دنبال و پیدا کنن (که نیاز به دانش و بینش و مهارت کافی داره). اکثر افراد ممکنه فکر کنن اینکه مثلا یه روز یه داده ای خراب شد یه اتفاق دیگه ای بوده، یجورایی شانسی بوده، تقصیر چیز دیگه ای بوده، یا بهرحال حوصله ندارن یا نمیتونن و بیخیالش میشن.
بهرحال هر برنامه و عملیاتی و هر تراکنشی اونقدری مهم نیست که این مسئله توش مطرح باشه و به چشم بیاد و جدی گرفته بشه.
ولی مثلا در تراکنشهای مالی این مهم میشه.
بخاطر همین اگر از کسانی که در صنعت بانکداری و تجارت الکترونیک برنامه نویسی میکنن و تجربش رو دارن بپرسید، احتمالا خیلی بیشتر با این مسئله و راهکارهاش آشنا هستن.
بنده هم تجربهء عملی چندانی ندارم اما مثلا یک بار که برنامهء خودم رو با یک اسکنر امنیتی اسکن میکردم اینطور تداخل ها رو مشاهده کردم و پیگیر شدم و علتش رو حدس زدم. کس دیگری بود مسلم بدونید یا اصلا متوجه نمیشد یا پیگیری نمیکرد یا اصلا هرچی فکر میکرد بازم نمیتونست بفهمه. نمیخوام از خودم تعریف کنم، ولی اینطور باریک بینی ها و کشف باگهای ظریف کار هرکسی نیست. بلکه کار کسانی هست که 100 بار یه چیزی رو تست میکنه، یه بار میبینه یه کاراکتر نقطه یجا اضافه شده، یا یک چیزی چند پیکسل جاش تغییر کرد، یه چیزی درست کار نکرد، بیخیال نمیشه، نمیگه شانسی بود، بلکه میره ته و توش رو دربیاره که اون نقطه هه یا اون 2 پیکسل فضای اضافی از کجا اومد فلان چیز چرا اجرا نشد چی شد چطور شد منشاء چی بود! من همچین آدمی بودم همیشه؛ کوچکترین چیزی حتی یک بار تصادفا میدیدم، میرفتم دنبالش حالا یا ذهنی یا اگر میشد تست هم میکردم تا دست آخر بفهمم علتش چی بوده.


حالا فكرشم نميشه كرد كه رو بانكهاي اطلاعاتي كه مهمترين نمونه بارز همين مثئله هست پياده سازي نشده باشه.مثل اینکه که بگی چرا جلوگیری از SQL Injection در بانکهای اطلاعاتی پیاده سازی نشده.
نه عزیزم اینطور نیست که خود برنامه بتونه همهء این موارد رو بطور خودکار شناسایی و حل کنه.
بلکه خیلی جاها نیاز به تشخیص برنامه نویسه. این وظیفهء برنامه نویسه و هیچ نرم افزاری نمیتونه تمام این موارد رو بطور خودکار پوشش بده. بنابراین امکانات لازم برای جلوگیری از این موارد رو در اختیار برنامه نویس قرار دادن. این برنامه نویسه که باید بفهمه کجا باید از چه امکاناتی چرا استفاده کنه.
همونطور که مثلا توابع اسکیپ رو گذاشتن برای جلوگیری از SQL Injection، و این شما هستید که باید جای استفاده از اونا رو بفهمید و استفاده کنید، توابع و امکانات مربوط به مدیریت دسترسی همزمان رو هم گذاشتن، که شما خودتون باید بفهمید و استفاده کنید.
این مواردی که مد نظر منه چیزی نیست که تشخیص و حلش در سطح بانک اطلاعاتی باشه. در سطح کد و الگوریتمه و منطق برنامس، که فقط خود برنامه نویس میتونه ازش بطور کامل و دقیق مطلع باشه.
اون مواردی هم که در سطح بانک اطلاعاتی هستن، خب طبیعتا در همون سطح پیاده سازی شده و بصورت خودکار انجام میشن و ما بطور معمول باهاشون کاری نداریم.



در كل ميخوام اينو بگم كه هيچ وقت نميشه 2 تا كوئري مربوط به يه كار كه حتي 1% احتمالش بره تو كار هم اختلال ايجاد ميكنن در يك زمان اجرا نميشه و 100% خود پيكر بندي اين سيستم ها طوريه كه صف انتظار انجام تراكنش دارن دقيقا براي جلوگيري از همين برخورد 2 كوئري مثل هم با هم.شما اصلا قضیه رو متوجه نشدید.
مثالهایی که من زدم پس چی هستن؟
میخواید براتون نمونه کد و تست عملی هم بذارم؟

eshpilen
سه شنبه 14 آبان 1392, 18:50 عصر
متاسفانه باید بگم سطح برنامه نویسان از نظر پایه خیلی پایینه.
هیچی نمیدونید از مسائل ظریف.
از همزمانی چیزی نمیدونید، از تداخل چیزی نمیدونید، از امنیت چیزی نمیدونید، از الگوریتم هم چیز زیادی نمیدونید.
ولی من اینقدر روی اینا تحقیق و تفکر داشتم که صرفا ذهنی میتونم خیلی از مسائل و باگها رو پیشبینی کنم. مواردی که بیشتر بقیهء افراد ممکنه هیچوقت متوجه وجود اونا هم نشن!

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

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

H:Shojaei
سه شنبه 14 آبان 1392, 22:34 عصر
اول بگم كه من اصلا در حد اين بحثا نيستم كه خيالتون راحت بشه و راحتتر جواب بدين بدون هيچ توهيني كه شايد پيش بياد تو تاپيكاي بعدي.:لبخندساده:

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

همون طور كه خودتون هم گفتيد بحث سر ميلي ثانيس و با توجه به سرعتي كه تو اين طور عمليات هست براي اين كه يه تراكنشي بخواد با يكي ديگه تداخل داشته باشه بايد تو هزارم ميلي ثانيه اين انجام بشه كه خيلي خيلي دور از انتظاره درسته و من نميدونم اگر پيش بياد چطور ميشه فهميد يا تشخيص داد...


خب بستگی داره به برنامه، میزان ترافیک، نوع عملیات کاربران،و شانس و غیره.
مشکلات همزمانی چیزی نیست که هرجایی پیش بیاد یا هر زمانی پیش بیاد.
...........
تا دست آخر بفهمم علتش چی بوده.

خب ايني كه شما ميفرماييد درست ولي الآن واقعا اين مساله مبهمه چون تا حالا تو دنياي واقعي پيش نيومده يا اگرم پيش اومده ما ازش بي خبريم پس به اين نميشه استناد كرد كه شايد يه جايي يه خطايي باعثش اين تداخلها باشه و چون اون شخص دنبالش نرفته اين موضوع مبهم مونده تا يه مثال واقعي نباشه نميشه بهش استناد كرد...


مثل اینکه که بگی چرا جلوگیری از SQL Injection در بانکهای اطلاعاتی پیاده سازی نشده.
...
این شما هستید که باید جای استفاده از اونا رو بفهمید و استفاده کنید، توابع و امکانات مربوط به مدیریت دسترسی همزمان رو هم گذاشتن، که شما خودتون باید بفهمید و استفاده کنید.

والا من كه هرچي سرچ كردم هيچ چيزي در رابطه با اين مدريت زمان در پايگاه داده ها حتي يه سر نخ هم پيدا نكردم چه برسه به تابع و اين طور چيزا...
اگر هست ما رو هم راهنمايي كنيد بريم ياد بگيريم.
و يه چيز ديگه به هيچ عنوان اصلا نميشه بحث Sql Injection رو با اين بحث يكي كرد چون اصلا يكي دوست داره تمام كاراكتر ها مجاز باشن و اگر اين از سمت خود بانك جلي گيري بشه يه نوع محدوديت محسوب ميشه و باعث شايد كم شدن طرفداراش كه اينو نميخواد قطعا و يه چيز ديگه هم اين كه مدريت زمان كار كاربر نيست كه بخواد خودش تو پروژه هاش انجام بده چون هيچ وقت اونا كاربرا شونو در اين سطحي كه شما تصور ميكنيد تصور نميكنن. ;)


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

يعني شما ميفرماييد كه يه بانك اطلاعاتي هيچ الگوريتمي پشتش نيست و حتي اگرم باشه اين مبحث هم كلا تو اونا نميگنجه!!
در اين باره يه جستو جويي زدم يه جا اينو نوشته بود (البته فكر ميكنم موصق نبود ولي تنها چيزي كه من پيدا كردم همين بود):
مديريت تداخل اطلاعات:
اين نوع مديريت مربوط به سرويسهاي بانكهاي اطلاعاتي در سطح شبكه مي باشد كه وظيفه كنترل دستيابي به فايلها را براي جلوگيري از تداخل دسترسي همزمان به فايلها را بر عهده دارد.
واقعا ميشه يه مساله به اين مهمي رو بيان واگذار كنن به كاربر بگن آقا شما هركار دوست داري بكن بلدي از خطاهاي احتمالي جلوگيري كن بلدم نيستي...!!!
و اگرم خطايي وجود داشته باشه كه اونا نتونسته باشن جلوشو بگيرن ديگه واي به حال باقيه البته نميخوام خودمونو دست كم بگيرم كه باز روشنفكران عزيز بريزن اينجا.
ولي يه كم فكر كنيم ميبينيم يه گروه معلوم نيست چند نفري از متخصصين نشستن اين كارو كردن حالا از اين چشم پوشي كردن ميشه!!!


شما اصلا قضیه رو متوجه نشدید.
مثالهایی که من زدم پس چی هستن؟
میخواید براتون نمونه کد و تست عملی هم بذارم؟
خب حالا من يه مثال تو همون سبك خودتون ميزنم كه شما حدس بزنيد من فهميدم يا نه:
يه فيلد داريم كه مثلا مال ثبت نام يا يه مسابقس
حالا قراره 1000 نفر كه تعدادشون از قبل مشخصه تو يه ساعت جواب بدن به اون مسابقه يا ثبت نام كنن توش
حالا به نظر شما اون طور كه شما گفتيد بايد حداقل يه بار يه اختلال رخ بده و يه پاسخ ثبت نشه ديگه درسته
اصلا مسابقه نه چند نمونه مشابه هست كه تعداد تراكنشها مشخصه و بايد به همين ترتيبي كه هست اجرا بشن اينا به مشكل نخوردن!! حالا يكيشون مهم نبوده و مشكلشو نگفته كه 999 تا جواب داشتيم اوناي ديگه چي...
حالا تمام كساني كه اين برنامه ها رو نوشتن مدريت زمان انجام دادن؟ كه اين مشكل براشون پيش نيومده يا ميدونستن كه بايد انجام بدن يا نه اصلا پيش نيومده.
اگر مشكلي تو اين نوع پيش بياد كم كه نداريم از اين نمونه برنامه ها پس اگر خطايي بوجود اومده باشه بايد تو نت پر باشه از اين خطاها و مدريتشون ديگه.

MMSHFE
سه شنبه 14 آبان 1392, 23:31 عصر
تا جایی که میدونم، اگه به درستی از قفلها استفاده بشه، DBMS به اندازه کافی در زمینه مدیریت صف درخواستها خوب عمل میکنه. برای مثال، برنامه ای مثل نود رو درنظر بگیرین که با سیستم پیامک کار میکنه و به محض درخواست دادن، توی دیتابیس ثبت میشه. خوب در اینجا با اون حجم مشارکت مردم، خیلی پیش میاد که درخواستهایی همزمان برسن (البته باز هم نه کاملاً همزمان چون CPU توی فرکانسی داره کار میکنه که برای مثال، کوچکترین واحد زمانیش (Tick) چیزی بین 2 تا 3 میلیاردم ثانیه است. حالا چقدر احتمال داره توی این فاصله کوچک زمانی، دو درخواست دقیقاً همزمان برسن؟! اگه به فرض هم رسیدن، به محض اینکه یکیشون وارد شد، میتونه قفل بگذاره روی جدول و بقیه توی نوبت میمونن تا قفل آزاد بشه. بعلاوه توی لینوکس با نصب پکیج mysql-queues میشه این مدیریت رو بهتر کرد. بهتره درمورد Management of concurrent or simultaneous requests in MySQL یا بطور کلی هر DBMS دیگه، تحقیق مفصلی داشته باشین. کار با دیتابیس که فقط در حد یک کوئری ساده فرستادن نیست. اونهم توی پروژه هایی با حساسیت بالا. قفلها و سایر ابزارها هم برای تفریح گذاشته نشدن. یک مدیر دیتابیس قوی، از تمام این ابزارها برای جلوگیری از مشکلات احتمالی، استفاده بهینه میکنه.

eshpilen
چهارشنبه 15 آبان 1392, 08:12 صبح
همون طور كه خودتون هم گفتيد بحث سر ميلي ثانيس و با توجه به سرعتي كه تو اين طور عمليات هست براي اين كه يه تراكنشي بخواد با يكي ديگه تداخل داشته باشه بايد تو هزارم ميلي ثانيه اين انجام بشه كه خيلي خيلي دور از انتظاره درسته و من نميدونم اگر پيش بياد چطور ميشه فهميد يا تشخيص داد...
نخیر همش اشتباهه.
بحث میلی ثانیه نیست.
تازه همون میلی ثانیه هم باشه خیلی دور از انتظار نیست و اتفاقا میتونه زیاد پیش بیاد.
فکر کردید سرور چیه؟
سرورها معمولا چندین CPU دارن، هر CPU چندین هسته داره.
این همه مغز پردازنده واسه چیه؟
واسه پردازش موازی/همزمان است دیگه!
بعد اونوقت میگید دیتابیس رو جوری درست کردن که میاد و کوئری ها رو دونه دونه اجرا میکنه؟
اینطور هیچ استفاده ای از این منابع سخت افزار افزوده نمیشه. انگار که داره با یه PC قدیمی کار میکنه.
مثلا 1000 تا کوئری میرسه به دیتابیس، اگر هرکدام یک دهم ثانیه بخواد طول بکشه، درخواست آخر 100 ثانیه باید منتظر بمونه.
البته این اجرای همزمان همونطور که قبلا اشاره کردم واسه درخواستهای read هست. چون در سطح دیتابیس هر تعداد درخواست read همزمان مشکلی ایجاد نمیکنن، ولی write اینطور نیست.


خب ايني كه شما ميفرماييد درست ولي الآن واقعا اين مساله مبهمه چون تا حالا تو دنياي واقعي پيش نيومده يا اگرم پيش اومده ما ازش بي خبريم پس به اين نميشه استناد كرد كه شايد يه جايي يه خطايي باعثش اين تداخلها باشه و چون اون شخص دنبالش نرفته اين موضوع مبهم مونده تا يه مثال واقعي نباشه نميشه بهش استناد كرد...خب منکه چند دفه گفتم میخواید براتون تست بنویسم.
ولی کسی نگفت باشه بنویس ببینیم.
چرا؟
اگر هم انتظار دارید منتظر باشیم یجا این پدیده رو مشاهده کنیم، خب نمیشه که! تا چه وقت صبر کنیم، چطوری متوجه بشیم...
بعضی چیزها رو حتی تست هم نمیشه کرد درحال حاضر، ولی از نظر تئوریک میشه و باید اونا رو پیشبینی و براشون تمهید کرد. مثلا در مسائل امنیتی و رمزنگاری اینطوریه. خیلی موارد رو من و شما امکانات یا وقتش رو نداریم تست کنیم، اما امروز یا فردا یکی دیگه ممکنه داشته باشه.
اون برنامه نویسی که فقط به موارد تجربی اشراف داشته باشه و اونا رو درنظر بگیره، سطح خودش پایینه از نظر علمی! همه چیز که اینطوری تجربی نیست آخه!
شاید بخاطر همینه که مردم میرن از خودشون الگوریتم رمزنگاری اختراع میکنن و وقتی خودشون و دونفر غیرمتخصص دیگه مثل خودشون نمیتونن اون رو بشکنن، فکر میکنن همه چیز حله!
یه چیزایی هست به ظاهر درست کار کردنش دلیل بر درستیش نیست. علم و تئوری هم میخواد. معیارهای بیشتر و مطمئن تری نیاز داره.


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


و يه چيز ديگه به هيچ عنوان اصلا نميشه بحث Sql Injection رو با اين بحث يكي كرد چون اصلا يكي دوست داره تمام كاراكتر ها مجاز باشن و اگر اين از سمت خود بانك جلي گيري بشه يه نوع محدوديت محسوب ميشه و باعث شايد كم شدن طرفداراش كه اينو نميخواد قطعاتصورت از علت این قضیه هم نشون میده که درست درکش نکردی.
اصلا پرداختن به این موضوع در سطح بانک اطلاعاتی نیست و بهش ربطی نداره.
بانک اطلاعاتی از کد برنامهء شما اطلاعی نداره که بفهمه اون کوئری که بهش میاد فلان کاراکترهاش رو مثلا برنامه نویس مستقیما ننوشته و از ورودی های کاربر اومدن.
بانک اطلاعاتی فقط یکسری کوئری رو از برنامهء شما دریافت میکنه که طبیعتا شامل هردوی فرامین SQL و دیتا میشن.


و يه چيز ديگه هم اين كه مدريت زمان كار كاربر نيست كه بخواد خودش تو پروژه هاش انجام بده چون هيچ وقت اونا كاربرا شونو در اين سطحي كه شما تصور ميكنيد تصور نميكنن. ;) هان؟ :متفکر:


اين نوع مديريت مربوط به سرويسهاي بانكهاي اطلاعاتي در سطح شبكه مي باشد كه وظيفه كنترل دستيابي به فايلها را براي جلوگيري از تداخل دسترسي همزمان به فايلها را بر عهده دارد.
واقعا ميشه يه مساله به اين مهمي رو بيان واگذار كنن به كاربر بگن آقا شما هركار دوست داري بكن بلدي از خطاهاي احتمالي جلوگيري كن بلدم نيستي...!!!
و اگرم خطايي وجود داشته باشه كه اونا نتونسته باشن جلوشو بگيرن ديگه واي به حال باقيه البته نميخوام خودمونو دست كم بگيرم كه باز روشنفكران عزيز بريزن اينجا.
ولي يه كم فكر كنيم ميبينيم يه گروه معلوم نيست چند نفري از متخصصين نشستن اين كارو كردن حالا از اين چشم پوشي كردن ميشه!!!میگم شما هنوز موضوع و موارد مورد نظر رو متوجه نشدید، وگرنه میفهمیدید که به بانک اطلاعاتی ربطی نداره.
بله DBMS هم در سطح خودش با چنین مسائلی مواجه هست و اونا رو لحاظ کرده و بطور خودکار انجام میده. ولی اینطور مسائل در سطح بالاتر و منطق و الگوریتم برنامه هم وجود دارن که بانک اطلاعاتی اصولا نمیتونه ازشون اطلاعات کافی داشته باشه که اونا رو مدیریت کنه. بانک اطلاعاتی فقط کوئری هایی رو که دریافت میکنه اجرا میکنه. دیگه روی زمانبندی و اینکه هر کوئری از چه درخواستی اومده و منظور چند کوئری روی هم چی بوده، نظری نداره. مثلا اگر درخواست A دوتا کوئری 1 و 2 میفرسته، و درخواست B هم همینطور، بانک اطلاعاتی ممکنه اول کوئری A1 رو دریافت کنه و توی صف بذاره، بعد کوئری B1 رو دریافت کنه و توی صف بذاره، بعد کوئری A2، و بعد کوئری B2، و به همین ترتیب هم که دریافت کرده اجرا میکنه، نه اینکه بگه اول باید کوئری های درخواست A رو اجرا کنم و بعد کوئری های درخواست B رو. این هم که کوئری ها با چه ترتیبی به بانک اطلاعاتی برسن در کنترل بانک اطلاعاتی نیست و به الگوریتم و اولویت اجرای سیستم عامل برای برنامه ها که تحت تاثیر هزارتا پارامتر غیرقابل پیشبینی دقیق است بستگی داره.
بانک اطلاعاتی مدیریت فقط در سطح خودش داره. یعنی مثلا موقعی که یک کوئری داره توی یک رکوردی write میکنه، هیچ کوئری read ای رو روی اون رکورد اجرا نمیکنه. همینطور وقتی در یک زمان یک یا چند کوئری read دارن یک رکوردی رو میخونن، هیچ کوئری write ای رو روی اون رکورد اجرا نمیکنه و در صف نگه میداره. این اون مدیریتی هست که شما بهش اشاره میکنید و بانک اطلاعاتی خودش انجام میده، نه اون مواردی که بنده بهش اشاره دارم و برنامه نویس باید صریحا براشون چاره بکنه.


حالا قراره 1000 نفر كه تعدادشون از قبل مشخصه تو يه ساعت جواب بدن به اون مسابقه يا ثبت نام كنن توش
حالا به نظر شما اون طور كه شما گفتيد بايد حداقل يه بار يه اختلال رخ بده و يه پاسخ ثبت نشه ديگه درستهخیر در این مورد مسئله ای نداریم. چون جواب هر نفر در یک رکورد جداگانه ثبت میشه. اینجا منبع مشترکی وجود نداره.
اون مواردی که من میگم وقتی پیش میان که 1- یک داده ای بین کوئری ها مشترک باشه 2- در درخواستها ترکیبی از کوئری های read و write داشته باشیم 3- منطق برنامه طوری باشه که نباید کوئری های یک درخواست بین کوئری های درخواست دیگر اجرا بشن.

پس میبینید که این سه شرط همزمان باید بروز کنن.
بخاطر همینه که چنین مسئله ای در عمل هرجا و هر موقعی پیش نمیاد و آمارش کمه.


اصلا مسابقه نه چند نمونه مشابه هست كه تعداد تراكنشها مشخصه و بايد به همين ترتيبي كه هست اجرا بشن اينا به مشكل نخوردن!! حالا يكيشون مهم نبوده و مشكلشو نگفته كه 999 تا جواب داشتيم اوناي ديگه چي...یه مثال واقعی و دقیق بزنی بهتره.
ولی فکر کنم اونایی که من مثال زدم همین باشن دیگه.
ضمنا میشه تست هم کرد.
البته اینم درنظر بگیر که ممکنه در خیلی موارد طرفها راهکارهایی رو برای این قضیه انتخاب کرده باشن. مثلا شاید کوئری هایی که باید به ترتیب اجرا بشن در یک ترنزکشن قرار داده شده باشن (و ممکنه هدف طرف از استفاده از تزنزکشن هم اصلا این مسئلهء تداخل کوئری ها نبوده باشه).
البته بنده چون ترنزکشن تاحالا کار نکردم در این مورد که چه تضمین هایی میده و آیا ترتیب کوئری های چند درخواست رو حفظ میکنه یا نه مطمئن نیستم و احتمالا سرفرصت باید تست کنم تا مطمئن بشم.


اگر مشكلي تو اين نوع پيش بياد كم كه نداريم از اين نمونه برنامه ها پس اگر خطايي بوجود اومده باشه بايد تو نت پر باشه از اين خطاها و مدريتشون ديگه. توی نت خطا زیاد هست (حالا نمیگم علت همش دقیقا همین مسئله مورد بحث ما بوده).
ولی گوش کسی بدهکار نیست.
من خودم زیاد دیدم.
طرف پیامی که نوشته مثلا راست و چپ و بهم ریختگی ترکیب فارسی و انگلیسی رو درست نمیکنه، درحالیکه راه حل داره و سخت هم نیست؛ پس به همین شکل خطاهایی که گهگاه ممکنه در برنامش پیش بیان رو هم ممکنه حل نکنه یا اصلا نتونه علتش رو بفهمه و حل کنه. همه که اینقدر دقیق و جدی نیستن. و هر برنامه و هر عملیاتی هم اونقدر اهمیت نداره که مجبور بشن درستش کنن. همونطور که گفتم این مسائل بیشتر در مواردی که مثلا عملیات بانکی و مالی و اینطور چیزها هست اهمیت زیادی پیدا میکنه و غیرقابل نادیده گیری میشه.
هر موردی هم مشخص نمیشه.
مثلا کی چطوری میخواد بفهمه یک شمارندهء تعداد بازدید سایت که الان عددش روی 20984 است درواقع باید 10 تا بیشتر میبود؟ 10 تا بازدید بخاطر تداخل کوئری ها شمرده نشدن، اما معلومه که هیچوقت کسی متوجه این نخواهد شد.

eshpilen
چهارشنبه 15 آبان 1392, 08:25 صبح
تا جایی که میدونم، اگه به درستی از قفلها استفاده بشه، DBMS به اندازه کافی در زمینه مدیریت صف درخواستها خوب عمل میکنه.
خب دیگه ما هم همین رو گفتیم.
باید قفل رو برنامه نویس استفاده کنه.


برای مثال، برنامه ای مثل نود رو درنظر بگیرین که با سیستم پیامک کار میکنه و به محض درخواست دادن، توی دیتابیس ثبت میشه. خوب در اینجا با اون حجم مشارکت مردم، خیلی پیش میاد که درخواستهایی همزمان برسن (البته باز هم نه کاملاً همزمان چون CPU توی فرکانسی داره کار میکنه که برای مثال، کوچکترین واحد زمانیش (Tick) چیزی بین 2 تا 3 میلیاردم ثانیه است. حالا چقدر احتمال داره توی این فاصله کوچک زمانی، دو درخواست دقیقاً همزمان برسن؟! اگه به فرض هم رسیدن، به محض اینکه یکیشون وارد شد، میتونه قفل بگذاره روی جدول و بقیه توی نوبت میمونن تا قفل آزاد بشه.
مهندس شما هم مثل اینکه قضیه رو اونطور که باید نگرفتی.
اگر پست قبلی بنده رو بخونید فکر کنم روشن بشید.
اصلا نیازی نیست که دو درخواست دقیقا همزمان برسن. اختلاف میتونه تا چند ثانیه هم برسه.


کار با دیتابیس که فقط در حد یک کوئری ساده فرستادن نیست. اونهم توی پروژه هایی با حساسیت بالا. قفلها و سایر ابزارها هم برای تفریح گذاشته نشدن.
منم همین رو گفتم. خیلی خوبه که شما هم صریحا تایید کردید تا اونایی که فکر میکنن اینا همش حرف من یک نفر هست یخورده بیشتر دقت کنن.

MMSHFE
چهارشنبه 15 آبان 1392, 09:31 صبح
حق با جناب eshpilen هست. ببینید، DBMS صف داره ولی یک صف ساده که درخواستها توی نوبت قرار بگیرن برای اجرا. حالا فرض کنید یک اسکریپت 10 تا کوئری میخواد بفرسته و بین این درخواستها هم یکسری پردازش توی خود اسکریپت انجام میشه. خوب احتمالش کم نیست که چند نفر همین اسکریپت رو درخواست کنن و بنا به مسائلی مثل فشار روی CPU سرور یا آماده نبودن منبعی که توی اسکریپت بهش نیاز هست و یا هر موضوع دیگه، کوئری 1 از درخواست 1 بره برای دیتابیس و بعد درخواست 1 وارد حلقه توی اسکریپت بشه و توی این فاصله، کوئری 1 از درخواست 2 برسه به دیتابیس. اینجا اگه اسکریپت 1 نیاز داره که جدول تا پایان اسکریپت تغییری نکنه، باید جدول رو قفل کنه تا درخواستهای بعدی تا وقتی که قفل آزاد نشده باشه، توی صف بمونن و پردازش نشن. وظیفه DBMS نیست که منطق برنامه شما رو بدونه.

eshpilen
چهارشنبه 15 آبان 1392, 11:32 صبح
اینم یه مثال ساده.
فایل ضمیمه رو دانلود کنید.

دیتابیس test رو ایجاد کنید اگر وجود نداره.
فایل sql جدول test هم که توی فایلها هست ایمپورت کنید تا جدولش ایجاد بشه.

بعد در مرورگر هر دو فایل test.php و test2.php رو با سرعت باز کنید.
من یه ‎sleep(10)‎ توی کد بین کوئری read و write گذاشتم، که هم قضیهء تداخل کوئری ها رخ بده و هم فرصت داشته باشید هر دو صفحه رو در مرورگر باز کنید (برای سرعت بیشتر میتونید آدرس هر دو رو از قبل در آدرسبار دو تب جداگانه بنویسید و بعد برای اجرای هر دو فقط وارد آدرسبار هر تب شده و اینتر رو بزنید).

کد رو اینجا هم میذارم تا بدون دانلود کردن هم بشه بررسیش کرد و متوجه قضیه بشید:


<?php

error_reporting(E_ALL);
ini_set('display_errors', '1');

header('Content-Type: text/html; charset=utf-8');
header("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT");
header("Expires: Mon, 26 Jul 1997 05:00:00 GMT");
header("Cache-Control: private, no-store, no-cache, must-revalidate, post-check=0, pre-check=0, max-age=0");
header('Pragma: private');
header("Pragma: no-cache");

mysql_connect('localhost', 'root', '');

mysql_select_db('test');

$res=mysql_query('select `counter` from `test`');

$row=mysql_fetch_array($res);

$counter=$row[0];

echo "Read: $counter";

$counter++;

sleep(10);

mysql_query("update `test` set `counter`=$counter");

echo "<br>Write: $counter";

?>

وقتی دو صفحه رو اجرا کنیم بعد در نتیجه مشاهده میکنیم که هردو یک مقدار رو خوندن و یکی بهش اضافه کردن، و در نتیجه به شمارنده فقط یک واحد اضافه شده (میتونید با phpmyadmin هم مستقیما روی جدول صحت این قضیه رو بررسی کنید)، درحالیکه باید دوتا اضافه میشد چون دو درخواست جداگانه اجرا شدن و هدف ما شمردن این درخواستها بوده.

البته این فقط یک مثال ساده بود که اولا ثابت میکنه دیتابیس کوئری ها رو به هر ترتیبی که بهش میرسن اجرا میکنه و کاری به مسائل دیگه (مثل اینکه هر کوئری از کدام درخواست/کانکشن آمده) نداره، دوما اینکه تداخل کوئری های درخواستهای مختلف میتونه باعث اشتباه شدن نتیجه بشه.

ضمنا این فقط مثال بود. الان ما این مورد رو بدون قفل هم میتونیم جلوگیری کنیم با نوشتن کوئری ها به یک شکل دیگه:

mysql_query("update `test` set `counter`=`counter`+1");
یادتون نره بعد از تغییر کوئری های update و اجرای برنامه، مقدار درج شده در جدول رو با phpmyadmin بررسی کنید (خود برنامه درست نشون نمیده).

در این حالت دیتابیس خودش عمل دسترسی همزمان رو مدیریت میکنه، چون تمام عملیات بصورت کوئری مشخص شده و در داخل خود DBMS صورت میگیره، و بنابراین مشکلی پیش نمیاد.
ولی وقتی شما شمارنده رو در خارج از کوئری، و در کد خودتون افزایش میدید، دیتابیس نسبت به این امر امکان آگاهی و مدیریتی نداره (طبیعتا هرچی شما بگید رو کورکورانه اجرا میکنه، که بایدم اینطور باشه).

اینطور موارد ساده رو میشه به روشهایی مثل این حل کرد، اما مسلما همهء موارد اینقدر واضح و ساده نیستن و نمیشه با این روش اونا رو حل کرد. بنابراین باید از تمهیدات دیگری مثل قفل استفاده کرد.

eshpilen
چهارشنبه 15 آبان 1392, 11:39 صبح
سعی میکنم سرفرصت با استفاده از ترنزکشن هم تست انجام بدم و نتیجش رو بذارم.

eshpilen
چهارشنبه 15 آبان 1392, 12:13 عصر
حالا در مثال قبلی ممکنه کسی بگه ثابت نمیکنه که کوئری ها در خود دیتابیس هم میتونن بصورت همزمان اجرا بشن.
این درسته؛ مثال قبلی این مورد رو ثابت نمیکنه، ولی دیدید که برای پیش آمدن تداخل کوئری های چند درخواست، درواقع به این ویژگی اصلا نیازی هم نیست.

MMSHFE
چهارشنبه 15 آبان 1392, 12:18 عصر
در تکمیل توضیحات جناب eshpilen عرض کنم که MySQL مدیریت سشن داره یعنی با تنظیمات پیشفرض، فقط درخواستهای همزمان از یک سشن رو توی صف میگذاره و درنتیجه کلاینتهای مختلف میتونن همزمان کوئری اجرا کنن. البته به شرطی که Process کوئریها قابلیت تفکیک داشته باشه (مثل SELECT چند قسمتی یا Transaction و...) و همچنین پردازنده سرور هم بتونه پردازش موازی رو پشتیبانی کنه (انتظار نداشته باشین این قابلیت روی سیستم Pentium III یک هسته ای کار کنه!)
راه حلش قطعی جلوگیری از پردازشهای موازی هم همونطور که قبلاً گفتم، استفاده صحیح از قفلهاست.

H:Shojaei
چهارشنبه 15 آبان 1392, 12:22 عصر
خب من از صحبتهاي آقاي eshpilen و آقاي شهركي كه اينجا اساتيد منن و من عذر ميخوام كه دارم باهاشون بحث ميكنم اينو فهميدم كه ميفرماييد:
اين كه درخواستها وقتي به سمت db ميرن تو يه صف البته موازي قرار ميگيرن و تا حدودي خود db چك ميكنه كه مثلا اگر يه تيبلي داره توسط يه درخواست edit ميشه
درخواست ديگري نياد و اگرم اومد تو همون صف انتظار احتمالا قرار بگيره كه واسش هم آقاي شهركي اين مثال رو زدن:

کوئری 1 از درخواست 1 بره برای دیتابیس و بعد درخواست 1 وارد حلقه توی اسکریپت بشه و توی این فاصله، کوئری 1 از درخواست 2 برسه به دیتابیس. اینجا اگه اسکریپت 1 نیاز داره که جدول تا پایان اسکریپت تغییری نکنه، باید جدول رو قفل کنه تا درخواستهای بعدی تا وقتی که قفل آزاد نشده باشه، توی صف بمونن و پردازش نش
حالا مشكل اصلي كه بحثش هست تو اين تاپيك و جناب eshpilen دارن روش تاكيد ميكنن طبق اين صحبتاشون:

1- یک داده ای بین کوئری ها مشترک باشه 2- در درخواستها ترکیبی از کوئری های read و write داشته باشیم 3- منطق برنامه طوری باشه که نباید کوئری های یک درخواست بین کوئری های درخواست دیگر اجرا بشن.
اينه كه شايد يه زماني درخواست 1 بره به db و بعد درخواست 2 هم كه در همون رابطه هست ارسال بشه به شرطي كه هر دو هم زمان برسن و در سمت برنامه هيچ كاري براش انجام نشده كه درخواستها مدريت بشن و اون عملياتي كه تو خود الگوريتم db هست و قراره تيبل رو در اختيار يكي از اين دو درخواست بذاره دچار اختلال شه چون دوتا درخواست با يه محتوا داره كه نبايد با هم ميومدن ولي اومدن حالا اگر همه اين اتفاقات پيش بيان يه ثبت اشتباه يه error يا بهم ريختن داده ها پيش مياد منظورتون همينه اين درسته ديگه ..
...................


خیر در این مورد مسئله ای نداریم. چون جواب هر نفر در یک رکورد جداگانه ثبت میشه. اینجا منبع مشترکی وجود نداره.
اون مواردی که من میگم وقتی پیش میان که 1- یک داده ای بین کوئری ها مشترک باشه 2- در درخواستها ترکیبی از کوئری های read و write داشته باشیم 3- منطق برنامه طوری باشه که نباید کوئری های یک درخواست بین کوئری های درخواست دیگر اجرا بشن.
پس میبینید که این سه شرط همزمان باید بروز کنن.
بخاطر همینه که چنین مسئله ای در عمل هرجا و هر موقعی پیش نمیاد و آمارش کمه.

در اين باره كه منبع اشتراكي نداريم ميشه گفت يه فيلد اشتراكي ميتونيم داشته باشيم اون هم فيلد منحصر به فرد آي دي هست...
اگر 2 درخواست ثبت اون طور كه بيان كردين سه حالت روش پيش بياد پس اين رويه كلا دچار مشكل ميشه و بايد نمونه ازش زياد باشه.

eshpilen
چهارشنبه 15 آبان 1392, 12:56 عصر
اينه كه شايد يه زماني درخواست 1 بره به db و بعد درخواست 2 هم كه در همون رابطه هست ارسال بشه به شرطي كه هر دو هم زمان برسن و در سمت برنامه هيچ كاري براش انجام نشده كه درخواستها مدريت بشن و اون عملياتي كه تو خود الگوريتم db هست و قراره تيبل رو در اختيار يكي از اين دو درخواست بذاره دچار اختلال شه چون دوتا درخواست با يه محتوا داره كه نبايد با هم ميومدن ولي اومدن حالا اگر همه اين اتفاقات پيش بيان يه ثبت اشتباه يه error يا بهم ريختن داده ها پيش مياد منظورتون همينه اين درسته ديگه ..
الگوریتم db دچار اختلالی نمیشه.
اون کد نمونه که من گذاشتم رو بررسی کنید ببینید به db ربط داره یا خود برنامه!
در کل وقتی چند کوئری دارید که نباید کوئری دیگری (طبیعتا از درخواست جداگانه ای) بین اونا امکان اجرا شدن داشته باشه، باید قفلی چیزی استفاده کنید.
راستی وقتی میگیم درخواست منظورمون درخواستهای وب هست. یعنی همون Page view و امثالهم.


در اين باره كه منبع اشتراكي نداريم ميشه گفت يه فيلد اشتراكي ميتونيم داشته باشيم اون هم فيلد منحصر به فرد آي دي هست...
اگر 2 درخواست ثبت اون طور كه بيان كردين سه حالت روش پيش بياد پس اين رويه كلا دچار مشكل ميشه و بايد نمونه ازش زياد باشه. اگر آیدی رو به دیتابیس unique معرفی کرده باشید، دو آیدی یکسان هیچوقت در دیتابیس درج نمیشه. ولی خطا ممکنه پیش بیاد. یعنی یک یا چند کوئری با شکست مواجه بشه (بعلت duplicate key error).
و اینم اگر تولید آیدی رو بعهدهء دیتابیس بذارید، یعنی مثلا auto-increment باشه، همچین خطایی هم پیش نمیاد.

یه مثال میزنم.
من توی سیستم رجیستر و لاگین خودم برای ثبت نام کاربر میامدم و اول چک میکردم که ایمیلی که کاربر وارد کرده در دیتابیس وجود داره یا نه (read)، اگر وجود نداشت میامدم و رکورد کاربر جدید رو در دیتابیس درج میکردم (write).
یک بار که با یک اسکنر امنیتی برنامم رو اسکن کردم متوجه شدم که دو اکانت کاربری با یک ایمیل یکسان در دیتابیس ثبت کرده!
فکر کردم چطوری چنین اتفاقی افتاده.
دیدم تنها چیزی که ممکنه باشه اینه که دو درخواست همزمان اومده با یک ایمیل، یا بهرصورتی کوئری های read هردوی این دو درخواستها قبل از کوئری های write اونا اجرا شده، در نتیجه هر دو درخواست از مرحلهء چک کردن عدم وجود ایمیل عبور کردن، و بعدش هم که دو رکورد با یک ایمیل یکسان در دیتابیس درج کردن.
اینجا دیتابیس جلوی این ایمیل تکراری رو نگرفت، چون من فیلد ایمیل رو بعنوان unique به دیتابیس معرفی نکرده بودم. مشکل در کد من بود.
حالا برای رفع این مشکل (در این مورد خاص) دو کار میشه کرد. یک راه اینه که فیلد ایمیل رو در تعریف جدول unique معرفی کرد؛ به این شکل دیتابیس اجازه نمیده دو رکورد با یک ایمیل ثبت بشن، ولی درخواستهای ثبت نام با یک ایمیل یکسان ممکنه با خطای duplicate key مواجه بشن؛ البته چنین چیزی در واقعیت تقریبا پیش نمیاد، چون بعیده دو درخواست ثبت نام با یک ایمیل یکسان به سرور ارسال بشه. ولی همونطور که گفتم مثلا یک اسکنر امنیتی ممکنه به هر دلیلی این کار رو بکنه (شاید در شرایط خاصی که روی سیستم من رخ داد).
راه حل دیگر اینه که قبل از اجرای کوئری read یک قفل بذاریم و بعد از اجرای کوئری write قفل رو آزاد کنیم.
به این شکل در فاصلهء بین اجرای این دو کوئری هیچ کوئری دیگری نمیتونه اجرا بشه (منجمله کوئری های read درخواستهای دیگر).

البته اون روش unique کردن فیلد در همه جا قابل استفاده نیست. فقط در مواردی مثل این میشه استفاده کرد.
مثلا در مثال شمارنده، unique کردن ستون counter هیچ فایده ای نداره و مشکل رو حل نمیکنه، چون تمام مقادیر در یک رکورد ثبت میشن و نه در چند رکورد.

eshpilen
چهارشنبه 15 آبان 1392, 13:18 عصر
شما باید توجه کنید که دیتابیس هیچ ارتباطی با خود PHP نداره.
دیتابیس یه برنامه و سیستم جداگانه است.
خبر نداره توی کد شما چه منطق و کوئری هایی است.
شما فقط به دیتابیس وصل میشید و کوئری ها رو براش میفرستید.
شما دو کوئری میفرستید که از نظر شما بهم مرتبط هستن، مثلا یک مقدار رو میخونید و یکی اضافه میکنید و دوباره با یک کوئری دیگری در دیتابیس آپدیت میکنید، اما از نظر دیتابیس اینا فقط دو کوئری جداگانه هستن و هیچ ارتباطی بین اینها نمیتونه قائل باشه.
بین کوئری های شما اگر کس دیگری هم کوئری دیگری بفرسته، کوئری اون شخص رو اجرا میکنه، ولو اونم همون رکورد و داده های شما رو بخونه یا دستکاری کنه و باعث اختلال در عملیات و دیتای شما بشه. واسه دیتابیس هیچ فرقی نمیکنه کوئری چه زمانی و از کجا میاد. صرفا هرچی از هرجا بهش برسه اجرا میکنه.
دیتابیس صبر نمیکنه تا شما توی برنامتون فکر کنید (یا درواقع همون پردازش) و تمام کوئری هایی رو که مد نظر داشتید اجرا کنید تا بعد بیاد کوئری های اون شخص دیگر رو هم اجرا کنه. دیتابیس اصلا نمیدونه آیا شما کوئری دیگری هم خواهید داشت و چه زمانی.
ارتباط شما با دیتابیس فقط یک کانکشن سوکتی است که مثل لوله میمونه که هر کوئری از طریق اون از برنامهء شما به دیتابیس میرسه. دیتابیس هیچوقت خبر نداره که کوئری بعدی چه زمانی میاد واسه چیه نوعش چیه به کوئری های قبلی ربطش چیه و اصلا میاد یا نه.

H:Shojaei
چهارشنبه 15 آبان 1392, 13:27 عصر
خيلي خيلي خيلي ببخشيد غذز ميخوام كه اينو ميگم ولي مثالي كه براي test اين مشكل گذاشتيد كاملا اشتباهه...
شما يه سطر در جدول دارين كه مقدار فيلد counter برابر با 0 هست...
خب حالا ما تو هردو برنامه ميايم و مقدار اون رو ميخونيم ميذاريم داخل يه متغير counter كه مقدارش در هر دو برنامه ميشه 0 تا اينجا كه مشكلي نيست
حالا شما اومدين همين متغير رو يكي تو هر برنامه اضافه كردين كه تو هر برنامه مقدارش ميشه 1 يعني تا اينجا مقدار counter در هر دو برنامه برابر 1 هست
خب حالا اومدين تو هر دو برنامه همين متغير counter رو كه مقدارش 1 هست رو تو جدول به فيلد counter نسبت دادين.
يعني وقتي مقدار counter ما 1 هست در هز دو برنامه هيچ فرقي نداره كه يكي از برنامه ها اجرا بشن يا هر دو مقدار متغير 1 هست كه اون هم ميره تو جدول...
ديگه تو اين كه فكر نميكنم شبهه اي باشه...
حالا من يه مثال ميزنم تو پست بعدي به همين روش شما كه تست هم شده شما تحليلش كنيد...

eshpilen
چهارشنبه 15 آبان 1392, 13:44 عصر
مشابه این کدی که من گذاشتم خیلی ها برای شمارندهء سایتشون استفاده میکنن.
دو صفحه ای هم که این کد یکسان رو توش گذاشتیم و باز کردیم بجای دو بازدید جداگانه از دو کاربر مستقل فرض کنید.
دو کاربر سایت رو بازدید میکنن، اما به شمارنده فقط یکی اضافه میشه.
چرا؟
چون الگوریتم ما مسئلهء امکان تداخل کوئری های چند درخواست جداگانه رو درنظر نگرفته.
یعنی ممکنه هر دو درخواست که به سرور میرسن، قبل از اینکه کوئری write یکی از اونا اجرا شده بشه، کوئری های read هردو اجرا شده باشه. این یک احتمال همیشگی است و نمیشه تضمین کرد که اینطور نشه، مگر اینکه الگوریتم این مورد رو لحاظ کرده باشه با قفل یا روش دیگری اگر ممکن باشه.

حالا کجاش چطوری به چی بی ربطه، من متوجه نشدم!

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

colors
چهارشنبه 15 آبان 1392, 13:46 عصر
من توی سیستم رجیستر و لاگین خودم برای ثبت نام کاربر میامدم و اول چک میکردم که ایمیلی که کاربر وارد کرده در دیتابیس وجود داره یا نه (read)، اگر وجود نداشت میامدم و رکورد کاربر جدید رو در دیتابیس درج میکردم (write).
یک بار که با یک اسکنر امنیتی برنامم رو اسکن کردم متوجه شدم که دو اکانت کاربری با یک ایمیل یکسان در دیتابیس ثبت کرده!
فکر کردم چطوری چنین اتفاقی افتاده.
دیدم تنها چیزی که ممکنه باشه اینه که دو درخواست همزمان اومده با یک ایمیل، یا بهرصورتی کوئری های read هردوی این دو درخواستها قبل از کوئری های write اونا اجرا شده، در نتیجه هر دو درخواست از مرحلهء چک کردن عدم وجود ایمیل عبور کردن، و بعدش هم که دو رکورد با یک ایمیل یکسان در دیتابیس درج کردن.
یکی از پروژهامو آوردم همین تستو زدم دیدم همین مشکل رو داره! یعنی نباید کاربری بتونه با نام و ایمیل یکسان ثبت نام کنه! ولی وقتی دوتا کوئری همزمان از کروم و فایرفاکس میزدم هردوشون ثبت میشن!
یه usleep متغییر قبل از انجام کوئری گذاشتم مشکل حل شد.

usleep(rand(500000, 1000000));

colors
چهارشنبه 15 آبان 1392, 13:48 عصر
البته کامل حل نشده. ده بار تست کردم 9 بار جلشو گرفت یه بار دوتاشون ثبت شدن

colors
چهارشنبه 15 آبان 1392, 13:50 عصر
الان که نام و ایمیل رو طبق گفته های جناب eshpilen یونیک کردم مشکل کامل حل شده!

eshpilen
چهارشنبه 15 آبان 1392, 13:51 عصر
یکی از پروژهامو آوردم همین تستو زدم دیدم همین مشکل رو داره! یعنی نباید کاربری بتونه با نام و ایمیل یکسان ثبت نام کنه! ولی وقتی دوتا کوئری همزمان از کروم و فایرفاکس میزدم هردوشون ثبت میشن!
یه usleep متغییر قبل از انجام کوئری گذاشتم مشکل حل شد.

usleep(rand(500000, 1000000));

البته کامل حل نشده. ده بار تست کردم 9 بار جلشو گرفت یه بار دوتاشون ثبت شدن

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

colors
چهارشنبه 15 آبان 1392, 13:54 عصر
خب دیگه این به هیچ وجه راه اساسی نیست.
روی زمانبندی و تصادف که نمیشه در یک کار اصولی حساب کرد!

اتفاقا خیلی اساسیه. به سادگی جلوی خطای duplicate key رو میگیره.
پس مشکل حل شد. استفاده از تاخیر و یونیک کردن فیلدهای غیر تکراری

H:Shojaei
چهارشنبه 15 آبان 1392, 14:22 عصر
مشابه این کدی که من گذاشتم خیلی ها برای شمارندهء سایتشون استفاده میکنن.
دو صفحه ای هم که این کد یکسان رو توش گذاشتیم و باز کردیم بجای دو بازدید جداگانه از دو کاربر مستقل فرض کنید.
دو کاربر سایت رو بازدید میکنن، اما به شمارنده فقط یکی اضافه میشه.
چرا؟
چون الگوریتم ما مسئلهء امکان تداخل کوئری های چند درخواست جداگانه رو درنظر نگرفته.
یعنی ممکنه هر دو درخواست که به سرور میرسن، قبل از اینکه کوئری write یکی از اونا اجرا شده بشه، کوئری های read هردو اجرا شده باشه. این یک احتمال همیشگی است و نمیشه تضمین کرد که اینطور نشه، مگر اینکه الگوریتم این مورد رو لحاظ کرده باشه با قفل یا روش دیگری اگر ممکن باشه.

حالا کجاش چطوری به چی بی ربطه، من متوجه نشدم!

دقیقا این مثال یک مورد تداخل درخواستها رو نشون میده. چون اگر مثلا فقط یک صفحه رو رفرش کنید این مشکل هیچوقت پیش نمیاد، اگر فقط یک کاربر باشه این مشکل هیچوقت پیش نمیاد، اما از یکی که بیشتر شد امکان رخداد پیدا میکنه.
بله ميفهمم شما چي ميگيد ولي مثالي كه شما زديد اگر توسط 1 برنامه يا 100000 برنامه هم اجرا بشه يه خروجي داره و يه عملكرد يكسان تو تمام اون 100000 سيستم...
شما در هر صورت تو تمام برنامه ها فيلد رو ميخونيد قبل از اين كه هيچ editي انجام بشه روي فيلد بعد يه مقدار جديد بهش اضافه ميكنيد و بعدشم كه مقدار تو اين 100000 برنامه معلومه چيه رو درج ميكنيد تو تيبل از شما والا بعيده ديگه خودتون يه تريس ديگه بكنيد برنامه ولي از ديد كد يكي ديگه بهش نگاه كنيد ماشالله قدرت نقدتونم كه بالاست ديگه :چشمک:.
-------------------------------
حالا مثال من به همون روش:
فقط واسه لود هم زمان همون sleep كه گذاشتيد هست ولي جهت يادآورري ميگم ctrl رو نگه دارين 2 تا تب رو بگيرين و راست كليك بعدشم reload

با همون جدول و همون فيلد counter البته counter فرقي نداره كه چند باشه يه مقدار داشته باشه فقط.
دو تا برنامه هست كه هركدوم از يه جا اجرا ميشن....
اولي كدش اينه(test.php):


error_reporting(E_ALL);
ini_set('display_errors', '1');

header('Content-Type: text/html; charset=utf-8');
header("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT");
header("Expires: Mon, 26 Jul 1997 05:00:00 GMT");
header("Cache-Control: private, no-store, no-cache, must-revalidate, post-check=0, pre-check=0, max-age=0");
header('Pragma: private');
header("Pragma: no-cache");

mysql_connect('localhost', 'root', '');

mysql_select_db('test');

sleep(10);
mysql_query("update `test` set `counter`=20");
$res=mysql_query("select * from `test`");
$row=mysql_fetch_array($res);
echo $row['counter']."<br />";

----------------
و دومي(test1.php) كدش اينه:


error_reporting(E_ALL);
ini_set('display_errors', '1');

header('Content-Type: text/html; charset=utf-8');
header("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT");
header("Expires: Mon, 26 Jul 1997 05:00:00 GMT");
header("Cache-Control: private, no-store, no-cache, must-revalidate, post-check=0, pre-check=0, max-age=0");
header('Pragma: private');
header("Pragma: no-cache");

mysql_connect('localhost', 'root', '');

mysql_select_db('test');

sleep(10);
mysql_query("update `test` set `counter`=10");
$res=mysql_query("select * from `test`");
$row=mysql_fetch_array($res);
echo $row['counter']."<br />";

حالا طريقه ي كار كردشون:
برنامه ي اول ميره فيلد counter رو به عدد 20 تغيير ميده يعني هرچي كه بود ميشه 20 و برنامه دوم ميره اونو به عدد 10 تغيير ميده موضوع ما اينه كه آيا اين دو تا كوئري با هم تداخلي پيدا ميكنن يه نه به هم ربطي ندارن و هر كدوم جداگانه عملياتشون انجام ميشه....
من اومدم بعد از اين كه فيلد counter رو update كردم بلافاصيه همونجا مقدارش رو از همون سطر بيرون كشيدم و چاپش كردم كه تو هر برنامه اين كار به صورت جداگانه انجام ميشه بنابراين اگر بين اين دو درخواست update تداخل هايي از اين قبيل پيش بياد:
1-كه يكيشون به دليل همزمان بودن اجرا نشه:پس مقداري كه بعد از واكشي انجام ميشه بايد تو هردو تا page كه چاپ شده يكي باشه چون يكي از update ها اجرا نشده.
2-هيچ كدوم اجرا نشه: در اين صورت اصلا فيلدمون تغييري نميكنه.
3-هر دو همزمان اجرا بشن (يعني وقتي اين داره update ميكنه اون هم آپديت كنه): اين كه بايد يا ارور بده كه نميده چون خطايي به اين شكل فكر نميكنم داشته باشيم يا همون اتفاق قبلي يعني يكي از اونا عمل نكنه و قضيه 1 پيش بياد و يا هم قضيه 2.
*3- اين كه هر دو اجرا بشن و هر كدوم مقدار خودشون رو تو جدول قرار بدن حالا يكي زودتر يا يكي ديرتر ولي بالاخره مقادير ست ميشه و كوئري ها به هم ربطي پيدا نميكنن: كه در اين صورت شما متوجه ميشيد كه تو هر page يه مقدار كه درج شده بوده تو كدهاي بعديش واكشي شده و همون چاپ ميشه كه تو هر پيج هم مقدار فرق داره و همون مقداري هست كه درج شده.
ولي يه نتيجه از اين من گرفتم كه كاملا هم طبيعي هست كه هر بار اولويت به يكي از كوئري ها داده ميشه يعني بعد چندين بار تست فهميدم يه بار مثلا كوئري A اول اجرا ميشه چون مقدار نهايي تو بانك مقدار اون بود و يه بار كوئري B.
و در آخر هم اينو بگم كه همين مثال رو تو هر پيج با 100 بار كوئري زدن (تو يه حلقه) انجام دادم يعني 100 تا سطر درج كردم و حالا با دو برنامه اين 100 سطر رو update كردم كه هيچ تداخلي پيش نميومد هر كدوم كار خودش رو انجام ميداد.

eshpilen
چهارشنبه 15 آبان 1392, 14:24 عصر
اتفاقا خیلی اساسیه. به سادگی جلوی خطای duplicate key رو میگیره.
پس مشکل حل شد. استفاده از تاخیر و یونیک کردن فیلدهای غیر تکراری
یونیک کردن فیلد کار خوبیه، ولی جلوی خطای سیستمی دادن به کاربر رو نمیگیره. فقط جلوی درج اطلاعات اشتباه در دیتابیس رو میگیره.
اون بخش اتکا روی زمانبندی و توابع رندومه که اصولی نیست. یعنی ممکنه احتمال خطا دادن رو خیلی کاهش بده، ولی بازم خطا ممکنه در موارد معدودی پیش بیاد.
بعدم از کجا معلوم در جای دیگه در شرایط دیگه یه روز دیگری این خطاها خیلی بیشتر نشدن؟
موضوع اینه که راه حل که اساسی نباشه، نمیشه روی چیزی حساب کرد.
یونیک کردن رو هم گذاشتن در سطح دیتابیس معمولا بعنوان آخرین خط دفاعی و اینکه جلوی خسارت حاصل از باگهای برنامه ها گرفته بشه.
پس اصولی بخوای کار کنی باید یه قفلی چیزی هم در سطح برنامه بذاری. مگر اینکه یوزرفرندلی برات مهم نباشه. آیا خوبه کاربر یه پیام خطای گنده و قرمز Duplicate key error ببینه درحالیکه هیچ خطایی مرتکب نشده و فکر کنه سیستم شما ایراد داره، یا اینکه بجاش سیستم بهش اطلاع بده که نام کاربری یا ایمیل مورد نظر قبلا در سیستم ثبت شده؟
البته در این مورد خاص، یعنی ایمیل، زیاد مشکلی نیست، چون احتمال اینکه افرادی با یک ایمیل یکسان درخواست بفرستن خیلی خیلی کمه.

colors
چهارشنبه 15 آبان 1392, 14:34 عصر
یونیک کردن فیلد کار خوبیه، ولی جلوی خطای سیستمی دادن به کاربر رو نمیگیره. فقط جلوی درج اطلاعات اشتباه در دیتابیس رو میگیره.
اون بخش اتکا روی زمانبندی و توابع رندومه که اصولی نیست. یعنی ممکنه احتمال خطا دادن رو خیلی کاهش بده، ولی بازم خطا ممکنه در موارد معدودی پیش بیاد.
بعدم از کجا معلوم در جای دیگه در شرایط دیگه یه روز دیگری این خطاها خیلی بیشتر نشدن؟
موضوع اینه که راه حل که اساسی نباشه، نمیشه روی چیزی حساب کرد.
یونیک کردن رو هم گذاشتن در سطح دیتابیس معمولا بعنوان آخرین خط دفاعی و اینکه جلوی خسارت حاصل از باگهای برنامه ها گرفته بشه.
پس اصولی بخوای کار کنی باید یه قفلی چیزی هم در سطح برنامه بذاری. مگر اینکه یوزرفرندلی برات مهم نباشه. آیا خوبه کاربر یه پیام خطای گنده و قرمز Duplicate key error ببینه درحالیکه هیچ خطایی مرتکب نشده و فکر کنه سیستم شما ایراد داره، یا اینکه بجاش سیستم بهش اطلاع بده که نام کاربری یا ایمیل مورد نظر قبلا در سیستم ثبت شده؟
البته در این مورد خاص، یعنی ایمیل، زیاد مشکلی نیست، چون احتمال اینکه افرادی با یک ایمیل یکسان درخواست بفرستن خیلی خیلی کمه.

بله موافقم و الان فکر کنم بعد از نزدیک 50-60 بار تست فقط یک بار خطای duplicate key رو زد که اونم چون با ajax ثبت نام انجام میشه به جای نمایش خود خطای php میزنه که عملیات ناموفق بود. این مراحل و الگوریتم ثبت نام هم میتونه تاثیر گذار باشه. بعد از ارسال فرم اول نام چیک میشه و اگه به دلیلی ردش کنه میرسه به ایمیل و بعد insert کردن که میتونه تو یکی از این سرمرحله که دوتاش read و آخری write هست گیر کنه و به کاربر اخطار بدی

colors
چهارشنبه 15 آبان 1392, 14:37 عصر
البته در این مورد خاص، یعنی ایمیل، زیاد مشکلی نیست، چون احتمال اینکه افرادی با یک ایمیل یکسان درخواست بفرستن خیلی خیلی کمه.

حالا اینجاش زیاد مهم نیست, مثلا تو سیستم من نباید نام و ایمیل یکسان باشه پس احتمالا تو هر هزار قرن شاید شاید شاید یه همچین درخواستی دقیق در یک تایم ارسال بشه, هدف ما بیشتر این اسکنرها هستن

eshpilen
پنج شنبه 16 آبان 1392, 07:30 صبح
شما يه سطر در جدول دارين كه مقدار فيلد counter برابر با 0 هست...
خب حالا ما تو هردو برنامه ميايم و مقدار اون رو ميخونيم ميذاريم داخل يه متغير counter كه مقدارش در هر دو برنامه ميشه 0 تا اينجا كه مشكلي نيست
حالا شما اومدين همين متغير رو يكي تو هر برنامه اضافه كردين كه تو هر برنامه مقدارش ميشه 1 يعني تا اينجا مقدار counter در هر دو برنامه برابر 1 هست
خب حالا اومدين تو هر دو برنامه همين متغير counter رو كه مقدارش 1 هست رو تو جدول به فيلد counter نسبت دادين.

خب این دقیقا کلیت الگوریتمی هست که خیلی افراد برای شمارنده سایتشون استفاده میکنن.
یعنی اینو قبول ندارید؟
ما دقیقا همون الگوریتم رو پیاده کردیم. منتها برای اینکه چگونگی تداخل بین کوئری ها رو نشون بدیدم یه وقفهء زمانی بین read و write ایجاد کردیم که باعث میشه هر دو درخواست قبل از اینکه درخواست دیگر write خودش رو انجام داده باشه read کنن.
به خروجی برنامه هم نیازی نیست اکتفا کنید. بعد از انجام این تست با phpmyadmin اون فیلد رو در دیتابیس چک کنید ببینید چندتا اضافه شده.
اگر ما اون وقفهء زمانی رو نذاریم، مشکلی پیش نمیاد و بطور معمول میبینید که شمارنده دوتا اضافه میشه (که درسته چون ما دو درخواست داشتیم). مگر اینکه خود سیستم وقفه ای به علتی ایجاد بکنه (ولی در شرایط لوکال و تست محدود احتمالش کمه).
حالا من نمیدونم شما کجای این تست رو چرا اشتباه میدونید؟
میشه بیشتر توضیح بدید.
در روی سرورهای اینترنتی هم همین الگوریتم رو ملت دارن اجرا میکنن.
حالا چند درخواست همزمان میاد، کافیه دوتاش قبل از اینکه write کرده باشن read کنن، اونوقت تعداد شمارش شده یکی کمتر از میزان واقعی خواهد بود. اگر سه تا قبل از اینکه write کنن read کنن، دوتا کمتر از میزان واقعی شمرده میشه، و الی آخر به همین شکل برای هر تعداد درخواست.


بله ميفهمم شما چي ميگيد ولي مثالي كه شما زديد اگر توسط 1 برنامه يا 100000 برنامه هم اجرا بشه يه خروجي داره و يه عملكرد يكسان تو تمام اون 100000 سيستم...
شما در هر صورت تو تمام برنامه ها فيلد رو ميخونيد قبل از اين كه هيچ editي انجام بشه روي فيلد بعد يه مقدار جديد بهش اضافه ميكنيد و بعدشم كه مقدار تو اين 100000 برنامه معلومه چيه رو درج ميكنيد تو تيبل از شما والا بعيده ديگه خودتون يه تريس ديگه بكنيد برنامه ولي از ديد كد يكي ديگه بهش نگاه كنيد ماشالله قدرت نقدتونم كه بالاست ديگه :چشمک:.
خب دیگه ما چون عمدا با ایجاد یک وقفهء زمانی بزرگ کاری کردیم که احتمال رخ دادن این تداخل 100% بشه، همیشه همین نتیجه رو میده. ولی در شرایط واقعی که همهء درخواستها اینطور عمل نمیکنن و فقط کسر کوچکی از اونها گهگاه دچار این وضعیت میشن. حالا این احتمال و تعداد میتونه کم و بیش باشه بسته به سرور و ترافیک و برنامه و پارامترهای غیرقابل پیشبینی زیادی که وجود دارن. واسه یکی ممکنه عرض یک سال هم رخ نده اصلا، واسه یکی دیگه ممکنه روزی یک بار رخ بده، واسه یکی ممکنه بیشتر. خلاصه معلوم نمیکنه.

eshpilen
پنج شنبه 16 آبان 1392, 07:49 صبح
-------------------------------
حالا مثال من به همون روش:
فقط واسه لود هم زمان همون sleep كه گذاشتيد هست ولي جهت يادآورري ميگم ctrl رو نگه دارين 2 تا تب رو بگيرين و راست كليك بعدشم reload

با همون جدول و همون فيلد counter البته counter فرقي نداره كه چند باشه يه مقدار داشته باشه فقط.
دو تا برنامه هست كه هركدوم از يه جا اجرا ميشن....
اولي كدش اينه(test.php):


error_reporting(E_ALL);
ini_set('display_errors', '1');

header('Content-Type: text/html; charset=utf-8');
header("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT");
header("Expires: Mon, 26 Jul 1997 05:00:00 GMT");
header("Cache-Control: private, no-store, no-cache, must-revalidate, post-check=0, pre-check=0, max-age=0");
header('Pragma: private');
header("Pragma: no-cache");

mysql_connect('localhost', 'root', '');

mysql_select_db('test');

sleep(10);
mysql_query("update `test` set `counter`=20");
$res=mysql_query("select * from `test`");
$row=mysql_fetch_array($res);
echo $row['counter']."<br />";

----------------
و دومي(test1.php) كدش اينه:


error_reporting(E_ALL);
ini_set('display_errors', '1');

header('Content-Type: text/html; charset=utf-8');
header("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT");
header("Expires: Mon, 26 Jul 1997 05:00:00 GMT");
header("Cache-Control: private, no-store, no-cache, must-revalidate, post-check=0, pre-check=0, max-age=0");
header('Pragma: private');
header("Pragma: no-cache");

mysql_connect('localhost', 'root', '');

mysql_select_db('test');

sleep(10);
mysql_query("update `test` set `counter`=10");
$res=mysql_query("select * from `test`");
$row=mysql_fetch_array($res);
echo $row['counter']."<br />";

حالا طريقه ي كار كردشون:
برنامه ي اول ميره فيلد counter رو به عدد 20 تغيير ميده يعني هرچي كه بود ميشه 20 و برنامه دوم ميره اونو به عدد 10 تغيير ميده موضوع ما اينه كه آيا اين دو تا كوئري با هم تداخلي پيدا ميكنن يه نه به هم ربطي ندارن و هر كدوم جداگانه عملياتشون انجام ميشه....
من اومدم بعد از اين كه فيلد counter رو update كردم بلافاصيه همونجا مقدارش رو از همون سطر بيرون كشيدم و چاپش كردم كه تو هر برنامه اين كار به صورت جداگانه انجام ميشه بنابراين اگر بين اين دو درخواست update تداخل هايي از اين قبيل پيش بياد:
1-كه يكيشون به دليل همزمان بودن اجرا نشه:پس مقداري كه بعد از واكشي انجام ميشه بايد تو هردو تا page كه چاپ شده يكي باشه چون يكي از update ها اجرا نشده.
2-هيچ كدوم اجرا نشه: در اين صورت اصلا فيلدمون تغييري نميكنه.
3-هر دو همزمان اجرا بشن (يعني وقتي اين داره update ميكنه اون هم آپديت كنه): اين كه بايد يا ارور بده كه نميده چون خطايي به اين شكل فكر نميكنم داشته باشيم يا همون اتفاق قبلي يعني يكي از اونا عمل نكنه و قضيه 1 پيش بياد و يا هم قضيه 2.
*3- اين كه هر دو اجرا بشن و هر كدوم مقدار خودشون رو تو جدول قرار بدن حالا يكي زودتر يا يكي ديرتر ولي بالاخره مقادير ست ميشه و كوئري ها به هم ربطي پيدا نميكنن: كه در اين صورت شما متوجه ميشيد كه تو هر page يه مقدار كه درج شده بوده تو كدهاي بعديش واكشي شده و همون چاپ ميشه كه تو هر پيج هم مقدار فرق داره و همون مقداري هست كه درج شده.
ولي يه نتيجه از اين من گرفتم كه كاملا هم طبيعي هست كه هر بار اولويت به يكي از كوئري ها داده ميشه يعني بعد چندين بار تست فهميدم يه بار مثلا كوئري A اول اجرا ميشه چون مقدار نهايي تو بانك مقدار اون بود و يه بار كوئري B.
و در آخر هم اينو بگم كه همين مثال رو تو هر پيج با 100 بار كوئري زدن (تو يه حلقه) انجام دادم يعني 100 تا سطر درج كردم و حالا با دو برنامه اين 100 سطر رو update كردم كه هيچ تداخلي پيش نميومد هر كدوم كار خودش رو انجام ميداد.
شما sleep رو باید بین دو کوئری بذارید، وگرنه هیچ تاثیری نداره.
هدف sleep اینه که بین read و write وقفهء لازم رو ایجاد بکنه. اگر بین اینا نباشه که هیچ کاری نمیکنه جز علافی ما!!
اگر sleep رو بین کوئری ها ببرید، مشاهده میکنید که هر دو درخواست یک مقدار رو نشون میدن، که البته خیلی طبیعی است، چون کوئری write ای که آخر اجرا شده آخرین مقدار رو در فیلد درج کرده، و طبیعتا هر دو درخواست همون مقدار رو از جدول میخونن.


1-كه يكيشون به دليل همزمان بودن اجرا نشه:پس مقداري كه بعد از واكشي انجام ميشه بايد تو هردو تا page كه چاپ شده يكي باشه چون يكي از update ها اجرا نشده.این گزینه منتفی است.
هر دو همیشه اجرا میشن.
ما کی گفتیم که کوئری های همزمان اجرا نمیشن؟!
مسئله ترتیب اجراست که کوئری های یک درخواست بین کوئری های درخواست دیگر اجرا میشه، نه اینکه کوئری های خاصی اصلا اجرا نشن.
کوئری های write به نوبت اجرا میشن. هرکدام زودتر وارد DBMS شده باشه زودتر اجرا میشه. توی صف میرن.
کوئری های read همزمان هم به هر تعداد میتونن هم همزمان اجرا بشن و هم اگر به دلایلی لازم باشه، توی صف برن و نوبتی اجرا بشن.
بهرحال در تست های ما اصولا به همزمانی در سطح دیتابیس نیازی نیست. بلکه پیش و پس افتادن کوئری های مختلف درخواستهاست که باعث این باگ میشه.

eshpilen
پنج شنبه 16 آبان 1392, 11:00 صبح
ضمنا مسائل همزمانی/تداخل درخواست ها فقط درمورد دیتابیس پیش نمیان یا فقط دیتابیس و سمت سرور درش درگیر نیست.
بعنوان مثال اینجا یه ایراد از یک سیستم احراز هویت با امنیت بالا گرفتم، که در اون درخواستهای با فاصلهء کوتاه از یک کاربر موجب ایجاد false positive میشن (اشتباها بعنوان سرقت کوکی شناسایی میشه): http://security.stackexchange.com/questions/45016/a-problem-with-the-cookie-theft-detection-mechanism-of-barry-jaspans-improved-p
البته لزوما نیازی نیست که درخواستها فاصلهء خیلی کمی داشته باشن. گاهی بعلت کند شدن سیستم کلاینت یا سرور هم این حالت میتونه پیش بیاد.

این سیستم احراز هویت که سرقت کوکی رو هم شناسایی میکنه، توسط یک فرد کاملا حرفه ای که در امنیت/رمزنگاری هم تخصص داره طراحی شده.
یعنی حتی افراد حرفه ای هم ممکنه برنامه هاشون چنین باگهایی داشته باشه.
البته اون طرفی که جواب داده (که مشکوکم همون طراح سیستم باشه) راهکار نسبتا خوبی هم براش ارائه داد.

FastCode
شنبه 28 دی 1392, 12:00 عصر
یک دیتابیس ساده مثل voldemort روی یک سرور معمولی تا ۲۰۰ هزار تراکنش بر ثانیه رو انجام میده.
پیشنهاد میکنم یک نگاه دیگه به روش کارتون بندازید.چون sleep یکی از توابعی هست که در طراحی سیستمهای اطلاعاتی استفاده نمیشه.(این رو جدی گفتم)

برای حل مشکل اصلی مطرح شده هم راههای زیادی وجود داره که میشه به دیتابیس های توزیع شده به عنوان مطرح ترین جواب و بعد از اون به انواع replication اشاره کرد.

من همه روشهای گفته شده رو قبلا انجام دادم.مثلا اضافه کردن یک برنامه واسط.استفاده از تراکنش.مدیریت تراکنش سمت کلاینت یا سرور.کپی کردن اطلاعات سمت کلاینت.نگهداری اطلاعات در یک دیتابیس موقت.
و باور کنید اگر این روشها جواب میداد شروع نمیکردم به نوشتن: https://github.com/Behrooz-Amoozad/BD2