@runzhliu
2018-06-10T06:05:26.000000Z
字数 3986
阅读 1763
springboot
swagger2
zookeeper
参考资料
https://segmentfault.com/a/1190000004356362a
https://holynull.gitbooks.io/zookeeper/content/pei_zhi_fu_wu_configuration_service.html
http://curator.apache.org/getting-started.htmla
http://www.uedsc.com/346763.html
分布式应用的配置管理很麻烦,使用 ZK 可以解决,但是如果只能用 ZK 的客户端来做配置信息的 CRUD,那也不会轻松,因此最好能有一个界面来进行操作。利用上述这三个框架,基本上就可以快速开发配置管理中心了。
为什么需要配置管理中心?这个可能跟组内业务相关。比较典型的是搜索和推荐系统中集成的 ab 测试组件。如何调整实验比例,如何配置实验组,都会对业务和系统产生很大的影响。拥有配置管理中心之后,可以很方便的将配置写入 ZK,然后让系统对 ZK 内的配置信息进行读取。集中式配置管理的思路是,将配置信息保存在 Zookeeper 的某个目录节点中,然后将所有需要修改的应用机器监控配置信息的状态,一旦配置信息发生变化,每台应用机器就会收到 Zookeeper 的通知,然后从 Zookeeper 获取新的配置信息应用到系统中。实现配置的集中式管理和动态更新。可以简单的理解为配置数据与程序分离。
整个配置管理中心稍微比较难的地方在于根据业务特点来设计 ZK 数据的存取和配置信息的版本控制。
主要依赖如下:
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-recipes</artifactId>
<version>2.12.0</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jetty</artifactId>
<version>2.0.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>2.0.2.RELEASE</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.8.0</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.8.0</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<version>2.0.2.RELEASE</version>
<scope>test</scope>
</dependency>
需要说明一下,没有用原生的 zookeeper 来开发,而是 curator,它是抽象程度更高,更易用的 ZK 客户端,推荐其官方教程学习。
Spring boot 启动主要依赖于以下程序。Application
是默认的启动类,引入 Swagger2
则是引入其 UI 并且可以配置页面展示的默认信息。
.
├── Application.java
├── JacksonConfig.java
└── Swagger2.java
配置信息以 KV 形式写入。本文中,一组配置元信息需要通过 project -> group -> key
来获取。
配置管理中心提供4种接口,增加配置、删除配置、回滚指定版本的配置以及获取配置的历史版本。主要提供了 ConfigManager
作为高层应用接口,分别代理了 Scala 的 Curator 封装中的相应的方法。具体的配置路径可以根据组内项目情况进行设计。
关于配置管理,大概存在几种可能:增加配置信息、删除配置信息、展示配置信息,再加上能够回滚之前任意版本的配置信息。当然还有其他操作,使用者可以自行设计和实现。
关于以上管理方式,可以设置一个静态方法来实现:
object ConfigManager {
private[this] val configManager = new ConfigManager(JacksonUtil)
def addNewConf[V](project: String, group: String, key: String, value: V): Unit = {
configManager.addNewConf(project, group, key, value)
}
def show[V](project: String, group: String, key: String)(implicit m: Manifest[V]): Map[String, V] = {
configManager.show(project, group, key)
}
def rollback(project: String, group: String, key: String, version: String): Try[_] = {
configManager.rollback(project, group, key, version)
}
def remove(project: String, group: String, key: String): Unit = {
configManager.remove(project, group, key)
}
}
由于操作方式比较多,这里仅就增加配置做点说明:
/**
* 添加项目配置.
*
* @param project 项目名
* @param group 组别名
* @param key 实验名
* @param value 配置值
* @param maxChildrenLength
* @tparam V
* @throws java.lang.Exception
*/
@throws(classOf[Exception])
def addNewConf[V](project: String,
group: String,
key: String,
value: V,
maxChildrenLength: Int = 10): Unit = {
require(maxChildrenLength >= 1)
val path = ZKPaths.makePath(ZK_ROOT_PATH,
project,
Array(group, key, System.currentTimeMillis().toString): _*)
val valueBytes = serializationUtil.serialize(value)
ZKUtil.addNode(path, valueBytes)
val children = ZKUtil.listChildren(path).map(_.toLong)
if (children.length > MAX_CHILDREN_LENGTH) {
val minDateChild = children.sortBy(x => x).head
logger.info(s"remove min child: $minDateChild.")
ZKUtil.removeZNode(s"$path/$minDateChild")
}
}
当需要增加配置信息的时候,只要给出诸如之前设计的,包括 project, group, key
等信息,作为 ZK 的节点,然后添加需要的数据 value
就可以了。关于如何通过 Crurator 来控制添加节点数据的操作,可以进一步在项目中进行跳转来阅读。
然后添加配置信息,可以通过 Swagger2 的页面提供的 RESTful Api 来进行绑定。
@RequestMapping(value = Array("/add"), method = Array(RequestMethod.POST))
@ApiOperation(value = "添加配置", notes = "添加配置")
def add(@RequestBody conf: CommonStringConfig): ResponseMsg = {
try {
ConfigManager.addNewConf(conf.project, conf.group, conf.key, conf.value)
ResponseMsg()
} catch {
case NonFatal(e) =>
logger.error("add error.", e)
ResponseMsg(-1, e.toString)
}
}
测试该方法可以在页面中进行操作,点解 Try it out
就可以在页面中添加配置信息。