分布式配置管理平台

分布式配置管理平台

为了更好的解决分布式环境下多台服务实例的配置统一管理问题,本文提出了一套完整的分布式配置管理解决方案(简称为disconf[4],下同)。首先,实现了同构系统的配置发布统一化,提供了配置服务server,该服务可以对配置进行持久化管理并对外提供restful接口,在此基础上,基于zookeeper实现对配置更改的实时推送,并且,提供了稳定有效的容灾方案,以及用户体验良好的编程模型和WEB用户管理界面。其次,实现了异构系统的配置包管理,提出基于zookeeper的全局分布式一致性锁来实现主备统一部署、系统异常时的主备自主切换。通过在百度内部以及外部等多个产品线的实践结果表明,本解决方案是有效且稳定的。

技术背景

在一个分布式环境中,同类型的服务往往会部署很多实例。这些实例使用了一些配置,为了更好地维护这些配置就产生了配置管理服务。通过这个服务可以轻松地管理成千上百个服务实例的配置问题。

王阿晶提出了基于zooKeeper的配置信息存储方案的设计与实现[1], 它将所有配置存储在zookeeper上,这会导致配置的管理不那么方便,而且他们没有相关的源码实现。淘宝的diamond[2]是淘宝内部使用的一个管理持久配置的系统,它具有完整的开源源码实现,它的特点是简单、可靠、易用,淘宝内部绝大多数系统的配置都采用diamond来进行统一管理。他将所有配置文件里的配置打散化进行存储,只支持KV结构,并且配置更新的推送是非实时的。百度内部的BJF配置中心服务[3]采用了类似淘宝diamond的实现,也是配置打散化、只支持KV和非实时推送。

同构系统是市场的主流,特别地,在业界大量使用部署虚拟化(如JPAAS系统,SAE,BAE)的情况下,同一个系统使用同一个部署包的情景会越来越多。但是,异构系统也有一定的存在意义,譬如,对于“拉模式”的多个下游实例,同一时间点只能只有一个下游实例在运行。在这种情景下,就存在多台实例机器有“主备机”模式的问题。目前国内并没有很明显的解决方案来统一解决此问题。

功能特点与设计理念

disconf是一套完整的基于zookeeper的分布式配置统一解决方案。

它的功能特点是

  • 支持配置(配置项+配置文件)的分布式化管理
    • 配置发布统一化
    • 配置发布、更新统一化(云端存储、发布):配置存储在云端系统,用户统一在平台上进行发布、更新配置。
    • 配置更新自动化:用户在平台更新配置,使用该配置的系统会自动发现该情况,并应用新配置。特殊地,如果用户为此配置定义了回调函数类,则此函数类会被自动调用。
  • 配置异构系统管理
    • 异构包部署统一化:这里的异构系统是指一个系统部署多个实例时,由于配置不同,从而需要多个部署包(jar或war)的情况(下同)。使用Disconf后,异构系统的部署只需要一个部署包,不同实例的配置会自动分配。特别地,在业界大量使用部署虚拟化(如JPAAS系统,SAE,BAE)的情况下,同一个系统使用同一个部署包的情景会越来越多,Disconf可以很自然地与他天然契合。 异构主备自动切换:如果一个异构系统存在主备机,主机发生挂机时,备机可以自动获取主机配置从而变成主机。
    • 异构主备机Context共享工具:异构系统下,主备机切换时可能需要共享Context。可以使用Context共享工具来共享主备的Context。
  • 注解式编程,极简的使用方式:我们追求的是极简的、用户编程体验良好的编程方式。通过简单的标注+极简单的代码撰写,即可完成复杂的配置分布式化。
  • 需要Spring编程环境

它的设计理念是:

  • 简单,用户体验良好:
    • 摒弃了打散化配置的管理方式[2,3],仍旧采用基于配置文件的编程方式,这和程序员以前的编程习惯(配置都是放在配置文件里)一致。特别的,为了支持较为小众的打散化配置功能,还特别支持了配置项。
    • 采用了基于XML无代码侵入编程方式:只需要几行XML配置,即可实现配置文件发布更新统一化、自动化。
    • 采用了基于注解式的弱代码侵入编程方式:通过编程规范,一个配置文件一个配置类,代码结构简单易懂。XML几乎没有任何更改,与原springXML配置一样。真正编程时,几乎感觉不到配置已经分布式化
  • 可以托管任何类型的配置文件,这与[2,3]只能支持KV结构的功能有较大的改进。
  • 配置更新实时推送
  • 提供界面良好Web管理功能,可以非常方便的查看配置被哪些实例使用了。

