How does Hash persistence work?
Short answer
Hash persistence maps the value of a key defined with a Smart Variable in the Hash Key field (e.g. the client IP, an HTTP header, a cookie value) to the selected Backend Service and keeps it in a table on TR7. On the first request, the Backend Service is selected by the algorithm of the vService; subsequent requests with the same key go to the same Backend Service until the record duration (Hash Key Expire Time, default 7 days) expires. Since it does not require a cookie, it is used on the L7 TCP vService as well as on HTTP. The table is device-local; it is not shared between cluster devices and is reset when the vService is reloaded.
How Does It Work?
- When a request arrives, the key is created by combining the values of the Smart Variables in the Hash Key list.
- If the key is in the table, the request goes to the recorded server and the duration of the record is refreshed.
- If the key is not in the table, the server is selected by the algorithm of the vService (e.g. Least Connection) and the mapping is written to the table.
- The record is deleted if no request arrives during Hash Key Expire Time.
- If the table becomes full, the oldest records are discarded.
Fields
| Field | Default | Range |
|---|---|---|
| Hash Key | The form opens with the first suitable Smart Variable; at least one entry is required, and the same entry cannot be added twice | – |
| Hash Key List Size | 3,000,000 records | 10,000 – 100,000,000 |
| Hash Key Expire Time | 7 days | 10 minutes – 365 days |
Key Examples
| Key (Smart Variable) | Suitable case |
|---|---|
| Client IP address | Simple IP persistence (caution behind NAT) |
Request header (e.g. X-Client-ID, API key) | API clients, clients that do not support cookies |
| Request cookie | Persistence based on the session cookie of the application |
| URL / query parameter | Cache layer, per-tenant routing |
| Connection-level variables in L7 TCP (e.g. the client IP) | On the L7 TCP vService, only the Smart Variables resolved at connection level are listed (Variables · Which Variables a Field Lists) |
By adding functions (e.g. Hash, JWT Payload Query, Replace) to the Smart Variables, the key can be shortened or extracted.
Relationship with the Algorithm
Hash persistence and the distribution method are selected separately: new keys are distributed by the algorithm (e.g. Least Connection), and the mapping is kept in the table. In hash algorithms such as Source, however, the server is selected with a hash calculation, and the distribution method cannot be selected separately. The hash table is not preserved when the vService configuration is reloaded; details are given on the Does saving a configuration change reset the persistence tables? page.
In TR7
- Location: Load Balancer → Load Balancer vService List → vService → Edit → Details → LB Algorithm box → Persistence → Hash (Persistence); Hash Key, Hash Key List Size and Hash Key Expire Time appear only while Hash is selected; it is saved with Save. While a self-persistent algorithm is selected, the Persistence field does not appear.
- WEB-CLI:
--persistence dynamicPersistence, the keys--dynamicPersistenceKeys.N, the table size--dynamicPersistenceTableSize, the duration--dynamicPersistenceTableExpire.val/.unit. - Cluster: The settings are transferred to the peer device automatically while Clustering is on and Manual Sync Mode is off (default); the table, however, is separate on each device. If the traffic is received by more than one device at the same time, or if the VIP moves to the peer device, the same key is mapped again with the algorithm on the other device.
Common Misconceptions
- "Hash calculates the server from the key, like an algorithm." The algorithm selects the server the first time; Hash only stores the mapping.
- "The table is shared in the cluster." It is device-local.
- "The key has to be the client IP." It can be any Smart Variable; for users behind NAT, a key other than the IP is recommended.
- "Requests without the key are also persistent." Requests whose key value arrives empty share the same empty key; it should be ensured that the key is present in every request.
How it is done in the documentation
