[源碼閱讀] 阿里SOFA服務註冊中心MetaServer(1)

[源碼閱讀] 阿里SOFA服務註冊中心MetaServer(1)

0x00 摘要

SOFARegistry 是螞蟻金服開源的一個生產級、高時效、高可用的服務註冊中心。本系列將帶領你們一塊兒分析其MetaServer的實現機制,本文爲第一篇,介紹MetaServer整體架構。html

本系列整體參考了官方的博客,具體請參見"0xFF 參考"。你們能夠把參考做爲總綱,我這系列文章做爲註釋補遺翻閱。java

0x01 服務註冊中心

1.1 服務註冊中心簡介

在微服務架構下,一個互聯網應用的服務端背後每每存在大量服務間的相互調用。例如服務 A 在鏈路上依賴於服務 B,那麼在業務發生時,服務 A 須要知道服務 B 的地址,才能完成服務調用。而分佈式架構下,每一個服務每每都是集羣部署的,集羣中的機器也是常常變化的,因此服務 B 的地址不是固定不變的。若是要保證業務的可靠性,服務調用者則須要感知被調用服務的地址變化。node

既然成千上萬的服務調用者都要感知這樣的變化,那這種感知能力便下沉成爲微服務中一種固定的架構模式:服務註冊中心linux

服務註冊中內心,有服務提供者和服務消費者兩種重要的角色,服務調用方是消費者,服務被調方是提供者。對於同一臺機器,每每兼具二者角色,既被其它服務調用,也調用其它服務。服務提供者將自身提供的服務信息發佈到服務註冊中心,服務消費者經過訂閱的方式感知所依賴服務的信息是否發生變化。web

服務註冊中心在服務調用的場景中,扮演一個「中介」的角色,服務發佈者 (Publisher) 將服務發佈到服務註冊中心,服務調用方 (Subscriber) 經過訪問服務註冊中心就可以獲取到服務信息,進而實現調用。算法

Subscriber 在第一次調用服務時,會經過 Registry 找到相應的服務的 IP 地址列表,經過負載均衡算法從 IP 列表中取一個服務提供者的服務器調用服務。同時 Subscriber 會將 Publisher 的服務列表數據緩存到本地,供後續使用。當 Subscriber 後續再調用 Publisher 時,優先使用緩存的地址列表,不須要再去請求Registry。spring

+----------+                                    +---------+
|Subscriber| <--------+              +--------+ |Publisher|
+----------+          |              |          +---------+
                      |              |
+----------+          |              v
|Subscriber| <--------+   +----------++         +---------+
+----------+          <---+ Registry  | <-------+Publisher|
                      |   +----------++         +---------+
+----------+          |              ^
|Subscriber| <--------+              |
+----------+                         |
                                     |          +---------+
                                     +----------+Publisher|
                                                +---------+

服務註冊中心Registry的最主要能力是服務註冊和服務發現兩個過程。數據庫

  • 服務註冊的過程最重要是對服務發佈的信息進行存儲。
  • 服務發現的過程是把服務發佈端的全部變化(包括節點變化和服務信息變化)及時準確的通知到訂閱方的過程。

1.2 SOFARegistry 整體架構

1.2.1 分層

SOFARegistry 做爲服務註冊中心,分爲4個層,分別爲:編程

  • Client 層

Client 層是應用服務器集羣。Client 層是應用層,每一個應用系統經過依賴註冊中心相關的客戶端 jar 包,經過編程方式來使用服務註冊中心的服務發佈和服務訂閱能力。bootstrap

  • Session 層

Session層是服務器集羣。顧名思義,Session 層是會話層,經過長鏈接和 Client 層的應用服務器保持通信,負責接收 Client 的服務發佈和服務訂閱請求。

在服務註冊中心的服務端由於每一個存儲節點對應的客戶端的連接數據量有限,必須進行特殊的一層劃分用於專門收斂無限擴充的客戶端鏈接,而後在透傳相應的請求到存儲層。

該層只在內存中保存各個服務的發佈訂閱關係,對於具體的服務信息,只在 Client 層和 Data 層之間透傳轉發。Session 層是一個無數據狀態的代理層,能夠隨着 Client 層應用規模的增加而擴容

由於 SOFARegistry 的服務發現須要較高的時效性,對外表現爲主動推送變動到客戶端,因此推送的主體實現也集中在 Session 層,內部的推拉結合主要是經過 Data 存儲層的數據版本變動推送到全部 Session 節點,各個 Session 節點根據存儲的訂閱關係和首次訂閱獲取的數據版本信息進行比對,最終肯定推送給那些服務消費方客戶端。

  • Data 層

數據服務器集羣。Data 層經過分片存儲的方式保存着所用應用的服務註冊數據。數據按照 dataInfoId(每一份服務數據的惟一標識)進行一致性 Hash 分片,多副本備份,保證數據的高可用。Data 層能夠隨着數據規模的增加,在不影響業務的前提下實現平滑的擴縮容

  • Meta 層

元數據服務器集羣。這個集羣管轄的範圍是 Session 服務器集羣和 Data 服務器集羣的服務器信息,其角色就至關於 SOFARegistry 架構內部的服務註冊中心,只不過 SOFARegistry 做爲服務註冊中心是服務於廣大應用服務層,而 Meta 集羣是服務於 SOFARegistry 內部的 Session 集羣和 Data 集羣,Meta 層可以感知到 Session 節點和 Data 節點的變化,並通知集羣的其它節點

1.3 爲何要分層

SOFARegistry 內部爲何要進行數據分層,是由於系統容量的限制

在 SOFARegistry 的應用場景中,體量龐大的數據主要有兩類:Session 數據、服務信息數據。兩類數據的相同之處在於其數據量都會不斷擴展,而不一樣的是其擴展的緣由並不相同:

  • Session 是對應於 Client 的鏈接,其數據量是隨着業務機器規模的擴展而增加,
  • 服務信息數據量的增加是由 Publisher 的發佈所決定。

因此 SOFARegistry 經過分層設計,將兩種數據隔離,從而使兩者的擴容互不影響。

圖3 - 分層,擴容互不影響

這也是 SOFARegistry 設計三層模型的緣由,經過 SessionServer 來負責與 Client 的鏈接,將每一個 Client 的鏈接數收斂到 1,這樣當 Client 數量增加時,只須要擴容 SessionServer 集羣就能夠了。 因此從設計初衷上咱們就可以看出來 SessionServer 必需要知足的兩個主要能力:從 DataServer 獲取服務信息數據;以及保存與 Client 的會話。

0x02 MetaServer

2.1簡介

MetaServer 在 SOFARegistry 中,承擔着集羣元數據管理的角色,用來維護集羣成員列表,能夠認爲是 SOFARegistry 註冊中心的註冊中心。

MetaServer 做爲 SOFARegistry 的元數據中心,其核心功能能夠歸納爲:集羣成員列表管理。好比:

  • 節點列表的註冊與存儲
  • 節點列表的變動通知
  • 節點健康監測

當 SessionServer 和 DataServer 須要知道集羣列表,而且須要擴縮容時,MetaServer 將會提供相應的數據。

其內部架構以下圖所示:

內部架構圖

MetaServer 基於 Bolt, 經過 TCP 私有協議的形式對外提供服務,包括 DataServer, SessionServer 等,處理節點的註冊,續約和列表查詢等請求。

同時也基於 Http 協議提供控制接口,好比能夠控制 session 節點是否開啓變動通知, 健康檢查接口等。

成員列表數據存儲在 Repository 中,Repository 被一致性協議層進行包裝,做爲 SOFAJRaft 的狀態機實現,全部對 Repository 的操做都會同步到其餘節點, 經過Rgistry來操做存儲層。

MetaServer 使用 Raft 協議保證高可用和數據一致性, 同時也會保持與註冊的節點的心跳,對於心跳超時沒有續約的節點進行驅逐,來保證數據的有效性。

