前言
本文主要记录一下配置keycloak集群中session共享的过程。
问题出现
在之前的一篇博文HAproxy的Sticky Session中曾经提到过用户的登录请求在多台keycloak之间跳来跳去的问题使用了HAproxy的sticky session解决了。其实原理就是HAproxy在请求的cookie里面做了标记,当同一个客户端再次发起请求的时候,HAproxy直接将请求路由到上一次接受请求的主机上,所以成功解决了登录问题。但是,后面发现,这个貌似只适用于登录keycloak的管理界面,对于应用调用keycloak进行认证的流程(OAuth)并不适用。应用跳转到keycloak获取认证之后重定向回来还是会出现不断跳,直到成功找到token为止。
分析问题
通过查看HAproxy的访问日志发现,用户在浏览器输入用户名密码之后,点击登录,随即浏览器向HAproxy发起了一条登录请求,HAproxy将请求透传到后端某一台keycloak上,然后认证成功之后重定向到应用内部。这个时候应用后台会带着keycloak的返回的token信息去请求keycloak校验token,校验成功则认证成功,失败则认证失败。就在这时问题出现了。因为是应用后台发起的请求,所以并未带有相应的cookie,所以此时会随机去到后端某一台keycloak,如果幸运正好路由到刚才接受认证请求的keycloak上,那么马上就认证成功,如果不幸运。。那么就会出现请求失败,然后由于设置了重试机制,那么会再次发起认证,然后再去校验token。。这就出现了不断跳转或者说直观上的浏览器不断自动重新加载的情况了。
寻找出路
经过分析之后感觉cookie是解决不了问题了,继而转向了session共享的办法。其实思路也很简单,就是在任意一台机上面认证,整个集群马上就有相关的token信息,那么无论访问哪一台keycloak获取token都是可以的,同时HAproxy也不再需要做任何配置。
解决办法
因为用的是standalone-ha方式搭建的集群,那么使用的standalone-ha.xml里面也已经有了共享session共享的配置。使用的是infinispan分布式缓存来存储session信息。这里只需要将distribute部分里面owner改成集群的节点数目即可,是为了防止挂掉部分机器之后丢失信息。其次要重点关注的是配置keycloak集群通讯协议。keycloak默认使用的是MPING协议,也就是Multicast PING。其实就是udp广播模式。但是在我们的环境里这做不了,因为做了很多防火墙规则。那么就需要修改集群的通讯协议。一开始使用的是TCPPING方式,但是后来发现JDBC_PING更为高效。 原因是使用TCPPING的话,每次集群扩容都必须更改每个节点的server列表并逐个重启,而JDBC_PING则是将集群成员信息记录在数据表,扩容只需要连接这个库就可以获取集群成员并通知所有节点。
至此,问题解决。其实主要的是两点,一个是集群通讯协议,另一个就是缓存副本数。
参考
http://www.jgroups.org/manual/html/protlist.html
https://kb.novaordis.com/index.php/WildFly_Clustering_without_Multicast