[keycloak-dev] Slight refactoring of InfinispanUserSessionProvider

Schuster Sebastian (INST/ESY1) Sebastian.Schuster at bosch-si.com
Tue May 16 03:38:02 EDT 2017

Hi Marek,

You mentioned in your proposed solution that " The changes may not be guaranteed in same order in every DC". Wouldn't that be a problem as it leads to inconsistent data in different data centers?

Best regards,

P.S.: If I recall correctly, Infinispan does not support a "serializable" isolation level preventing lost updates, so even if Keycloak used the transaction API, it would not help...

Mit freundlichen Grüßen / Best regards

 Sebastian Schuster

Engineering and Support (INST/ESY1) 
Bosch Software Innovations GmbH | Schöneberger Ufer 89-91 | 10785 Berlin | GERMANY | www.bosch-si.com
Tel. +49 30 726112-485 | Fax +49 30 726112-100 | Sebastian.Schuster at bosch-si.com

Sitz: Berlin, Registergericht: Amtsgericht Charlottenburg; HRB 148411 B 
Geschäftsführung: Dr.-Ing. Rainer Kallenbach, Michael Hahn 

-----Original Message-----
From: keycloak-dev-bounces at lists.jboss.org [mailto:keycloak-dev-bounces at lists.jboss.org] On Behalf Of Marek Posolda
Sent: Montag, 15. Mai 2017 18:25
To: keycloak-dev at lists.jboss.org
Subject: [keycloak-dev] Slight refactoring of InfinispanUserSessionProvider

In today's call with Stian and Hynek, we discussed the possible refactoring of InfinispanUserSessionProvider to be reliable in cluster/cross-dc environment.

Current implementation has tightly couple between the model
(UserSessionAdapter) and underlying infinispan entity. For example when you call "userSessionModel.setLastSessionRefresh(123)" it directly delegates this call to infinispan entity and calls "entity.setLastSessionRefresh(123)" .

Some issues with this approach:

1) Possibility of lost updates in cluster - It can happen that there are more concurrent requests updating same userSession. There is a fix by Bill [1], which adds the thread-safety to UserSessionEntity and fixes the issue in local environment. However in cluster with more nodes, it can still happen that there is "lost update". I've created the JIRA [2] for this with details. In shortcut, what can happen is, that there is
request1 processed on node1 and request2 processed on node2 in parallel. 
Both requests read the sessionEntity and then both perform concurrent update and commits their transaction. Then the latter update wins and overwrites the first update as the state when it read the entity didn't yet contain the first update.

2) Rollback doesn't work correctly. Basically when we do this:


the keycloak transaction should be rolled-back and session in infinispan cache shouldn't be updated to lastSessionRefresh 123. However in current implementation, rollback doesn't work and entity is always updated in local environment and may be updated in cluster too (in case that calling node is the owner of session entity). That's because we are not using infinispan transaction API and calling "entity.setLastSessionRefresh(123)" directly updates the entity instance referenced by infinispan storage.

3) Cross-dc support with good performance

Ideal is to fix all issues and ensure consistency, but have the same/similar performance at the same time and not introduce additional uneccessary locking.

Possible solution:

- Every change to UserSessionModel won't delegate directly to infinispan sessionEntity as it's now. Instead it will track the change through changelogs/events, which are saved locally in our infinispan transaction (eg. AddClientToSessionEvent, LastSessionRefreshUpdateEvent).

- During Keycloak transaction commit are changelogs applied to sessionEntity. It may use atomic operation "cache.replace(key, oldValue, newValue)" and the pattern like this:

boolean replaced = false;

while (!replaced) {
     SessionEntity oldSession = cache.get("123");
     // Will update session entity based on the changes tracked in infinispan transaction
     SessionEntity updatedSession = applyChanges(oldSession);
     replaced = cache.replace("123", oldSession, updatedSession); } {code}

- In cross-dc environment are changes sent to another datacenter. That will receive changes (eg. AddClientToSessionEvent) and apply changes locally in the datacenter and update the sessionEntity in the infinispan. It shouldn't be a problem that those events are sent between datacenters through the asynchronous channel. The changes may not be guaranteed in same order in every DC, but all of them will be triggered and there won't be lost updates. So the cache "sessions" won't be directly replicated through the cross-dc, but instead the changes will be sent between datacenters.

What do you think? Can you see some issues with this approach?


[1] https://issues.jboss.org/browse/KEYCLOAK-4821
[2] https://issues.jboss.org/browse/KEYCLOAK-4898

keycloak-dev mailing list
keycloak-dev at lists.jboss.org

More information about the keycloak-dev mailing list