خطوة 21: التخزين المؤقت للأداء

5.0 version
Maintained

التخزين المؤقت للأداء

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

اخفاء معلومات خاصة بالHTTP

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

دعنا نخفي الصفحة الرئيسية لمدة ساعة

patch_file
 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
@@ -37,9 +37,12 @@ class ConferenceController extends AbstractController
      */
     public function index(ConferenceRepository $conferenceRepository)
     {
-        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;
     }

     /**

تقوم الطريقة ()setSharedMaxAge بتكوين انتهاء صلاحية ذاكرة التخزين المؤقت لوكلاء عكسيين. استخدم ()setMaxAge للسيطرة على ذاكرة التخزين المؤقت للمستعرض. يتم التعبير عن الوقت بالثواني (ساعة واحدة = 60 دقيقة = 3600 ثانية).

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

تنشيط Symfony HTTP Cache Kernel

لاختبار استراتيجية ذاكرة التخزين المؤقت HTTP ، استخدم الوكيل العكسي Symfony HTTP:

patch_file
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
--- a/public/index.php
+++ b/public/index.php
@@ -1,6 +1,7 @@
 <?php

 use App\Kernel;
+use Symfony\Bundle\FrameworkBundle\HttpCache\HttpCache;
 use Symfony\Component\ErrorHandler\Debug;
 use Symfony\Component\HttpFoundation\Request;

@@ -21,6 +22,11 @@ if ($trustedHosts = $_SERVER['TRUSTED_HOSTS'] ?? $_ENV['TRUSTED_HOSTS'] ?? false
 }

 $kernel = new Kernel($_SERVER['APP_ENV'], (bool) $_SERVER['APP_DEBUG']);
+
+if ('dev' === $kernel->getEnvironment()) {
+    $kernel = new HttpCache($kernel);
+}
+
 $request = Request::createFromGlobals();
 $response = $kernel->handle($request);
 $response->send();

إلى جانب كونه وكيل 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 الذي يعرض المؤتمرات فقط:

patch_file
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
--- a/src/Controller/ConferenceController.php
+++ b/src/Controller/ConferenceController.php
@@ -45,6 +45,16 @@ class ConferenceController extends AbstractController
         return $response;
     }

+    /**
+     * @Route("/conference_header", name="conference_header")
+     */
+    public function conferenceHeader(ConferenceRepository $conferenceRepository)
+    {
+        return new Response($this->twig->render('conference/header.html.twig', [
+            'conferences' => $conferenceRepository->findAll(),
+        ]));
+    }
+
     /**
      * @Route("/conference/{slug}", name="conference")
      */

قم بإنشاء القالب المقابل:

templates/conference/header.html.twig
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 للاتصال بوحدة التحكم التي أنشأناها للتو:

patch_file
 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:

patch_file
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
--- a/config/packages/framework.yaml
+++ b/config/packages/framework.yaml
@@ -10,7 +10,7 @@ framework:
         cookie_secure: auto
         cookie_samesite: lax

-    #esi: true
+    esi: true
     #fragments: true
     php_errors:
         log: true

ثم ، استخدم render_esi بدلا من render:

patch_file
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
--- a/templates/base.html.twig
+++ b/templates/base.html.twig
@@ -8,7 +8,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/ `` ليست كذلك. لقد حققنا شيئًا رائعًا: وجود الصفحة الكاملة في ذاكرة التخزين المؤقت ولكن لا يزال هناك جزء ديناميكي واحد.

هذا ليس ما نريده بالرغم من ذلك. قم بتخزين صفحة الرأس في ذاكرة التخزين المؤقت لمدة ساعة ، بغض النظر عن أي شيء آخر:

patch_file
 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