在可用性方面,只要未超過半數節點掛掉,集羣均可以正常對外提供服務,半數以上掛掉,Raft 協議沒法選主和日誌複製,所以沒法保證註冊的成員數據的一致性和有效性。整個集羣不可用 不會影響 Data 和 Session 節點的正常功能,只是沒法感知節點列表變化。

2.2 問題

空談無用,just show the code。因而讓咱們帶着問題來思考,即從宏觀和微觀角度來思考MetaServer應該實現什麼功能,具體是怎麼實現的。

思考:

  • MetaServer具體是以什麼方式實現。
  • MetaServer如何實現高可用。
  • MetaServer如何實現或者應用內部通信協議。
  • MetaServer如何保持DataNode列表和SessionNode列表。
  • MetaServer如何處理節點列表變動推送。
  • MetaServer如何處理節點列表查詢。
  • MetaServer如何處理MetaServer如何保證數據一致性。
  • 各個集羣是如何搭建,如何完成高可用。

下面咱們就一一分析。

0x03 代碼結構

咱們在 sofa-registry-5.4.2/server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta 看看目錄和文件結構。

按照目錄咱們能夠大體瞭解功能

  • MetaApplication.java :MetaServer程序主體,入口。
  • bootstrap :負責MetaServer的啓動和配置。
  • executor :負責各類定時管理任務,他的啓動設置是在 MetaServerBootstrap.initRaft 之中。
  • listener :SOFARegistry 採用了 Handler - Task & Strategy - Listener 的方式來應對服務註冊中的各類場景和任務,這樣的處理模型可以儘量的讓代碼和架構清晰整潔。
  • node :對業務節點的抽象,包括DataNode,SessionNode,MetaNode。
  • registry :經過Registry來操做存儲層,全部對 Repository 的操做都會同步到其餘節點。
  • remoting :對外交互接口,提供各類對外的 handler。
  • repository :集羣節點列表存儲在 Repository 中,經過 Raft 強一致性協議對外提供節點註冊、續約、列表查詢等 Bolt 請求,從而保障集羣得到的數據是強一致性的。Repository 被一致性協議層進行包裝,做爲 SOFAJRaft 的狀態機實現。
  • resource :http Server的接口,用來響應控制消息。
  • store :封裝了存儲節點的操做。
  • task :封裝了異步執行邏輯,經過TaskDispatcher,TaskExecutors 來執行各類定義好的異步Task。

具體代碼結構以下:

.
├── MetaApplication.java
├── bootstrap
│   ├── AbstractNodeConfigBean.java
│   ├── EnableMetaServer.java
│   ├── MetaServerBootstrap.java
│   ├── MetaServerConfig.java
│   ├── MetaServerConfigBean.java
│   ├── MetaServerConfiguration.java
│   ├── MetaServerInitializerConfiguration.java
│   ├── NodeConfig.java
│   ├── NodeConfigBeanProperty.java
│   └── ServiceFactory.java
├── executor
│   └── ExecutorManager.java
├── listener
│   ├── DataNodeChangePushTaskListener.java
│   ├── PersistenceDataChangeNotifyTaskListener.java
│   ├── ReceiveStatusConfirmNotifyTaskListener.java
│   └── SessionNodeChangePushTaskListener.java
├── node
│   ├── DataNodeService.java
│   ├── MetaNodeService.java
│   ├── NodeOperator.java
│   ├── NodeService.java
│   ├── SessionNodeService.java
│   └── impl
│       ├── DataNodeServiceImpl.java
│       ├── MetaNodeServiceImpl.java
│       └── SessionNodeServiceImpl.java
├── registry
│   ├── MetaServerRegistry.java
│   └── Registry.java
├── remoting
│   ├── DataNodeExchanger.java
│   ├── MetaClientExchanger.java
│   ├── MetaServerExchanger.java
│   ├── RaftExchanger.java
│   ├── SessionNodeExchanger.java
│   ├── connection
│   │   ├── DataConnectionHandler.java
│   │   ├── MetaConnectionHandler.java
│   │   ├── NodeConnectManager.java
│   │   └── SessionConnectionHandler.java
│   └── handler
│       ├── AbstractServerHandler.java
│       ├── DataNodeHandler.java
│       ├── FetchProvideDataRequestHandler.java
│       ├── GetNodesRequestHandler.java
│       ├── RenewNodesRequestHandler.java
│       └── SessionNodeHandler.java
├── repository
│   ├── NodeConfirmStatusService.java
│   ├── NodeRepository.java
│   ├── RepositoryService.java
│   ├── VersionRepositoryService.java
│   ├── annotation
│   │   └── RaftAnnotationBeanPostProcessor.java
│   └── service
│       ├── DataConfirmStatusService.java
│       ├── DataRepositoryService.java
│       ├── MetaRepositoryService.java
│       ├── SessionConfirmStatusService.java
│       ├── SessionRepositoryService.java
│       └── SessionVersionRepositoryService.java
├── resource
│   ├── BlacklistDataResource.java
│   ├── DecisionModeResource.java
│   ├── HealthResource.java
│   ├── MetaDigestResource.java
│   ├── MetaStoreResource.java
│   ├── PersistentDataResource.java
│   ├── RenewSwitchResource.java
│   └── StopPushDataResource.java
├── store
│   ├── DataStoreService.java
│   ├── MetaStoreService.java
│   ├── RenewDecorate.java
│   ├── SessionStoreService.java
│   └── StoreService.java
└── task
    ├── AbstractMetaServerTask.java
    ├── Constant.java
    ├── DataNodeChangePushTask.java
    ├── MetaServerTask.java
    ├── PersistenceDataChangeNotifyTask.java
    ├── ReceiveStatusConfirmNotifyTask.java
    ├── SessionNodeChangePushTask.java
    └── processor
        ├── DataNodeSingleTaskProcessor.java
        ├── MetaNodeSingleTaskProcessor.java
        └── SessionNodeSingleTaskProcessor.java

16 directories, 75 files

0x04 啓動運行

啓動能夠參考 https://www.sofastack.tech/projects/sofa-registry/server-quick-start/

SOFARegistry 支持兩種部署模式,分別是集成部署模式及獨立部署模式。

4.1 集成部署

4.1.1 Linux/Unix/Mac

啓動命令:sh bin/startup.sh

4.1.2 Windows

雙擊 bin 目錄下的 startup.bat 運行文件。

4.1.3 啓動信息

經過下列log咱們能夠看到啓動信息。

MetaApplication

[2020-09-12 20:23:05,463][INFO][main][MetaServerBootstrap] - Open meta server port 9612 success!
[2020-09-12 20:23:08,198][INFO][main][MetaServerBootstrap] - Open http server port 9615 success!
[2020-09-12 20:23:10,298][INFO][main][MetaServerBootstrap] - Raft server port 9614 start success!group RegistryGroup
[2020-09-12 20:23:10,322][INFO][main][MetaServerInitializerConfiguration] - Started MetaServer

DataApplication

[2020-09-12 20:23:25,004][INFO][main][DataServerBootstrap] - Open http server port 9622 success!
[2020-09-12 20:23:26,084][INFO][main][DataServerBootstrap] - start server success
[2020-09-12 20:23:26,094][INFO][main][DataApplication] - Started DataApplication in 10.217 seconds (JVM running for 11.316)

SessionApplication

[2020-09-12 20:23:50,243][INFO][main][SessionServerBootstrap] - Open http server port 9603 success!
[2020-09-12 20:23:50,464][INFO][main][SessionServerInitializer] - Started SessionServer
[2020-09-12 20:23:50,526][INFO][main][SessionApplication] - Started SessionApplication in 12.516 seconds (JVM running for 13.783)

各個 Server 的默認端口分別爲:

meta.server.sessionServerPort=9610
meta.server.dataServerPort=9611
meta.server.metaServerPort=9612
meta.server.raftServerPort=9614
meta.server.httpServerPort=9615

可訪問三個角色提供的健康監測 API,或查看日誌 logs/registry-startup.log:

# 查看meta角色的健康檢測接口:
$ curl http://localhost:9615/health/check
{"success":true,"message":"... raftStatus:Leader"}