详细设计

架构设计

disconf服务集群模式

disconf的模块架构图

每个模块的简单介绍如下:

  • Disconf-core
    • 分布式通知模块:支持配置更新的实时化通知
    • 路径管理模块:统一管理内部配置路径URL
  • Disconf-client
    • 配置仓库容器模块:统一管理用户实例中本地配置文件和配置项的内存数据存储
    • 配置reload模块:监控本地配置文件的变动,并自动reload到指定bean
    • 扫描模块:支持扫描所有disconf注解的类和域
    • 下载模块:restful风格的下载配置文件和配置项
    • watch模块:监控远程配置文件和配置项的变化
    • 主备分配模块:主备竞争结束后,统一管理主备分配与主备监控控制
    • 主备竞争模块:支持分布式环境下的主备竞争
  • Disconf-web
    • 配置存储模块:管理所有配置的存储和读取
    • 配置管理模块:支持配置的上传、下载、更新
    • 通知模块:当配置更新后,实时通知使用这些配置的所有实例
    • 配置自检监控模块:自动定时校验实例本地配置与中心配置是否一致
    • 权限控制:web的简单权限控制
  • Disconf-tools
    • context共享模块:提供多实例间context的共享。

流程设计

运行流程详细介绍:

与2.0版本的主要区别是支持了:主备分配功能/主备切换事件。

  • 启动事件A:以下按顺序发生。
    • A3:扫描静态注解类数据,并注入到配置仓库里。
    • A4+A2:根据仓库里的配置文件、配置项,去 disconf-web 平台里下载配置数据。这里会有主备竞争
    • A5:将下载得到的配置数据值注入到仓库里。
    • A6:根据仓库里的配置文件、配置项,去ZK上监控结点。
    • A7+A2:根据XML配置定义,到 disconf-web 平台里下载配置文件,放在仓库里,并监控ZK结点。这里会有主备竞争。
    • A8:A1-A6均是处理静态类数据。A7是处理动态类数据,包括:实例化配置的回调函数类;将配置的值注入到配置实体里。
  • 更新配置事件B:以下按顺序发生。
    • B1:管理员在 Disconf-web 平台上更新配置。
    • B2:Disconf-web 平台发送配置更新消息给ZK指定的结点。
    • B3:ZK通知 Disconf-cient 模块。
    • B4:与A4一样。
    • B5:与A5一样。
    • B6:基本与A4一样,唯一的区别是,这里还会将配置的新值注入到配置实体里。
  • 主备机切换事件C:以下按顺序发生。
    • C1:发生主机挂机事件。
    • C2:ZK通知所有被影响到的备机。
    • C4:与A2一样。
    • C5:与A4一样。
    • C6:与A5一样。
    • C7:与A6一样。

模块实现


disconf-web

分布式配置Web平台服务 模块

推荐使用最新的Chrome或Firefox浏览.

注:由于迭代开发快速多变的原因,当前UI可能与下图略有改变。

运行样式

主页

登录页

可以使用 admin admin 进行登录。

主界面

http://ww3.sinaimg.cn/mw1024/60c9620fgw1emxv1nw0u4j20qp0homy0.jpg

左上角可以选择APP和环境,选择之后,就会在中间出现若干个版本,

选择版本后,就会显示 APP、环境、版本 三个条件下的配置列表:

http://ww1.sinaimg.cn/mw1024/60c9620fgw1emyww39wjmj20qw0keq6m.jpg

表格中 各个列的意义是:

  • APP:使用哪个APP,及它的ID
  • KEY:配置文件或配置项
  • 配置内容:配置文件或配置项在配置中心中的值
  • 实例列表:使用此配置文件或配置项的所有实例列表,及每个实例的配置值。如果实例的配置值与配置中心的值不一致,这里会标识出来。
  • 修改时间:修改此配置的最后一次时间
  • 操作:个性、删除、下载

