Skip to content

Issue #2079, Add cluster support for strict sessions and lazy write #2264

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

Conversation

zorro-fr24
Copy link
Contributor

  • Add ini setting redis.session.early_refresh to allow for session TTL updates on session start ( requires redis server version 6.2 or greater )
  • Enable cluster session support for strict mode sessions ( via PS_VALIDATE_SID_FUNC )
  • Cluster sessions used to write on every session, now we only write if the session has been modified.
  • Send EXPIRE instead of SETEX if sessioh has not been changed
  • If early refresh is enabled use GETEX for initial session read
  • When strict sessions are enabled, check whether the session exists first, validate sid and regenerate if necessary

( Tests pass locally )

The purpose of these changes are to improve the efficiency of the RedisCluster session handler under high traffic. Strict session support has also been added as a side effect of implementing PS_MOD_UPDATE_TIMESTAMP.

session.lazy_write supports the notion that we do not attempt to write session data if it has not been modified, however with redis cluster sessions we always write session on close.

This patch modifies this behaviour to issue SETEX only if data has changed, and EXPIRE otherwise to bump the session TTL

The following performance improvements are observed when running over the network:

image

Legend:
1: redis-rw/1:1,25b      2: redis-rw/2:1,25b     3: redis-rw/4:1,25b      4: redis-rw/10:1,25b   
5: redis-rw/100:1,25b    6: redis-rw/1:1,25kb    7: redis-rw/2:1,25kb     8: redis-rw/4:1,25kb   
9: redis-rw/10:1,25kb   10: redis-rw/100:1,25kb 11: redis-rw/1:1,250kb   12: redis-rw/2:1,250kb  
13: redis-rw/4:1,250kb  14: redis-rw/10:1,250kb 15: redis-rw/100:1,250kb 
+---------+----------------+------------------+
| subject | set            | mode             |
+---------+----------------+------------------+
| redis   | rw/1:1,25b     | 5.279ms -1.50%   |
| redis   | rw/2:1,25b     | 5.311ms -2.19%   |
| redis   | rw/4:1,25b     | 5.223ms -4.44%   |
| redis   | rw/10:1,25b    | 5.337ms -1.51%   |
| redis   | rw/100:1,25b   | 5.321ms -0.74%   |
| redis   | rw/1:1,25kb    | 9.876ms -2.05%   |
| redis   | rw/2:1,25kb    | 8.751ms -12.68%  |
| redis   | rw/4:1,25kb    | 7.971ms -22.65%  |
| redis   | rw/10:1,25kb   | 7.676ms -25.38%  |
| redis   | rw/100:1,25kb  | 7.351ms -27.80%  |
| redis   | rw/1:1,250kb   | 51.727ms +0.92%  |
| redis   | rw/2:1,250kb   | 41.960ms -19.30% |
| redis   | rw/4:1,250kb   | 36.070ms -30.44% |
| redis   | rw/10:1,250kb  | 32.242ms -37.61% |
| redis   | rw/100:1,250kb | 31.196ms -39.24% |
+---------+----------------+------------------+

Performance improvements for small payload sizes are negligible, however as the session payload size increases and the session read to write ratio increases we see a marked improvement in latency.

We can also further improve performance by eliminating an extra roundtrip through the use of GETEX when the session is opened, rather than updating the TTL at the end:

Comparing GETEX vs EXPIRE in the patched version
image

+---------+----------------+-----------------+
| subject | set            | mode            |
+---------+----------------+-----------------+
| redis   | rw/1:1,25b     | 5.262ms -0.32%  |
| redis   | rw/2:1,25b     | 3.972ms -25.21% |
| redis   | rw/4:1,25b     | 3.330ms -36.25% |
| redis   | rw/10:1,25b    | 2.909ms -45.49% |
| redis   | rw/100:1,25b   | 2.689ms -49.47% |
| redis   | rw/1:1,25kb    | 10.025ms +1.51% |
| redis   | rw/2:1,25kb    | 7.415ms -15.26% |
| redis   | rw/4:1,25kb    | 6.165ms -22.66% |
| redis   | rw/10:1,25kb   | 5.385ms -29.85% |
| redis   | rw/100:1,25kb  | 4.984ms -32.19% |
| redis   | rw/1:1,250kb   | 51.405ms -0.62% |
| redis   | rw/2:1,250kb   | 39.593ms -5.64% |
| redis   | rw/4:1,250kb   | 33.705ms -6.56% |
| redis   | rw/10:1,250kb  | 30.029ms -6.86% |
| redis   | rw/100:1,250kb | 28.247ms -9.45% |
+---------+----------------+-----------------+

Comparing GETEX to develop:
image

This has less of an impact on large payload requests, but can greatly reduce the response time of lighter session sizes

The big caveat here is that GETEX requires redis 6.2, which is why I put it behind a config option ( it causes the session TTL to be counted from session start, rather than the end - which might impact long running scripts ). If you would prefer to maintain compatibility with older versions, then I can refactor this PR and remove early refresh, and just include support for SET-EXPIRE. If, however, you are happy to include this change, then it may be worth while to port support for this feature into standalone redis sessions too ( happy to attempt this aswell ).

Please see here for details on how session transactions differ between different modes

Comments welcome

 * Add ini setting redis.session.early_refresh to allow for session TTL updates on session start ( requires redis server version 6.2 or greater )
 * Enable cluster session support for strict mode sessions ( via PS_VALIDATE_SID_FUNC )
 * Cluster sessions used to write on every session, now we only write if the session has been modified.
 * Send EXPIRE instead of SETEX if sessioh has not been changed
 * If early refresh is enabled use GETEX for initial session read
 * When strict sessions are enabled, check whether the session exists first, validate sid and regenerate if necessary
@michael-grunder michael-grunder self-assigned this Nov 28, 2022
@michael-grunder
Copy link
Member

Excellent, thanks for the PR. I'll go over it in the next couple of days.

As an aside what did you use for the benchmarking visualizations?

@zorro-fr24
Copy link
Contributor Author

Great, thanks @michael-grunder
The visualisation is via phpbench's report console output in "benchmark" mode, and using tag refs to compare to previous runs.
Cheers

@michael-grunder michael-grunder merged commit b6cf636 into phpredis:develop Dec 6, 2022
@michael-grunder
Copy link
Member

Great PR, merged!

@zorro-fr24
Copy link
Contributor Author

Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants