Skip to content

Commit c060a05

Browse files
committed
improve caching of the user context hash lookup in Varnish
Thanks to Bastian Jaillot (@bastnic) for reporting the performance analysis and proposing this solution. Further details can be found at #496
1 parent 39999a6 commit c060a05

File tree

8 files changed

+80
-1
lines changed

8 files changed

+80
-1
lines changed

CHANGELOG.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,17 @@ Changelog
33

44
See also the [GitHub releases page](https://github.com/FriendsOfSymfony/FOSHttpCache/releases).
55

6+
2.10.1
7+
------
8+
9+
### Varnish Cache
10+
11+
* Added a `fos_user_context_hash` method to be called in `vcl_hash` when using the user context
12+
hash mechanism. This can avoid performance problems Varnish can run into when the hash `Vary`s on
13+
the basic authentication or session cookie.
14+
If you use the user context, read the updated documentation and call `fos_user_context_hash` in
15+
your `vcl_hash` function.
16+
617
2.10.0
718
------
819

doc/varnish-configuration.rst

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -297,6 +297,10 @@ To enable this feature, add the following to ``your_varnish.vcl``:
297297
call fos_user_context_recv;
298298
}
299299
300+
sub vcl_hash {
301+
call fos_user_context_hash;
302+
}
303+
300304
sub vcl_backend_response {
301305
call fos_user_context_backend_response;
302306
}
@@ -314,6 +318,10 @@ To enable this feature, add the following to ``your_varnish.vcl``:
314318
call fos_user_context_recv;
315319
}
316320
321+
sub vcl_hash {
322+
call fos_user_context_hash;
323+
}
324+
317325
sub vcl_fetch {
318326
call fos_user_context_fetch;
319327
}
@@ -346,6 +354,13 @@ request with :ref:`a proper user hash <return context hash>`.
346354
set the ``req.url`` to a fixed URL. Otherwise Varnish would cache every
347355
hash lookup separately.
348356

357+
The ``fos_user_context_hash`` should be used to separate the cache of the
358+
hash lookup. If you don't do that, Varnish can run into performance issues
359+
because the user hash lookup creates a `large number of variants`_. If your
360+
hash is taking into account other headers than ``Authorization`` and
361+
``Cookie``, create your own ``vcl_hash`` function that adds all those
362+
headers to ``hash_data`` for user context hash lookup requests.
363+
349364
However, if you have a :ref:`paywall scenario <paywall_usage>`, you need to
350365
leave the original URL unchanged. For that case, you would need to write
351366
your own VCL.
@@ -470,5 +485,6 @@ To enable this feature, add the following to ``your_varnish.vcl``:
470485
.. _ykey documentation: https://docs.varnish-software.com/varnish-cache-plus/vmods/ykey/
471486
.. _Cache Invalidation chapter of the Varnish documentation: http://book.varnish-software.com/4.0/chapters/Cache_Invalidation.html#hashtwo-xkey-varnish-software-implementation-of-surrogate-keys
472487
.. _installing xkey: https://github.com/varnish/varnish-modules#installation
488+
.. _large number of variants: https://github.com/varnishcache/varnish-cache/pull/3520
473489
.. _`builtin VCL`: https://github.com/varnishcache/varnish-cache/blob/5.0/bin/varnishd/builtin.vcl
474490
.. _`default VCL`: https://github.com/varnishcache/varnish-cache/blob/3.0/bin/varnishd/default.vcl

resources/config/varnish-3/fos_user_context.vcl

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,10 @@ sub fos_user_context_recv {
4343

4444
# Force the lookup, the backend must tell not to cache or vary on all
4545
# headers that are used to build the hash.
46+
#
47+
# To avoid massive performance issues when caching the hash lookup request, see
48+
# fos_user_context_hash
49+
4650
return (lookup);
4751
}
4852

@@ -67,6 +71,21 @@ sub fos_user_context_recv {
6771
}
6872
}
6973

74+
/**
75+
* When caching the hash lookup request with a session or basic auth, we should include that
76+
* information in the hash.
77+
*
78+
* If we would only rely on Varnish keeping the variants of the response apart with the Vary
79+
* header, Varnish has to lookup the right variant. With a large number of users, this is extremly
80+
* inefficient as Varnish does not optimize Variant search and we get O(n) on the number of users.
81+
*/
82+
sub fos_user_context_hash {
83+
if (req.http.accept == "application/vnd.fos.user-context-hash") {
84+
hash_data(req.http.Cookie);
85+
hash_data(req.http.Autorization);
86+
}
87+
}
88+
7089
sub fos_user_context_fetch {
7190
if (req.restarts == 0
7291
&& req.http.accept ~ "application/vnd.fos.user-context-hash"

resources/config/varnish-3/fos_user_context_url.vcl

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@
77
* file that was distributed with this source code.
88
*/
99

10+
/**
11+
* This function is in a separate file so that you can easily adjust the lookup URL to your needs.
12+
*/
1013
sub user_context_hash_url {
1114
set req.url = "/_fos_user_context_hash";
1215
}

resources/config/varnish/fos_user_context.vcl

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,10 @@ sub fos_user_context_recv {
4343

4444
# Force the lookup, the backend must tell not to cache or vary on all
4545
# headers that are used to build the hash.
46+
#
47+
# To avoid massive performance issues when caching the hash lookup request, see
48+
# fos_user_context_hash
49+
4650
return (hash);
4751
}
4852

@@ -67,6 +71,21 @@ sub fos_user_context_recv {
6771
}
6872
}
6973

74+
/**
75+
* When caching the hash lookup request with a session or basic auth, we should include that
76+
* information in the hash.
77+
*
78+
* If we would only rely on Varnish keeping the variants of the response apart with the Vary
79+
* header, Varnish has to lookup the right variant. With a large number of users, this is extremly
80+
* inefficient as Varnish does not optimize Variant search and we get O(n) on the number of users.
81+
*/
82+
sub fos_user_context_hash {
83+
if (req.http.accept == "application/vnd.fos.user-context-hash") {
84+
hash_data(req.http.Cookie);
85+
hash_data(req.http.Autorization);
86+
}
87+
}
88+
7089
sub fos_user_context_backend_response {
7190
if (bereq.http.accept ~ "application/vnd.fos.user-context-hash"
7291
&& beresp.status >= 500

resources/config/varnish/fos_user_context_url.vcl

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@
77
* file that was distributed with this source code.
88
*/
99

10+
/**
11+
* This function is in a separate file so that you can easily adjust the lookup URL to your needs.
12+
*/
1013
sub user_context_hash_url {
1114
set req.url = "/_fos_user_context_hash";
1215
}

tests/Functional/Fixtures/varnish-3/user_context.vcl

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,15 @@ sub vcl_recv {
55
call fos_user_context_recv;
66
}
77

8+
sub vcl_hash {
9+
call fos_user_context_hash;
10+
}
11+
812
sub vcl_fetch {
913
call fos_user_context_fetch;
1014
}
1115

1216
sub vcl_deliver {
1317
call fos_debug_deliver;
1418
call fos_user_context_deliver;
15-
}
19+
}

tests/Functional/Fixtures/varnish/user_context.vcl

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,10 @@ sub vcl_recv {
55
call fos_user_context_recv;
66
}
77

8+
sub vcl_hash {
9+
call fos_user_context_hash;
10+
}
11+
812
sub vcl_backend_response {
913
call fos_user_context_backend_response;
1014
}

0 commit comments

Comments
 (0)