微服务系列(八)之配置中心Apollo

1.背景与介绍

  随着微服务架构的发展,企业级项目由无数的服务组成,这时候急需用到集中管理、治理的配置的组件,来统一管理各个服务的开关、配置参数、数据库地址、服务器等等,然而这还不够,还要对这个管理配置的组件有着修改后实时发布、多环境、灰度发布、权限控制、审核等等机制,由此配置中心出现了,而由携程开源的apollo(阿波罗)人气最高、高可用性、各种功能非常完善,当然最关键选择apollo的一点是,文档真的非常非常完善,==本篇文章主要介绍基于docker版本的apollo搭建,apollo的一些核心概念、架构设计以及中间遇到的一些问题解决方案。

官方文档 开源地址

2.apollo核心概念

  1. application 就是字面意思应用,比如在apollo上新建一个配置项目,就是这个应用名称,设置一个appid做为唯一标识。
  2. environment 环境,apollo支持多环境配置管理,比如dev、fat、uat、pro,每个环境部署的代码,从对应的环境中读取配置。
  3. cluster 集群,apollo支持,同一个application应用+环境,按照不同集群来读取不同的配置,这个我没有实战中试过,感兴趣的可以去试试,根据官方文档来操作。
  4. namespace 命名空间,在apollo上建立项目(应用)时候,会默认在application命名空间下,我们的配置中,有许多项目都共同使用,比如数据库连接、服务发现KEY/VALUE等等各种公共的配置项,这时候就可以放到共享命名空间下,开放给所有客户端去拉取这个命名空间下的配置。

3.apollo架构设计

  这是apollo官方提供的架构图,由图可见,这是典型的微服务架构,如果做过微服务的同学看起来比较容易,这里面涉及的服务、中间件拆分细节如下:

  1. ConfigService 配置服务,依赖configDb数据库,提供配置获取接口,为客户端推送配置更新通知,客户端直连或者通过slb地址连接。
  2. AdminService 后端服务,依赖configDb数据库,提供配置管理接口,提供配置增删改查等等接口,Portal管理界面使用该服务。
  3. Client 就是我们的API服务,依赖ConfigService,通过configService获取应用配置,或者长连接实时更新;
  4. Portal 阿波罗的管理界面,依赖Portal数据库,依赖AdminService;
  5. Euraka 一个服务注册与发现的中间件,ConfigService和AdminService都注册在这,apollo默认架构是这个组件与ConfigService部署在一起,也可以独立部署出去。
  6. MetaServer 这个相当于,Euraka的一个反向代理
  7. NginxLB 负载均衡器,如果是分布式部署的话,ConfigService与AdminService同过这个负载地址拉拉取对应的服务发现的反向代理MetaServer地址;

  configService和AdminService都是无状态的,因此可以横向无线扩展,于是携程就引入只支持java的服务发现中间件Euraka引入进来,当服务启动时候,自动注册服务,Portal与java客户端(client)通过Euraka的SLB地址来发现服务列表,后来呢,因为要支持其他语言,又引入MetaServer做为Euraka的反向代理中间件,而MetaServer也做成集群,暴漏SLB地址,这样把Euraka的SLB换成MetaServer的SLB地址,所有语言都可以轻易使用Apollo。 如图:

写到这的时候,突发一个思考,由于目前主流微服务架构,单服务大概率都是基于docker部署的且多pod形式存在,本身该服务这些pod会有一个负载IP,但是通过服务注册发现后,有两种注册方式:

  1. pod实例本身ip地址注册,这种的话,服务发现拉取服务列表,是会把所有pod都拉回来,我们代码本身要进行轮询负载算法进行选择;
  2. pod负载IP地址注册,这样的话,服务发现拉取回来就是负载地址,不需要我们写轮询算法;

