Skip to content

improve caching of the user context hash lookup in Varnish #497

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Dec 21, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,17 @@ Changelog

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

2.12.0 (unreleased)
-------------------

### Varnish Cache

* Added a `fos_user_context_hash` method to be called in `vcl_hash` when using the user context
hash mechanism. This can avoid performance problems Varnish can run into when the hash `Vary`s on
the basic authentication or session cookie.
If you use the user context, read the updated documentation and call `fos_user_context_hash` in
your `vcl_hash` function.

2.11.0
------

Expand Down
16 changes: 16 additions & 0 deletions doc/varnish-configuration.rst
Original file line number Diff line number Diff line change
Expand Up @@ -295,6 +295,10 @@ To enable this feature, add the following to ``your_varnish.vcl``:
call fos_user_context_recv;
}

sub vcl_hash {
call fos_user_context_hash;
}

sub vcl_backend_response {
call fos_user_context_backend_response;
}
Expand All @@ -312,6 +316,10 @@ To enable this feature, add the following to ``your_varnish.vcl``:
call fos_user_context_recv;
}

sub vcl_hash {
call fos_user_context_hash;
}

sub vcl_fetch {
call fos_user_context_fetch;
}
Expand Down Expand Up @@ -344,6 +352,13 @@ request with :ref:`a proper user hash <return context hash>`.
set the ``req.url`` to a fixed URL. Otherwise Varnish would cache every
hash lookup separately.

The ``fos_user_context_hash`` should be used to separate the cache of the
hash lookup. If you don't do that, Varnish can run into performance issues
because the user hash lookup creates a `large number of variants`_. If your
hash is taking into account other headers than ``Authorization`` and
``Cookie``, create your own ``vcl_hash`` function that adds all those
headers to ``hash_data`` for user context hash lookup requests.

However, if you have a :ref:`paywall scenario <paywall_usage>`, you need to
leave the original URL unchanged. For that case, you would need to write
your own VCL.
Expand Down Expand Up @@ -468,5 +483,6 @@ To enable this feature, add the following to ``your_varnish.vcl``:
.. _ykey documentation: https://docs.varnish-software.com/varnish-cache-plus/vmods/ykey/
.. _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
.. _installing xkey: https://github.com/varnish/varnish-modules#installation
.. _large number of variants: https://github.com/varnishcache/varnish-cache/pull/3520
.. _`builtin VCL`: https://github.com/varnishcache/varnish-cache/blob/5.0/bin/varnishd/builtin.vcl
.. _`default VCL`: https://github.com/varnishcache/varnish-cache/blob/3.0/bin/varnishd/default.vcl
19 changes: 19 additions & 0 deletions resources/config/varnish-3/fos_user_context.vcl
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,10 @@ sub fos_user_context_recv {

# Force the lookup, the backend must tell not to cache or vary on all
# headers that are used to build the hash.
#
# To avoid massive performance issues when caching the hash lookup request, see
# fos_user_context_hash

return (lookup);
}

Expand All @@ -67,6 +71,21 @@ sub fos_user_context_recv {
}
}

/**
* When caching the hash lookup request with a session or basic auth, we should include that
* information in the hash.
*
* If we would only rely on Varnish keeping the variants of the response apart with the Vary
* header, Varnish has to lookup the right variant. With a large number of users, this is extremly
* inefficient as Varnish does not optimize Variant search and we get O(n) on the number of users.
*/
sub fos_user_context_hash {
if (req.http.accept == "application/vnd.fos.user-context-hash") {
hash_data(req.http.Cookie);
hash_data(req.http.Autorization);
}
}

sub fos_user_context_fetch {
if (req.restarts == 0
&& req.http.accept ~ "application/vnd.fos.user-context-hash"
Expand Down
3 changes: 3 additions & 0 deletions resources/config/varnish-3/fos_user_context_url.vcl
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@
* file that was distributed with this source code.
*/

/**
* This function is in a separate file so that you can easily adjust the lookup URL to your needs.
*/
sub user_context_hash_url {
set req.url = "/_fos_user_context_hash";
}
19 changes: 19 additions & 0 deletions resources/config/varnish/fos_user_context.vcl
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,10 @@ sub fos_user_context_recv {

# Force the lookup, the backend must tell not to cache or vary on all
# headers that are used to build the hash.
#
# To avoid massive performance issues when caching the hash lookup request, see
# fos_user_context_hash

return (hash);
}

Expand All @@ -67,6 +71,21 @@ sub fos_user_context_recv {
}
}

/**
* When caching the hash lookup request with a session or basic auth, we should include that
* information in the hash.
*
* If we would only rely on Varnish keeping the variants of the response apart with the Vary
* header, Varnish has to lookup the right variant. With a large number of users, this is extremly
* inefficient as Varnish does not optimize Variant search and we get O(n) on the number of users.
*/
sub fos_user_context_hash {
if (req.http.accept == "application/vnd.fos.user-context-hash") {
hash_data(req.http.Cookie);
hash_data(req.http.Autorization);
}
}

sub fos_user_context_backend_response {
if (bereq.http.accept ~ "application/vnd.fos.user-context-hash"
&& beresp.status >= 500
Expand Down
3 changes: 3 additions & 0 deletions resources/config/varnish/fos_user_context_url.vcl
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@
* file that was distributed with this source code.
*/

/**
* This function is in a separate file so that you can easily adjust the lookup URL to your needs.
*/
sub user_context_hash_url {
set req.url = "/_fos_user_context_hash";
}
6 changes: 5 additions & 1 deletion tests/Functional/Fixtures/varnish-3/user_context.vcl
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,15 @@ sub vcl_recv {
call fos_user_context_recv;
}

sub vcl_hash {
call fos_user_context_hash;
}

sub vcl_fetch {
call fos_user_context_fetch;
}

sub vcl_deliver {
call fos_debug_deliver;
call fos_user_context_deliver;
}
}
4 changes: 4 additions & 0 deletions tests/Functional/Fixtures/varnish/user_context.vcl
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@ sub vcl_recv {
call fos_user_context_recv;
}

sub vcl_hash {
call fos_user_context_hash;
}

sub vcl_backend_response {
call fos_user_context_backend_response;
}
Expand Down