Skip to content

[Performance] Varnish ban regex has very poor performance #495

Description

@bastnic

The regexp used in Varnish ban has very poor performance.

This is a backport of a fix already merged in API Platform, where it's a little easier to fix because we know in advance the pattern of the tags to ban. More specifically, on APIP, we know that a tag always began with a / and as they are iri, they are unique and not nested. We can then strip the first group (^|,).

This is not the case here where tags could be anything.
This is something I wanted to talk since a long time but didn't took the time to share because I don't have the correct generic solution. Maybe you will have one.


The current ban regexp is not optimize and killed my varnish server to 100% cpu.

Several reasons, but let's explain how that work. This is a question of

rq/s * ban/s * size of the cache tags header * complexity of the regexp

I've a high number of requests and bans per seconds. The response has a lot of tags.

But I only ban one resource at a time, so the regexp was not that complex at first look.

Varnish stores all ban in a (deduplicated) list. Each cached resource has a pointer to the last ban checked.
If you add bans, when you call a cached resources, it will check against all the new bans and store the last ones.

The number of regexp analysis was high, but I can change my traffic, so I can only adjust the header itself or the regexp.

I looked at the regexp first

((^|,)/pim/v1/variants($|,))|((^|,)/pim/v1/variants/e3615f0c-a957-4a85-88b9-8db30d5c5c02($|,))|((^|,)/pim/v1/models/bebdee7b-fb53-448b-b79e-1bcf0dbcf050($|,))

Step 1: checking the begining of the resources is not useful if tags are only handled by apip.

(/pim/v1/variants($|,))|(/pim/v1/variants/e3615f0c-a957-4a85-88b9-8db30d5c5c02($|,))|(/pim/v1/models/bebdee7b-fb53-448b-b79e-1bcf0dbcf050($|,))

Stepe 2: regrouping the end tag at the end is better.

(/pim/v1/variants|/pim/v1/variants/e3615f0c-a957-4a85-88b9-8db30d5c5c02|/pim/v1/models/bebdee7b-fb53-448b-b79e-1bcf0dbcf050)($|,)

Step 3: remove the prefix from the regexp

(/variants|/variants/e3615f0c-a957-4a85-88b9-8db30d5c5c02|/models/bebdee7b-fb53-448b-b79e-1bcf0dbcf050)($|,)

Step 4: remove the prefix from the source header

Bench:

subject mean diff
benchCurrent 1.612μs 7.91x
benchStep1 0.575μs 2.82x
benchStep2 0.504μs 2.47x
benchStep3 0.492μs 2.41x
benchStep4 0.204μs 1.00x

On my production, I published Step3 today at 12:15:

image

On another project, I will let you guess when the patch was released:
image

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions