微服务架构-实现技术之具体实现工具与框架8:Spring Cloud Config原理与注意事项
一、配置中心的由来及选择
(一)配置中心由来
互联网时代下的分布式系统,应用部署在N台服务器上或在云化环境以多实例呈现,如果一个实例一个实例(或一台服务器一台服务器)进行修改配置和重启,一是维护成本极高,二是不现实,配置中心的思想便应运而生。配置中心用作集中管理不同环境和不同集群配置,以及在修改配置后实时动态推送到应用动态更新。
配置中心管理作为微服务六大实现技术之一,从模型上来分析,包括4大分类、4个核心需求和2个维度分析,在分布式下配置中心在实现上需要满足3大需求:高效获取、实时感知、分布式访问。基本理论在之前博客中已经讲解过
(二)配置中心要求具备的功能
配置中心应该剧本具备以下基本功能,具体如图:
这里只展示了基本的实现功能,从功能特性、技术路线、可用性和易用性方面还有更多的功能要求,具体可以见(四)以及对应的配置中心实现方案对比。
(三)配置中心基本流转图和支撑体系分析
具体可如图所示:
(四)多种配置中心的选择与对比方案
具体对比分类 | 具体对比项 | 重要程度 | Spring Cloud Config | Netflix Archaius | Ctrip Apollo | DisConf |
功能特性 | 静态配置管理 | 高 | 基于file | 无 | 支持 | 支持 |
动态配置管理 | 高 | 支持 | 支持 | 支持 | 支持 | |
统一管理 | 高 | 无,需要git、数据库等 | 无 | 支持 | 支持 | |
多维度管理 | 中 | 无,需要git、数据库等 | 无 | 支持 | 支持 | |
变更管理 | 高 | 无,需要git、数据库等 | 无 | 无 | 无 | |
本地配置缓存 | 高 | 无 | 无 | 支持 | 支持 | |
配置更新策略 | 中 | 无 | 无 | 无 | 无 | |
配置锁 | 中 | 支持 | 不支持 | 不支持 | 不支持 | |
配置校验 | 中 | 无 | 无 | 无 | 无 | |
配置生效时间 | 高 | 重启生效,手动刷新 | 手动刷新生效 | 实时 | 实时 | |
配置更新推送 | 高 | 需要手动触发 | 需要手动触发 | 支持 | 支持 | |
配置定时拉取 | 高 | 无 | 无 | 支持 | 配置更新目前依赖事件驱动,client重启或server推送操作 | |
用户权限管理 | 中 | 无,需要git、数据库等 | 无 | 支持 | 支持 | |
授权、审核、审计 | 中 | 无,需要git、数据库等 | 无 | 界面直接提供发布历史和回滚按钮 | 操作记录有赖数据库,但无查询接口 | |
配置版本管理 | 高 | git | 无 | 支持 | 无,需要git、数据库等 | |
配置合规检测 | 高 | 不支持 | 不支持 | 支持(还需完善) | ||
实例配置监控 | 高 | 需要结合Spring Admin | 不支持 | 支持 | 支持,可以查看每个配置在哪台机器上加载 | |
灰度发布 | 中 | 不支持 | 不支持 | 支持 | 不支持部分更新 | |
告警通知 | 中 | 不支持 | 不支持 | 支持邮件方式告警 | 支持邮件方式告警 | |
统计报表 | 中 | 不支持 | 不支持 | 不支持 | 不支持 | |
依赖关系 | 高 | 不支持 | 不支持 | 不支持 | 不支持 | |
技术路线 | 支持Spring Boot | 高 | 原生支持 | 低 | 支持 | 与Spring Boot无关 |
支持Spring Config | 高 | 原生支持 | 低 | 支持 | 与Spring Cloud无关 | |
客户端支持 | 低 | java | java | java、.net | java | |
业务系统入侵性 | 高 | 入侵性弱 | 入侵性弱 | 入侵性弱 | 入侵性弱,支持注解和xml | |
可依赖组件 | 高 | |||||
可用性 | 单点故障(SPOF) | 高 | 支持HA部署 | 支持HA部署 | 支持HA部署 | 支持HA部署,高可用由ZK提供 |
多数据中心部署 | 高 | 支持 | 支持 | 支持 | 支持 | |
配置获取性能 | 高 | unkown | unkown | unkown | unkown | |
易用性 | 配置界面 | 中 | 无,需要git、数据库等操作 | 无 | 统一界面 | 统一界面 |
结论:
- 从整体上来看的话,携程的Apollo性能及各方面相对于其他配置中心而言是最好的,因为其支持pring Boot和Spring Config,所以在微服务架构中建议最好采用Apollo来作为配置中心;
- Spring Cloud Config相对Apollo性能与支持没有很全面,但是可以采用一定的开源技术及现有技术进行改善加之原生支持pring Boot和Spring Config,在微服务架构中也是强烈建议采用的方案;
- 其他两种方案在微服务架构中不建议采用,在此不做分析。
我们主要对Spring Cloud Config进行分析和理解,Apollo做辅助分析,关于Apollo的相关知识有时间在进行学习和分享。
二、Spring Cloud Config概述及基本实现方法介绍
Spring Cloud Config是Spring Cloud微服务体系中的配置中心,是一个集中化外部配置的分布式系统,由服务端和客户端组成,其不依赖于注册中心,是一个独立的配置中心,支持多种存储配置信息形式,目前主要有jdbc、value、native、svn、git,其中默认是git。重点讨论功能有如下两个方面:
- 将程序中配置的各种功能开关、参数配置、服务器地址——>修改后实时生效
- 灰度发布、分环境、分集群管理配置———>全面集中化管理
因为采用native方式必然决定了每次配置完相关文件后一定要重启Spring Cloud Config,所以一般我们不会采用此方案,在实际操作中我们主要的实现方案有以下四种:Spring Cloud Config结合Git实现配置中心方案+Spring Cloud Config结合关系型数据库实现配置中心方案+Spring Cloud Config结合非关系型数据库实现配置中心方案+Spring Cloud Config与Apollo配置结合实现界面化配置中心方案。
三、Spring Cloud Config结合Git实现配置中心方案
(一)Git版基本工作原理(未加Spring Cloud Bus热刷新)
配置客户端启动时会向服务器发起请求,服务端接收到客户端的请求后,根据配置的仓库地址将Git上的文件克隆到本地的一个临时目录中,这个目录是一个Git的本地仓库目录,然后服务端再读取本地文件返回给客户端。这样做的好处是,当Git服务器故障或者网络请求异常时,保证服务端仍然可以正常工作。
在实际实现上,服务端需要配置好git的uri地址信息以及search-paths信息,并在对应Git中与之相对应,客户端在bootstrap文件中按照其内容和具体文件名进行配置label、uri、name、profile等消息即可,但是在基本实现上如果修改文件后依旧需要重启来解决此问题,所以需要进行手动刷新或结合Spring Cloud Bus进行热刷新。
(二)Git多种配置信息讲解
关于Git配置信息而言,其主要有以下几种方式:
1.本地仓库
Spring Cloud Config默认使用Git,对Git的配置也最简单,Config Server可用uri、username、password这三个参数就可以读取配置了,通过Git的版本控制可以使Config Server适应特殊的场景。
测试时我们也可以使用本地仓库的方式,使用file://
前缀,那么uri的配置就可以写作
-
spring:
-
cloud:
-
config:
-
server:
-
git:
-
uri: file://${user.home}/config-repo #注意:Windows系统需要使用file:///前缀
-
# ${user.home}代表当前用户的家目录
2.占位符配置URI
Spring Cloud Config Server支持占位符的使用,支持{application}
、{profile}
、{label}
这些占位符对Git的uri配置,通过占位符使用应用名称来区分应用对应的仓库然后进行使用。这里需要注意仓库名称和仓库下面的配置文件名称一致才可以,因为配置了spring.cloud.config.name默认占位符匹配的是spring.application.name。
-
spring:
-
cloud:
-
config:
-
server:
-
git:
-
uri: https://github.com/hellxz/SpringCloudlearn/config-repo/{application}
-
#此时spring.application.name的值会填充到这个uri中,从而达到动态获取不同位置的配置
3.匹配并配置多个仓库
Spring Cloud Config Server除了使用{应用名}/{环境名}
来匹配配置仓库外,还支持通过带有通配符的表达式来匹配。
当有多个匹配规则的时候,可以用逗号分隔多个{应用名}/{环境名}
配置规则。以官方文档例子举例:
-
spring:
-
cloud:
-
config:
-
server:
-
git:
-
uri: https://github.com/spring-cloud-samples/config-repo #默认的仓库
-
#注意:配置多个仓库时,Config Server 在启动时会直接克隆第一个仓库的配置库,其他配置库只有请求时才会clone到本地
-
repos:
-
simple: https://github.com/simple/config-repo
-
special:
-
pattern: special*/dev*,*special*/dev*
-
uri: https://github.com/special/config-repo
-
local:
-
pattern: local*
-
uri: file:/home/configsvc/config-repo
-
test:
-
pattern:
-
– ‘*/development’
-
– ‘*/staging’
-
uri: https://github.com/development/config-repo
如果{应用名}/{环境名}
不能匹配到仓库,那么就在默认的uri下去查找配置文件。
上边的例子中,
- simple 仓库自动匹配到
simple/*
- special 仓库的pattern,第一个是应用名以special开头,环境名以dev开头;第二个是应用名包含special,环境名以dev开头;多个匹配到同一uri的pattern用逗号分割
- local 仓库的的pattern也会自动补全为
local*/*
- test仓库中的 pattern 是以通配符开始的,需要使用单引号
4.子目录存储
通过spring.cloud.config.server.git.searchPaths
来定位到Git仓库的子目录中,相当于在uri后加上searchPaths的目录。
searchPaths参数的配置也支持使用{应用名}、{环境名}、{分支名}占位符,比如spring.cloud.config.server.git.searchPaths={应用名}
,通过这样的配置,我们能让每一个应用匹配到自己的目录中。如下举例:
-
spring:
-
cloud:
-
config:
-
server:
-
git:
-
uri: https://github.com/spring-cloud-samples/config-repo
-
searchPaths: ‘{application}’
5.访问权限
使用Git仓库的时候,使用HTTP认证需要使用username和password属性来配置账户,具体如下:
(还可以使用SSH认证,Config Server本地的.ssh文件或使用私钥等进行配置,如:http://cloud.spring.io/spring-cloud-static/Finchley.RELEASE/single/spring-cloud.html#_git_ssh_configuration_using_properties)
-
spring:
-
cloud:
-
config:
-
server:
-
git:
-
uri: https://github.com/spring-cloud-samples/config-repo
-
username: trolley
-
password: strongpassword
(三)基本的手动刷新和结合Spring Cloud Bus热刷新
为了避免重启项目才能获取最新的配置信息,可以进一步优化做到手动刷新和结合Spring Cloud Bus进行热刷新,其基本要求一般不改动服务端相关配置和代码,但是需要各客户端增加断点访问依赖和安全依赖,这样就可以对外通过访问客户端刷新断点uri来进行刷新操作,手动刷新就是直接访问断点的方式,虽然简单,但是如果每次都要手动刷新的话,面对微服务很多的情况下,就会因为操作人员忘记或者遗漏的情况,从而造成服务出错。在生产实践中,我们往往要求结合Spring Cloud Bus进行热刷新。
结合Spring Cloud Bus进行热刷新的操作如上图所示,用户更新配置信息时,检查到Git Hook变化,触发Hook配置地址的调用,Config Server接收到请求并发布消息,Bus将消息发送到Config Client,当Config Client接收到消息后重新发送请求加载配置消息。
四、Spring Cloud Config结合关系型数据库MYSQL实现配置中心方案
(一)基本实现原理
Spring Cloud Config是一个独立的配置中心,支持多种存储配置信息形式,其中包括jdbc方式,其基本原理图如下:
git有它天然的优势,比如多版本管理、分支管理、提交审核策略等等,但是如果相对其中存储的数据做细粒度的权限控制,就力不从心了。我们可以将持久化从git迁移到MySQL上,这样的好处就是,可以针对配置中心,方便开发出一些对外接口,例如一些用户可配置的动态改更新的参数,同时,由于是数据库方式,当让可以自己在此基础上实现视图化和刷新机制,整体上显得更加优雅。
(二)基本要求讲解
具体实现上,需要Config Server端增加服务中心jar包、-配置中心jar包、连接msql数据库相关jar包这三个必须的jar包,在配置文件中需要增加对应的服务名称、连接配置信息、mysql 属性配置、指定注册中心地址等,具体我们要分析的是连接配置信息:
-
#连接配置信息
-
spring:
-
application:
-
name: config-server-jdbc
-
profiles:
-
active: jdbc
-
cloud:
-
config:
-
server:
-
default-label: dev
-
jdbc:
-
sql: SELECT akey , avalue FROM config_server where APPLICATION=? and APROFILE=? and LABEL=?
连接配置信息中:
- spring.profiles.active=jdbc ,自动实现JdbcEnvironmentRepository。
- sql语句自定义,否则会默认为“SELECT KEY, VALUE from PROPERTIES where APPLICATION=? and PROFILE=? and LABEL=?”,具体可以参考 JdbcEnvironmentRepository 实现。非必须,这里由于采用mysql数据源,
key
、value
是保留关键词,原生的实现语句会报错,所以需要重写一下这句查询语句(如果存储的表结构设计不同于上面准备的内容,也可以通过这个属性的配置来修改配置的获取逻辑) - 数据库建表为config_server,由于key,value和profile是mysql关键字,所以都在最前面加了a。当然表名字段名都可以自定义。
- {application} 对应客户端的”spring.application.name”属性;
- {aprofile} 对应客户端的 “spring.profiles.active”属性(逗号分隔的列表);
- {label} 对应服务端属性,这个属性能标示一组配置文件的版本.
- 只要 select出来是两个字段 ,框架会 自动包装到environment的map<key,value> 。
然后便是启动类等注解配置和数据库相关操作与构建,相关代码具体见后面博客及github。
注意,JDBC存储的使用思路,具体使用实际上还有很多可以优化的空间,比如:索引的优化、查询语句的优化;如果还需要进一步定制管理,对于表结构的优化也是很有必要的。
五、Spring Cloud Config结合非关系性数据库MongoDB实现配置中心方案
(一)基本实现原理
Spring Cloud Config作为独立的配置中心,支持多种存储配置信息形式,但是没有提供MongoDB的方式,但是目前已经有相关孵化器,其基本原理图如下:
其基本原理与关系型数据库原理相类似,相关代码具体见后面博客及github。
(二)基本要求讲解
具体实现上,需要Config Server端增加服务中心jar包、-配置中心jar包、连接mongo数据库相关jar包这三个必须的jar包,在配置文件中需要增加对应的服务名称、连接配置信息、mongo属性配置、指定注册中心地址等,相关代码具体见后面博客及github。
六、Spring Cloud Config使用技能及功能扩展
(一)基本实用技能:本地参数覆盖远程参数
主要是指使用本地的参数覆盖远程的参数,这在开发的时候经常会用到,主要配合内容如下:
-
spring:
-
cloud:
-
config:
-
allowOverride: true
-
overrideNone: true
-
overrideSystemProperties: false
这三个属性的意思是:
- spring.cloud.config.allowOverride:如果想要远程配置优先级高,那么allowOverride设置为false;如果想要本地配置优先级高那么allowOverride设置为true,默认为true;
- spring.cloud.config.overrideNone:overrideNone为true时本地配置优先级高,包括系统环境变量、本地配置文件等等,默认为false;
- spring.cloud.config.overrideSystemProperties:只有系统环境变量或者系统属性才能覆盖远程配置文件的配置,本地配置文件中配置优先级低于远程配置,默认为true。
(二)客户端自动刷新实现
在一些应用上面,不需要在服务端批量推送的时候,客户端本身需要获取变化参数的情况,这个时候需要使用客户端自动刷新来完成该功能。具体实现上,可以单独在二方包中增加一个用于自动刷新的功能,引入spring-cloud-config-client和spring-cloud-autoconfigure,并且增加自动配置类(增加间隔刷新时间),在该类中主要注入端点类,通过定时任务和刷新时间,进行配置请求刷新,添加配置后,我们将二方包引入到实际的客户端应用中。
在客户端中需要引入spring-cloud-config-client、spring-boot-starter-security和我们刚刚新做的二方包,并且在对应的配置文件中增加spring.cloud.config.refreshInterval内容,写一个相关的控制器便可以开始测试了,相关代码具体见后面博客及github。
(三)客户端回退功能实现
客户端可以匹配回退机制,主要用于以下两种场景,应用回退手段来处理案例:
- 因为一定原因出现了网络中断的情况;
- 配置服务因为一定的原因进行维护而关闭。
当启用回退时,客户端适配器将“缓存”本地文件系统中的计算属性。要启用回退功能,只需要指定存储缓存的位置即可。
在具体实现上,我们同样需要在二方包增加对应可以实现客户端回退功能的内容,引入spring-cloud-config-client和spring-security-rsa,增加自动配置类(包含回退本地配置文件所在的文件和名称、要回退配置文件的路径、用来创建本地回退文件的方法)和相关配置内容,
(四)客户端安全认证机制JWT实现
Spring Cloud Config客户端使用JWT身份验证方法代替标准的基本身份验证,这种方式需要对服务端和客户端都要改造,具体如下:
- 客户端向服务端授权Rest Controller发送请求并且带上用户名和密码;
- 服务端返回JET Token;
- 客户端查询服务端的配置需要在Header中带上token令牌进行认证。
在具体实现上,需要在二方包中引入jwt相关内容,并将该二方包作为基本包使用,在此二方包中pom中必须需要引入一下这三项内容spring-boot-autoconfigure、spring-boot-autoconfiguration-processor、spring-cloud-starter-config,创建Config配置类(引入标示username和password以及endpoint内容,同时增加初始化init并采用注解@PostConstruct,表明在Servelt构造函数和Init()方法之间执行具体容器加载),并进一步创建实体类LoginRequest(对应请求username和password)和实体类Token(对应生成的token)。
将此二方包引入到客户端的pom中,同时引入spring-cloud-config-client,并且在对应bootstrap文件中添加用于参与安全认证所需要的username、password、endpoint(是一个http地址,config server的访问授权地址)。增加启动类和控制器进行测试。
接下来就需要对服务端的代码进行分析和讨论了,首先,需要在pom中引入spring-cloud-config-server、jwt、gson、spring-boot-starter-security,创建JwtAuthenticationRequest类用于传递用户名和密码,创建JwtAuthenticationResponse实体类返回token信息,创建JwtUser用户认证信息实体类,创建JWT的token认证过滤器和JWT工具类(用于生成token和token验证),创建JWT认证端点类(在认证过程中,未能认证通过的直接返回401状态码),接着创建一个认证账号的验证类MemberServiceImpl及将数据封装为json返回客户端的WebAuthenticationDetailsSourceImpl,最后创建Config进行安全和过滤的自动配置类,增加控制器用于测试,相关代码具体见后面博客及github。相关具体类调用时序图如下:
七、Spring Cloud Config实现客户端及服务端高可用方案
(一)客户端高可用原理及方案
客户端的高可用方式,从方案角度来看,主要还是用file的形式,和前面客户端的回退方案思路大致一样,客户端高可用主要是解决当服务端不可用的情况下,在客户端仍然可以正常启动。从客户端的角度出发,不是增加配置中心的高可用性,而是降低客户端对配置中心的依赖程度,从而提高整个分布式架构的健壮性。
具体实现上,仍然需要创建一个二方包,在二方包中引入spring-cloud-config-client,并且配置属性加载类,创建配置类命名为ConfigSupportConfiguration(主要是用于判断远程加载信息是否可用,如果不能用则将读取加载本地配置文件启动),同时在二方包中增加配置文件spring.factories指明org.springframework.cloud.bootstrap.BootstrapConfiguration。
将该二方包引入对应的客户端的pom中,同时引入spring-cloud-config-client,在bootstrap文件中增加backup开关并指明你备份的本地地址fallbackLocation,增加对应的启动类和控制器用于测试,相关代码具体见后面博客及github。
(二)服务端高可用原理及方案
服务端的高可用在生产环境中也一样重要,通过结合Eureka注册中心的方式来搭建Spring Cloud Config Server高可用,通过Ribbon的负载均衡选择一个Config Server进行连接来获取配置信息,具体流程见上图。
具体实现上,Eureka相关开发与之前是一样的,不用做多余的代码工作;服务端的pom文件中需要引入spring-cloud-config-server和spring-cloud-starter-netflix-eureka-client,其他按照之前的开发即可;客户端的pom文件中需要引入spring-cloud-config-client和spring-cloud-starter-netflix-eureka-client,并且在bootstrap中不在配置spring.cloud.config.uri信息用于指定Server端地址,而是增加了三个新的配置,具体如下:
- spring.cloud.config.discovery.enabled:开启Config服务发现支持;
- spring.cloud.config.discovery.serviceId:指定Server端的name,也就是Server端spring.application.name;
- euraka.client.service-url.defaultZone:只想注册中心的地址。
接着,按照以往的流程测试高可用就可以了,相关代码具体见后面博客及github。
八、Spring Cloud Config与Apollo配置使用实现界面化操作
(一)Apollo基本概述及基本功能介绍
1.Apollo简介
Apollo(阿波罗)是携程框架部研发并开源的一款生产级的配置中心产品,它能够集中管理应用在不同环境、不同集群的配置,配置修改后能够实时推送到应用端,并且具备规范的权限、流程治理等特性,适用于微服务配置管理场景。
Apollo目前在国内开发者社区比较热,在Github上有超过5k颗星,在国内众多互联网公司有落地案例,可以说Apollo是目前配置中心产品领域Number1的产品,其成熟度和企业级特性要远远强于Spring Cloud体系中的Spring Cloud Config产品。
Apollo采用分布式微服务架构,它的架构有一点复杂,Apollo的作者宋顺虽然给出了一个架构图,但是如果没有一定的分布式微服务架构基础的话,则普通的开发人员甚至是架构师也很难一下子理解。
2.Apollo基本功能介绍
- 统一管理不同环境、不同集群的配置:Apollo提供了一个统一界面集中式管理不同环境(environment)、不同集群(cluster)、不同命名空间(namespace)的配置;同一份代码部署在不同的集群,可以有不同的配置,比如zk的地址等;通过命名空间(namespace)可以很方便的支持多个不同应用共享同一份配置,同时还允许应用对共享的配置进行覆盖
- 配置修改实时生效(热发布): 用户在Apollo修改完配置并发布后,客户端能实时(1秒)接收到最新的配置,并通知到应用程序
- 版本发布管理: 所有的配置发布都有版本概念,从而可以方便地支持配置的回滚
- 灰度发布: 支持配置的灰度发布,比如点了发布后,只对部分应用实例生效,等观察一段时间没问题后再推给所有应用实例
- 权限管理、发布审核、操作审计:应用和配置的管理都有完善的权限管理机制,对配置的管理还分为了编辑和发布两个环节,从而减少人为的错误。 所有的操作都有审计日志,可以方便的追踪问题
- 客户端配置信息监控: 可以在界面上方便地看到配置在被哪些实例使用
- 提供Java和.Net原生客户端:提供了Java和.Net的原生客户端,方便应用集成;支持Spring Placeholder, Annotation和Spring Boot的ConfigurationProperties,方便应用使用(需要Spring 3.1.1+);同时提供了Http接口,非Java和.Net应用也可以方便的使用
- 提供开放平台API:Apollo自身提供了比较完善的统一配置管理界面,支持多环境、多数据中心配置管理、权限、流程治理等特性。不过Apollo出于通用性考虑,对配置的修改不会做过多限制,只要符合基本的格式就能够保存。对于有些使用方,它们的配置可能会有比较复杂的格式,而且对输入的值也需要进行校验后方可保存,如检查数据库、用户名和密码是否匹配。对于这类应用,Apollo支持应用方通过开放接口在Apollo进行配置的修改和发布,并且具备完善的授权和权限控制。
- 部署简单:配置中心作为基础服务,可用性要求非常高,这就要求Apollo对外部依赖尽可能地少。目前唯一的外部依赖是MySQL,所以部署非常简单,只要安装好Java和MySQL就可以让Apollo跑起来。Apollo还提供了打包脚本,一键就可以生成所有需要的安装包,并且支持自定义运行时参数
(二)Apollo总体架构模块分析
总体架构模块如下图所示:
其主要包含了四个核心模块和三个辅助模块:
1.四个核心模块及其主要功能
- ConfigService:提供配置获取接口、配置推送接口,服务于Apollo客户端;
- AdminService:提供配置管理接口、配置修改发布接口,服务于管理界面Portal;
- Client:为应用获取配置,支持实时更新,通过MetaServer获取ConfigService的服务列表,使用客户端软负载SLB方式调用ConfigService
- Portal:配置管理界面,通过MetaServer获取AdminService的服务列表,使用客户端软负载SLB方式调用AdminService
(ConfigService和AdminService都是多实例无状态的部署,需要将自身注册到Eureka中并保持心跳)
2.三个辅助服务发现模块
- Eureka:用于服务发现和注册,Config/AdminService注册实例并定期报心跳,和ConfigService在一起部署
- MetaServer:Portal通过域名访问MetaServer获取AdminService的地址列表,Client通过域名访问MetaServer获取ConfigService的地址列表。相当于一个Eureka Proxy,逻辑角色和ConfigService在一起部署
- NginxLB:和域名系统配合,协助Portal访问MetaServer获取AdminService地址列表;和域名系统配合,协助Client访问MetaServer获取ConfigService地址列表;和域名系统配合,协助用户访问Portal进行配置管理
Apollo可以和Spring Cloud Config搭建的微服务进行无缝集成。
3.为什么选择Eureka作为服务注册中心,而不是使用传统的zk、etcd呢?
有以下几方面的原因:
- 它提供了完整的Service Registry和Service Discovery实现。首先是提供了完整的实现,并且也经受住了Netflix自己的生产环境考验,相对使用起来会比较省心。
- 和Spring Cloud无缝集成:项目本身就使用了Spring Cloud和Spring Boot,同时Spring Cloud还有一套非常完善的开源代码来整合Eureka,所以使用起来非常方便。另外,Eureka还支持在我们应用自身的容器中启动,也就是说我们的应用启动完之后,既充当了Eureka的角色,同时也是服务的提供者。这样就极大的提高了服务的可用性。这一点是我们选择Eureka而不是zk、etcd等的主要原因,为了提高配置中心的可用性和降低部署复杂度,我们需要尽可能地减少外部依赖。
- Open Source:由于代码是开源的,所以非常便于了解它的实现原理和排查问题。
(三)Apollo客户端设计与运行环境介绍
1.Apollo客户端设计
Apollo客户端的实现原理:
- 客户端和服务端保持了一个长连接,从而能第一时间获得配置更新的推送。
- 客户端还会定时从Apollo配置中心服务端拉取应用的最新配置。
这是一个fallback机制,为了防止推送机制失效导致配置不更新
客户端定时拉取会上报本地版本,所以一般情况下,对于定时拉取的操作,服务端都会返回304 – Not Modified
定时频率默认为每5分钟拉取一次,客户端也可以通过在运行时指定System Property: apollo.refreshInterval来覆盖,单位为分钟。
- 客户端从Apollo配置中心服务端获取到应用的最新配置后,会保存在内存中
- 客户端会把从服务端获取到的配置在本地文件系统缓存一份
在遇到服务不可用,或网络不通的时候,依然能从本地恢复配置
- 应用程序可以从Apollo客户端获取最新的配置、订阅配置更新通知
2.配置更新推送实现
Apollo客户端和服务端保持了一个长连接,从而能第一时间获得配置更新的推送。长连接实际上我们是通过Http Long Polling实现的,具体而言:
- 客户端发起一个Http请求到服务端
- 服务端会保持住这个连接30秒
- 如果在30秒内有客户端关心的配置变化,被保持住的客户端请求会立即返回,并告知客户端有配置变化的namespace信息,客户端会据此拉取对应namespace的最新配置
- 如果在30秒内没有客户端关心的配置变化,那么会返回Http状态码304给客户端
- 客户端在服务端请求返回后会自动重连
考虑到会有数万客户端向服务端发起长连,在服务端使用了async servlet(Spring DeferredResult)来服务Http Long Polling请求。
3.环境要求
- Java1.7+
- Guava15.0+ : Apollo客户端默认会引用Guava 19,如果你的项目引用了其它版本,请确保版本号大于等于15.0
- 注:对于Apollo客户端,如果有需要的话,可以做少量代码修改来降级到Java 1.6