# 查看data角色的健康檢測接口:
$ curl http://localhost:9622/health/check
{"success":true,"message":"... status:WORKING"}

# 查看session角色的健康檢測接口:
$ curl http://localhost:9603/health/check
{"success":true,"message":"..."}

4.2 獨立部署

在這裏咱們能夠看出來各類集羣是如何搭建,以及如何在集羣內部通信,分佈式協調。

按照常理來講,每一個集羣都應該依賴zookeeper之類的軟件來進行本身內部的協調,好比統一命名服務、狀態同步服務、集羣管理、分佈式應用配置項。但實際上咱們沒有發現相似的使用。

具體看配置文件發現,每臺機器都要設置全部的metaServer的host。這說明Data Server, Session Server則強依賴Meta Server。

實際上,MetaServer 使用 Raft 協議保證高可用和數據一致性, 同時也會保持與註冊的節點的心跳,對於心跳超時沒有續約的節點進行驅逐,來保證數據的有效性。Meta 層可以感知到 Session 節點和 Data 節點的變化,並通知集羣的其它節點

這就涉及到各個角色的 failover 機制:

  • MetaServer 集羣部署,內部基於 Raft 協議選舉和複製,只要不超過 1⁄2 節點宕機,就能夠對外服務。
  • DataServer 集羣部署,基於一致性 Hash 承擔不一樣的數據分片,數據分片擁有多個副本,一個主副本和多個備副本。若是 DataServer 宕機,MetaServer 能感知,並通知全部 DataServer 和 SessionServer,數據分片可 failover 到其餘副本,同時 DataServer 集羣內部會進行分片數據的遷移。
  • SessionServer 集羣部署,任何一臺 SessionServer 宕機時 Client 會自動 failover 到其餘 SessionServer,而且 Client 會拿到最新的 SessionServer 列表,後續不會再鏈接這臺宕機的 SessionServer。

4.2.1 部署meta

每臺機器在部署時須要修改 conf/application.properties 配置:

# 將3臺meta機器的ip或hostname配置到下方(填入的hostname會被內部解析爲ip地址)
nodes.metaNode=DefaultDataCenter:<meta_hostname1>,<meta_hostname2>,<meta_hostname3>
nodes.localDataCenter=DefaultDataCenter

4.2.2 部署data

每臺機器在部署時須要修改 conf/application.properties 配置:

# 將3臺 meta 機器的 ip 或 hostname 配置到下方(填入的 hostname 會被內部解析爲 ip 地址)
nodes.metaNode=DefaultDataCenter:<meta_hostname1>,<meta_hostname2>,<meta_hostname3>
nodes.localDataCenter=DefaultDataCenter
data.server.numberOfReplicas=1000

4.2.3 部署 session

每臺機器在部署時須要修改 conf/application.properties 配置:

# 將3臺 meta 機器的 ip 或 hostname 配置到下方(填入的 hostname 會被內部解析爲 ip 地址)
nodes.metaNode=DefaultDataCenter:<meta_hostname1>,<meta_hostname2>,<meta_hostname3>
nodes.localDataCenter=DefaultDataCenter
nodes.localRegion=DefaultZone

0x05 整體邏輯

MetaServer 在啓動時,會啓動三個 Bolt Server,而且註冊 Processor Handler,處理對應的請求:

  • DataServer:處理 DataNode 相關的請求;
  • SessionServer:處理 SessionNode 相關的請求;
  • MetaServer:處理MetaNode相關的請求;

而後啓動 HttpServer, 用於處理 Admin 請求,提供推送開關,集羣數據查詢等 Http 接口。

最後啓動 Raft 服務, 每一個節點同時做爲 RaftClient 和 RaftServer, 用於集羣間的變動和數據同步。

5.1 程序主體

MetaServer 是一個SpringBootApplication,主要起做用的就是EnableMetaServer。

@EnableMetaServer
@SpringBootApplication
public class MetaApplication {
    public static void main(String[] args) {
        SpringApplication.run(MetaApplication.class, args);
    }
}

具體參見下圖

+-------------------+
| @EnableMetaServer |
|                   |
|  MetaApplication  |
+-------------------+

EnableMetaServer註解引入了MetaServerConfiguration

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(MetaServerConfiguration.class)
public @interface EnableMetaServer {
}

MetaServerConfiguration是各類配置,而且引入 MetaServerInitializerConfiguration負責啓動。

@Configuration
@Import(MetaServerInitializerConfiguration.class)
@EnableConfigurationProperties
public class MetaServerConfiguration {
}

因此咱們能夠知道:

  • MetaServerConfiguration :負責配置
  • MetaServerInitializerConfiguration : 負責啓動

因而程序總結結構演化爲下圖:

(Init)
                            +------------------------------------+
                            | MetaServerInitializerConfiguration |
                            +-------------+----------------------+
                                          ^
+-------------------+                     |
| @EnableMetaServer |                     |
|                   |                     |
|  MetaApplication  |                     |
+-------------+-----+                     | (Configuration)
              |                 +---------+---------------+
              +-------------->  | MetaServerConfiguration |
                                +-------------------------+

下面咱們開始引入配置。

5.2 配置

MetaServer 模塊的各個 bean 在 JavaConfig 中統一配置,JavaConfig 類爲 MetaServerConfiguration。

5.2.1 配置分類

MetaServerConfiguration 具體有如下幾類配置:

  • Bootstrap,負責MetaServer啓動配置,是核心啓動類。
  • ServerConfig,負責MetaServer的配置項,好比MetaServerConfig,NodeConfig,PropertySplitter。
  • ServerServiceConfiguration,負責服務相關的配置,好比 sessionNodeService,storeServiceFactory,sessionStoreService。
  • ServerRepositoryConfiguration,負責Repository相關的配置,好比dataRepositoryService,sessionRepositoryService等。
  • ServerRemotingConfiguration,負責網絡相關配置,好比BoltExchange,JerseyExchange,這裏隨後會重點說明。
  • ResourceConfiguration,負責Resource相關配置,好比 jerseyResourceConfig,persistentDataResource。
  • ServerTaskConfiguration,負責各類 task 相關配置 ,好比dataNodeSingleTaskProcessor。
  • ExecutorConfiguation,ExecutorManager相關配置。
  • MetaDBConfiguration,DB相關配置。

具體縮略版代碼以下 :

@Configuration
@Import(MetaServerInitializerConfiguration.class)
@EnableConfigurationProperties
public class MetaServerConfiguration {
    @Bean
    @ConditionalOnMissingBean
    public MetaServerBootstrap metaServerBootstrap() {
    }

    @Configuration
    protected static class MetaServerConfigBeanConfiguration {
    }

    @Configuration
    public static class MetaServerServiceConfiguration {
    }

    @Configuration
    public static class MetaServerRepositoryConfiguration {
    }

    @Configuration
    public static class MetaServerRemotingConfiguration {
    }

    @Configuration
    public static class ResourceConfiguration {
    }

    @Configuration
    public static class MetaServerTaskConfiguration {
    }

    @Configuration
    public static class ExecutorConfiguation {
    }

    @Configuration
    public static class MetaDBConfiguration {
    }  
}

咱們的圖進化以下:

(Init)
                            +------------------------------------+
                            | MetaServerInitializerConfiguration |
                            +-------------+----------------------+      +---------------------+
                                          ^                       +-->  | MetaServerBootstrap |
+-------------------+                     |                       |     +---------------------+
| @EnableMetaServer |                     |                       |     +---------------------------------+
|                   |                     |                       +-->  |MetaServerConfigBeanConfiguration|
|  MetaApplication  |                     |                       |     +---------------------------------+
+--------------+----+                     |                       |     +------------------------------+
               |                          |                       +-->  |MetaServerServiceConfiguration|
               |                          |                       |     +------------------------------+
               |                          |                       |     +---------------------------------+
               |                          |                       +-->  |MetaServerRepositoryConfiguration|
               |                          |                       |     +---------------------------------+
               |                          | (Configuration)       |     +-------------------------------+
               |                +---------+---------------+       +-->  |MetaServerRemotingConfiguration|
               +--------------> | MetaServerConfiguration | +-----+     +-------------------------------+
                                +-------------------------+       |     +----------------------+
                                                                  +-->  |ResourceConfiguration |
                                                                  |     +----------------------+
                                                                  |     +---------------------------+
                                                                  +-->  |MetaServerTaskConfiguration|
                                                                  |     +---------------------------+
                                                                  |     +---------------------+
                                                                  +-->  |ExecutorConfiguation |
                                                                  |     +---------------------+
                                                                  |     +--------------------+
                                                                  +-->  |MetaDBConfiguration |
                                                                        +--------------------+

下圖爲了手機閱讀

5.2.2 handler的配置

這裏要特殊提一下handler的配置,由於這是後續分析的主體之一,是三個 Bolt Server的handler

@Configuration
public static class MetaServerRemotingConfiguration {

    @Bean
    public Exchange boltExchange() {
        return new BoltExchange();
    }

    @Bean
    public Exchange jerseyExchange() {
        return new JerseyExchange();
    }

    @Bean(name = "sessionServerHandlers")
    public Collection<AbstractServerHandler> sessionServerHandlers() {
        Collection<AbstractServerHandler> list = new ArrayList<>();
        list.add(sessionConnectionHandler());
        list.add(sessionNodeHandler());
        list.add(renewNodesRequestHandler());
        list.add(getNodesRequestHandler());
        list.add(fetchProvideDataRequestHandler());
        return list;
    }

    @Bean(name = "dataServerHandlers")
    public Collection<AbstractServerHandler> dataServerHandlers() {
        Collection<AbstractServerHandler> list = new ArrayList<>();
        list.add(dataConnectionHandler());
        list.add(getNodesRequestHandler());
        list.add(dataNodeHandler());
        list.add(renewNodesRequestHandler());
        list.add(fetchProvideDataRequestHandler());
        return list;
    }

    @Bean(name = "metaServerHandlers")
    public Collection<AbstractServerHandler> metaServerHandlers() {
        Collection<AbstractServerHandler> list = new ArrayList<>();
        list.add(metaConnectionHandler());
        list.add(getNodesRequestHandler());
        return list;
    }
}

因而咱們的整體架構進化具體見下圖

(Init)
                        +------------------------------------+
                        | MetaServerInitializerConfiguration |
                        +--------------+---------------------+
                                       ^
                                       |
                                       |
                                       |
                                       |
                                       |                             +---------------------+
                                       |                       +-->  | MetaServerBootstrap |
+-------------------+                  |                       |     +---------------------+
| @EnableMetaServer |                  |                       |     +---------------------------------+
|                   |                  |                       +-->  |MetaServerConfigBeanConfiguration|
|  MetaApplication  |                  |                       |     +---------------------------------+
+--------------+----+                  |                       |     +------------------------------+             +-----------------------+
               |                       |                       +-->  |MetaServerServiceConfiguration|      +--->  | sessionServerHandlers |
               |                       |                       |     +------------------------------+      |      +-----------------------+
               |                       |                       |     +---------------------------------+   |      +--------------------+
               |                       |                       +-->  |MetaServerRepositoryConfiguration+------->  | dataServerHandlers |
               |                       |                       |     +---------------------------------+   |      +--------------------+
               |                       | (Configuration)       |     +-------------------------------+     |      +--------------------+
               |             +---------+---------------+       +-->  |MetaServerRemotingConfiguration|     +--->  | metaServerHandlers |
               +-----------> | MetaServerConfiguration | +-----+     +-------------------------------+            +--------------------+
                             +-------------------------+       |     +----------------------+
                                                               +-->  |ResourceConfiguration |
                                                               |     +----------------------+
                                                               |     +---------------------------+
                                                               +-->  |MetaServerTaskConfiguration|
                                                               |     +---------------------------+
                                                               |     +---------------------+
                                                               +-->  |ExecutorConfiguation |
                                                               |     +---------------------+
                                                               |     +--------------------+
                                                               +-->  |MetaDBConfiguration |
                                                                     +--------------------+

手機上閱讀以下:

關於handler配置,進一步細化以下圖

(Init)

                                                                                                                +-->  sessionConnectionHandler
                                                                                                                |
                                                                                                                |
                                                                                                                +-->  sessionNodeHandler
                                                                                     +-----------------------+  |
                                                                              +--->  | sessionServerHandlers +--+
                                        +---------------------+               |      +-----------------------+  +-->  renewNodesRequestHandler
                                  +-->  | MetaServerBootstrap |               |                                 |
                                  |     +---------------------+               |                                 |
                                  |     +---------------------------------+   |                                 +-->  getNodesRequestHandler
                                  +-->  |MetaServerConfigBeanConfiguration|   |                                 |
                                  |     +---------------------------------+   |                                 |
                                  |     +------------------------------+      |                                 +-->  fetchProvideDataRequestHandler
                                  +-->  |MetaServerServiceConfiguration|      |
                                  |     +------------------------------+      |
                                  |     +---------------------------------+   |                                 +-->  dataConnectionHandler
                                  +-->  |MetaServerRepositoryConfiguration+---+                                 |
                                  |     +---------------------------------+   |                                 |
                                  |     +-------------------------------+     |      +--------------------+     +-->  getNodesRequestHandler
+-------------------------+       +-->  |MetaServerRemotingConfiguration|     +--->  | dataServerHandlers +-----+
| MetaServerConfiguration | +-----+     +-------------------------------+     |      +--------------------+     |
+-------------------------+       |     +----------------------+              |                                 +-->  dataNodeHandler
                                  +-->  |ResourceConfiguration |              |                                 |
                                  |     +----------------------+              |                                 |
                                  |     +---------------------------+         |                                 +-->  renewNodesRequestHandler
                                  +-->  |MetaServerTaskConfiguration|         |                                 |
                                  |     +---------------------------+         |                                 |
                                  |     +---------------------+               |                                 +-->  fetchProvideDataRequestHandler
                                  +-->  |ExecutorConfiguation |               |
                                  |     +---------------------+               |
                                  |     +--------------------+                |
                                  +-->  |MetaDBConfiguration |                |                                 +---> metaConnectionHandler
                                        +--------------------+                |      +--------------------+     |
                                                                              +----> | metaServerHandlers +-----+
                                                                                     +--------------------+     +---> getNodesRequestHandler

手機上如圖

這個就對應了參考中的圖例:

MetaServer 在啓動時,會啓動三個 Bolt Server,而且註冊 Processor Handler,處理對應的請求:

meta-server

  • DataServer:處理 DataNode 相關的請求;
  • SessionServer:處理 SessionNode 相關的請求;
  • MetaServer:處理MetaNode相關的請求;

0x06 啓動

系統是經過對MetaServerBootstrap的控制來完成了啓動。

MetaServer 模塊的各個 bean 在 JavaConfig 中統一配置,JavaConfig 類爲 MetaServerConfiguration。

啓動入口類爲 MetaServerInitializerConfiguration,該類不禁 JavaConfig 管理配置,而是繼承了 SmartLifecycle 接口,在啓動時由 Spring 框架調用其 start 方法。

public class MetaServerInitializerConfiguration implements SmartLifecycle {
    @Autowired
    private MetaServerBootstrap metaServerBootstrap;

    @Override
    public void start() {
    	metaServerBootstrap.start();
			MetaServerInitializerConfiguration.this.running.set(true);
    }

    @Override
    public void stop() {
        this.running.set(false);
        metaServerBootstrap.destroy();
    }
}

具體見下圖,由於 metaServerBootstrap 是經過配置生成,因此init過程指向配置部分。

(Init)
                        +------------------------------------+  start,stop
                        | MetaServerInitializerConfiguration +----------------+
                        +--------------+---------------------+                |
                                       ^                                      |
                                       |                                      |
                                       |                                      |
                                       |                                      |
                                       |                                      v
                                       |                             +---------------------+
                                       |                       +-->  | MetaServerBootstrap |