4.配置发布的实时通知设计

  客户在portal操作发布后,内部调用adminService接口进行对配置数据库的操作,然后发送ReleaseMessage给ConfigService,收到消息后,通知Client。   推送ReleaseMessage的实现原理如下,本来想通过消息队列的形式,但人家做为开源框架,不想使用多的外部依赖,所以通过数据库消息表形式来完成简单的消息队列,具体流程如下:

  1. AdminService发布后,会往ReleaseMessage表里插入一条配置的APPID+Cluster+NameSpace的记录;
  2. ConsigService有一个线程每秒扫描一次,如果有新纪录话,就会通知到所有消息监听器,官方给的叫ReleaseMessageListener,具体不做详细了解,感兴趣的去看;
  3. 监听器得到消息后,会降配置内容,通知给所有客户端;
  4. 客户端发起个HTTP请求到ConfigService的 监听器接口,但是这个监听器接口会把这个请求挂起,因为客户端在配置apollo的时候会根据appid和namespace来获取关心的配置,所以挂起请求的同时,60秒内,如果这个监听器没有接收到其关心的配置消息,就返回304,相反如果有其关心的配置消息,接口会立即返回给客户端其关心的nameSpace信息,然后客户端立即再发起请求ConfigService获取这些namespace下的配置内容。

5.客户端实现原理

  1. 通过上述通知设计可知,客户端通过Long Http Polling与configService保持一个长连接,来第一时间获取最新的NameSpace更新信息;
  2. 为了防止长连接推送失败,客户端每5分钟也会去请求一下ConfigService,通过对比版本信息,来获取关心的最新配置;
  3. 客户端拿到最新配置后,会缓存到本地一份,这样遇到apollo服务不可用或者网络不通时候,可以从本地恢复配置;

6.apollo的高可用性

直接贴出官方给出的表格

7.apollo部署

  说真的,携程这个开源的配置中心,文档真的非常非常细,大赞!从单体部署到分布式部署以及各种形式部署,都非常详细,文档地址:部署文档,这里由于小霸王服务器问题,我们只部署一个环境的非分布式部署来搭建apollo,真正的生产环境上,公司的运维会扛起分布式部署大旗,我们后端辅助即可哈哈。

  本文部署使用基于docker方式:

  1. 先安装mysql,每安装的去安装,这里不多说;

  2. 搭建所依赖的两个数据库ApolloPortalDB和ApolloConfigDB,我这选择从人家github上直接下载脚本,去执行,数据脚本传送,下载完后,在navcat上直接执行,会得到两个数据库

  3. 拉取configService镜像

bash 复制代码
docker pull apolloconfig/apollo-configservice:1.8.0
  1. 运行configService容器
ini 复制代码
docker run -p 8080:8080 \
    -e SPRING_DATASOURCE_URL="jdbc:mysql://你的mysql地址:3306/ApolloConfigDB?characterEncoding=utf8" \
    -e SPRING_DATASOURCE_USERNAME=数据库用户 -e SPRING_DATASOURCE_PASSWORD=数据库密码 \
    -d -v /tmp/logs:/opt/logs --name apollo-configservice apolloconfig/apollo-configservice:1.8.0
  1. 拉取adminService镜像
bash 复制代码
docker pull apolloconfig/apollo-adminservice:1.8.0
  1. 运行adminService容器
ini 复制代码
docker run -p 8090:8090 \
    -e SPRING_DATASOURCE_URL="jdbc:mysql://你的mysql地址:3306/ApolloConfigDB?characterEncoding=utf8" \
    -e SPRING_DATASOURCE_USERNAME=数据库用户 -e SPRING_DATASOURCE_PASSWORD=数据库密码 \
    -d -v /tmp/logs:/opt/logs --name apollo-adminservice apolloconfig/apollo-adminservice:1.8.0
  1. 拉取portal镜像
bash 复制代码
docker pull apolloconfig/apollo-portal:1.8.0
  1. 运行portal容器
ini 复制代码
docker run -p 8070:8070 \
    -e SPRING_DATASOURCE_URL="jdbc:mysql://你的mysql地址:3306/ApolloPortalDB?characterEncoding=utf8" \
    -e SPRING_DATASOURCE_USERNAME=数据库用户 -e SPRING_DATASOURCE_PASSWORD=数据库密码 \
    -e APOLLO_PORTAL_ENVS=dev,pro \  (注意这里,你需要什么环境,就填写哪些,运行起来会自动更新数据库ApolloPortalDB中的apollo.portal.envs,这测试只写dev)
    -e DEV_META=http://你的metaService:8080 (注意,configService与euraka正常启动在同一进程) 
    -d -v /tmp/logs:/opt/logs --name apollo-portal apolloconfig/apollo-portal:1.8.0

全部运行起来后,查看docker运行情况如下图:

8.apollo管理界面使用

1.运行portal地址,默认账号密码是apollo/admin,登录

