أداء / استقرار ملف مخطط للذاكرة - أصلي أو mponbytebypuffer - مقابل OL FileOutstream

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

سؤال

أؤيد تطبيق Java Legacy يستخدم ملفات مسطحة (نص عادي) للمثابرة. نظرا لطبيعة التطبيق، يمكن أن يصل حجم هذه الملفات إلى 100s ميغابايت يوميا، وغالبا ما يكون عامل الحد الأقصى في أداء التطبيق ملف IO. يستخدم التطبيق حاليا OL عادي java.io.fileoutputstream لكتابة البيانات إلى القرص.

في الآونة الأخيرة، كان لدينا العديد من المطورين يؤكدون أن استخدام الملفات المعينة بالذاكرة، التي يتم تنفيذها في الكود الأصلي (C / C ++) والوصول عبر JNI، ستوفر أداء أكبر. ومع ذلك، تستخدم FileOutPttream الأساليب الأصلية بالفعل بطريقتها الأساسية (أي كتابة (البايت [])، لذلك يبدو افتراضا ضعيفا دون بيانات صعبة أو على الأقل أدلة قصصية.

لدي العديد من الأسئلة حول هذا:

  1. هل هذا التأكيد صحيح حقا؟ هل سيتم تعيين ذاكرة الملفات دائماتوفير أسرع io مقارنة مع ملفات java fileOutstream؟

  2. هل توفر الفئة MappedBytebuffer التي تم الوصول إليها من FileChannel نفس الوظيفة كمكتبة ملفات معينة من الذاكرة التي تم الوصول إليها عبر JNI؟ ما هو mappedbytebuffer يفتقر إلى أنه قد يقودك إلى استخدام حل JNI؟

  3. ما هي مخاطر استخدام الملفات المعينة بالذاكرة للقرص IO في تطبيق الإنتاج؟ وهذا هو، والتطبيقات التي لها ججهة متواصلة مع الحد الأدنى من إعادة تمهيد (مرة واحدة في الشهر، كحد أقصى). فضل الحكايات الحقيقية من تطبيقات الإنتاج (جافا أو غير ذلك).

السؤال رقم 3 مهم - يمكنني الإجابة على هذا السؤال بنفسي جزئيا من خلال كتابة تطبيق "لعبة"، فإن Perf اختبارات IO باستخدام الخيارات المختلفة الموضحة أعلاه، ولكن عن طريق نشر ذلك، آمل أن أكون حكايات / بيانات حقيقية لمضغها.

تحرير] التوضيح - كل يوم من أيام التشغيل، يقوم التطبيق بإنشاء ملفات متعددة تتراوح الحجم من 100 ميغابايت إلى 1 أزعج. في المجموع، قد يكون التطبيق يكتب العربات المتعددة من البيانات يوميا.

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

المحلول

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

إذا كنت تكتب بيانات جديدة فقط على القرص من التطبيق الخاص بك، فإن الذاكرة المعينة I / O ربما لن يساعد الكثير. لا أرى أي سبب تريد استثمار الوقت في بعض الحل الأصلي المشفرة. يبدو أن هذا مجرد تعقيد كبير للتطبيق الخاص بك، مما قدمت حتى الآن.

إذا كنت متأكدا من أنك بحاجة فعلا إلى أداء I / O أفضل - أو مجرد أداء في قضيتك، فسأطلع إلى حل الأجهزة مثل صفيف قرص مضبوط. غالبا ما تكون رمي المزيد من الأجهزة في المشكلة أكثر فعالية من حيث التكلفة من وجهة نظر الأعمال أكثر من قضاء الوقت لتحسين البرنامج. كما أنه عادة ما تكون أسرع في التنفيذ وأكثر موثوقية.

بشكل عام، هناك الكثير من المزالق في الأمثل في البرنامج. سوف تقدم أنواعا جديدة من المشاكل إلى طلبك. قد تعمل في مشاكل الذاكرة / GC سحق مما يؤدي إلى مزيد من الصيانة / الضبط. أسوأ جزء هو أن العديد من هذه القضايا ستكون من الصعب اختبارها قبل الإنتاج.

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

نصائح أخرى

الذاكرة المعينة I / O لن تجعل الأقراص تعمل بشكل أسرع (!). للوصول الخطي، يبدو أنه لا معنى له قليلا.

المخزن المؤقت NIO معين هو الشيء الحقيقي (التحذير المعتاد حول أي تنفيذ معقول).

كما هو الحال مع المخازن المؤقتة Nio المخصصة NIO المخصصة، فإن المخازن المؤقتة ليست ذاكرة طبيعية ولن تغنيها بكفاءة. إذا قمت بإنشاء العديد منهم قد تجد أنك تنفد من مساحة الذاكرة / العنوان دون نفاد كومة Java. من الواضح أن هذا ما تقلق مع العمليات الجارية الطويلة.

من تجربتي، تقوم الملفات المعينة بالذاكرة أفضل بكثير من الوصول العادي في الوقت الفعلي واستخدام الثبات. لقد عملت في المقام الأول باستخدام C ++ على Windows، لكن عروض Linux متشابهة، وأنت تخطط لاستخدام JNI على أي حال، لذلك أعتقد أنه ينطبق على مشكلتك.

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

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

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

آمل أن يساعد.

بالنسبة إلى النقطة 3 - إذا تعطل الجهاز وهناك أي صفحات لم يتم مسحها على القرص، فقد تضيع. شيء آخر هو إهدار مساحة العنوان - رسم خرائط ملف إلى الذاكرة المستهلكات المستهلكين (ويتطلب مساحة متجاورة)، وبصحة جيدة، على آلات 32 بت، محدودة بعض الشيء. لكنك قلت حوالي 100 ميغابايت - لذلك لا ينبغي أن يكون مشكلة. شيء آخر - يتطلب توسيع حجم ملف MMAPED بعض العمل.

على فكرة، هذا مناقشة لذلك يمكن أن تعطيك أيضا بعض الأفكار.

لقد فعلت ذلك ل دراسة حيث أقارن أداء الكتابة إلى الخام ByteBuffer مقابل أداء الكتابة إلى MappedByteBuffer. وبعد يتم دعم الملفات المعينة بالذاكرة من قبل نظام التشغيل والكتابات الخاصة بهم جيدة جدا كما يمكنك أن ترى في أرقامي القياسية. يؤدي أداء الكتب المتزامنة عبر Filechannel إلى أبطأ حوالي 20 مرة وهذا هو السبب في أن الناس يقومون بالتسجيل غير المتزامن طوال الوقت. في دراستي، أعطي مثالا على كيفية تنفيذ التسجيل غير المتزامن من خلال قائمة انتظار خالية من القفل وخالية من القمامة للأداء النهائي قريب جدا من الخام ByteBuffer.

إذا كتبت عددا أقل من البايتات، فستكون أسرع. ماذا لو قمت بتصفيتها من خلال gzipoutputtream، أو ماذا لو كتبت بياناتك إلى zipfiles أو jarfiles؟

كما ذكر أعلاه، استخدم Nio (AKA جديد IO). هناك أيضا ايو جديد جديد يخرج.

الاستخدام السليم لحل محرك الأقراص الثابتة RAID سيساعدك، ولكن سيكون ذلك الألم.

أنا حقا أحب فكرة ضغط البيانات. الذهاب ل gzipoutputstream المتأنق! من شأنه أن يضاعف الإنتاجية الخاصة بك إذا كان وحدة المعالجة المركزية يمكن أن تابع. من المحتمل أنه يمكنك الاستفادة من الآلات المزدوجة العادية الآن، إيه؟

--stosh.

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