<html>
<head>
<meta content="text/html; charset=windows-1252"
http-equiv="Content-Type">
</head>
<body bgcolor="#FFFFFF" text="#000000">
<br>
<br>
<div class="moz-cite-prefix">On 2/17/2016 3:09 PM, Marek Posolda
wrote:<br>
</div>
<blockquote cite="mid:56C4D363.6030906@redhat.com" type="cite">
<meta content="text/html; charset=windows-1252"
http-equiv="Content-Type">
<div class="moz-cite-prefix">On 17/02/16 18:11, Bill Burke wrote:<br>
</div>
<blockquote cite="mid:56C4A9AC.9050508@redhat.com" type="cite">
<pre wrap="">Currently, adding or deleting a client, or updating a realm causes
invalidation/eviction of the realm and all clients in that realm. To
make matters worse, the next time the realm is accessed, it queries and
loads each client and its relationships. Why do we do this? When a
realm invalidation happens, the cache has no idea if the realm is just
being updated or removed entirely from the DB. With a realm removal, you
also need to evict the cache of all clients within the realm. So, a
cached realm MUST have a list of all clients within it. As a result,
the more clients that get added, keycloak gets slower and slower.
Eventually though the cache stabilizes after inserts/update/deletes
subside and we get back to normal performance, but you can see a nasty
blip for a little bit.</pre>
</blockquote>
We don't need to eagerly preload all clients when realm is loaded.
Infinispan has streaming/predicate API and we are using it in many
places (see InfinispanUserSessionProvider and all the stuff in
package org.keycloak.models.sessions.infinispan.<span
style="background-color:#e4e4ff;">stream</span>
<meta http-equiv="content-type" content="text/html;
charset=windows-1252">
). So when entry is invalidated, we can have cacheListener, which
will query infinispan to return all cached clients of the realm
and remove them. I can see that we already have listener. So
possibly we can just change this line to use predicate query:
<a moz-do-not-send="true" class="moz-txt-link-freetext"
href="https://github.com/keycloak/keycloak/blob/master/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/locking/LockingCacheRealmProviderFactory.java#L141">https://github.com/keycloak/keycloak/blob/master/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/locking/LockingCacheRealmProviderFactory.java#L141</a><br>
<br>
<br>
</blockquote>
<br>
Lol, i was sort of kind of doing that doing cache.values(). This
makes it much easier with much less refactoring.<br>
<br>
<blockquote cite="mid:56C4D363.6030906@redhat.com" type="cite">
Other option is, that we can try to optimize eager preload and see
if we can reduce number of SQL queries at startup. For example, it
seems that CachedClient constructor sends SQL query to preload
just realm roles. And then each client sends another SQL query to
preload his client roles (method CachedClient.cacheRoles ).
Couldn't we instead send one SQL query to load all roles of realm
(both realm and client roles)? Maybe we can even send one big SQL
query to load realm with all it's objects <span
class="moz-smiley-s1"><span> :-) </span></span>Possibly some
FetchType.EAGER in Hibernate entities could help here.<br>
<br>
</blockquote>
<br>
yeah, we should start looking into stuff like this. We can at
least reduce the number of sql calls for caching a client or realm
individually. I'm not sure how feasible it is though or how much
better it is. Realms and clients contain more than a few one to
many relationships which would make the query result HUGE if I
remember how joins work.<br>
<br>
<pre class="moz-signature" cols="72">--
Bill Burke
JBoss, a division of Red Hat
<a class="moz-txt-link-freetext" href="http://bill.burkecentral.com">http://bill.burkecentral.com</a></pre>
</body>
</html>