2.什么是创建项目?独立管理你微服务中一个或一类的私有配置集合,比如我有个订单服务,我这里就建一个OrderApi项目,正常情况下,有1个货几个公共项目,其他都是业务类项目。

3.修改部门,在数据库ApolloPortalDB.表ServerConfig.organizations修改。下面具体怎么使用,也没什么可说的,实在不会就照着文档来官方使用说明

4.我新建了一个docker-api的项目,和一个share公共项目,并分别新增和发布了配置,注意下,命名空间,公有私有的属性问题;

9..net core使用apollo

1.新建一个.net core3.1项目,nuget包安装Com.Ctrip.Framework.Apollo.Configuration; 2.启动类构造函数

scss 复制代码
 public IConfiguration Configuration { get; }

        public Startup(IConfiguration configuration)
        {
		//输出debug日志在控制台,方便查找问题
           Com.Ctrip.Framework.Apollo.Logging.LogManager.UseConsoleLogging(Com.Ctrip.Framework.Apollo.Logging.LogLevel.Debug);
            var builder = new ConfigurationBuilder()
                .AddApollo(configuration.GetSection("apollo"))
                .AddNamespace("yf.Share")
                .AddDefault();
            Configuration = builder.Build();
        }

3.appsetting.json

json 复制代码
{
  "apollo": {
    "AppId": "docker-api1",
    "MetaServer": "http://xxxxxxx:8080",
    "ConfigServer": [ "http://xxxxxxxx:8080/" ]
  }
}

4.Api

csharp 复制代码
 [HttpGet("get/configs")]
        public async Task<IActionResult> GetConfigs()
        {
            var res = "";
            //获取公共命名空间下的配置
            var publicConfig = configuration["env"];
            //获取该私有项目下的配置
            var privateConfig = configuration["myConfig1"];
            res = $"公共:{publicConfig},私有:{privateConfig}";
            return Ok(res);

        }

5.运行

10.常见问题

按照官方文档搭建部署的话,基本会碰到如下问题,为避免新人踩坑浪费时间,现总结如下: 1.当容器全部启动成功后,新建完项目,点击进去,右上角弹窗报错"请联系管理员",我大概记得这么个问题,查看容器日志发现,apollo的ApolloConfigDB数据库中的ServerConfig中的eureka.service.url配置的默认是本地URL,由于docker的隔离性,所以请求失败,我们去这里给改成docker间可通信地址即可。

2.都配置完后,管理界面也都正常发布,但是代码里死活取不到数据,这个问题查了好久,终于最后在github上提问中找到篇这个问题的帖子,查看问题,就是startup中给debug日志打开,可以看到在注册apollo的时候的控制台日志,原因就客户端在连接configService服务列表时,通过metaserver(eureka反向代理地址)时候,默认取的是内网容器IP,在我们客户端没法访问,所以解决方案,就是appsetting中增加ConfigServer配置,来指定即可解决。

3.搭建时候,重点查看

相关推荐
米丘3 天前
微前端之 Web Components 完全指南
微服务·html
霸道流氓气质5 天前
领域驱动设计(DDD)在 Spring Boot 微服务中的实践指南
运维·spring boot·微服务
霸道流氓气质6 天前
Spring Boot 微服务性能优化完全指南
spring boot·微服务·性能优化
地瓜伯伯6 天前
从MESI缓存一致性协议讲透synchronized的底层
java·spring boot·spring·spring cloud·微服务·springcloud
Devin~Y6 天前
大厂 Java 面试实录:从音视频内容社区到 AI RAG 的全链路技术设计
java·spring boot·redis·spring cloud·微服务·kafka·音视频
递归尽头是星辰6 天前
AI 访问数据仓库:从直连到微服务化
数据仓库·人工智能·微服务·dataagent·ai数据治理
就改了6 天前
Windows 环境 SkyWalking 完整实操教程
windows·微服务·skywalking
至乐活着7 天前
Docker Compose多服务编排实战:从零搭建Node.js+MySQL+Redis全栈应用
docker·微服务·devops·容器编排·compose
就改了7 天前
微服务异步场景链路断裂完整解决方案
微服务·云原生·架构
山东点狮信息科技有限公司7 天前
点狮OA-企业级 OA 办公自动化系统架构设计与实践
spring cloud·微服务·性能优化·架构·系统架构