تخزين النتائج المرقّمة مؤقتًا والتطهير عند التحديث - كيفية الحل؟

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

سؤال

لقد قمت بإنشاء منتدى، ونحن نقوم بتنفيذ حل التخزين المؤقت لـ apc وmemcache لحفظ بعض الأعمال في قاعدة البيانات.

لقد بدأت في تنفيذ طبقة ذاكرة التخزين المؤقت باستخدام مفاتيح مثل "Categories::getAll"، وإذا كان لدي بيانات خاصة بالمستخدم، فسوف أقوم بإلحاق المفاتيح بأشياء مثل معرف المستخدم، حتى تحصل على "User::getFavoriteThreads|1471".عندما يقوم مستخدم بإضافة موضوع مفضل جديد، أقوم بحذف مفتاح ذاكرة التخزين المؤقت، وسيقوم بإعادة إنشاء الإدخال.

ومع ذلك، وهنا تأتي المشكلة:

كنت أرغب في تخزين المواضيع في المنتدى.بسيط بما فيه الكفاية، "Forum::getThreads|$iForumId".لكن...مع ترقيم الصفحات، سأضطر إلى تقسيم هذا إلى عدة إدخالات ذاكرة التخزين المؤقت، على سبيل المثال

"Forum::getThreads|$iForumId|$iLimit|$iOffset".

ولا بأس، حتى يقوم شخص ما بنشر موضوع جديد في المنتدى.سيتعين علي الآن حذف جميع المفاتيح الموجودة أسفل "Forum::getThreads|$iForumId", ، بغض النظر عن الحد والإزاحة.

ما هي الطريقة الجيدة لحل هذه المشكلة؟أفضل حقًا عدم تكرار كل الحدود والإزاحة الممكنة حتى أجد شيئًا لم يعد مطابقًا.

شكرًا.

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

المحلول

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

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

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

نصائح أخرى

مجرد تحديث:قررت أن وجهة نظر جوش بشأن استخدام البيانات كانت جيدة جدًا.من غير المرجح أن يستمر الأشخاص في مشاهدة الصفحة 50 من المنتدى.

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

بهذه الطريقة، يمكنني استخدام مفتاح ذاكرة تخزين مؤقت واحد لكل منتدى، ولا يستغرق الأمر سوى القليل من الجهد لمسح/تحديث ذاكرة التخزين المؤقت :-)

أود أيضًا أن أشير إلى أنه في الاستعلامات الأخرى ذات الموارد الثقيلة، استخدمت نموذج flungabunga، لتخزين العلاقات بين المفاتيح.لسوء الحظ، لن يسمح لي Stack Overflow بقبول إجابتين.

شكرًا!

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

ال ExtendedMemcache->set تقبل الطريقة 3 وسيطات ($strGroup,$strKey, $strValue) عند الاتصال ، ستخزن العلاقة بين $strGroup, ، و $strKey, ، في الممتلكات المحمية ثم انتقل إلى تخزين $strKey ل $strValue العلاقة في memcache.

يمكنك بعد ذلك إضافة طريقة جديدة إلى ExtendedMemcache فئة تسمى "deleteGroup"، والتي، عند تمرير سلسلة، ستجد المفاتيح المرتبطة بتلك المجموعة، وتقوم بمسح كل مفتاح بدوره.

سيكون شيء من هذا القبيل:http://pastebin.com/f566e913bآمل أن يكون كل ذلك منطقيًا ويعمل لصالحك.

ملاحظة.أفترض أنك إذا أردت استخدام المكالمات الثابتة، فمن الممكن حفظ الخاصية المحمية فيها memcache نفسها تحت المفتاح الخاص بها.مجرد فكرة.

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

أحد الحلول الممكنة هو عدم ترقيم الصفحات في ذاكرة التخزين المؤقت لسلاسل الرسائل في المنتدى، بل بدلاً من ذلك وضع معلومات سلسلة المحادثات فيه Forum::getThreads|$iForumId.ثم في كود PHP الخاص بك، قم فقط بسحب ما تريده لتلك الصفحة المحددة، على سبيل المثال.

$page = 2;
$threads_per_page = 25;
$start_thread = $page * $threads_per_page;

// Pull threads from cache (assuming $cache class for memcache interface..)
$threads = $cache->get("Forum::getThreads|$iForumId");

// Only take the ones we need
for($i=$start_thread; $i<=$start_thread+$threads_per_page; $i++)
{
    // Thread display logic here...
    showThread($threads[$i]);
}

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

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

لست متأكدًا من مقدار الأداء الذي قد يعنيه هذا، لكنه يبدو غير فعال بعض الشيء.سأجري بعض الاختبارات وأرى كيف ستسير الأمور.نشكرك على الاقتراح المنظم (وبعض التعليمات البرمجية لعرضه، شكرًا!).

كن حذرًا جدًا عند القيام بهذا النوع من التحسين دون وجود حقائق ثابتة يمكن قياسها.

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

رداً على فلونجابونجا:

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

على سبيل المثال

get seqno_mygroup
23

get mygroup23_mykey
<mykeydata...>
get mygroup23_mykey2
<mykey2data...>

ثم "لحذف" المجموعة ببساطة:

incr seqno_mygroup

هاهو:

get seqno_mygroup
24

get mygroup24_mykey
...empty

إلخ..

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