@@ -50,9 +50,12 @@ class ConferenceController extends AbstractController
      */
     public function conferenceHeader(ConferenceRepository $conferenceRepository)
     {
-        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;
     }

     /**

تم تمكين ذاكرة التخزين المؤقت الآن لكلا من الطلبين:

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:

patch_file
 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
--- 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;
@@ -54,4 +56,19 @@ class AdminController extends AbstractController
             'comment' => $comment,
         ]);
     }
+
+    /**
+     * @Route("/admin/http-cache/{uri<.*>}", methods={"PURGE"})
+     */
+    public function purgeHttpCache(KernelInterface $kernel, Request $request, string $uri)
+    {
+        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_DEFAULT_ROUTE_URL`/admin/http-cache/
$ curl -I -X PURGE -u admin:admin `symfony var:export SYMFONY_DEFAULT_ROUTE_URL`/admin/http-cache/conference_header

يعرض الأمر الفرعي `` symfony var: export SYMFONY_DEFAULT_ROUTE_URL `` عنوان URL الحالي لخادم الويب المحلي.

Note

لا تحتوي وحدة التحكم على اسم مسار حيث لن تتم الإشارة إليه مطلقًا في الكود.

تجميع مسارات مماثلة بإستعمل Prefix

المساران في وحدة تحكم المشرف لهما نفس البادئة `` admin/ `` بدلاً من تكرارها في جميع المسارات ، قم بإعادة بناء الطرق لتكوين البادئة على الفصل نفسه:

patch_file
 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
--- a/src/Controller/AdminController.php
+++ b/src/Controller/AdminController.php
@@ -15,6 +15,9 @@ use Symfony\Component\Routing\Annotation\Route;
 use Symfony\Component\Workflow\Registry;
 use Twig\Environment;

+/**
+ * @Route("/admin")
+ */
 class AdminController extends AbstractController
 {
     private $twig;
@@ -29,7 +32,7 @@ class AdminController extends AbstractController
     }

     /**
-     * @Route("/admin/comment/review/{id}", name="review_comment")
+     * @Route("/comment/review/{id}", name="review_comment")
      */
     public function reviewComment(Request $request, Comment $comment, Registry $registry)
     {
@@ -58,7 +61,7 @@ class AdminController extends AbstractController
     }

     /**
-     * @Route("/admin/http-cache/{uri<.*>}", methods={"PURGE"})
+     * @Route("/http-cache/{uri<.*>}", methods={"PURGE"})
      */
     public function flushHttpCache(KernelInterface $kernel, Request $request, string $uri)
     {

التخزين المؤقت للعمليات المكثفة للذاكرة / وحدة المعالجة المركزية

ليس لدينا خوارزميات تستهلك الكثير من الذاكرة أو وحدة المعالجة المركزية على الموقع. للتحدث عن * ذاكرة التخزين المؤقت المحلية / local caches * ، دعنا ننشئ أمرًا يعرض الخطوة الحالية التي نعمل عليها (لنكون أكثر دقة ، اسم علامة Git المرتبط بتنفيذ Git الحالي).

يسمح لك مكون Symfony Process بتشغيل أمر والحصول على النتيجة مرة أخرى (standard and error output) ؛ قم بتثبيته:

1
$ symfony composer req process

بناء الأمر:

src/Command/StepInfoCommand.php
 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

ولف الكود بمنطق ذاكرة التخزين المؤقت:

patch_file
 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:

patch_file
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
--- a/.symfony/services.yaml
+++ b/.symfony/services.yaml
@@ -7,3 +7,12 @@ queue:
     type: rabbitmq:3.5
     disk: 1024
     size: S
+
+varnish:
+    type: varnish:6.0
+    relationships:
+        application: 'app:http'
+    configuration:
+        vcl: !include
+            type: string
+            path: config.vcl

استخدم Varnish كنقطة دخول رئيسية في المسارات:

patch_file
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:

.symfony/config.vcl
1
2
3
sub vcl_recv {
    set req.backend_hint = application.backend();
}

تمكين دعم ESI على Varnish

يجب تمكين دعم ESI على Varnish بشكل صريح لكل طلب. لجعله عالميًا، يستخدم Symfony الرؤوس القياسية `` Surrogate-Capability `` و `` Surrogate-Control `` للتفاوض بشأن دعم ESI:

.symfony/config.vcl
 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 لإبطال ذاكرة التخزين المؤقت:

patch_file
 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.