Apollo介绍以及应用

传统应用配置问题

  • 静态配置
    • 传统应用的配置,都是静态配置,写在配置文件中,运行时无法动态修改,如果修改之后,就需要重启应用
  • 配置格式不统一
    • 开发人员习惯不同,使用XML、properties、DB存储配置
  • 易引起事故
    • 在上线时,有时会忘记修改配置文件,将测试环境的变量变成线上
  • 配置修改麻烦,周期长
    • 在部署多个服务器时,修改配置费时费力
  • 缺少安全审计和版本控制
    • 没有版本控制,在出现问题时,无法及时进行回滚。

配置中心解决方法

  • 静态配置
    • 集中式配置,所有的配置信息都保存到配置中心
  • 配置格式不统一
    • 配置中心统一管理格式,开发人员不用关心格式,通过界面管理
  • 易引发事故
    • 环境隔离,不同的环境使用不同的配置,互不干扰
    • 配置修改之后,可以生效
  • 配置麻烦,周期长
  • 配置集中一次修改,实时通知到所有客户端
  • 缺少安全审计和版本控制
  • 所有修改都有历史记录,方便查找修改人和时间
  • 可以按需退回到历史版本

配置基本概念

配置定义

  • 可独立于程序的可配变量
  • 同一份程序在不同配置下会有不同行为
  • 应用场景:连接字符串、应用配置、业务配置

配置形态

  • 程序内部硬编码(坚决反对)
  • 配置文件:将配置写入xml、properties文件中
  • 环境变量:根据环境不同,传递到程序中
  • 启动参数:将参数传递到程序中
  • 基于数据库:将配置写入到数据库

配置治理

  • 权限控制和审计:要保留用户的操作记录和权限
  • 不同环境、集群配置管理:根据不同环境,获取不同的配置
  • 框架类组件配置管理:获取配置,是否开启功能
  • 灰度发布:进行公测,环境隔离

配置分类和场景

动态配置

  • 应用配置
    • 请求超时、线程池、队列、缓存、数据库连接池的容量、日志级别、限流熔断阈值、黑白名单
  • 功能开关
    • 蓝绿发布、灰度开关、降级开关、HA高可用开关、DB迁移
  • 业务配置
    • 促销规律、贷款额度、利率等业务参数、A/B测试

静态配置

  • 安全配置
    用户名、密码、令牌、许可证户等
  • 环境相关
    • 数据库/中间件/其他服务的连接字符串

开关驱动开发原理

优点

  • 新功能和代码发布分离,减轻发布风险
  • 迭代速度快,快速创新实现
  • 可定时高级A/B测试
  • 相对复杂发布系统,投入成本相对低
  • 没有分支开发的合并冲突问题

缺点

  • 代码侵入、需要定期清理
  • 需要开关配置中心配合
  • 需要DevOps文化和流程配合

Apollo 功能亮点

  • 统一管理不同环境、不同集群的配置
    • Apollo提供了一个统一界面集中式管理不同环境(environment)、不同集群(cluster)、不同命名空间(namespace)的配置。
    • 同一份代码部署在不同的集群,可以有不同的配置,比如zk的地址等
    • 通过命名空间(namespace)可以很方便的支持多个不同应用共享同一份配置,同时还允许应用对共享的配置进行覆盖
  • 配置修改实时生效(热发布)
    • 用户在Apollo修改完配置并发布后,客户端能实时(1秒)接收到最新的配置,并通知到应用程序。
  • 版本发布管理
    • 所有的配置发布都有版本概念,从而可以方便的支持配置的回滚。
  • 灰度发布
    • 支持配置的灰度发布,比如点了发布后,只对部分应用实例生效,等观察一段时间没问题后再推给所有应用实例。
  • 权限管理、发布审核、操作审计
    • 应用和配置的管理都有完善的权限管理机制,对配置的管理还分为了编辑和发布两个环节,从而减少人为的错误。
    • 所有的操作都有审计日志,可以方便的追踪问题。
  • 客户端配置信息监控
    • 可以方便的看到配置在被哪些实例使用
  • 提供Java和.Net原生客户端
    • 提供了Java和.Net的原生客户端,方便应用集成
    • 支持Spring Placeholder,Annotation和Spring Boot的ConfigurationProperties,方便应用使用
    • 同时提供了Http接口,非Java和.Net应用也可以方便的使用
  • 提供开放平台API
    • Apollo自身提供了比较完善的统一配置管理界面,支持多环境、多数据中心配置管理、权限、流程治理等特性。
    • 不过Apollo出于通用性考虑,对配置的修改不会做过多限制,只要符合基本的格式就能够保存。
    • 配置可能会有比较复杂的格式,如xml, json,需要对格式做校验。
    • 还有一些使用方如DAL,不仅有特定的格式,而且对输入的值也需要进行校验后方可保存,如检查数据库、用户名和密码是否匹配。
    • 对于这类应用,Apollo支持应用方通过开放接口在Apollo进行配置的修改和发布,并且具备完善的授权和权限控制
  • 部署简单
    • 配置中心作为基础服务,可用性要求非常高,这就要求Apollo对外部依赖尽可能地少
    • 目前唯一的外部依赖是MySQL,所以部署非常简单,只要安装好Java和MySQL就可以让Apollo跑起来
    • Apollo还提供了打包脚本,一键就可以生成所有需要的安装包,并且支持自定义运行时参数

