同一个应用连接两个Zookeeper集群的方法
背景
- 因为应用服务用到了Dubbo,Dubbo 依赖了 Zookeeper作为注册中心。
- 应用服务同时还需要连接到KAFKA,且Kafka开启了SASL认证。
问题
对于一个开源中间件来说,集群安全是很重要的,但是在实现上,认证方式就那么几种:
- GSSAPI (唯一实现:Kerberos,Java可以使用JAAS对其进行支持)
- SASL (Java可以使用JAAS对其进行支持)
- PLAIN_TEXT (没认证)
- SSL
那么如果全局指定了JAAS,访问两个SASL配置账户不同的集群,就会必然有一个失败。
分析
对于Zookeeper,它使用了JAAS,它仅仅简单粗暴的通过读取zookeeper.sasl.client
和java.security.auth.login.config
这两个全局环境变量来判断要不要使用SASL认证,无法通过其他方式来改变这种行为。
对于Kafka,它巧妙地实现了javax.security.auth.login.Configuration
,也就是org.apache.kafka.common.security.JaasConfig
。可以通过代码中直接指定 sasl.jaas.config
(slankka:0715.2020) 来表示此Topic的连接认证方式,十分灵活。
此外,Apache Flume 也收益于此,Flume如果同时连接加密和不加密的 多套Kafka集群,可以按照单个Kafka Source/Sink 进行Topic级别细粒度的配置认证方式,而不是通过JVM参数直接全局固定。
那么解决方案就有好几种:
- 修改使用Zookeeper的客户端连接器。
- 修改Zookeeper源码。
- 运行时指定Jaas,启动时不指定。
- 通过创建单独的进程指定JAAS参数
- 通过Java调用Linux命令,访问Kafka/Zookeeper配置好的客户端来执行某些操作。
额外技术细节
Zookeeper 本身的连接是极为困难的,现在开源社区总共有两种Zookeeper Java Client(暂且称为Zookeeper连接器):
- zkclient(zk101tec)
- Curator
具体区别不在这里详述。
对于 Dubbo 2.7.1 以后的版本,我通过检查源码,发现 Dubbo已经去除 zkclient(zk101tec)依赖,已经完全切换到 Apache Curator。
如果修改 Zookeeper连接器,那就要确定项目中,引入的框架使用的是哪一种连接器。
解决方案
解决办法正如前文指出,有三种,最便宜实用的方法就是方案三: 在运行时指定jaas配置。运行完毕再恢复上次的配置。在切换期间可能会存在几毫秒的其他Zookeeper集群访问的问题,但是这已经是极小的影响了。
另外,Zookeeper社区,有人指出这种设计的不足:
ZOOKEEPER-2139:Support multiple ZooKeeper client, with different configurations, in a single JVM
通过查看提交记录发现,社区已经针对Zookeeper的构造函数提供了 ZkClientConfig这个参数类,可以实现自定义的配置。
Github 2139 Commit
可以看出,这些版本以后才能支持:release-3.6.1 release-3.6.1-1 release-3.6.1-0 release-3.6.0 release-3.6.0-4 release-3.6.0-3 release-3.6.0-2 release-3.6.0-1 release-3.6.0-0
当Zookeeper支持了以后,就可以用方案1,或者类似于Kafka的方式来更好的解决。
总结
Kafka的这种设计值得我们学习,减少具体配置对环境变量的依赖。
涉及到的技术有:JAAS,Kafka, Zookeeper