سؤال

لدي تطبيق ويب يتلقى الرسائل من خلال واجهة HTTP، على سبيل المثال:

http://server/application?source=123&destination=234&text=hello

يحتوي هذا الطلب على معرف المرسل وهوية المستلم ونص الرسالة.

يجب معالجة هذه الرسالة مثل:

  • العثور على كائن المستخدم المطابق لكل من المصدر والوجهة من قاعدة البيانات
  • إنشاء شجرة من الكائنات:رسالة تحتوي على حقل لنص الرسالة وكائنين للمستخدم للمصدر والوجهة
  • استمرار هذه الشجرة إلى قاعدة بيانات.

سيتم تحميل الشجرة بواسطة تطبيقات أخرى لا أستطيع لمسها.

أستخدم Oracle كقاعدة بيانات دعم وJPA مع Toplink لمهام معالجة قاعدة البيانات.إذا كان ذلك ممكنا، سأبقى مع هؤلاء.

بدون الكثير من التحسين، يمكنني تحقيق ما يقرب من 30 طلبًا/ثانية من الإنتاجية في بيئتي.هذا ليس كثيرًا، سأحتاج إلى 300 طلب/ثانية تقريبًا.لذلك قمت بقياس مكان عنق الزجاجة في الأداء ووجدت أنه يستدعي ذلك em.persist() يستغرق معظم الوقت.إذا قمت ببساطة بالتعليق على هذا السطر، فإن الإنتاجية تتجاوز 1000 طلب/ثانية.

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

من الواضح أنني بحاجة إلى تحسين أداء الإدراج هنا.ولكن كما ذكرت سابقًا، أود الاستمرار في استخدام JPA وToplink لهذا الغرض، وليس JDBC خالصًا.

هل تعرف طريقة لإنشاء إدراجات دفعة باستخدام JPA وToplink؟هل يمكنك التوصية بأي تقنية أخرى لتحسين أداء JPA المستمر؟

معلومات إضافية:

تعني عبارة "الطلبات/الثانية" هنا:إجمالي عدد الطلبات / إجمالي الوقت من بداية الاختبار إلى آخر سجل مكتوب في قاعدة البيانات.

حاولت إجراء المكالمات إلى em.persist() غير متزامن عن طريق إنشاء قائمة انتظار في الذاكرة بين عناصر servlet والمستمر.لقد ساعد الأداء بشكل كبير.ومع ذلك، فقد نمت قائمة الانتظار بسرعة كبيرة، وبما أن التطبيق سيتلقى حوالي 200 طلب/ثانية بشكل مستمر، فهذا ليس حلاً مقبولاً بالنسبة لي.

في هذا النهج المنفصل قمت بجمع طلبات لمدة 100 مللي ثانية واتصلت بها em.persist() على كافة العناصر التي تم جمعها قبل ارتكاب الصفقة.يتم تخزين EntityManagerFactory مؤقتًا بين كل معاملة.

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

المحلول

يجب عليك فصل واجهة JPA واستخدام واجهة TopLink API العارية.ربما يمكنك رمي الكائنات التي تستمر فيها في UnitOfWork وتنفيذ UnitOfWork وفقًا لجدولك الزمني (متزامن أو غير متزامن).لاحظ أن إحدى تكاليف em.persist() هي الاستنساخ الضمني الذي يحدث للرسم البياني للكائن بأكمله.سيعمل TopLink بشكل أفضل إذا قمت uow.registerObject()‎ باعتراض المستخدمين بنفسك، مما يوفر على نفسه اختبارات الهوية التي يتعين عليه القيام بها بخلاف ذلك.لذلك سوف ينتهي بك الأمر مع:

uow=sess.acquireUnitOfWork();
for (job in batch) {
 thingyCl=uow.registerObject(new Thingy());
 user1Cl=uow.registerObject(user1);
 user2Cl=uow.registerObject(user2);
 thingyCl.setUsers(user1Cl,user2Cl);
}
uow.commit();

هذه مدرسة قديمة جدًا TopLink راجع للشغل ؛)

لاحظ أن الدُفعة ستساعد كثيرًا، لأن كتابة الدُفعات، وخاصة كتابة الدُفعات مع ربط المعلمات، ستبدأ، وفي هذا المثال البسيط من المحتمل أن يكون لها تأثير كبير جدًا على أدائك.

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

نصائح أخرى

ما هو مقياسك لـ "الطلبات/الثانية"؟بمعنى آخر ماذا يحدث للطلب الحادي والثلاثين؟ما هو المورد الذي تم حظره؟إذا كان هذا هو جزء الواجهة الأمامية/servlet/الويب، فهل يمكنك تشغيل em.persist() في موضوع آخر والعودة على الفور؟

أيضًا، هل تقوم بإنشاء معاملات في كل مرة؟هل تقوم بإنشاء كائنات EntityManagerFactory مع كل طلب؟

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