Apollo 架构

核心概念

概念 应用 环境 集群 配置项
解释 应用程序的唯一标识,存储位置为
/META-INF/app.properties
功能不同,不同环境,存储位置为
/opt/settings/server.properties
一个应用不同实例的分组,不同集群,
拥有不同的配置
支持xml、properties、json格式

注意:配置项存放位置:(1)私有配置env+app+cluster+namespace+item_key;(2)共有配置:env+cluster+namespace+item_key。

命名空间

一个应用不同配置的分组,默认的命名空间为application。

命名空间类型

  • 私有类型:只能被所属应用获取
  • 共有类型:环境变量必须全局唯一
  • 关联类型:私有继承公开并覆盖、定制公共组建配置场景

基础模型

基础模型的流程:

1.用户登陆Apollo系统之后,在配置中心修改配置并发布

2.在用户发布配置之后,会同知道Apollo客户端更新配置

3.Apollo客户端会定时从配置中心拉取最新的配置、更新本地配置并通知到应用

架构模块介绍

Config Server

  • 提供配置获取接口
  • 提供配置更新推送接口(基于Http long polling)
    • 服务端使用 Spring DeferredResult实现异步化,从而大大增加长连接数量
    • 目前使用的tomcat embed默认配置是最多10000个连接
  • 接口服务对象为Apollo客户端

Admin Service

  • 提供配置管理接口
  • 提供配置修改、发布等接口
  • 接口服务对象为Portal

Meta Server

  • Portal通过域名访问Meta Server获取Admin Service服务列表(IP+Port)
  • Client通过域名访问Meta Server获取Config Service服务列表(IP+Port)
  • Meta Server从Eureka获取Config Service和Admin Service的服务信息,相当于是一个Eureka Client
  • 增设一个Meta Server的角色主要是为了封装服务发现的细节,对Portal和Client而言,永远通过一个Http接口获取Admin Service和Config Service的服务信息,而不需要关心背后实际的服务注册和发现组件
  • Meta Server只是一个逻辑角色,在部署时和Config Service是在一个JVM进程中的,所以IP、端口和Config Service一致

Eureka

  • 基于Eureka和Spring Cloud Netflix提供服务注册和发现
  • Config Service和Admin Service会向Eureka注册服务,并保持心跳
  • 为了简单起见,目前Eureka在部署时和Config Service是在一个JVM进程中的(通过Spring Cloud Netflix)

Portal

  • 提供Web界面供用户管理配置
  • 通过Meta Server获取Admin Service服务列表(IP+Port),通过IP+Port访问服务
  • 在Portal侧做load balance、错误重试

Client

  • Apollo提供的客户端程序,为应用提供配置获取、实时更新等功能
  • 通过Meta Server获取Config Service服务列表(IP+Port),通过IP+Port访问服务
  • 在Client侧做load balance、错误重试

框架如何保证实时更新

用户在Portal发布配置之后,AdminService会将配置写入到ReleaseMessage表中,ConfigServer会定期扫描ReleaeMessage表,会实时通知客户端。(长连接,通过Http Long Polling实现)

客户端还会定时从Apollo配置中心拉取配置(推拉结合,Spring DeferredResult、定期拉配置)

高可用

1.Config/Admin/Portal 都是用负载均衡技术,来保证高可用。
2.服务端的实时推送技术、客户端定时拉取配置,保证及时性,如果拉取不到,客户端使用本地缓存的配置,保证高可用。

为什么使用Eureka

  • 它提供了完整的Service Registry和Service Discovery实现
    +首先是提供了完整的实现,并且也经受住了Netflix自己的生产环境考验,相对使用起来会比较省心。
  • 和Spring Cloud无缝集成
    • 同时Spring Cloud还有一套非常完善的开源代码来整合Eureka,使用起来非常方便。
    • Eureka支持在应用自身的容器中启动,也就是说应用启动完之后,既充当了Eureka的角色,同时也是服务的提供者。这样就极大的提高了服务的可用性。
      +为了提高配置中心的可用性和降低部署复杂度,我们需要尽可能地减少外部依赖。
  • 开源
    +由于代码是开源的,所以非常便于我们了解它的实现原理和排查问题

Apollo 于Spring Boot 结合

pom依赖

<parent>
    <artifactId>spring-boot-starter-parent</artifactId>
    <groupId>org.springframework.boot</groupId>
    <version>2.1.8.RELEASE</version>
</parent>
<properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
    <java.version>1.8</java.version>
</properties>

<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.4.0</version>
    </dependency>
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
    </dependency>
