KEYCLOAK-11019 Initial support for lazy offline user-session loading#7722
Conversation
pedroigor
left a comment
There was a problem hiding this comment.
Overall, looks good to me.
It should not break existing behavior while making possible to lazy load offline sessions. The impact on sessions list should be expected as we discussed in the mailing list.
Let's see what @mposolda thinks about it.
f3e36a0 to
1256be1
Compare
|
Rebased on current master |
martin-kanis
left a comment
There was a problem hiding this comment.
@thomasdarimont Thank you for the PR.
Is this feature somehow tested? If not, maybe it's worth to add some tests.
Next the JpaUserSessionPersisterProvider.java should use Java Streams as we recently changed collections to streams where ever that make sense. See the suggestions inline.
Finally I would add javadocs to newly introduced methods in UserSessionPersisterProvider.java interface.
|
@martin-kanis Thanks or your suggestions. I'd prefer to leave the code as is for now, to keep the style in this class consistent. Btw. I think the JPA query result stream in I'm fine with adding the javadoc comments to the new API. Regarding tests, how can I test offline-sessions with a custom |
1256be1 to
8c8ee34
Compare
|
@thomasdarimont Actually the streamification epic was finished by this commit which also covers the |
fe3571a to
50467ac
Compare
|
@martin-kanis Thanks for the hint. I just rebased the PR to the current master and revised the Streams API usage as you suggested. Do you have an idea how I could address the testing issues I mentioned above? |
I also think "streamification" should not be a design principle, but used when (after testing and profiling) and where it makes sense. |
stianst
left a comment
There was a problem hiding this comment.
I don't really know what was agreed on in the thread as it was a lot of back and forth, mixing short-term and long-term. This is kinda why we have the design proposals in the first place so we can have a written down agreed upon plan, as mailing lists are okay for discussions, but terrible way of capturing the output of a discussion.
So as lazy loading from the DB is disabled by default, I assume that's because it's breaking something, as otherwise it would just make no sense to have this as an option and just always lazy load offline sessions from the DB. What specifically is being broken?
stianst
left a comment
There was a problem hiding this comment.
I'm going to request at least some changes here:
- Describe what the side-effects are. It seems like to me that this may break anything that views/lists offline sessions in cases where the sessions hasn't been lazy loaded yet, including the ability for users and admins to view/manage offline sessions. If that's the case I don't really like the idea of merging this PR
- If it's an option it needs documenting. If there are going to be difference in behaviour it has to be documented. As it stands this is a "hidden" config option that only a select few will know about, and anyone that stumbles across it won't know what benefits/drawbacks the option provides
|
I would say that loading data and blocking at boot time is by itself a broken design. And for this particular case, it has a huge impact on use cases using offline sessions. We have quite a few workarounds already to overcome this problem (e.g.: sessionsPerSegment, DB indexes, not sure if documented) that works until a certain point. Oracle, for instance, has a serious limitation on how much you can set sessionsPerSegment. IMO, the proposed changes provide a good balance for those facing the problem we are fixing while sacrificing some functionality that is not used or important. It should also help to pave the road for further improvements and in a proper fix that not necessarily impacts existing functionality. |
|
Hello @stianst, @pedroigor, @martin-kanis, Thanks a lot for the great discussion and useful feedback! "Describe what the side-effects are."
"If it's an option, it needs documenting"I'd document this alongside the mentioned @stianst This PR is an IMHO workaround that solves a current flaw in Keycloak's offline-session handling that affects a large number of Keycloak deployments. This helps to solve scalability problems for IMHO a large number of users today. Some useful enhancements
This is, of course, not a replacement for the mid-long term storage architecture redesign :) |
|
@thomasdarimont Thanks for the update, that's very useful information. Main thing I'd want is that there is no limitations that prevents people from being able to use it. For the account console will it load offline sessions from the DB for the given user so the user can see offline sessions even though they haven't been pre-loaded yet? For the admin console if I look at sessions for a given user does it show them then? Reminding myself how the sessions management looks like in the admin console there's options to logout sessions for a given user, or all sessions, not for an individual application. So as long as we can logout for a given user I think we're covered here as a "working workaround" ;) |
|
@stianst thanks for the quick reply.
Good catch. If the offline user-session pre-loading is disabled and the offline user-session is not loaded yet, then the "revoke grant" button is missing in the applications page of the account-console. The current implementation of the ApplicationsBean seems to load the offline-sessions only from the cache.
If the offline user-session is not loaded yet, then user/consents will not list the offline_access grant. I give this a quick try now. |
3b1b0e8 to
4bdfbe8
Compare
|
@stianst @pedroigor I just updated the PR with the changes to fix the issues mentioned by stian
I think the only caveat rest is that admin-console -> clients -> client -> Offline Access will only show offline-sessions that are loaded in memory. The (total) number of offline sessions will be the correct count of offline-sessions in the database. |
There was a problem hiding this comment.
I think it is good to have pagination support here, but I wasn't sure about default limits.
There was a problem hiding this comment.
IMO pagination support may not be so urgent for the users? I suppose that it will be very rare that single user has for example 1000 offline sessions? Pagination makes sense for the clients IMO and it is already available in the admin console (however not yet supported in the PR as mentioned in the comment).
02b6e62 to
c508329
Compare
|
Just rebased on current master |
hmlnarik
left a comment
There was a problem hiding this comment.
Hi @thomasdarimont Thank you for patience - it took a while for me to get to this PR as I'm still in a catch-up mode after an unexpected long term leave.
Overall it looks good to me, only the indices could be improved as you have also mentioned. I've done some analysis of the queries here. Based on the analysis, I am suggesting change the indices, please see inline.
There was a problem hiding this comment.
I believe that IDX_OFFLINE_USS_BY_USER and IDX_OFFLINE_USS_BY_USERSESS would be more helpful if structured differently:
IDX_OFFLINE_USS_BY_USERSESSas index on(REALM_ID, OFFLINE_FLAG, USER_SESSION_ID)(different field order)IDX_OFFLINE_USS_BY_USERas index on(USER_ID, REALM_ID, OFFLINE)
There was a problem hiding this comment.
Thanks, I'll adjust the indices as you suggested.
There was a problem hiding this comment.
Reversing the two fields, ie. index on (CLIENT_ID, OFFLINE_FLAG) would be more helpful. OFFLINE_FLAG selectivity is rather bad, so it roughly corresponds to seq scan, while client_id is rather very specific. Sole CLIENT_ID is used in deleteClientSessionsByClient query.
There was a problem hiding this comment.
The indices could be improved, see below. The analysis of how to improve the indices is here
|
Hi @thomasdarimont, would you have time to move this PR forward? |
|
Hi @thomasdarimont This PR has been inactive for almost two weeks. Will you be able to move this PR forward? |
|
@hmlnarik yes, I have a few days vacation ahead and I'm going to use some of my time to work on this. As I've been also involved in the user-profile / validation API discussion, I had to adjust some priorities ;-) |
…ase query if in-memory lookup fails for offline sessions Allow to configure pre-loading of offline user-sessions We now allow to configure whether offline user-sessions should be preloaded on startup from the database. We now trigger offline user-sessions loading when UserSessionProvider#getOfflineUserSessionsStream(realm,user) is called. This ensures that the user can revoke the offline_access consent via the account console. Additionally the (offline) user consents are now displayed correctly for a user in the admin-console. Offline user-sessions are now correctly display if offline user-sessions are loaded lazily. Add note about unsupported lazy offline session loading by broker info: Currently we don't support lazy offline user-session lookup by brokerSessionId and brokerUserId. See: keycloak#7722 (review) Keep behavior of 'logout all sessions' and don't delete dangling offline sessions. As discussed in keycloak#7722 (comment) Throw on unsupported dynamic offline user-session lookups from database
… user-session lookups
Removed redundant condition checking. We use the `coalesce` function to make the queries work for a specific realm / client or all, e.g.: ``` clientSess.clientId = coalesce(CAST(:clientId as text), clientSess.clientId) ``` Note that the explicit cast is required to treat null values as text to avoid confusing databases.
c508329 to
ea19d79
Compare
|
@hmlnarik I updated the indices and rebased the branch again. Btw. did you see #7902? I think that and this PR would work well together. There is also the idea of expiring offline session cache entries to keep memory consumption low mentioned here: #7902 (comment) |
|
@thomasdarimont Apologies I did not respond. Thank you for the updates, the PR looks much better. Could you please have a look at the failures of GitHub actions? They are related to this PR. Yup, #7902 looks interesting though I've not yet have a chance to go through it in detail. |
|
@thomasdarimont We (me and @nigtrifork) have been experimenting with lazy loading of the offlineClientSessions as an extension of this PR. The idea was to avoid the synchonization issues mentionen in the discoussion in #7902 if the offline session caches are configured to expire. |
…ase query if in-memory lookup fails for offline sessions Allow to configure pre-loading of offline user-sessions We now allow to configure whether offline user-sessions should be preloaded on startup from the database. We now trigger offline user-sessions loading when UserSessionProvider#getOfflineUserSessionsStream(realm,user) is called. This ensures that the user can revoke the offline_access consent via the account console. Additionally the (offline) user consents are now displayed correctly for a user in the admin-console. Offline user-sessions are now correctly display if offline user-sessions are loaded lazily. Add note about unsupported lazy offline session loading by broker info: Currently we don't support lazy offline user-session lookup by brokerSessionId and brokerUserId. See: keycloak#7722 (review) Keep behavior of 'logout all sessions' and don't delete dangling offline sessions. As discussed in keycloak#7722 (comment) Throw on unsupported dynamic offline user-session lookups from database
|
@thomasdarimont I opened a new PR #8033 which includes this PR plus rebase to current master plus adds some model tests. Let us please know whether you wish pull those changes here or we can close this PR and proceed with #8033. Thank you. |
|
@martin-kanis thanks for the update! I have no problem closing this PR and continue in the combined efforts in the new one. |
|
Thank you @thomasdarimont and @martin-kanis. Closing this one in favor of #8033. |
…ase query if in-memory lookup fails for offline sessions Allow to configure pre-loading of offline user-sessions We now allow to configure whether offline user-sessions should be preloaded on startup from the database. We now trigger offline user-sessions loading when UserSessionProvider#getOfflineUserSessionsStream(realm,user) is called. This ensures that the user can revoke the offline_access consent via the account console. Additionally the (offline) user consents are now displayed correctly for a user in the admin-console. Offline user-sessions are now correctly display if offline user-sessions are loaded lazily. Add note about unsupported lazy offline session loading by broker info: Currently we don't support lazy offline user-session lookup by brokerSessionId and brokerUserId. See: keycloak#7722 (review) Keep behavior of 'logout all sessions' and don't delete dangling offline sessions. As discussed in keycloak#7722 (comment) Throw on unsupported dynamic offline user-session lookups from database
This PR introduces initial support for lazy-loading of offline user-sessions.
See the discussion on the keycloak-dev group
As a start, we allow to disable the pre-loading of offline sessions from the database. At a later stage we can also disable the pre-loading from a remote-cache storage.
If an offline user-session is missing from the infinispan sessions or clientSession cache, we try to find the offline user-session in the database. If the session is found, we dynamically import it into the appropriate infinispan cache.
Additionally we now allow to disable loading of offline user-sessions during startup via the new
preloadOfflineSessionsFromDatabaseproperty of theinfinispan userSessionsprovider.patch-standalone-ha.cli:
build the keycloak distribution from source:
once this is finished, you can find your Keycloak distribution in
distribution/server-dist/targetas .zip or .tar.gz.Apply
patch-standalone-ha.clitostandalone-ha.xmlStart Keycloak:
You should now see a DEBUG log message like:
If you try to obtain a new access token for a given (offline) refresh-token you should see the following in the log: