Apollo 统一配置中心
Apollo(阿波罗)是携程框架部门研发的开源配置管理中心
能够集中化管理应用不同环境、不同集群的配置,配置修改后能够实时推送到应用端,并且具备规范的权限、流程治理等特性
地址 https://github.com/ctripcorp/apollo
特性
统一管理不同环境、不同集群的配置
配置修改实时生效(热发布)
版本发布管理
灰度发布
权限管理、发布审核、操作审计
客户端配置信息监控
提供Java和.Net原生客户端
提供开放平台API
部署简单
Apollo架构图
Config Service提供配置的读取、推送等功能,服务对象是Apollo客户端 Admin Service提供配置的修改、发布等功能,服务对象是Apollo Portal(管理界面) Config Service和Admin Service都是多实例、无状态部署,所以需要将自己注册到Eureka中并保持心跳 在Eureka之上架了一层Meta Server用于封装Eureka的服务发现接口 Client通过域名访问Meta Server获取Config Service服务列表(IP+Port),而后直接通过IP+Port访问服务,同时在Client侧会做load balance、错误重试 Portal通过域名访问Meta Server获取Admin Service服务列表(IP+Port),而后直接通过IP+Port访问服务,同时在Portal侧会做load balance、错误重试 为了简化部署,会把Config Service、Eureka和Meta Server三个逻辑角色部署在同一个JVM进程中
1.搭建 Apollo 配置中心
参照 https://github.com/ctripcorp/apollo/wiki/Quick-Start
(1)下载Quick Start安装包
(2)创建Apollo服务端需要两个数据库
ApolloPortalDB
ApolloConfigDB
(3)解压Quick Start安装包,修改demo.sh数据库配置
# apollo config db info apollo_config_db_url=jdbc:mysql://localhost:3306/ApolloConfigDB?characterEncoding=utf8 apollo_config_db_username=root apollo_config_db_password=root # apollo portal db info apollo_portal_db_url=jdbc:mysql://localhost:3306/ApolloPortalDB?characterEncoding=utf8 apollo_portal_db_username=root apollo_portal_db_password=root
(4)服务启动与关闭
在git下执行启动脚本
./demo.sh start
关闭
./demo.sh stop
(5)浏览器打开http://localhost:8070/
输入用户名 apollo,密码 admin
http://localhost:8080/
2.spring boot集成
(1)依赖
<dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>com.ctrip.framework.apollo</groupId> <artifactId>apollo-client</artifactId> <version>1.6.0</version> </dependency> <!-- 为了编码方便,并非apollo 必须的依赖 --> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-lang3</artifactId> <version>3.8.1</version> </dependency> </dependencies> <dependencyManagement> <dependencies> <dependency> <groupId>com.ctrip.framework.apollo</groupId> <artifactId>apollo-client</artifactId> <version>1.2.0</version> </dependency> </dependencies> </dependencyManagement>
(2)启动类
package com.xyz.provider; import com.ctrip.framework.apollo.spring.annotation.EnableApolloConfig; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication @EnableApolloConfig public class ProviderApplication { public static void main(String[] args) { SpringApplication.run(ProviderApplication.class, args); } }
(3)配置
server.port=8010 spring.application.name=service-provider # 应用全局唯一的身份标识 app.id = springboot-apollo # Apollo Meta Server 地址 apollo.meta = http://localhost:8080 # 自定义本地配置文件缓存路径 apollo.cacheDir = ./config # 设置在应用启动阶段就加载 Apollo 配置 apollo.bootstrap.enabled = true # 注入 application namespace apollo.bootstrap.namespaces = application apollo.bootstrap.eagerLoad.enabled = true logging.level.com.xyz.provider.controller=debug order.discount = 75
说明:
app.id:AppId是应用的身份信息,是配置中心获取配置的一个重要信息
apollo.bootstrap.enabled:在应用启动阶段,向Spring容器注入被托管的application.properties文件的配置信息
apollo.bootstrap.eagerLoad.enabled:将Apollo配置加载提到初始化日志系统之前
logging.level.com.xyz.provider.controller:调整 controller 包的 log 级别,用来在配置中心动态配置日志级别
(4)控制器
package com.xyz.provider.controller; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Value; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; @RestController public class HelloController { private static Logger logger = LoggerFactory.getLogger(HelloController.class); @Value("${server.port}") String port; @Value(("${order.discount}")) Integer discount; @GetMapping("hello") public String hello(String name) { logger.debug("debug log..."); logger.info("info log..."); logger.warn("warn log..."); return "hello " + name + " ,i am from port:" + port + ",discount:" + discount; } }
启动项目
GET http://localhost:8010/hello?name=beibei
返回
hello beibei ,i am from port:8011,discount:75
(5)配置
创建项目
说明:
部门:选择应用所在的部门
应用AppId:用来标识应用身份的唯一id,格式为string,需要和客户端application.properties中配置的app.id对应
应用名称:应用名,仅用于界面展示
应用负责人:选择的人默认会成为该项目的管理员,具备项目权限管理、集群创建、Namespace创建等权限
新增配置
发布配置
编辑完配置后,需要发布配置,才能生效
发布后再次请求http://localhost:8010/hello?name=beibei
返回 hello beibei ,i am from port:8011,discount:50
说明:
服务的端口依然还是 8010,因为 apollo 修改配置,不会像Spring Cloud Config 那样去重启应用
重启应用后,客户端会使用配置中心中配置的端口
2020-05-27 11:19:48.064 DEBUG 14880 --- [nio-8011-exec-1] c.x.provider.controller.HelloController : debug log...
2020-05-27 11:19:48.064 INFO 14880 --- [nio-8011-exec-1] c.x.provider.controller.HelloController : info log...
2020-05-27 11:19:48.064 WARN 14880 --- [nio-8011-exec-1] c.x.provider.controller.HelloController : warn log...
说明:
在配置中心修改日志等级,发布后也没法立即生效,需要重启应用
重启后
2020-05-27 11:21:57.780 INFO 13200 --- [nio-8011-exec-1] c.x.provider.controller.HelloController : info log...
2020-05-27 11:21:57.780 WARN 13200 --- [nio-8011-exec-1] c.x.provider.controller.HelloController : warn log...
添加监听
package com.xyz.provider.config; import com.ctrip.framework.apollo.Config; import com.ctrip.framework.apollo.model.ConfigChangeEvent; import com.ctrip.framework.apollo.spring.annotation.ApolloConfig; import com.ctrip.framework.apollo.spring.annotation.ApolloConfigChangeListener; import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.logging.LogLevel; import org.springframework.boot.logging.LoggingSystem; import org.springframework.context.annotation.Configuration; import javax.annotation.PostConstruct; import java.util.Set; @Configuration public class LoggerConfig { private static final Logger logger = LoggerFactory.getLogger(LoggerConfig.class); private static final String LOGGER_TAG = "logging.level."; @Autowired private LoggingSystem loggingSystem; @ApolloConfig private Config config; @ApolloConfigChangeListener private void configChangeListter(ConfigChangeEvent changeEvent) { refreshLoggingLevels(); } @PostConstruct private void refreshLoggingLevels() { Set<String> keyNames = config.getPropertyNames(); for (String key : keyNames) { if (StringUtils.containsIgnoreCase(key, LOGGER_TAG)) { String strLevel = config.getProperty(key, "info"); LogLevel level = LogLevel.valueOf(strLevel.toUpperCase()); loggingSystem.setLogLevel(key.replace(LOGGER_TAG, ""), level); logger.info("{}:{}", key, strLevel); } } } }
说明:
@ApolloConfig注解:将Apollo服务端的中的配置注入到这个类中
@ApolloConfigChangeListener注解:监听配置中心配置的更新事件,若该事件发生,则调用refreshLoggingLevels方法处理该事件
ConfigChangeEvent:获取被修改配置项的key集合,以及被修改配置项的新值、旧值和修改类型等信息
2020-05-27 11:26:18.211 WARN 4636 --- [nio-8011-exec-4] c.x.provider.controller.HelloController : warn log...
Apollo与SpringCloud Config的对比Apollo | Spring Cloud Config | |
配置界面 | 同一界面管理不同环境/集群配置 | 无,通过git操作 |
配置生效时间 | 实时 | 重启生效,或Refresh,git hook+MQ |
版本管理 | 界面尚志杰提供发布历史和回滚按钮 | 无 |
灰度发布 | 支持 | 不支持 |
授权/审计/审核 | 界面直接操作,且支持修改和发布权限分离 | 需要通过git仓库设置,且不支持修改和发布权限分离 |
实时配置监控 | 可以方便看到当前那些客户端在使用哪些配置 | 不支持 |
配置获取性能 | 快 | 较慢 |
客户端支持 | 原生支持Java/.Net,提供API,支持Spring annotation | Spring应用+annotation支持 |
Apollo是企业生产级配置中心,使用范围更广