</dependencies>

yml文件

app:
  id: SampleApp
apollo:
  bootstrap:
    enabled: true
  meta: https://localhost:8080

function:
  switch:
    open: false

current:
  version: v1
server:
  port: 9000

添加Apollo配置

package com.edu.apollo.config;

import lombok.Data;
import org.springframework.beans.factory.annotation.Value;

@Data
public class DemoGlobalConfig {
    @Value("${current.version}")
    public String currentVersion;
    @Value("${function.switch.open}")
    public boolean switchFlag;
}
package com.edu.apollo.config;

import com.ctrip.framework.apollo.spring.annotation.EnableApolloConfig;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
@EnableApolloConfig
public class DemoApolloConfig {
    @Bean
    public DemoGlobalConfig globalConfig() {
        return new DemoGlobalConfig();
    }
}

相对应的Controller

package com.edu.apollo.controller;

import com.edu.apollo.config.DemoGlobalConfig;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.env.Environment;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;


@RestController
public class ApolloConfigController {
    @Autowired
    DemoGlobalConfig demoGlobalConfig;

    @Autowired
    Environment environment;

    @CrossOrigin
    @RequestMapping(value = "/config", method = RequestMethod.GET)
    public ResponseEntity<String> getApolloConfig() {
        String currentVersion = demoGlobalConfig.getCurrentVersion();
        return new ResponseEntity<String>(currentVersion,HttpStatus.OK);
    }
    //check whether the parameter is valid or not
    @CrossOrigin
    @RequestMapping(value = "/parameter", method = RequestMethod.GET)
    public ResponseEntity<String> getApolloConfigByParameter(@RequestParam String parameter) {
        String result = environment.getProperty(parameter);
        if (result == null){
            result = "defaultValue";
        }
        return new ResponseEntity<String>(result,HttpStatus.OK);
    }
}

添加开关

package com.edu.apollo.service;

public interface SwitchService {
    public String getSwitchData();
}
package com.edu.apollo.service.impl;

import com.edu.apollo.config.DemoGlobalConfig;
import com.edu.apollo.service.SwitchService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class SwitchServiceImpl implements SwitchService {
    @Autowired
    private DemoGlobalConfig demoGlobalConfig;

    @Override
    public String getSwitchData() {
        if (demoGlobalConfig.isSwitchFlag()) {
            return "new";
        } else {
            return "old";
        }
    }
}
package com.edu.apollo.controller;

import com.edu.apollo.service.SwitchService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class SwitchController {

    @Autowired
    private SwitchService switchService;

    @GetMapping(value = "/switch")
    public ResponseEntity<String> getSwitchOpen(){
        return new ResponseEntity<String>(switchService.getSwitchData(),HttpStatus.OK);
    }
}

在启动程序的时候,需要添加环境变量:-Dapollo.configService=http://localhost:8080

Apollo启动过程

start config service  for client 
start admin service for portal 8090
start portal service 8070
eureka 8080
apollo cache:/opt/data/{appid}/config-cache  要有读写权限

运行步骤

校验是否启动成功

在程序启动之后,需要进行校验: http://localhost:9000/config

返回值为v1

校验Apollo是否生效

在Apollo界面上更改配置为current.version=v2
在程序启动之后,需要进行校验: http://localhost:9000/config

返回值为v2

开关功能校验

在程序启动之后,需要进行校验: http://localhost:9000/switch

返回值为old

在Apollo界面上更改配置为function.switch.open=true

在程序启动之后,需要进行校验: http://localhost:9000/config

返回值为v2

参考文献

Apollo配置中心设计
微服务架构~携程Apollo配置中心架构剖析
source code

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,294评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,493评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,790评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,595评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,718评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,906评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,053评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,797评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,250评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,570评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,711评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,388评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,018评论 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,796评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,023评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,461评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,595评论 2 350

推荐阅读更多精彩内容

  • 一、总体设计 1.1 基础模型 如下即是Apollo的基础模型: 用户在配置中心对配置进行修改并发布 配置中心通知...
    蜗牛先森1230阅读 5,248评论 0 4
  • 配置中心发展背景随着程序功能的日益复杂,程序的配置日益增多:各种功能的开关、参数的配置、服务器的地址……对程序配置...
    缄默_8421阅读 15,587评论 3 19
  • Apollo(阿波罗)是携程框架部门研发的分布式配置中心,能够集中化管理应用不同环境、不同集群的配置,配置修改后能...
    BeckJin阅读 3,756评论 0 1
  • 在Spring Boot 2.0 整合携程Apollo配置中心一文中,我们在本地快速部署试用了Apollo。本文将...
    AaronSimon阅读 17,622评论 1 24
  • 引子 皇城的夜,向来是不寂寞的。城南的箫声仿佛愣是要将这肃杀的严冬挽成杨柳依依的四月。亦河两岸熙熙攘攘的人群似乎完...
    碧空_96ed阅读 138评论 0 1