+-------------------+                  |                       |     +---------------------+
| @EnableMetaServer |                  |                       |     +---------------------------------+
|                   |                  |                       +-->  |MetaServerConfigBeanConfiguration|
|  MetaApplication  |                  |                       |     +---------------------------------+
+--------------+----+                  |                       |     +------------------------------+             +-----------------------+
               |                       |                       +-->  |MetaServerServiceConfiguration|      +--->  | sessionServerHandlers |
               |                       |                       |     +------------------------------+      |      +-----------------------+
               |                       |                       |     +---------------------------------+   |      +--------------------+
               |                       |                       +-->  |MetaServerRepositoryConfiguration+------->  | dataServerHandlers |
               |                       |                       |     +---------------------------------+   |      +--------------------+
               |                       | (Configuration)       |     +-------------------------------+     |      +--------------------+
               |             +---------+---------------+       +-->  |MetaServerRemotingConfiguration|     +--->  | metaServerHandlers |
               +-----------> | MetaServerConfiguration | +-----+     +-------------------------------+            +--------------------+
                             +-------------------------+       |     +----------------------+
                                                               +-->  |ResourceConfiguration |
                                                               |     +----------------------+
                                                               |     +---------------------------+
                                                               +-->  |MetaServerTaskConfiguration|
                                                               |     +---------------------------+
                                                               |     +---------------------+
                                                               +-->  |ExecutorConfiguation |
                                                               |     +---------------------+
                                                               |     +--------------------+
                                                               +-->  |MetaDBConfiguration |
                                                                     +--------------------+

手機上以下

6.1 架構

MetaServerBootstrap是核心啓動類,該類主要包含了三類組件:外部節點通訊組件、Raft 服務通訊組件、定時器組件。

  • 外部節點通訊組件:在該類中有幾個 Server 通訊對象,用於和其它外部節點進行通訊。其中 httpServer 主要提供一系列 http 接口,用於 dashboard 管理、數據查詢等;sessionServer 主要是處理一些session相關的服務;dataServer 則負責數據相關服務;metaServer 負責meta server的註冊;

  • Raft 服務 :用於集羣間的變動和數據同步,raftExchanger 就起到這個做用;

  • 定時器組件:例如定時檢測節點信息、定時檢測數據版本信息;具體可見 ExecutorManager,這是一個啓動各類管理線程的地方。他的啓動設置是在 MetaServerBootstrap.initRaft 之中 。

6.2 類定義

MetaServerBootstrap的定義以下:

public class MetaServerBootstrap {
    @Autowired
    private MetaServerConfig                  metaServerConfig;

    @Autowired
    private Exchange                          boltExchange;

    @Autowired
    private Exchange                          jerseyExchange;

    @Autowired
    private ExecutorManager                   executorManager;

    @Resource(name = "sessionServerHandlers")
    private Collection<AbstractServerHandler> sessionServerHandlers;

    @Resource(name = "dataServerHandlers")
    private Collection<AbstractServerHandler> dataServerHandlers;

    @Resource(name = "metaServerHandlers")
    private Collection<AbstractServerHandler> metaServerHandlers;

    @Autowired
    private ResourceConfig                    jerseyResourceConfig;

    @Autowired
    private ApplicationContext                applicationContext;

    @Autowired
    private RaftExchanger                     raftExchanger;

    private Server                            sessionServer;

    private Server                            dataServer;

    private Server                            metaServer;

    private Server                            httpServer;

}

能夠參見下圖

+-----------------+
                                                                                 +---->  | metaServerConfig|
                                                                                 |       +-----------------+
                                                                                 |       +--------------+
                                                                                 +---->  | boltExchange |
                                                                                 |       +--------------+
                                                                                 |       +--------------+
                                                                                 +---->  |jerseyExchange|
                                                                                 |       +--------------+
                                                                                 |       +---------------+
                                                                                 +---->  |executorManager|
                                                                                 |       +---------------+
                                                                                 |       +---------------------+
                                                                                 +---->  |sessionServerHandlers|
                                                                                 |       +---------------------+
                                                                                 |       +-----------------+
                                                                                 +---->  |dataServerHandler|
       (Init)                                                                    |       +-----------------+
+------------------------------------+  start,stop   +---------------------+     |       +------------------+
| MetaServerInitializerConfiguration +-------------> | MetaServerBootstrap | +-------->  |metaServerHandlers|
+------------------------------------+               +---------------------+     |       +------------------+
                                                                                 |       +-------------+
                                                                                 +---->  |raftExchanger|
                                                                                 |       +-------------+
                                                                                 |       +-------------+
                                                                                 +---->  |sessionServer|
                                                                                 |       +-------------+
                                                                                 |       +-----------+
                                                                                 +---->  |dataServer |
                                                                                 |       +-----------+
                                                                                 |       +-----------+
                                                                                 +---->  |metaServer |
                                                                                 |       +-----------+
                                                                                 |       +----------+
                                                                                 +---->  |httpServer|
                                                                                 |       +----------+
                                                                                 |       +---------------------+
                                                                                 +---->  |jerseyResourceConfig |
                                                                                 |       +---------------------+
                                                                                 |       +-------------------+
                                                                                 +---->  |applicationContext |
                                                                                         +-------------------+

手機參見下圖

6.3 通訊 Exchange

由於前面代碼中有

@Autowired
private Exchange                          boltExchange;

@Autowired
private Exchange                          jerseyExchange;

這裏要特殊說明下Exchange。

Exchange 做爲 Client / Server 鏈接的抽象,負責節點之間的鏈接。在創建鏈接中,能夠設置一系列應對不一樣任務的 handler (稱之爲 ChannelHandler),這些 ChannelHandler 有的做爲 Listener 用來處理鏈接事件,有的做爲 Processor 用來處理各類指定的事件,好比服務信息數據變化、Subscriber 註冊等事件。

圖4 - 每一層各司其職,協同實現節點通訊

圖 - 每一層各司其職,協同實現節點通訊

各類節點在啓動的時候,利用 Exchange 設置了一系列 ChannelHandler,好比:

private void openDataRegisterServer() {
    try {
        if (dataStart.compareAndSet(false, true)) {
            dataServer = boltExchange.open(new URL(NetUtil.getLocalAddress().getHostAddress(),
                metaServerConfig.getDataServerPort()), dataServerHandlers
                .toArray(new ChannelHandler[dataServerHandlers.size()]));
        }
    } 
}

6.4 啓動入口

前面已經提到,啓動入口類爲 MetaServerInitializerConfiguration,該類不禁 JavaConfig 管理配置,而是繼承了 SmartLifecycle 接口,在啓動時由 Spring 框架調用其 start 方法。

該方法中調用了 MetaServerBootstrap # start 方法,用於啓動一系列的初始化服務。

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.SmartLifecycle;

public class MetaServerInitializerConfiguration implements SmartLifecycle {
    @Autowired
    private MetaServerBootstrap metaServerBootstrap;‘
      
    @Override
    public void start() {
            metaServerBootstrap.start();
            MetaServerInitializerConfiguration.this.running.set(true);
    }
}

6.4.1 啓動服務Server

前面提到,MetaServerBootstrap 在啓動時,會啓動三個 Bolt Server,而且註冊 Processor Handler,處理對應的請求:

  • DataServer:處理 DataNode 相關的請求;
  • SessionServer:處理 SessionNode 相關的請求;
  • MetaServer:處理MetaNode相關的請求;

而後啓動 HttpServer, 用於處理 Admin 請求,提供推送開關,集羣數據查詢等 Http 接口。

最後啓動 Raft 服務, 每一個節點同時做爲 RaftClient 和 RaftServer, 用於集羣間的變動和數據同步。爲支持高可用特性,對於 MetaServer 來講,存儲了 SOFARegistry 的元數據,爲了保障 MetaServer 集羣的一致性,其採用了 Raft 協議來進行選舉和複製。

具體代碼參見:

public void start() {
        openSessionRegisterServer();
        openDataRegisterServer();
        openMetaRegisterServer();
        openHttpServer();
        initRaft();
}

