本例子基於 spring boot + spring cloud alibaba + spring cloud, nacos作為服務注冊中心和配置中心。
簡介
Nacos 是Spring Cloud Alibaba 的一個組件。致力於發現、配置和管理微服務。
Nacos名字:前四個字母分別為 Naming 和 Configuration 的前兩個字母,最后的 s 為 Service。
下載啟動
版本選擇
如果是使用spring boot + spring cloud alibaba + spring cloud全家桶。那么版本選擇一定要按照官網匹配,否則會因jar包沖突導致項目啟動失敗。
我們可以去spring cloud alibaba的版本說明查看
在此文中,我選擇的版本為spring boot - 2.2.5.RELEASE, spring cloud alibaba - 2.2.1.RELEASE, spring cloud - Hoxton.SR3
下載
nacos下載地址 https://github.com/alibaba/nacos/releases
根據上面的版本說明,我這里選擇1.2.1
啟動
下載解壓后,進入bin目錄
可以看到啟動命令。其中cmd是window系統使用,sh是linux系統使用。
我們本地測試使用windows環境,直接雙擊startup.cmd
即可。linux環境請執行./startup.sh -m standalone
(standalone代表單機啟動,實際使用應做集群,集群數量三台起步)
查看控制台
nacos默認端口是8848,可不是某手機,8848代表珠穆朗瑪峰的高度(但是現在高度好像是8844了)。
啟動nacos后,訪問localhost:8848/nacos/index.html,可以看到nacos后台。在這里可以對服務和配置做可視化管理(當然現在是空的,一會兒項目啟動就有東西了)。
注冊中心
先看看如何作為服務注冊中心
服務注冊
1 項目pom添加依賴
<!-- spring boot 項目 -->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.5.RELEASE</version>
<relativePath/>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- 服務注冊/發現 -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<!-- spring cloud alibaba 依賴管理 -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>2.2.1.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
2 application.properties添加配置
# 服務端口
server.port=8081
# 服務名
spring.application.name=service-provider
# 服務注冊中心地址
spring.cloud.nacos.discovery.server-addr=127.0.0.1:8848
3 啟動類上添加服務發現注解
@EnableDiscoveryClient
@SpringBootApplication
public class ProviderApplication {
public static void main(String[] args) {
SpringApplication.run(ProviderApplication.class, args);
}
}
PS:這里不加@EnableDiscoveryClient也行,Spring Cloud Dalston.SR4版本之后會自動向注冊中心注冊
4 啟動查看
啟動服務,刷新nacos后台就能看到這個服務了
服務調用
為了說明服務調用,我們先以同樣的方式配置好另外一個服務
1 pom添加依賴
同上,略
2 application.properties添加配置
# 服務端口
server.port=9091
# 服務名
spring.application.name=service-consumer
# 服務注冊中心地址
spring.cloud.nacos.discovery.server-addr=127.0.0.1:8848
3 啟動類
@SpringBootApplication
public class ConsumerApplication {
public static void main(String[] args) {
SpringApplication.run(ConsumerApplication.class, args);
}
}
4 啟動查看
可以看到,我們有兩個微服務了
5 引入openfeign
openfeign是spring cloud的組件,為微服務之間的調用提供了解決方案。
openfeign的使用也非常簡單,我們在service-consumer項目的基礎上繼續完善
1) pom添加依賴
<dependencies>
... //省略之前已添加
<!-- 服務調用 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
... //省略之前已添加
<!-- spring cloud 依賴管理 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Hoxton.SR3</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
2) 編寫遠程調用類
package com.test.consumer.feign;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
@FeignClient("service-provider")
public interface ProviderFeignService {
@RequestMapping("provider/test")
public Result providerTest(@RequestBody TestEntity testEntity, @RequestParam String name);
}
映射說明: @FeignClient括號里是要調用的微服務名稱,@RequestMapping括號里是被調用微服務的具體api路徑。
傳參說明: 實體類添加@RequestBody,字符串和普通類型添加@RequestParam。
這個service就和我們平時普通的service一樣,在controller使用@Autowired依賴注入即可。
3) 啟動類添加@EnableFeignClients
@EnableFeignClients(basePackages = "com.test.consumer.feign")
@SpringBootApplication
public class ConsumerApplication {
public static void main(String[] args) {
SpringApplication.run(ConsumerApplication.class, args);
}
}
說明: @EnableFeignClients括號里是要實行遠程調用服務所在的包路徑,即上面遠程調用類所在的包路徑。
現在回到service-provider添加一個測試controller就可以調用成功了
@RestController
@RequestMapping("provider")
public class TestController {
@PostMapping("test")
public Result test(TestEntity testEntity, String name) {
Result result = new Result();
// do something, balabala
return result;
}
}
Result是自定義返回類,略。
原理簡述
服務注冊中心的實現,大概依賴三個重要的定時任務
- 客戶端定時任務:定時發送心跳,告訴nacos我還活着
- 客戶端定時任務:定時拉取可用服務,放在本地緩存。openfeign調用時自行選用緩存中服務
- 服務端定時任務,定時刷新可用列表,踢掉太久沒發心跳的客戶端【默認15秒未發心跳的會被踢出】
小結
以上,我們實現了服務注冊與發現,服務間遠程調用。
配置中心
問題說明
隨着業務越來越復雜,我們會面臨一些問題:
- 微服務項目越來越多,配置文件也越來越多,管理起更麻煩
- 改動一個配置參數時,需要重新打包微服務重新發布
- 有時候希望改動某個參數可以立即生效
接下來,我們使用nacos解決這些問題。
1 添加pom依賴
<dependencies>
... //省略之前已添加
<!-- 配置中心 -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
</dependencies>
2 在application.properties設置運行環境
spring.profiles.active=dev
3 新建bootstrap.properties文件
# 服務名
spring.application.name=service-consumer
# 配置中心地址
spring.cloud.nacos.config.server-addr=127.0.0.1:8848
4 添加注解 @Value + @RefreshScope
@RefreshScope // 自動感知配置文件變化
@RequestMapping("test")
@RestController
public class TestController {
// 從配置文件獲取屬性值
@Value("{message}")
private String message;
@RequestMapping("message")
public String message() {
return message;
}
}
5 去nacos配置中心添加配置文件
這里Data Id就是配置文件名
6 啟動服務,驗證結果
服務啟動時會去配置中心找文件 ${prefix}-${spring.profile.active}.${file-extension}
prefix
默認為spring.application.name
,本例中即 service-consumer ;也可以通過配置spring.cloud.nacos.config.prefix
來指定spring.profile.active
就是當前環境對應的 profile,本例中即 dev ;如果spring.profile.active
不存在,這之前的連接符-
也將不存在,文件拼接格式變為${prefix}.${file-extension}
file-extension
就是文件后綴,默認為properties;可以通過配置spring.cloud.nacos.config.file-extension
來指定,但其值目前只支持properties
或yaml
根據上述說明,服務會去配置中心找的文件就是service-consumer-dev.properties,也即是第5步新增的配置文件。
瀏覽器訪問localhost:9091/test/message
就可以看到返回結果為panda
,即我們配置文件中的值。
然后去配置中心修改配置文件內容:
再次訪問localhost:9091/test/message
,可以看到返回結果變為panda2
如此,就解決了之前提到的三個問題:
- 配置文件和項目包分開,配置文件可統一管理
- 配置參數修改后,不需要重新打包項目,直接重啟項目就能讀到修改的值
- 對於一些需要立即生效的參數,使用@Value + @RefreshScope組合
7 小結
我們項目的啟動腳本里一般會加上profile,如測試環境java -jar order.jar --spring.profile.active=test
,生產環境java -jar order.jar --spring.profile.active=prod
。那么,同一個jar包,我們完全不需要任何改動,發布到不同環境,它自己就能讀取到不同環境的配置文件。
一"一個jar包,到處發布"。非常的方便。
namespace & group
我們已經把配置文件從項目中抽離出來了,然而這里仍有麻煩:如果我們有很多微服務,那么就對應有很多配置文件;這些文件還有各自不同環境的版本,也許還有不同業務場景下的版本。如果只是把這么多配置文件都單純放在一起,那么維護起來也會很困難。
1 說明
為了解決配置文件太多不好管理的問題,我們可以使用nacos提供的命名空間(namesapce)和組(group)的概念。
namespace可以看成是一個獨立的一級目錄,namespace之間相互隔離;組可以看成namespace下面的二級目錄,group之間同樣隔離。
之前說,服務啟動后會去配置中心找${prefix}-${spring.profile.active}.${file-extension}
,其實前面還得加上命名空間和組;即到底是去哪個命名空間下面的哪個組找配置文件。我們沒有配置這兩項,默認是去public下DEFAULT_GROUP找該文件。
而我們創建配置文件時並沒有指定命名空間和組,默認就放在了public下的DEFAULT_GROUP組。
所以才能正常讀取到配置文件。
2 解決方案
根據以上說明,我們可以使用微服務名來作為namespace。如一個商城項目,有訂單微服務(order),商品微服務(product),庫存微服務(stock)等,那我們就分別建立namespace為order, product, stock等。
然后,對於不同的業務場景,我們可以使用group來區分。比如雙11對應的組,我們就叫1111;618對應的組,我們就叫618
我們去命名空間菜單,點擊新建命名空間
依次添加三個命名空間后,回到配置列表,可以看到新建的命名空間
單擊命名空間,可選中之。我們在其中新建配置文件,組也是在建立配置文件時指定的。
連續建立不同組不同環境的配置文件,最后應該看起來類似這樣
然后其他微服務也如此,建立自己的不同組的不同環境的配置文件。
這里我們可以使用克隆功能,批量復制。
結果如下
如果微服務的配置差別不大的話,可以用這個方式批量復制,再去修改部分參數。
配置文件完成后,再去bootstrap.properties文件指定namespace和group
spring.cloud.nacos.config.group=1111
spring.cloud.nacos.config.namespace=12078634-abb1-4604-8678-45c11db8fe74
這里面的12078634-abb1-4604-8678-45c11db8fe74
就是order命名空間后面那一串id
3 小結
以上,我們分離了配置文件和項目。並且能根據微服務和業務分開管理。使得配置維護,項目發布都更加容易。
tip:這里其實有個問題,這個group切換,還是需要修改group后重新發布項目。所以,這里失去了之前說好的"一個jar包,到處發布"的特點。所以,實際使用中,如果沒有特別的業務場景,就使用一個默認group。只指定namespace,那么依舊可以做到不重新打包項目。
ps: 如果有同學知道項目啟動如何指定group,請指正,多謝。
自定義數據庫
默認情況下,nacos是使用了一個嵌入式數據庫。
如果想使用自己的數據庫(目前只支持mysql數據庫)
1 conf目錄下,修改application.properties文件。
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 #使用的mysql用戶名
db.password=xxx #使用的mysql連接密碼
2 將conf/nacos-mysql.sql表結構導入到自己的數據庫中
3 重新啟動啟動nacos,會發現之前的配置文件沒有了。重新添加配置文件,在mysql表里看到自己的配置文件內容。
集群
為了保證nacos本身的高可用,可以用三台nacos組成集群。
集群首先要使用自定義數據庫,不然三台集群的配置文件都不能保證一致,集群的基本意義就沒了。
1 復制conf目錄下的cluster.conf.example,重命名為cluster.conf,寫入三台nacos的ip地址
192.168.0.101
192.168.0.102
192.168.0.103
如果在同一台機器上測試,可以設定不同端口
127.0.0.1:8848
127.0.0.1:8858
127.0.0.1:8868
2 復制兩個nacos,放在不同的機器上(單機測試則去conf/application.properties修改端口)。啟動三台nacos。
3 nginx代理配置
# 集群節點
upstream nacos {
server 192.168.0.101:8848 weight=1;
server 192.168.0.102:8848 weight=1;
server 192.168.0.103:8848 weight=1;
}
# 本地集群節點
#upstream nacos {
#server 127.0.0.1:8848 weight=1;
#server 127.0.0.1:8858 weight=1;
#server 127.0.0.1:8868 weight=1;
#}
server {
listen 80;
server_name localhost;
location /nacos/ {
#代理
proxy_pass http://nacos/nacos/;
}
}
4 訪問
瀏覽器訪問http://localhost/nacos/index.html
即可
tip: 保證了Nacos不會有單點故障后,其背后的Mysql最好也做一個主從備份或高可用。