Apollo开发指南

准备工作和架构设计

Posted by HH on July 12, 2021

Apollo开发指南(一)

本文介绍了如何在本地使用IDE编译,运行Apollo,从而可以帮助大家了解Apollo的内在运行机制,同时也为自定义开发做好准备。

一、准备工作

1.1本地运行时环境

Apollo本地开发需要以下组件:

  1. java1.8+
  2. MySQL5.6.5+
  3. IDE没有特殊要求

其中MySQL需要创建Apollo数据库并倒入基础数据。具体请参照分布式部署指南中的准备工作,创建数据库。

1.2Apollo总体设计

1.2.1架构模块

overall-architecture

Apollo总共包含七个模块,其中四个模块是和功能相关的核心模块,另外三个模块都是辅助服务发现的的模块:

四个核心模块及主要功能
  1. ConfigService
    • 提供配置获取接口
    • 提供配置推送接口
    • 服务于Apollo客户端
  2. AdminService
    • 提供配置管理接口
    • 提供配置修改发布接口
    • 服务于管理界面Portal
  3. Client
    • 为了应用获取配置,支持实时更新
    • 通过MetaServer获取ConfigService的服务列表
    • 使用客户端软负载SLB方式调用ConfigService
  4. Portal
    • 配置管理界面
    • 通过MetaServer获取AdminService的服务列表
    • 使用客户端软负载SLB方式调用AdminService
三个辅助服务发现模块
  1. Eureka
    • 用于服务发现和注册
    • Config/AdminService注册实例并定期报心跳
    • 和ConfigService在一起部署
  2. MetaServer
    • Portal通过域名访问MetaServer获取AdminService的地址列表
    • Client通过域名访问MetaServer获取ConfigService的地址列表
    • 相当于一个Eureka Proxy
    • 逻辑角色,和ConfigService在一起部署
  3. NginxLB
    • 和域名系统配合,协助Portal访问MetaServer获取AdminService地址列表
    • 和域名系统配合,协助Client访问MetaServer获取ConfigService地址列表
    • 和域名系统配合,协助用户访问Portal进行配置管理。
1.2.2 架构剖析
架构V1

如果不考虑分布式微服务架构中的服务发现问题,Apollo最简单的架构入下图所示

image.png

要点:

  1. ConfigService是一个独立的微服务,服务于Client进行配置获取。
  2. Client和ConfigService保持长连接,通过一种推拉结合(push&pull)模式,在实现配置实时更新的同时,保证配置更新不丢失。
  3. AdminService是一个独立的微服务,服务于Portal进行配置管理。Portal通过调用AdminService进行配置管理和发布。
  4. ConfigService和AdminService共享ConfigDB,ConfigDB中存放项目在某个环境中的配置信息。ConfigService/AdminService/ConfigDB三者在每个环境中都要部署一份。
  5. Portal有一个独立的PortalDB,存放用户权限、项目和配置的元数据信息。Portal只需部署一份,它可以管理多套环境。
架构V2

为了保证高可用,ConfigService和AdminService都是无状态以集群方式部署的,这个时候就存在一个服务发现问题:Client怎么找到ConfigService?Portal怎么找到AdminService?为了解决这个问题,Apollo在其架构中引入了Eureka服务注册中心组件,实现微服务间的服务注册和发现,更新后的架构图如下所示:

image.png

要点:

  1. Config/AdminService启动后都会注册到Eureka服务注册中心,并且定期发送保活心跳。
  2. Eureka采用集群方式部署,使用分布式一致性协议保证每个实例的状态最终一致。
架构V3

我们知道Eureka是自带服务发现的Java客户端的,如果Apollo只支持java客户端连接,不支持其他语言客户端接入的话,那么Client和Portal只需要引入Eureka的Java客户端,就可以实现服务发现功能。发现目标服务后,通过客户端软负载(SLB,例如Ribbon)就可以路由到目标服务实例。这是一个经典的微服务架构,基于Eureka实现服务注册发现+客户端Ribbon配合实现软路由,如下面所示:

image.png

架构V4

Eureka原生仅支持Java客户端,如果要为多语言开发Eureka/Ribbon客户端,这个工作量很大,也不可控。为此Apollo的作者引入了MetaServer这个角色,他是Eureka的Proxy,将Eureka的服务发现接口以更简单明确的HTTP接口的形式暴露出来,方便Client/Portal通过简单的HTTPClient就可以查询到Config/AdminServer的地址列表。获取到服务实例地址列表之后,再以简单的客户端软负载(Client SLB)策略路由定位到目标实例,并发起调用。

现在还有一个问题,MetaServer本身是无状态以集群方式部署的,那么Client/Portal如何发现MetaServer呢?一种传统的做法是借助硬件或者软件负载均衡器,例如携程采用的是扩展后的NginxLB也称(Software Load Balancer),由运维为MetaServer集群配置一个域名,指向NginxLB,NginxLB再对MetaServer进行负载均衡和流量转发。Client/Portal通过域名+NginxLB间接访问MetaServer集群。

引入MetaServer和NginxLB之后的架构如下图所示:

image.png

架构V5

V4版本已经是比较完整的Apollo架构全貌,现在还剩一个环节:Portal也是无状态以集群方式部署的,用户如何发现和访问Portal?答案也是简单的传统做法,用户通过域名+NginxLB间接访问集群。

所以V5版本是包含用户端的最终的Apollo架构全貌,如下图所示:

image.png

1.3模块依赖图

模块依赖图