private void openHttpServer() {
        if (httpStart.compareAndSet(false, true)) {
            bindResourceConfig();
            httpServer = jerseyExchange.open(
                new URL(NetUtil.getLocalAddress().getHostAddress(), metaServerConfig
                    .getHttpServerPort()), new ResourceConfig[] { jerseyResourceConfig });
        }
}

private void initRaft() {
    raftExchanger.startRaftServer(executorManager);
    raftExchanger.startRaftClient();
    raftExchanger.startCliService();
}

6.4.1.1 BoltServer

Raft 和 Bolt 是SOFA所特殊實現,因此咱們暫不介紹其底層機制,之後有機會單獨開篇,下面提一下三個BoltServer。

private void openSessionRegisterServer() {
        if (sessionStart.compareAndSet(false, true)) {
            sessionServer = boltExchange
                .open(
                    new URL(NetUtil.getLocalAddress().getHostAddress(), metaServerConfig
                        .getSessionServerPort()), sessionServerHandlers
                        .toArray(new ChannelHandler[sessionServerHandlers.size()]));

        }
}

private void openDataRegisterServer() {
        if (dataStart.compareAndSet(false, true)) {
            dataServer = boltExchange.open(new URL(NetUtil.getLocalAddress().getHostAddress(),
                metaServerConfig.getDataServerPort()), dataServerHandlers
                .toArray(new ChannelHandler[dataServerHandlers.size()]));
        }
}

private void openMetaRegisterServer() {
        if (metaStart.compareAndSet(false, true)) {
            metaServer = boltExchange.open(new URL(NetUtil.getLocalAddress().getHostAddress(),
                metaServerConfig.getMetaServerPort()), metaServerHandlers
                .toArray(new ChannelHandler[metaServerHandlers.size()]));
        }
}

這幾個Server的handler就是咱們前面配置的

@Resource(name = "sessionServerHandlers")
private Collection<AbstractServerHandler> sessionServerHandlers;

@Resource(name = "dataServerHandlers")
private Collection<AbstractServerHandler> dataServerHandlers;

@Resource(name = "metaServerHandlers")
private Collection<AbstractServerHandler> metaServerHandlers;

具體參見下圖:

+------------------------+
                                    +-----------------+                                           +---> |sessionConnectionHandler|
                            +---->  | metaServerConfig|                                           |     +------------------------+
                            |       +-----------------+                                           |     +-------------------+
                            |       +--------------+                                              +---> |sessionNodeHandler |
                            +---->  | boltExchange |                                          +-->+     +-------------------+
                            |       +--------------+                                          |   |     +------------------------+
                            |       +--------------+                                          |   +---> |renewNodesRequestHandler|
                            +---->  |jerseyExchange|                                          |   |     +------------------------+
                            |       +--------------+                                          |   |     +----------------------+
                            |       +---------------+                                         |   +---> |getNodesRequestHandler|
                            +---->  |executorManager|                                         |   |     +----------------------+
                            |       +---------------+               +---------------------+   |   |     +------------------------------+
                            +-------------------------------------> |sessionServerHandlers+---+   +---> |fetchProvideDataRequestHandler|
                            |       +-------------+                 +---------------------+             +------------------------------+
                            +---->  |sessionServer| +------------------^
                            |       +-------------+                                                     +---------------------+
                            |                                                                     ----> |dataConnectionHandler|
                            |                                       +------------------+          |     +---------------------+
+---------------------+     +-------------------------------------> |dataServerHandlers+----------+     +----------------------+
| MetaServerBootstrap | +---+       +-----------+                   +------------------+          +---> |getNodesRequestHandler|
+---------------------+     +---->  |dataServer +----------------------^                          |     +----------------------+
                            |       +-----------+                                                 |     +---------------+
                            |                                                                     +---> |dataNodeHandler|
                            |                                       +------------------+          |     +---------------+
                            +------------------------------------>  |metaServerHandlers+------+   |     +------------------------+
                            |       +-----------+                   +------------------+      |   +---> |renewNodesRequestHandler|
                            +---->  |metaServer +----------------------^                      |   |     +------------------------+
                            |       +-----------+                                             |   |     +------------------------------+
                            |                                                                 |   +---> |fetchProvideDataRequestHandler|
                            |       +-------------+                                           |         +------------------------------+
                            +---->  |raftExchanger|                                           |
                            |       +-------------+                                           |
                            |                                                                 |
                            |       +----------+                                              |
                            +---->  |httpServer|                                              |          +---------------------+
                            |       +----------+                                              |    +-->  |metaConnectionHandler|
                            |       +---------------------+                                   +---->     +---------------------+
                            +---->  |jerseyResourceConfig |                                        |     +---------------------+
                            |       +---------------------+                                        +-->  |getNodesRequestHandle|
                            |       +-------------------+                                                +---------------------+
                            +---->  |applicationContext |
                                    +-------------------+

手機上

在初始化時候,大體堆棧以下 :

interest:55, RenewNodesRequestHandler (com.alipay.sofa.registry.server.meta.remoting.handler)
interest:61, SyncUserProcessorAdapter (com.alipay.sofa.registry.remoting.bolt)
registerUserProcessor:42, UserProcessorRegisterHelper (com.alipay.remoting.rpc.protocol)
registerUserProcessor:376, RpcServer (com.alipay.remoting.rpc)
registerUserProcessorHandler:159, BoltServer (com.alipay.sofa.registry.remoting.bolt)
initHandler:139, BoltServer (com.alipay.sofa.registry.remoting.bolt)
startServer:92, BoltServer (com.alipay.sofa.registry.remoting.bolt)
open:65, BoltExchange (com.alipay.sofa.registry.remoting.bolt.exchange)
open:36, BoltExchange (com.alipay.sofa.registry.remoting.bolt.exchange)
openSessionRegisterServer:149, MetaServerBootstrap (com.alipay.sofa.registry.server.meta.bootstrap)
start:108, MetaServerBootstrap (com.alipay.sofa.registry.server.meta.bootstrap)
start:51, MetaServerInitializerConfiguration (com.alipay.sofa.registry.server.meta.bootstrap)

以SessionServer爲例,在構建過程當中,調用到 BoltExchange . open。

private void openSessionRegisterServer() {
        if (sessionStart.compareAndSet(false, true)) {
            sessionServer = boltExchange
                .open(
                    new URL(NetUtil.getLocalAddress().getHostAddress(), metaServerConfig
                        .getSessionServerPort()), sessionServerHandlers
                        .toArray(new ChannelHandler[sessionServerHandlers.size()]));
        }   
}

BoltExchange中有

@Override
public Server open(URL url, ChannelHandler... channelHandlers) {
    BoltServer server = createBoltServer(url, channelHandlers);
    setServer(server, url);
    server.startServer();
    return server;
}

BoltServer中有

public void startServer() {
    if (isStarted.compareAndSet(false, true)) {
            boltServer = new RpcServer(url.getPort(), true);
            initHandler();
            boltServer.start();
    } 
}

private void initHandler() {
        if (initHandler.compareAndSet(false, true)) {
            boltServer.addConnectionEventProcessor(ConnectionEventType.CONNECT,
                new ConnectionEventAdapter(ConnectionEventType.CONNECT,
                    getConnectionEventHandler(), this));
            boltServer.addConnectionEventProcessor(ConnectionEventType.CLOSE,
                new ConnectionEventAdapter(ConnectionEventType.CLOSE, getConnectionEventHandler(),
                    this));
            boltServer.addConnectionEventProcessor(ConnectionEventType.EXCEPTION,
                new ConnectionEventAdapter(ConnectionEventType.EXCEPTION,
                    getConnectionEventHandler(), this));

            registerUserProcessorHandler();
        }
}

最後調用,會設定同步和異步的handler。

