هل لا يوجد شيء مشترك بين Rails أم أنه يمكن للطلبات المنفصلة الوصول إلى نفس متغيرات وقت التشغيل؟

StackOverflow https://stackoverflow.com/questions/1025432

سؤال

تعمل لغة PHP في بيئة خالية من أي شيء، وهو ما يعني في هذا السياق أن كل طلب ويب يتم تشغيله في بيئة نظيفة.لا يمكنك الوصول إلى بيانات طلب آخر إلا من خلال طبقة استمرارية منفصلة (نظام الملفات، قاعدة البيانات، وما إلى ذلك).

ماذا عن روبي أون ريلز؟لقد قرأت للتو مشاركة مدونة تفيد بأن الطلبات المنفصلة قد تصل إلى نفس متغير الفئة.

لقد خطر لي أن هذا ربما يعتمد على خادم الويب. الأسئلة الشائعة الخاصة بـ Mongrel ينص على أن Mongrel يستخدم مؤشر ترابط واحد لكل طلب - مما يقترح بيئة لا شيء مشترك.تستمر الأسئلة الشائعة في القول بأن RoR ليس مؤشر ترابط آمن، مما يشير أيضًا إلى أن RoR لن يكون موجودًا في بيئة مشتركة ما لم يعيد طلب جديد استخدام الكائنات الموجودة في الذاكرة التي تم إنشاؤها من الطلب السابق.

ومن الواضح أن هذا له تداعيات أمنية كبيرة.لذا لدي سؤالان:

  1. هل بيئة RoR مشتركة؟
  2. إذا تم تشغيل RoR في (أو قد تشغيل في بعض الظروف) بيئة مشتركة، ما هي المتغيرات وغيرها من تخزين البيانات التي يجب أن أشعر بجنون العظمة بشأنها؟

تحديث:سأوضح أكثر. في حاوية Java servlet، يمكنك الحصول على كائنات تستمر عبر طلبات متعددة.يتم ذلك عادةً للتخزين المؤقت للبيانات التي يمكن لعدة مستخدمين الوصول إليها، واتصالات قاعدة البيانات، وما إلى ذلك.في PHP لا يمكن القيام بذلك في طبقة التطبيق، بل يجب أن يتم ذلك في طبقة استمرارية منفصلة مثل Memcached.إذن السؤال ذو شقين هو:ما هو السيناريو الذي يشبه RoR (PHP أو Java) وإذا كان مثل Java، أيّ هل تستمر أنواع البيانات عبر طلبات متعددة؟

هل كانت مفيدة؟

المحلول

باختصار:

  1. لا يا ريلز أبداً يعمل في بيئة لا شيء مشترك.
  2. كن بجنون العظمة متغيرات الطبقة و متغيرات مثيل الفئة.

النسخة الأطول:

تبدأ عمليات ريلز دورة حياتها بتحميل إطار العمل والتطبيق.عادةً ما يتم تشغيل مؤشر ترابط واحد فقط، والذي سيعالج العديد من الطلبات خلال فترة حياته.ولذلك سيتم إرسال الطلبات بدقة بالتتابع.

ومع ذلك، تستمر كافة الفئات عبر الطلبات.وهذا يعني أي كائن تمت الإشارة إليه من الفئات والفئات التعريفية الخاصة بك (مثل متغيرات الفئة ومتغيرات مثيل الفئة) سوف يمكن مشاركتها عبر الطلبات. هذا قد يعضك, على سبيل المثال، إذا حاولت حفظ الأساليب (@var ||= expensive_calculation) في الخاص بك فصل الأساليب، مع توقع أنها ستستمر فقط أثناء الطلب الحالي.في الواقع، لن يتم إجراء الحساب إلا عند الطلب الأول.

ظاهريًا، قد يبدو من الجيد تنفيذ التخزين المؤقت، أو أي سلوك آخر يعتمد على الثبات عبر الطلبات.عادة، ليس كذلك.وذلك لأن معظم استراتيجيات النشر ستستخدم عديد تعمل عمليات ريلز على مواجهة طبيعتها المفردة.ببساطة، ليس من الرائع حظر جميع الطلبات أثناء انتظار استعلام بطيء في قاعدة البيانات، لذا فإن الطريقة السهلة للخروج هي إنتاج المزيد من العمليات.وبطبيعة الحال، لا تتشارك هذه العمليات أي شيء (ربما باستثناء بعض الذاكرة، والتي لن تلاحظها). هذا قد يعضك إذا قمت بحفظ الأشياء في متغيرات الفصل الدراسي أو متغيرات مثيل الفصل أثناء الطلبات.ثم، بطريقة أو بأخرى، تبدو الأشياء أحيانًا وكأنها موجودة، وأحيانًا تبدو وكأنها اختفت.(في الواقع، بالطبع، قد تكون البيانات موجودة أو لا تكون موجودة في البعض عملية, ، ويغيب في غيرها).