右上角可以

新建配置项、新建配置文件、新建APP

表格右上方

可以批量下载所有配置文件至本地,还可以查看ZK上的部署情况。

How to deploy

安装依赖软件

  • 安装Mysql(Ver 14.12 Distrib 5.0.45, for unknown-linux-gnu (x86_64) using EditLine wrapper)
  • 安装Tomcat(apache-tomcat-7.0.50)
  • 安装Nginx(nginx/1.5.3)
  • 安装 zookeeeper (zookeeper-3.3.0)
  • 安装 Redis (2.4.5)

准备配置

将你的配置文件放到此地址目录下(以下地址可自行设定):

home/work/dsp/disconf-rd/online-resources

配置文件包括:

- jdbc-mysql.properties (数据库配置)
- redis-config.properties (Redis配置)
- zoo.properties (Zookeeper配置)
- application.properties (应用配置)

注意,记得执行将application-demo.properties复制成application.properties:

cp application-demo.properties application.properties

设置War包将要被部署的地址(以下地址可自行设定):

/home/work/dsp/disconf-rd/war

构建

ONLINE_CONFIG_PATH=/home/work/dsp/disconf-rd/online-resources
WAR_ROOT_PATH=/home/work/dsp/disconf-rd/war
export ONLINE_CONFIG_PATH
export WAR_ROOT_PATH
cd disconf-web
sh deploy/deploy.sh

这样会在 /home/work/dsp/disconf-rd/war 生成以下结果:

-disconf-web.war  
-html  
-META-INF  
-WEB-INF

上线前的初始化工作

初始化数据库:

依次执行:

  • 执行 sql/1-init_table.sql
  • 执行 sql/2-data.sql
  • 执行 sql/20141201/disconf.sql

里面默认有6个用户

如果想自己设置初始化的用户名信息,可以参考代码来自己生成用户:

src/main/java/com/baidu/disconf/web/tools/UserCreateTools.java

部署War

修改server.xml文件,在Host结点下设定Context:

<Context path="" docBase="/home/work/dsp/disconf-rd/war"></Context>

并设置端口为 8015

启动Tomcat,即可。

部署 前端

修改 nginx.conf

upstream disconf {
    server 127.0.0.1:8015;
}

server {

    listen   8081;
    server_name localhost;
    access_log /home/work/var/logs/disconf/access.log;
    error_log /home/work/var/logs/disconf/error.log;

    location / {
        root /home/work/dsp/disconf-rd/war/html;
        if ($query_string) {
            expires max;
        }
    }

    location ~ ^/(api|export) {
        proxy_pass_header Server;
        proxy_set_header Host $http_host;
        proxy_redirect off;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Scheme $scheme;
        proxy_pass http://disconf;
    }
}

业务功能

  • 支持用户登录/登出
  • 浏览配置
    • 按 APP/版本/环境 选择
  • 修改配置
    • 修改配置项
    • 修改配置文件
  • 新建配置
    • 新建配置项
    • 新建配置文件
    • 新建APP

架构方案

Nginx(处理静态请求) + Tomcat(处理动态请求)

  • 后端
    • SpringMvc(3.1.2+)
    • Jdbc-Template
    • Mysql
    • RestFul API
    • Redis for user login/logout
    • H2内存数据库测试方案/Junit/SpringTest
  • 前端
    • HTML
    • Jquery(1.10.4):JS工具集合
    • Bootstrap(2.3.2):界面UI
    • Node(ejs/fs/eventproxy): 用于前端的HTML的模板化管理
  • 前后端接口(前后端分离)
    • 完全Ajax接口
    • JSON
    • RestFul API

Reference

  1. 王阿晶,邹仕洪: 基于ZooKeeper的配置信息存储方案的设计与实现
  2. 淘宝diamod实现:http://code.taobao.org/p/diamond/src/, 2012
  3. 百度BJF配置中心, 2014
  4. disconf github: https://github.com/knightliao/disconf, 2014
  5. 淘宝分布式配置管理服务Diamond
  6. zooKeeper和Diamond有什么不同
  7. diamond专题(一)-- 简介和快速使用