private void registerUserProcessorHandler() {
    if (channelHandlers != null) {
        for (ChannelHandler channelHandler : channelHandlers) {
            if (HandlerType.PROCESSER.equals(channelHandler.getType())) {
                if (InvokeType.SYNC.equals(channelHandler.getInvokeType())) {
                    boltServer.registerUserProcessor(new SyncUserProcessorAdapter(
                        channelHandler));
                } else {
                    boltServer.registerUserProcessor(new AsyncUserProcessorAdapter(
                        channelHandler));
                }
            }
        }
    }
}

6.4.1.2 HttpServer

以使用 Jetty 的 openHttpServer 爲例

啓動 HttpServer, 用於處理 Admin 請求,提供推送開關,集羣數據查詢等 Http 接口。

public class JerseyJettyServer implements Server {
    public static org.eclipse.jetty.server.Server createServer(final URI uri,
                                                               final ResourceConfig resourceConfig,
                                                               final boolean start) {

        JettyHttpContainer handler = ContainerFactory.createContainer(JettyHttpContainer.class,
            resourceConfig);

        int defaultPort = Container.DEFAULT_HTTP_PORT;
        final int port = (uri.getPort() == -1) ? defaultPort : uri.getPort();

        final org.eclipse.jetty.server.Server server = new org.eclipse.jetty.server.Server(
            new JettyConnectorThreadPool());

        final ServerConnector http = new ServerConnector(server, new HttpConnectionCustomFactory());
        http.setPort(port);
        server.setConnectors(new Connector[] { http });

        if (handler != null) {
            server.setHandler(handler);
        }

        if (start) {
            try {
                // Start the server.
                server.start();
            } 
        }
        return server;
    }  
}

其堆棧以下:

<init>:72, JerseyJettyServer (com.alipay.sofa.registry.remoting.jersey)
open:73, JerseyExchange (com.alipay.sofa.registry.remoting.jersey.exchange)
open:40, JerseyExchange (com.alipay.sofa.registry.remoting.jersey.exchange)
openHttpServer:205, MetaServerBootstrap (com.alipay.sofa.registry.server.meta.bootstrap)
start:114, MetaServerBootstrap (com.alipay.sofa.registry.server.meta.bootstrap)
start:51, MetaServerInitializerConfiguration (com.alipay.sofa.registry.server.meta.bootstrap)
doStart:173, DefaultLifecycleProcessor (org.springframework.context.support)
access$200:50, DefaultLifecycleProcessor (org.springframework.context.support)
start:350, DefaultLifecycleProcessor$LifecycleGroup (org.springframework.context.support)
startBeans:149, DefaultLifecycleProcessor (org.springframework.context.support)
onRefresh:112, DefaultLifecycleProcessor (org.springframework.context.support)
finishRefresh:880, AbstractApplicationContext (org.springframework.context.support)
refresh:546, AbstractApplicationContext (org.springframework.context.support)
refresh:693, SpringApplication (org.springframework.boot)
refreshContext:360, SpringApplication (org.springframework.boot)
run:303, SpringApplication (org.springframework.boot)
run:1118, SpringApplication (org.springframework.boot)
run:1107, SpringApplication (org.springframework.boot)
main:42, MetaApplication (com.alipay.sofa.registry.server.meta)

6.4.1.3 @RaftService

以下存儲由Raft來保證數據一致性,後文針對此有詳細講解。

@RaftService(uniqueId = "sessionServer")
public class SessionVersionRepositoryService 
  
@RaftService(uniqueId = "metaServer")
public class MetaRepositoryService  
  
@RaftService(uniqueId = "dataServer")
public class DataRepositoryService  
  
@RaftService(uniqueId = "sessionServer")
public class SessionRepositoryService   
  
@RaftService(uniqueId = "dataServer")
public class DataConfirmStatusService   
  
@RaftService(uniqueId = "sessionServer")
public class SessionConfirmStatusService

6.4.2 ExecutorManager

是一個啓動各類管理線程的地方,都是按期常規管理任務。

public class ExecutorManager {

    private ScheduledExecutorService scheduler;

    private ThreadPoolExecutor       heartbeatCheckExecutor;
    private ThreadPoolExecutor       checkDataChangeExecutor;
    private ThreadPoolExecutor       getOtherDataCenterChangeExecutor;
    private ThreadPoolExecutor       connectMetaServerExecutor;
    private ThreadPoolExecutor       checkNodeListChangePushExecutor;
    private ThreadPoolExecutor       raftClientRefreshExecutor;

    private MetaServerConfig         metaServerConfig;

    @Autowired
    private Registry                 metaServerRegistry;

    @Autowired
    private MetaClientExchanger      metaClientExchanger;

    @Autowired
    private RaftExchanger            raftExchanger;
  
   public void startScheduler() {

        init();

        scheduler.schedule(new TimedSupervisorTask("HeartbeatCheck", scheduler, heartbeatCheckExecutor,
                        metaServerConfig.getSchedulerHeartbeatTimeout(), TimeUnit.SECONDS,
                        metaServerConfig.getSchedulerHeartbeatExpBackOffBound(), () -> metaServerRegistry.evict()),
                metaServerConfig.getSchedulerHeartbeatFirstDelay(), TimeUnit.SECONDS);

        scheduler.schedule(
                new TimedSupervisorTask("GetOtherDataCenterChange", scheduler, getOtherDataCenterChangeExecutor,
                        metaServerConfig.getSchedulerGetDataChangeTimeout(), TimeUnit.SECONDS,
                        metaServerConfig.getSchedulerGetDataChangeExpBackOffBound(), () -> {
                    metaServerRegistry.getOtherDataCenterNodeAndUpdate(NodeType.DATA);
                    metaServerRegistry.getOtherDataCenterNodeAndUpdate(NodeType.META);
                }), metaServerConfig.getSchedulerGetDataChangeFirstDelay(), TimeUnit.SECONDS);

        scheduler.schedule(new TimedSupervisorTask("ConnectMetaServer", scheduler, connectMetaServerExecutor,
                        metaServerConfig.getSchedulerConnectMetaServerTimeout(), TimeUnit.SECONDS,
                        metaServerConfig.getSchedulerConnectMetaServerExpBackOffBound(),
                        () -> metaClientExchanger.connectServer()), metaServerConfig.getSchedulerConnectMetaServerFirstDelay(),
                TimeUnit.SECONDS);

        scheduler.schedule(
                new TimedSupervisorTask("CheckSessionNodeListChangePush", scheduler, checkNodeListChangePushExecutor,
                        metaServerConfig.getSchedulerCheckNodeListChangePushTimeout(), TimeUnit.SECONDS,
                        metaServerConfig.getSchedulerCheckNodeListChangePushExpBackOffBound(),
                        () -> metaServerRegistry.pushNodeListChange(NodeType.SESSION)),
                metaServerConfig.getSchedulerCheckNodeListChangePushFirstDelay(), TimeUnit.SECONDS);

        scheduler.schedule(
                new TimedSupervisorTask("CheckDataNodeListChangePush", scheduler, checkNodeListChangePushExecutor,
                        metaServerConfig.getSchedulerCheckNodeListChangePushTimeout(), TimeUnit.SECONDS,
                        metaServerConfig.getSchedulerCheckNodeListChangePushExpBackOffBound(),
                        () -> metaServerRegistry.pushNodeListChange(NodeType.DATA)),
                metaServerConfig.getSchedulerCheckNodeListChangePushFirstDelay(), TimeUnit.SECONDS);

        scheduler.schedule(new TimedSupervisorTask("RaftClientRefresh", scheduler, raftClientRefreshExecutor,
                        metaServerConfig.getSchedulerCheckNodeListChangePushTimeout(), TimeUnit.SECONDS,
                        metaServerConfig.getSchedulerCheckNodeListChangePushExpBackOffBound(),
                        () -> raftExchanger.refreshRaftClient()),
                metaServerConfig.getSchedulerCheckNodeListChangePushFirstDelay(), TimeUnit.SECONDS);

    }  
}

6.4.2.1 啓動

ExecutorManager 的啓動設置是在 MetaServerBootstrap.initRaft 之中,分別啓動RaftServer,RaftClient,CliService。

private void initRaft() {
    raftExchanger.startRaftServer(executorManager);
    raftExchanger.startRaftClient();
    raftExchanger.startCliService();
}