بعض تكوينات النشر (أبرزها JRuby + Glassfish) نكون في الواقع متعددة الخيوط.القضبان آمنة للخيط، لذلك يمكنها التعامل معها.لكن تطبيقك قد لا يكون آمنًا.يتم التخلص من جميع مثيلات وحدة التحكم بعد كل طلب، ولكن كما نعلم، تتم مشاركة الفئات. هذا قد يعضك إذا قمت بتمرير المعلومات في متغيرات الفئة أو في متغيرات مثيل الفئة.إذا لم تستخدم أساليب المزامنة بشكل صحيح، فقد ينتهي بك الأمر في جحيم حالة السباق.


كملاحظة جانبية:عادةً ما يتم تشغيل Rails في عمليات ذات ترابط واحد لأن تنفيذ خيط روبي سيء للغاية.لحسن الحظ، الأمور أفضل قليلاً في روبي 1.9.و أ كثير أفضل في JRuby.

مع اكتساب كل من تطبيقات Ruby هذه شعبية، يبدو من المحتمل أن تكتسب استراتيجيات نشر Rails متعددة الخيوط أيضًا شعبية وعددًا.إنها لفكرة جيدة أن تكتب طلبك مع وضع إرسال الطلب متعدد الخيوط في الاعتبار بالفعل.

نصائح أخرى

فيما يلي مثال بسيط نسبيًا يوضح ما يمكن أن يحدث إذا لم تكن حريصًا بشأن تعديل الكائنات المشتركة.

  1. إنشاء مشروع ريلز جديد: rails test

  2. إنشاء ملف جديد lib/misc.rb ووضع فيه هذا :

    class Misc
      @xxx = 'Hello'
      def Misc.contents()
        return @xxx
      end
    end
    
  3. إنشاء وحدة تحكم جديدة: ruby script/generate controller Posts index
  4. يتغير app/views/posts/index.html.erb ليحتوي على هذا الكود:

    <%
      require 'misc'; y = Misc.contents() ; y << ' (goodbye) '
    %>
    <pre><%= y %></pre>
    

    (هذا هو المكان الذي نقوم فيه بتعديل الكائن المشترك ضمنيًا.)

  5. أضف مسارات RESTful إلى config/routes.rb.
  6. ابدأ الخادم ruby script/server وتحميل الصفحة /posts عدة مرات.سوف ترى عدد ( goodbye) زيادة السلاسل بمقدار واحد في كل عملية إعادة تحميل متتالية للصفحة.

في متوسط ​​النشر الخاص بك باستخدام Passenger، من المحتمل أن يكون لديك عمليات تطبيق متعددة لا تشترك في أي شيء فيما بينها سوى الفئات داخل كل عملية والتي تحافظ على حالتها (الثابتة) من طلب إلى آخر.ومع ذلك، يقوم كل طلب بإنشاء مثيل جديد لوحدات التحكم الخاصة بك.

يمكنك تسمية هذا بمجموعة من بيئات الحالة المشتركة المتميزة.

لاستخدام تشبيه Java الخاص بك، يمكنك القيام بالتخزين المؤقت وجعله يعمل من طلب إلى طلب، لا يمكنك افتراض أنه سيكون متاحًا على كل طلب.

لا شيء مشترك هو في بعض الأحيان فكرة جيدة.ولكن ليس عندما يتعين عليك تحميل إطار عمل تطبيق كبير ونموذج مجال كبير وكمية كبيرة من التكوين لكل طلب.

لتحقيق الكفاءة، يحتفظ ريلز ببعض البيانات المتاحة في الذاكرة لمشاركتها بين جميع الطلبات طوال عمر التطبيق.معظم هذه البيانات للقراءة فقط، لذا لا داعي للقلق.

عندما تكتب تطبيقك، ابتعد عن الكتابة إلى الكائنات المشتركة (باستثناء قاعدة البيانات، على سبيل المثال، التي تأتي خارج الصندوق مع تحكم جيد في التزامن) ويجب أن تكون على ما يرام.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top