@runzhliu
2018-06-10T06:05:26.000000Z
字数 3986
阅读 1883
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).headlogger.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 就可以在页面中添加配置信息。
