خطوة 21: التخزين المؤقت للأداء
التخزين المؤقت للأداء¶
مشاكل الأداء قد تأتي مع الشعبية. بعض الأمثلة النموذجية: فهارس قاعدة البيانات المفقودة أو طن من طلبات SQL لكل صفحة.لن تواجه أي مشكلة في قاعدة بيانات فارغة ، ولكن مع زيادة عدد الزيارات والبيانات المتنامية ، قد تظهر في مرحلة ما.
اخفاء معلومات خاصة بالHTTP¶
يعد استخدام استراتيجيات التخزين المؤقت لـ HTTP طريقة رائعة لزيادة أداء المستخدمين النهائيين بأقل جهد ممكن. أضف ذاكرة التخزين المؤقت للوكيل العكسي في الإنتاج لتمكين التخزين المؤقت ، واستخدم CDN للتخزين المؤقت على الحافة للحصول على أداء أفضل.
دعنا نخفي الصفحة الرئيسية لمدة ساعة
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | --- a/src/Controller/ConferenceController.php
+++ b/src/Controller/ConferenceController.php
@@ -33,9 +33,12 @@ class ConferenceController extends AbstractController
#[Route('/', name: 'homepage')]
public function index(ConferenceRepository $conferenceRepository): Response
{
- return new Response($this->twig->render('conference/index.html.twig', [
+ $response = new Response($this->twig->render('conference/index.html.twig', [
'conferences' => $conferenceRepository->findAll(),
]));
+ $response->setSharedMaxAge(3600);
+
+ return $response;
}
#[Route('/conference/{slug}', name: 'conference')]
|
تقوم الطريقة ()setSharedMaxAge
بتكوين انتهاء صلاحية ذاكرة التخزين المؤقت لوكلاء عكسيين. استخدم ()setMaxAge
للسيطرة على ذاكرة التخزين المؤقت للمستعرض. يتم التعبير عن الوقت بالثواني (ساعة واحدة = 60 دقيقة = 3600 ثانية).
يعد التخزين المؤقت لصفحة المؤتمر أكثر صعوبة لأنه أكثر ديناميكية. يمكن لأي شخص إضافة تعليق في أي وقت ، ولا يريد أحد الانتظار لمدة ساعة لرؤيته عبر الإنترنت. في مثل هذه الحالات ، استخدم استراتيجية * التحقق من صحة HTTP.
تنشيط Symfony HTTP Cache Kernel¶
لاختبار استراتيجية ذاكرة التخزين المؤقت HTTP ، استخدم الوكيل العكسي Symfony HTTP:
1 2 3 4 5 6 7 8 | --- a/config/packages/framework.yaml
+++ b/config/packages/framework.yaml
@@ -15,3 +15,5 @@ framework:
#fragments: true
php_errors:
log: true
+
+ http_cache: true
|
إلى جانب كونه وكيل HTTP كامل العكسي ، يضيف الوكيل العكسي Symfony HTTP (عبر فئة HttpCache
) بعض معلومات التصحيح الجيدة كرؤوس HTTP. وهذا يساعد بشكل كبير في التحقق من صحة رؤوس ذاكرة التخزين المؤقت التي وضعناها.
التحقق من ذلك على الصفحة الرئيسية:
1 | $ curl -s -I -X GET https://127.0.0.1:8000/
|
1 2 3 4 5 6 7 8 9 10 11 | HTTP/2 200
age: 0
cache-control: public, s-maxage=3600
content-type: text/html; charset=UTF-8
date: Mon, 28 Oct 2019 08:11:57 GMT
x-content-digest: en63cef7045fe418859d73668c2703fb1324fcc0d35b21d95369a9ed1aca48e73e
x-debug-token: 9eb25a
x-debug-token-link: https://127.0.0.1:8000/_profiler/9eb25a
x-robots-tag: noindex
x-symfony-cache: GET /: miss, store
content-length: 50978
|
بالنسبة للطلب الأول ، يخبرك خادم التخزين المؤقت بأنه كان miss
وأنه أجرى store
لتخزين الاستجابة مؤقتًا. تحقق من رأس cache-control
لرؤية استراتيجية ذاكرة التخزين المؤقت المكونة.
للطلبات اللاحقة ، يتم تخزين الاستجابة مؤقتًا (تم أيضًا تحديث age
):
1 2 3 4 5 6 7 8 9 10 11 | HTTP/2 200
age: 143
cache-control: public, s-maxage=3600
content-type: text/html; charset=UTF-8
date: Mon, 28 Oct 2019 08:11:57 GMT
x-content-digest: en63cef7045fe418859d73668c2703fb1324fcc0d35b21d95369a9ed1aca48e73e
x-debug-token: 9eb25a
x-debug-token-link: https://127.0.0.1:8000/_profiler/9eb25a
x-robots-tag: noindex
x-symfony-cache: GET /: fresh
content-length: 50978
|
تجنب طلبات SQL باستخدام ESI¶
يقوم مستمع TwigEventSubscriber بإدخال متغير عمومي في Twig مع جميع كائنات المؤتمر. يفعل ذلك لكل صفحة واحدة من الموقع. ربما يكون هدفًا رائعًا للتحسين.
لن تضيف مؤتمرات جديدة كل يوم ، وبالتالي فإن الكود يبحث عن نفس البيانات بالضبط من قاعدة البيانات مرارًا وتكرارًا.
قد نرغب في تخزين ذاكرة التخزين المؤقت لأسماء المؤتمرات والبزاقات باستخدام ذاكرة التخزين المؤقت Symfony ، ولكن كلما أمكن ذلك ، أود الاعتماد على بنية تخزين HTTP المؤقتة.
عندما تريد التخزين المؤقت لجزء من الصفحة ، انقله خارج طلب HTTP الحالي عن طريق إنشاء طلب فرعي. ESI هي مباراة مثالية لحالة الاستخدام هذه. ESI هي وسيلة لتضمين نتيجة طلب HTTP في طلب آخر.
إنشاء وحدة تحكم تقوم بإرجاع جزء HTML الذي يعرض المؤتمرات فقط:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | --- a/src/Controller/ConferenceController.php
+++ b/src/Controller/ConferenceController.php
@@ -41,6 +41,14 @@ class ConferenceController extends AbstractController
return $response;
}
+ #[Route('/conference_header', name: 'conference_header')]
+ public function conferenceHeader(ConferenceRepository $conferenceRepository): Response
+ {
+ return new Response($this->twig->render('conference/header.html.twig', [
+ 'conferences' => $conferenceRepository->findAll(),
+ ]));
+ }
+
#[Route('/conference/{slug}', name: 'conference')]
public function show(Request $request, Conference $conference, CommentRepository $commentRepository, string $photoDir): Response
{
|
قم بإنشاء القالب المقابل:
1 2 3 4 5 | <ul>
{% for conference in conferences %}
<li><a href="{{ path('conference', { slug: conference.slug }) }}">{{ conference }}</a></li>
{% endfor %}
</ul>
|
اضغط على /conference_header
للتحقق من أن كل شيء يعمل بشكل جيد.
حان الوقت للكشف عن الخدعة! قم بتحديث تخطيط Twig للاتصال بوحدة التحكم التي أنشأناها للتو:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | --- a/templates/base.html.twig
+++ b/templates/base.html.twig
@@ -8,11 +8,7 @@
<body>
<header>
<h1><a href="{{ path('homepage') }}">Guestbook</a></h1>
- <ul>
- {% for conference in conferences %}
- <li><a href="{{ path('conference', { slug: conference.slug }) }}">{{ conference }}</a></li>
- {% endfor %}
- </ul>
+ {{ render(path('conference_header')) }}
<hr />
</header>
{% block body %}{% endblock %}
|
و voilà. قم بتحديث الصفحة ولا يزال موقع الويب يعرض نفسه.
Tip
استخدم لوحة ملفات التعريف "طلب / استجابة" Symfony لمعرفة المزيد عن الطلب الرئيسي وطلباته الفرعية.
الآن ، في كل مرة تضغط فيها صفحة في المتصفح ، يتم تنفيذ طلبين HTTP ، واحد للرأس وواحد للصفحة الرئيسية. لقد جعلت الأداء أسوأ. تهانينا!
يتم إجراء مكالمة HTTP لرأس المؤتمر حاليًا داخليًا بواسطة Symfony ، لذلك لا يتم تضمين رحلة ذهاب HTTP. هذا يعني أيضًا أنه لا توجد وسيلة للاستفادة من رؤوس ذاكرة التخزين المؤقت HTTP.
تحويل المكالمة إلى HTTP "حقيقي" باستخدام ESI.
أولاً ، قم بتمكين دعم ESI:
1 2 3 4 5 6 7 8 9 10 11 | --- a/config/packages/framework.yaml
+++ b/config/packages/framework.yaml
@@ -11,7 +11,7 @@ framework:
cookie_secure: auto
cookie_samesite: lax
- #esi: true
+ esi: true
#fragments: true
php_errors:
log: true
|
ثم ، استخدم render_esi
بدلا من render
:
1 2 3 4 5 6 7 8 9 10 11 | --- a/templates/base.html.twig
+++ b/templates/base.html.twig
@@ -10,7 +10,7 @@
<body>
<header>
<h1><a href="{{ path('homepage') }}">Guestbook</a></h1>
- {{ render(path('conference_header')) }}
+ {{ render_esi(path('conference_header')) }}
<hr />
</header>
{% block body %}{% endblock %}
|
إذا اكتشفت Symfony وكيلًا عكسيًا يعرف كيفية التعامل مع ESIs ، فسيمكنه الدعم تلقائيًا (إن لم يكن كذلك ، فإنه يعود لتقديم الطلب الفرعي بشكل متزامن).
بما أن الوكيل العكسي لSymfony يدعم ESIs ، فلنراجع سجلاته (قم بإزالة ذاكرة التخزين المؤقت أولاً - انظر "Purging" أدناه):
1 | $ curl -s -I -X GET https://127.0.0.1:8000/
|
1 2 3 4 5 6 7 8 9 10 11 12 | HTTP/2 200
age: 0
cache-control: must-revalidate, no-cache, private
content-type: text/html; charset=UTF-8
date: Mon, 28 Oct 2019 08:20:05 GMT
expires: Mon, 28 Oct 2019 08:20:05 GMT
x-content-digest: en4dd846a34dcd757eb9fd277f43220effd28c00e4117bed41af7f85700eb07f2c
x-debug-token: 719a83
x-debug-token-link: https://127.0.0.1:8000/_profiler/719a83
x-robots-tag: noindex
x-symfony-cache: GET /: miss, store; GET /conference_header: miss
content-length: 50978
|
قم بالتحديث عدة مرات: استجابة `` / `` مخزنة مؤقتًا والاستجابة `` Conference_header/ `` ليست كذلك. لقد حققنا شيئًا رائعًا: وجود الصفحة الكاملة في ذاكرة التخزين المؤقت ولكن لا يزال هناك جزء ديناميكي واحد.
هذا ليس ما نريده بالرغم من ذلك. قم بتخزين صفحة الرأس في ذاكرة التخزين المؤقت لمدة ساعة ، بغض النظر عن أي شيء آخر:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | --- a/src/Controller/ConferenceController.php
+++ b/src/Controller/ConferenceController.php
@@ -44,9 +44,12 @@ class ConferenceController extends AbstractController
#[Route('/conference_header', name: 'conference_header')]
public function conferenceHeader(ConferenceRepository $conferenceRepository): Response
{
- return new Response($this->twig->render('conference/header.html.twig', [
+ $response = new Response($this->twig->render('conference/header.html.twig', [
'conferences' => $conferenceRepository->findAll(),
]));
+ $response->setSharedMaxAge(3600);
+
+ return $response;
}
#[Route('/conference/{slug}', name: 'conference')]
|
تم تمكين ذاكرة التخزين المؤقت الآن لكلا من الطلبين:
1 | $ curl -s -I -X GET https://127.0.0.1:8000/
|
1 2 3 4 5 6 7 8 9 10 11 | HTTP/2 200
age: 613
cache-control: public, s-maxage=3600
content-type: text/html; charset=UTF-8
date: Mon, 28 Oct 2019 07:31:24 GMT
x-content-digest: en15216b0803c7851d3d07071473c9f6a3a3360c6a83ccb0e550b35d5bc484bbd2
x-debug-token: cfb0e9
x-debug-token-link: https://127.0.0.1:8000/_profiler/cfb0e9
x-robots-tag: noindex
x-symfony-cache: GET /: fresh; GET /conference_header: fresh
content-length: 50978
|
يحتوي رأس x-symfony-cache
على عنصرين: الطلب الرئيسي /
وطلب فرعي (conference_header ``ESI). كلاهما في ذاكرة التخزين المؤقت (``الطازجة
).
يمكن أن تختلف استراتيجية التخزين المؤقت عن الصفحة الرئيسية و ESIs الخاصة بها. إذا كانت لدينا صفحة "about" ، فقد نرغب في تخزينها لمدة أسبوع في ذاكرة التخزين المؤقت ، ولا يزال يتم تحديث الرأس كل ساعة.
قم بإزالة المستمع لأننا لسنا بحاجة إليه بعد الآن:
1 | $ rm src/EventSubscriber/TwigEventSubscriber.php
|
تطهير ذاكرة التخزين المؤقت HTTP للاختبار¶
يصبح اختبار موقع الويب في متصفح أو عبر الاختبارات الآلية أكثر صعوبة مع طبقة التخزين المؤقت.
يمكنك إزالة جميع ذاكرة التخزين المؤقت HTTP يدويًا عن طريق إزالة الدليل var/cache/dev/http_cache/
:
1 | $ rm -rf var/cache/dev/http_cache/
|
لا تعمل هذه الإستراتيجية بشكل جيد إذا كنت تريد فقط إبطال بعض عناوين URL أو إذا كنت تريد دمج إلغاء صلاحية ذاكرة التخزين المؤقت في اختباراتك الوظيفية. دعنا نضيف نقطة نهاية HTTP صغيرة ، للمسؤول فقط لإبطال بعض عناوين URL:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | --- a/src/Controller/AdminController.php
+++ b/src/Controller/AdminController.php
@@ -6,8 +6,10 @@ use App\Entity\Comment;
use App\Message\CommentMessage;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
+use Symfony\Bundle\FrameworkBundle\HttpCache\HttpCache;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
+use Symfony\Component\HttpKernel\KernelInterface;
use Symfony\Component\Messenger\MessageBusInterface;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Workflow\Registry;
@@ -52,4 +54,17 @@ class AdminController extends AbstractController
'comment' => $comment,
]);
}
+
+ #[Route('/admin/http-cache/{uri<.*>}', methods: ['PURGE'])]
+ public function purgeHttpCache(KernelInterface $kernel, Request $request, string $uri): Response
+ {
+ if ('prod' === $kernel->getEnvironment()) {
+ return new Response('KO', 400);
+ }
+
+ $store = (new class($kernel) extends HttpCache {})->getStore();
+ $store->purge($request->getSchemeAndHttpHost().'/'.$uri);
+
+ return new Response('Done');
+ }
}
|
تم تقييد وحدة التحكم الجديدة على طريقة HTTP`` PURGE``. هذه الطريقة ليست في معيار HTTP ، لكنها تستخدم على نطاق واسع لإبطال ذاكرة التخزين المؤقت.
بشكل افتراضي ، لا يمكن أن تحتوي معلمات المسار على /
لأنها تفصل بين أجزاء عنوان URL. يمكنك تجاوز هذا القيد لمعلمة المسار الأخيرة ، مثل uri
، عن طريق تعيين نمط المتطلبات الخاص بك (. *
).
يمكن أن تبدو الطريقة التي نحصل بها على مثيل `` HttpCache `` غريبة بعض الشيء ؛ نحن نستخدم فئة مجهولة حيث الوصول إلى الفصل "الحقيقي" غير ممكن. يلف مثيل `` HttpCache `` النواة الحقيقية ، التي لا تدرك طبقة التخزين المؤقت كما ينبغي.
قم بإبطال الصفحة الرئيسية ورأس المؤتمر عبر مكالمات cURL التالية:
1 2 | $ curl -I -X PURGE -u admin:admin `symfony var:export SYMFONY_PROJECT_DEFAULT_ROUTE_URL`/admin/http-cache/
$ curl -I -X PURGE -u admin:admin `symfony var:export SYMFONY_PROJECT_DEFAULT_ROUTE_URL`/admin/http-cache/conference_header
|
يعرض الأمر الفرعي `` symfony var: export SYMFONY_PROJECT_DEFAULT_ROUTE_URL `` عنوان URL الحالي لخادم الويب المحلي.
Note
لا تحتوي وحدة التحكم على اسم مسار حيث لن تتم الإشارة إليه مطلقًا في الكود.
تجميع مسارات مماثلة بإستعمل Prefix¶
المساران في وحدة تحكم المشرف لهما نفس البادئة `` admin/ `` بدلاً من تكرارها في جميع المسارات ، قم بإعادة بناء الطرق لتكوين البادئة على الفصل نفسه:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | --- a/src/Controller/AdminController.php
+++ b/src/Controller/AdminController.php
@@ -15,6 +15,7 @@ use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Workflow\Registry;
use Twig\Environment;
+#[Route('/admin')]
class AdminController extends AbstractController
{
private $twig;
@@ -28,7 +29,7 @@ class AdminController extends AbstractController
$this->bus = $bus;
}
- #[Route('/admin/comment/review/{id}', name: 'review_comment')]
+ #[Route('/comment/review/{id}', name: 'review_comment')]
public function reviewComment(Request $request, Comment $comment, Registry $registry): Response
{
$accepted = !$request->query->get('reject');
@@ -55,7 +56,7 @@ class AdminController extends AbstractController
]);
}
- #[Route('/admin/http-cache/{uri<.*>}', methods: ['PURGE'])]
+ #[Route('/http-cache/{uri<.*>}', methods: ['PURGE'])]
public function purgeHttpCache(KernelInterface $kernel, Request $request, string $uri): Response
{
if ('prod' === $kernel->getEnvironment()) {
|
التخزين المؤقت للعمليات المكثفة للذاكرة / وحدة المعالجة المركزية¶
ليس لدينا خوارزميات تستهلك الكثير من الذاكرة أو وحدة المعالجة المركزية على الموقع. للتحدث عن * ذاكرة التخزين المؤقت المحلية / local caches * ، دعنا ننشئ أمرًا يعرض الخطوة الحالية التي نعمل عليها (لنكون أكثر دقة ، اسم علامة Git المرتبط بتنفيذ Git الحالي).
يسمح لك مكون Symfony Process بتشغيل أمر والحصول على النتيجة مرة أخرى (standard and error output) ؛ قم بتثبيته:
1 | $ symfony composer req process
|
بناء الأمر:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | namespace App\Command;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Process\Process;
class StepInfoCommand extends Command
{
protected static $defaultName = 'app:step:info';
protected function execute(InputInterface $input, OutputInterface $output): int
{
$process = new Process(['git', 'tag', '-l', '--points-at', 'HEAD']);
$process->mustRun();
$output->write($process->getOutput());
return 0;
}
}
|
Note
يمكنك استخدام الأمر `` command:make `` لإنشاء الأمر:
1 | $ symfony console make:command app:step:info
|
ماذا لو أردنا تخزين النتيجة لبضع دقائق؟ استخدم ذاكرة التخزين المؤقت Symfony:
1 | $ symfony composer req cache
|
ولف الكود بمنطق ذاكرة التخزين المؤقت:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | --- a/src/Command/StepInfoCommand.php
+++ b/src/Command/StepInfoCommand.php
@@ -6,16 +6,31 @@ use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Process\Process;
+use Symfony\Contracts\Cache\CacheInterface;
class StepInfoCommand extends Command
{
protected static $defaultName = 'app:step:info';
+ private $cache;
+
+ public function __construct(CacheInterface $cache)
+ {
+ $this->cache = $cache;
+
+ parent::__construct();
+ }
+
protected function execute(InputInterface $input, OutputInterface $output): int
{
- $process = new Process(['git', 'tag', '-l', '--points-at', 'HEAD']);
- $process->mustRun();
- $output->write($process->getOutput());
+ $step = $this->cache->get('app.current_step', function ($item) {
+ $process = new Process(['git', 'tag', '-l', '--points-at', 'HEAD']);
+ $process->mustRun();
+ $item->expiresAfter(30);
+
+ return $process->getOutput();
+ });
+ $output->writeln($step);
return 0;
}
|
يتم استدعاء العملية الآن فقط إذا لم يكن عنصر `` app.current_step `` في ذاكرة التخزين المؤقت.
التنميط ومقارنة الأداء¶
لا تقم بإضافة ذاكرة التخزين المؤقت بدون مبالاة. ضع في اعتبارك أن إضافة بعض ذاكرة التخزين المؤقت يضيف طبقة من التعقيد. وبما أننا جميعًا سيئون جدًا في تخمين ما سيكون سريعًا وما هو بطيء ، فقد ينتهي بك الأمر في موقف حيث تجعل ذاكرة التخزين المؤقت تطبيقك أبطأ.
قم دائمًا بقياس تأثير إضافة ذاكرة التخزين المؤقت باستخدام أداة للتحليل مثل Blackfire.
ارجع إلى خطوة "الأداء" لمعرفة المزيد حول كيفية استخدام Blackfire لاختبار الكود قبل النشر.
إعداد ذاكرة التخزين المؤقت للخادم الوكيل العكسي Reverse Proxy Cache للإنتاج¶
لا تستخدم وكيل Symfony العكسي في الإنتاج. من الأفضل دائمًا استخدام وكيل عكسي مثل Varnish على البنية التحتية أو CDN تجاري.
أضف Varnish إلى خدمات SymfonyCloud:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | --- a/.symfony/services.yaml
+++ b/.symfony/services.yaml
@@ -2,3 +2,12 @@ db:
type: postgresql:13
disk: 1024
size: S
+
+varnish:
+ type: varnish:6.0
+ relationships:
+ application: 'app:http'
+ configuration:
+ vcl: !include
+ type: string
+ path: config.vcl
|
استخدم Varnish كنقطة دخول رئيسية في المسارات:
1 2 3 4 5 6 | --- a/.symfony/routes.yaml
+++ b/.symfony/routes.yaml
@@ -1,2 +1,2 @@
-"https://{all}/": { type: upstream, upstream: "app:http" }
+"https://{all}/": { type: upstream, upstream: "varnish:http", cache: { enabled: false } }
"http://{all}/": { type: redirect, to: "https://{all}/" }
|
أخيرًا ، قم بإنشاء ملف `` config.vcl '' لإعداد Varnish:
1 2 3 | sub vcl_recv {
set req.backend_hint = application.backend();
}
|
تمكين دعم ESI على Varnish¶
يجب تمكين دعم ESI على Varnish بشكل صريح لكل طلب. لجعله عالميًا، يستخدم Symfony الرؤوس القياسية `` Surrogate-Capability `` و `` Surrogate-Control `` للتفاوض بشأن دعم ESI:
1 2 3 4 5 6 7 8 9 10 11 | sub vcl_recv {
set req.backend_hint = application.backend();
set req.http.Surrogate-Capability = "abc=ESI/1.0";
}
sub vcl_backend_response {
if (beresp.http.Surrogate-Control ~ "ESI/1.0") {
unset beresp.http.Surrogate-Control;
set beresp.do_esi = true;
}
}
|
تطهير Varnish Cache¶
ربما لا تكون هناك حاجة أبدًا لإبطال ذاكرة التخزين المؤقت في الإنتاج ، باستثناء الأغراض الطارئة وربما في الفروع غير master
. إذا كنت بحاجة إلى مسح ذاكرة التخزين المؤقت في كثير من الأحيان ، فربما يعني هذا أنه يجب تعديل استراتيجية التخزين المؤقت (عن طريق خفض TTL أو باستخدام استراتيجية التحقق من الصحة بدلاً من انتهاء الصلاحية).
على أي حال ، دعنا نرى كيفية إعداد Varnish لإبطال ذاكرة التخزين المؤقت:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | --- a/.symfony/config.vcl
+++ b/.symfony/config.vcl
@@ -1,6 +1,13 @@
sub vcl_recv {
set req.backend_hint = application.backend();
set req.http.Surrogate-Capability = "abc=ESI/1.0";
+
+ if (req.method == "PURGE") {
+ if (req.http.x-purge-token != "PURGE_NOW") {
+ return(synth(405));
+ }
+ return (purge);
+ }
}
sub vcl_backend_response {
|
في الحياة الواقعية ، ربما تقيد عناوين IP بدلاً من ذلك كما هو موضح في مستندات Varnish.
امسح بعض عناوين URL:
1 2 | $ curl -X PURGE -H 'x-purge-token PURGE_NOW' `symfony env:urls --first`
$ curl -X PURGE -H 'x-purge-token PURGE_NOW' `symfony env:urls --first`conference_header
|
تبدو عناوين URL غريبة بعض الشيء لأن عناوين URL التي يتم إرجاعها بواسطة env:urls
تنتهي بالفعل بـ /
.
- « Previous خطوة 20: مراسلة المدراء
- Next » خطوة 22: تصميم واجهة المستخدم بواسطة Webpack
This work, including the code samples, is licensed under a Creative Commons BY-NC-SA 4.0 license.