當 Raft 選出 Leader 以後,會調用到 ExecutorManager # startScheduler。

  • 首先生成各個ThreadPoolExecutor;
  • 而後運行自己的 各個TimedSupervisorTask,其會調用不一樣的handler,好比 connectServer,getSchedulerHeartbeatFirstDelay 等等;

6.4.2.2 TimedSupervisorTask

TimedSupervisorTask 實現了 TimerTask。

public class TimedSupervisorTask extends TimerTask {
    private final ScheduledExecutorService scheduler;
    private final ThreadPoolExecutor       executor;
    private final long                     timeoutMillis;
    private final Runnable                 task;
    private String                         name;
    private final AtomicLong               delay;
    private final long                     maxDelay;

    @Override
    public void run() {
        Future future = null;
        try {
            future = executor.submit(task);
            // block until done or timeout
            future.get(timeoutMillis, TimeUnit.MILLISECONDS);
            delay.set(timeoutMillis);
        } catch {
						.....
        } finally {
            if (future != null) {
                future.cancel(true);
            }
            scheduler.schedule(this, delay.get(), TimeUnit.MILLISECONDS);
        }
    }
}

6.4.2.3 管理任務

能夠看到管理任務大體有:

  • HeartbeatCheck :心跳檢測;
  • GetOtherDataCenterChange :查看其餘數據中心的變化;
  • ConnectMetaServer :與其餘的MetaServer交互;
  • CheckSessionNodeListChangePush :看看Session節點的變化;
  • CheckDataNodeListChangePush :查看數據節點變化;
  • RaftClientRefresh :看看Raft 服務消息;

TimedSupervisorTask 會按期執行,好比 CheckDataNodeListChangePush 這個線程會按期執行 metaServerRegistry.pushNodeListChange(NodeType.DATA)) 來看看是否有變化。這裏就會用到DataNode註冊時候,Confirm的消息。

@Override
public void pushNodeListChange() {
    NodeOperator<DataNode> fireNode;
    if ((fireNode = dataConfirmStatusService.peekConfirmNode()) != null) {
        NodeChangeResult nodeChangeResult = getNodeChangeResult();
        Map<String, Map<String, DataNode>> map = nodeChangeResult.getNodes();
        Map<String, DataNode> addNodes = map.get(nodeConfig.getLocalDataCenter());
        if (addNodes != null) {
            Map<String, DataNode> previousNodes = dataConfirmStatusService.putExpectNodes(
                fireNode.getNode(), addNodes);
            if (!previousNodes.isEmpty()) {
                firePushDataListTask(fireNode, nodeChangeResult, previousNodes, true);
            }
        }
        firePushSessionListTask(nodeChangeResult, fireNode.getNodeOperate().toString());
    }
}

再好比按期去除過時的Node:

public class MetaServerRegistry implements Registry<Node> {
    @Override
    public void evict() {
        for (NodeType nodeType : NodeType.values()) {
            StoreService storeService = ServiceFactory.getStoreService(nodeType);
            if (storeService != null) {
                Collection<Node> expiredNodes = storeService.getExpired();
                if (expiredNodes != null && !expiredNodes.isEmpty()) {
                    storeService.removeNodes(expiredNodes);
                }
            }
        }
    }  
}

6.4.3 ServiceFactory

ServiceFactory 須要特殊說明,它提供了系統所須要的一系列服務。特殊之處在於,ServiceFactory 不是由 MetaServerBootstrap 負責啓動,而是由 Spring 負責啓動。由於 ServiceFactory 繼承了ApplicationContextAware,因此啓動時候生成

在Web應用中,Spring容器一般採用聲明式方式配置產生:開發者只要在web.xml中配置一個Listener,該Listener將會負責初始化Spring容器,MVC框架能夠直接調用Spring容器中的Bean,無需訪問Spring容器自己。在這種狀況下,容器中的Bean處於容器管理下,無需主動訪問容器,只需接受容器的依賴注入便可。

但在某些特殊的狀況下,Bean須要實現某個功能,但該功能必須藉助於Spring容器才能實現,此時就必須讓該Bean先獲取Spring容器,而後藉助於Spring容器實現該功能。爲了讓Bean獲取它所在的Spring容器,可讓該Bean實現ApplicationContextAware接口。

下面代碼能夠看出來,啓動了一系列服務。

public class ServiceFactory implements ApplicationContextAware {
    private static Map<NodeType, StoreService>       storeServiceMap   = new HashMap<>();
    private static Map<NodeType, NodeConnectManager> connectManagerMap = new HashMap<>();
    private static Map<NodeType, NodeService>        nodeServiceMap    = new HashMap<>();  
}

storeServiceMap = {HashMap@5107}  size = 3
 {Node$NodeType@5525} "SESSION" -> {SessionStoreService@5526} 
  key = {Node$NodeType@5525} "SESSION"
  value = {SessionStoreService@5526} 
 {Node$NodeType@4815} "DATA" -> {DataStoreService@5527} 
  key = {Node$NodeType@4815} "DATA"
  value = {DataStoreService@5527} 
 {Node$NodeType@5528} "META" -> {MetaStoreService@5529} 
  key = {Node$NodeType@5528} "META"
  value = {MetaStoreService@5529} 

connectManagerMap = {HashMap@5532}  size = 3
 {Node$NodeType@5525} "SESSION" -> {SessionConnectionHandler@5548} 
  key = {Node$NodeType@5525} "SESSION"
  value = {SessionConnectionHandler@5548} 
 {Node$NodeType@4815} "DATA" -> {DataConnectionHandler@5549} 
  key = {Node$NodeType@4815} "DATA"
  value = {DataConnectionHandler@5549} 
 {Node$NodeType@5528} "META" -> {MetaConnectionHandler@5550} 
  key = {Node$NodeType@5528} "META"
  value = {MetaConnectionHandler@5550} 

nodeServiceMap = {HashMap@5533}  size = 3
 {Node$NodeType@5525} "SESSION" -> {SessionNodeServiceImpl@5540} 
  key = {Node$NodeType@5525} "SESSION"
  value = {SessionNodeServiceImpl@5540} 
 {Node$NodeType@4815} "DATA" -> {DataNodeServiceImpl@5541} 
  key = {Node$NodeType@4815} "DATA"
  value = {DataNodeServiceImpl@5541} 
 {Node$NodeType@5528} "META" -> {MetaNodeServiceImpl@5542} 
  key = {Node$NodeType@5528} "META"
  value = {MetaNodeServiceImpl@5542}

至此,MetaServer的架構和啓動介紹完成,咱們下文將會介紹基本功能,好比註冊,存儲,續約等。

0xFF 參考

服務註冊中心 MetaServer 功能介紹和實現剖析 | SOFARegistry 解析

服務註冊中心如何實現 DataServer 平滑擴縮容 | SOFARegistry 解析

服務註冊中心數據一致性方案分析 | SOFARegistry 解析

服務註冊中心如何實現秒級服務上下線通知 | SOFARegistry 解析

服務註冊中心 Session 存儲策略 | SOFARegistry 解析

服務註冊中心數據分片和同步方案詳解 | SOFARegistry 解析

服務註冊中心 SOFARegistry 解析 | 服務發現優化之路

海量數據下的註冊中心 - SOFARegistry 架構介紹

服務端部署

客戶端使用

全面理解Raft協議

詳解螞蟻金服 SOFAJRaft | 生產級高性能 Java 實現

從JRaft來看Raft協議實現細節

SOFAJRaft—初次使用

JRaft 用戶指南 & API 詳解

怎樣打造一個分佈式數據庫——rocksDB, raft, mvcc,本質上是爲了解決跨數據中心的複製

sofa-bolt源碼閱讀(5)-日誌

Raft 爲何是更易理解的分佈式一致性算法

SOFAJRaft 源碼分析一(啓動流程和節點變化)

SOFAJRaft 實現原理 - 生產級 Raft 算法庫存儲模塊剖析

客戶端使用

相關文章
相關標籤/搜索