Nacos使用和註冊部分原始碼介紹
Nacos簡單介紹
Nacos致力於幫助您發現、配置和管理微服務。Nacos提供了一組簡單易用的特性集,幫助您快速實現動態服務發現、服務配置、服務元資料及流量管理。Nacos幫助您更敏捷和容易地構建、交付和管理微服務平臺。Nacos是構建以“服務”為中心的現代應用架構 (例如微服務正規化、雲原生正規化) 的服務基礎設施。
接下來主要介紹Nacos作為註冊中心的使用和註冊部分的原始碼解析。
Nacos安裝
Nacos預裝環境
Nacos 依賴 Java 環境來執行。如果您是從程式碼開始構建並執行Nacos,還需要為此配置 Maven環境這裡就不介紹Maven和Java安裝,大家自行安裝一下。
安裝的方式主要有兩種:
- 從GitHub上下載原始碼安裝:
//下載原始碼的地址
git clone https://github.com/alibaba/nacos.git
cd nacos/
//編譯原始碼
mvn -Prelease-nacos -Dmaven.test.skip=true clean install -U
ls -al distribution/target/
//進入編譯包
cd distribution/target/nacos-server-$version/nacos/bin
2.下載安裝包的形式:
tar -xvf nacos-server-$version.tar.gz
cd nacos/bin
啟動伺服器
啟動命令(standalone代表著單機模式執行,非叢集模式):
sh startup.sh -m standalone
關閉伺服器
sh shutdown.sh
單機環境下使用Mysql:
在0.7版本之前,在單機模式時nacos使用嵌入式資料庫實現資料的儲存,不方便觀察資料儲存的基本情況。0.7版本增加了支援mysql資料來源能力,具體的操作步驟:
- 安裝資料庫,版本要求:5.6.5+
- 初始化mysql資料庫,資料庫初始化檔案:nacos-mysql.sql
- 修改conf/application.properties檔案,增加支援mysql資料來源配置(目前只支援mysql),新增mysql資料來源的url、使用者名稱和密碼。
spring.datasource.platform=mysql
db.num=1
db.url.0=jdbc:mysql://127.0.0.1:3306/nacos?characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true
db.user=root
db.password=123456
對於單機來說我們就是玩個demo是夠的,但是對於生產來說我們就要考慮高可用的方案了:
對於叢集部署的方式如果在虛擬機器環境就採用Nagix負載3臺虛擬機器,對於K8S的環境通過Service負載3臺Pod的形式搭建高可用環境,對於資料庫選擇來說最好採用主從結構,保證資料庫的高可用。
整體的部署可能如下;
下圖就是搭建好以後的整體介面:
Nacos使用
1.建立一個Spring Boot空應用
2.編輯pom.xml檔案
<properties>
<springboot.vetsion>2.2.11.RELEASE</springboot.vetsion>
<spring-cloud-version>Hoxton.SR9</spring-cloud-version>
<spring-cloud-alibaba-version>2.2.3.RELEASE</spring-cloud-alibaba-version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>${springboot.vetsion}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud-version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>${spring-cloud-alibaba-version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
</dependencies>
3.建立應用的啟動專案
@SpringBootApplication(scanBasePackages = {"com.springcloud.study"})
@EnableDiscoveryClient
public class SystemApplication {
public static void main(String[] args) {
SpringApplication.run(SystemApplication.class, args);
}
}
4.配置application.yaml檔案
server:
port: 8081
spring:
application:
name: system
# 資料來源配置項
datasource:
url: jdbc:mysql://127.0.0.1:3306/study_user?useSSL=false&useUnicode=true&characterEncoding=UTF-8
driver-class-name: com.mysql.jdbc.Driver
username: root
password: 123456
#nacos基礎配置
cloud:
nacos:
discovery:
server-addr: 10.226.73.115:8886
#環境選擇
#namespace: b7d341fc-df29-45ce-b3cd-4415f66b1ee0
5.啟動專案
Nacos註冊部分原始碼分析
客戶端通過Rest介面式向Nacos Server註冊自己的服務,提供自身的元資料,比如ip地址、埠等資訊。 Nacos Server接收到註冊請求後,就會把這些元資料資訊儲存在一個雙層的記憶體Map中。對於註冊部分的原始碼整體上分為兩部分:
客戶端註冊原始碼
按照Spring Boot Starter的習慣,我們首先找到spring-cloud-starter-alibaba-nacos-discovery啟動項,如下圖所示:
標紅部分的NacosServiceRegistryAutoConfiguration是我們註冊部分關注的類,首先我們看下該類的整體的繼承結構:
重點關注AbstractAutoServiceRegistration介面,NacosAutoServiceRegistration該Bean的注入就是我們注入開始的:
整體看下該類,基本上是對AbstractAutoServiceRegistration繼承和實現,該類位於spring-cloud-common這個jar下面,Spring Cloud Commons模組是為了對微服務中的服務註冊與發現、負載均衡、熔斷器等功能提供一個抽象層程式碼,這個抽象層與具體的實現無關。這樣這些功能具體的實現上可以採用不同的技術去實現,並可以做到在使用時靈活的更換。
NacosAutoServiceRegistration內部存在一個@EventListener註解,@EventListener是一種事件驅動程式設計在spring4.2的時候開始有的,可以理解為ApplicationListener介面的擴充套件,方便我們使用,可以理解為Spring為我們提供的一個事件監聽、訂閱的實現,內部實現原理是觀察者設計模式;為的就是業務系統邏輯的解耦,提高可擴充套件性以及可維護性。事件釋出者並不需要考慮誰去監聽,監聽具體的實現內容是什麼,釋出者的工作只是為了釋出事件而已。
接下來我們重點看下AbstractAutoServiceRegistration內部start方法,
register的具體的實現類是NacosServiceRegistry,內部呼叫NacosNamingService的registerInstance方法,該方法內部通過呼叫NamingProxy的reqApi,通過NacosRestTemplate請求服務端的/instance方法註冊到服務端。
至此完成了客戶端註冊到服務端,下圖是整體的時序圖:
服務端註冊部分
服務端註冊相對比較複雜一點,這塊需要將Nacos原始碼下載一下,找到naming模組,InstanceController就是我們呼叫服務端的介面,如下圖所示:
接下來重點看下ServiceManager的registerInstance的方法,如下圖:
首先看下createEmptyService方法,該方法目的雙肩一個雙層的Map物件,用於儲存註冊應用的資訊,整體的結構Map(namespace, Map(group::serviceName, Service)),這裡正好對應註冊中心介紹時候的張圖,我們整體在看一下:
初始化的登錄檔結構以後,接下來就是將應用的資訊註冊新增到登錄檔中,主要分為兩步如下圖:
addIpAddresses就是獲取當前註冊服務的所有ip,整體的流程如下圖:
這裡的主要的重點是put方法,這裡我們全部按照CP的場景去解釋,AP的場景在未來的章節補充,CP的實現類是DistroConsistencyServiceImpl,如下圖:
通過把需要註冊到登錄檔的服務新增到阻塞隊列當中,Notifier本質上一個執行緒,然後通過執行run內部的hander方法,如下圖:
通過呼叫Service的onChange方法來變更登錄檔的資訊,內部主要通過updateIPs完成登錄檔資訊的表更,主要也是採用CopyOnWrite的思想,如下圖:
到此服務端的注入就完成了,這個裡面整體上有三處亮點:
1.CopyOnWrite的思想的廣泛應用;
2.通過阻塞佇列實現非同步任務提升系統性能,並且解決併發寫入問題;
3.觀察者設計的廣泛應用;
結束
歡迎大家點點關注,點點贊,感謝!