原文链接:www.enriquerecarte.com/2017-08-11/…
作者:Enrique Recarte
译者:Mr.lzc
在本文中,我们将了解如何使用Spring Cloud Config结合Zookeeper来管理配置。
介绍
我一直觉得很难定义什么是Zookeeper,下面试着给出本站的定义:
ZooKeeper是一个集中式的服务,用于维护配置信息、命名,提供分布式同步和分组服务。
简而言之,我认为Zookeeper基本上是一个存储信息、确保它在分布式系统中保持一致和同步的系统。其中存储什么样的信息,取决于你自己。例如,你可以存储一些有助于选主或实现分布式事务的信息。在我们的例子中,我们将使用它来存储我们的应用程序配置。
Zookeeper作为后端使用
Zookeeper在所谓的ZNodes中存储数据。你可以将这些ZNode看作是一个文件系统。ZNode的标识方式与文件非常相似,例如,你可以使用/config/ZookeeperSampleApplication/server.port标识一个ZNode,它可以包含类似于8081这样的一个值。
使用/符号来分隔开ZNode,ZNode可以同时具有值和子节点,所以/config也可以有一个值,也可以是ZookeeperSampleApplicationZNode的父节点。
为了给Zookeeper设置数据,你需要使用Zookeeper客户端,或者尝试找到一个可用的用户界面。在我们的示例中,我们将使用Exhibitor,它由Netflix创建然后作为开源发布。
Spring Cloud Config中的ZNode结构
使用Zookeeper,与Git后端示例中的运行时属性在属性文件中结构化的方式相同,该配置将在znode中结构化。让我们来看看他们是如何划分的。
假设你有一个名为zookeeampleapplication的应用程序,并且你有UAT和PROD环境,那么包含配置(如文件夹)的ZNode应该是这样的:
/config/ZookeeperSampleApplication,PROD/
/config/ZookeeperSampleApplication,UAT/
/config/ZookeeperSampleApplication/
/config/application,PROD/
/config/application,UAT/
/config/application/
让我们进一步看一下:
- 默认情况下所有的配置都位于
/confige的ZNode下,你可以通过设置spring.cloud.zookeeper.config.root属性来设置它的根节点。 /config/{application-name}是特定于应用程序的配置。- 当使用特定的配置文件运行时,你将在
/config/{application-name},{profile}中找到应用程序的配置。这在Git中相当于{application-name}-{profile}.properties文件。默认情况下,你可以使用逗号分隔配置文件,但是也可以通过设置spring.cloud.zookeeperconfig.profile-separator来更改。例如,如果你将其设置为-,那么你的ZNode将成为/config/ZookeeperSampleApplication-UAT。 /config/application这类ZNode包含应用到所有应用程序中的配置,该ZNode也是可以通过spring.cloud.zookeeper.config.defaultContext配置的。- 最后,如果你想对一个已有的配置文件,对所有的应用程序配置什么,那么你应该在
/config/application,{profile}ZNode下定义属性。
更具体地说,让我们看一个更详细的例子。如果你想为不用环境的应用程序定义不同的日志级别(在Spring Boot中通过设置属性logging.level.ROOT配置),
同时又要为你的应用程序和其他应用程序定义默认的配置(当这个配置文件不匹配),ZNode树看起来像这样:
你可以看到每个ZNode包含logging.level.ROOT的属性定义,对于选择配置UAT文件的应用程序的ZNode,取值为DEBUG(看Data as String属性)。
架构总览
与我们在上一篇关于Git设置的文章中看到的架构相比,这个设置的架构稍微简化了一些。
Spring Cloud Config将向你的应用程序添加一个ZokeeperPropertySource,该应用程序将使用Curator与Zookeeper通信。然后,只需设置Zookeeper集群,并告诉应用程序它位于何处。
实现细节
为了使用这个设置,假设你的应用程序已经是Spring Boot应用程序,你至少应该做以下事情:
-
- 你的客户端应用程序需要导入Spring Cloud Config Zookeeper客户端maven依赖项。
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-zookeeper-config</artifactId>
</dependency>
-
- 在classpath的根路径下定义一个名为
bootstrap.properties文件,该文件需要包括以下属性:
- 在classpath的根路径下定义一个名为
# The name of the application
spring.application.name: ZookeeperSampleApplication
# The connection string to for your Zookeeper instance.
spring.cloud.zookeeper.connectString: localhost:2181
这个文件将告诉Spring Cloud在应用程序启动的引导阶段加载远程Zookeeper配置。一旦Zookeper加载配置,库程序将确定哪些ZNodes适用于当前场景(应用程序名称和概要文件),并在环境中添加一个最高优先级的PropertySource,以确保Zookeeper属性在其他源之前找到属性文件或系统属性。
你可以在Github仓库中找到示例代码并使用它。
检测配置的变更
Zookeeper支持在ZNode改变时接收事件。Spring Cloud Config将与此事件挂钩,并将侦听器添加到它关心的ZNode。当添加、删除或更新这些ZNode时,它将刷新上下文。
请记住,即使上下文将自动刷新,你仍然需要确保读取配置的方式将自动支持刷新,否则可能需要使用@RefreshScope对使用配置的bean进行注解。有关Spring Cloud如何管理配置和刷新事件的更多信息,请参阅本系列的第一篇文章。
可以通过设置属性spring.cloud.zookeeper.config来启用或禁用自动刷新机制,默认为true。与任何Spring Cloud Config应用程序一样,只要启用了Spring Boot Actuators,就可以向应用程序发送POST /refresh请求用来刷新上下文。
结论
在我目前的项目中确实有Zookeeper实例,在过去我曾看到我目前公司的一些团队如何编写非常复杂的代码与之集成,以管理他们的配置,所以我在与它集成时总是有点犹豫。
然后,在Spring Cloud Config Zookeeper出现后,我们看了一下配置它有多容易,我们立即开始使用它。对于任何已经使用Zookeeper的项目来说,拥有一个可以为你管理ZNode结构的库以及监听事件和相应操作的库是一个巨大的进步。
话虽如此,我认为Zookeeper作为一个配置管理系统有一些缺点:
-
这是一个相当复杂的系统。我已经阅读了它的一些文档,但我仍然不清楚它是什么,以及它在内部是如何工作的。如果你以前没有使用过它,我认为你应该确保你的团队或公司里的某个人非常了解它。
-
默认情况下,它没有用户界面。它确实有一些命令行实用程序,但是在没有适当的用户界面的情况下,在Zookeeper中管理所有的配置是非常痛苦的。也有一些周边的UI,如前面示例中显示的Exhibitor,zkui或zk-web。
-
认证、授权和可审计性是不简单的或不存在的。我们曾经在生产中遇到过一个问题,因为有人用错误的值更改了ZNode,而且无法知道这已经发生了,或者是谁做的,以及是什么时候做的。也许有一些附加的选项可以添加其中的一些特性,但是正如我所说的,在配置管理系统中设置一些你想要的特性,比如批准更改、审计更改等等,看起来非常复杂。
总的来说,我认为从基础设施的角度来看,Zookeeper是一个非常复杂的解决方案,但是从应用的角度来看,像Spring Cloud Config Zookeeper这样的库,它将成为一个非常有趣的选择。