SpringCloud中Nacos服務注冊中心 + LoadBalancer服務負載均衡使用
- 前言
- Nacos
- 工作流程
- nacos安裝
- docker安裝
- window安裝
- 運行nacos
- 微服務集成nacos
- 高級特性
- 1.服務集群
- 配置方法
- 效果圖
- 模擬服務實例宕機
- 2.權重配置
- 3.環境隔離
- 如何啟動集群節點
- 本地啟動多個節點方法
- LoadBalancer
- 集成LoadBalancer
- LoadBalancer流程
- 源碼跟蹤
- 自定義負載均衡算法
- 使用自定義負載均衡算法
- 結語
😀大家好!我是向陽🌞,一個想成為優秀全棧開發工程師的有志青年!
📔今天來說一說SpringCloud中Nacos服務注冊中心 + LoadBalancer服務負載均衡使用。
前言
本篇文章主要是使用Nacos來注冊服務實例,使用Nacos來管理這些服務實例,然后使用LoadBalancer讓服務消費方負載均衡調用服務提供方。
這里有一些代碼準備,Contorller的代碼我就不貼了,貼一個order服務遠程調用user服務,獲取訂單對應的用戶信息。
這里使用的是RestTemplate來進行調用遠程服務,后續會用OpenFeign來進行替換優化。
@Service
public class OrderServiceImpl implements OrderService {@Autowiredprivate OrderMapper orderMapper;@Autowiredprivate RestTemplate restTemplate;/*** 查詢訂單(攜帶用戶信息)** @param orderId* @return*/@Overridepublic Order findOrderByOrderId(Long orderId) {Order order = orderMapper.findOrderByOrderId(orderId);User user = restTemplate.getForObject("http://ssgw-cloud-user/api/user/findUserByUserId/" + order.getUserId(),User.class);order.setUser(user);return order;}
}
Nacos
官方文檔地址:Nacos文檔地址
Nacos有多個特性,這里我們主要介紹的是他的服務發現和服務健康監測這個特性,他還有個我常用的特性,那就是動態配置服務,以后可能會說到。
我們把服務都注冊到Nacos里面,Nacos會對服務進行實時的健康檢查,阻止向不健康的主機或服務實例發送請求。
工作流程
通過注冊中心可以對服務提供方和服務消費方進行解耦。具體的工作模式如下圖所示:
工作流程說明:
- 服務提供方在啟動的時候,會向注冊中心注冊自己服務的詳情信息 (ip、端口號等) 。在注冊中心中會維護一張服務清單,保存這些注冊信息,注冊中心需要以心跳的方式(30s,服務向注冊中心發送心跳)去監測清單中的服務是否可用,如果不可用,需要在服務清單中剔除不可用的服務。
- 服務消費方向服務注冊中心咨詢服務,并獲取所有服務的實例清單,然后,按照指定的負載均衡算法從服務清單中選擇一個服務實例進行訪問。
- 每當服務提供方有節點不可用后,服務消費方會重新緩存可用的提供方信息(ip、端口號等)。
nacos安裝
docker安裝
直接在linux虛擬機中用docker進行以下命令即可。
# 拉取鏡像
docker pull nacos/nacos-server:v2.2.2# 創建容器
docker run --name nacos -e MODE=standalone -p 8848:8848 -p 9848:9848 -d nacos/nacos-server:v2.2.2# nacos2.x的版本新增了一個客戶端與服務端的gRpc的通訊端口號9848
window安裝
不同的版本有不同的注意事項,可以去官方文檔查閱,或者具體的細節可以查看其他博客,這里不詳細贅述。
二進制包下載地址
運行nacos
docker的運行在上面已經提到了,docker run xxx就已經運行了。
Window版本的docker配置文件默認是單機模式啟動,所以我們運行nacos要加上 standalone 這個命令。
startup.cmd -m standalone
運行成功的頁面,nacos的默認端口是8848,我們訪問:http://localhost:8848/nacos 即可訪問到圖形化界面,默認賬號密碼都是 nacos。
微服務集成nacos
在pom.xml中加入以下依賴:
<dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
在application.yml中加入以下配置:
spring:# 配置nacos注冊中心的地址cloud:nacos:discovery:server-addr: localhost:8848 # 如果在虛擬機安裝,則改成你對應的ip地址application: name: spzx-cloud-user # 每一個服務注冊到nacos注冊中心都需要提供一個服務名稱,order微服務注冊的時候需要更改微服務名稱
加入對應的配置文件后,在nacos圖形化界面就可以看到以下信息,這里我已經啟動了3個user服務,所以 ssgw-cloud-user 的實例數為3。
高級特性
1.服務集群
在實際生產環境中,為了保證每一個服務的高可用,那么,此時就需要去構建服務集群,但是,并不是說把所有的服務都部署在一個機房里。而是將多個服務分散的部署到不同的機房中,每一個機房的服務可以看做成是一個集群。
微服務互相訪問時,應該盡可能訪問同集群實例,因為本地訪問速度更快。當本集群內不可用時,才訪問其它集群。例如:上海機房內的order微服務應該優先訪問同機房的user微服務。
配置方法
配置yml文件:
spring:cloud:nacos:discovery:cluster-name: SH # 配置服務所屬集群
集成nacos的負載均衡算法,也是在yml文件中配置,配置了之后,就會按照服務集群來進行訪問對應的服務實例,訪問默認是隨機訪問。
spring:cloud:loadbalancer:nacos:enabled: true
一個服務不同實例配置不同的集群方法和下面如何啟動集群節點方法一樣,這里貼個圖。
我們這里用戶服務,兩個配置BJ,兩個配置SH,訂單服務配置了SH,根據上面的講述,如果我們訪問訂單服務的接口,我們應該優先訪問的是兩個SH的用戶服務。
配置了服務集群后,nacos的服務實例有所變化,如下面兩張圖。
效果圖
我們訪問訂單的接口,查看用戶服務的控制臺,我們可以看到只有配置了SH的兩個用戶服務控制臺信息有打印SQL語句,說明被只有這兩個服務被調用了。
其余三個我就不貼圖了…
模擬服務實例宕機
我們可以在nacos的圖形化界面中下線按鈕來下線對應的服務實例,這樣就模擬了服務宕機場景,此時我們下線兩個SH的用戶服務實例,我們訪問訂單接口,此時訪問就會訪問兩個BJ的服務實例,如下圖所示。
此時只會調用在配置在BJ的兩個服務實例中。
其余三個我就不貼圖了…
2.權重配置
我們可以對不同的服務進行權重配置,比如性能好的服務器權重就可以大一點,性能差的服務器泉州就可以小一點。
這個我們可以直接在nacos圖形化界面進行配置,點擊編輯后,即可在彈出的彈窗進行權重配置。
我們還可以在yml文件中進行配置:
spring:cloud:nacos:discovery:weight: 0.1
3.環境隔離
在實際的開發過程中,可能會存在很多個軟件環境:開發環境、測試環境、生產環境。
nacos也是支持多環境隔離配置的,在nacos中是通過namespace來實現多環境的隔離。
完整的服務注冊數據存儲結構如下所示:
namespace + group 才可以確定具體的微服務實例。默認情況下,所有service、group都在同一個namespace,名為public。
在nacos的圖形化界面就可以進行namespace的添加。
給微服務添加名稱空間的配置,來指定該微服務所屬環境,這里修改order的application.yml文件,改為dev:
spring:# 配置nacos注冊中心的地址cloud:nacos:discovery:namespace: dev # 配置服務實例所屬名稱空間
這個時候order和其他的user實例已經不在同一個namespace命名空間下了,這個時候我們再次訪問接口就會報錯,因為訪問不到了。
控制臺報錯找不到對應的實例:
我們也可以分配組,在yml配置文件中進行配置:
spring:# 配置nacos注冊中心的地址cloud:nacos:discovery:namespace: dev # 配置服務實例所屬名稱空間group: ORDER_GROUP
如何啟動集群節點
我們啟動多個user節點,讓order服務負載調用user節點。
本地啟動多個節點方法
我們對原本的user服務右鍵點擊,選擇Copy Configuration來拷貝配置,進而修改新的配置,我們這里修改端口,防止端口沖突啟動不起來。
服務名稱可改可不改使用默認的也可以,但是一定要覆蓋配置文件中的端口號。
選擇Override configuration properties后,添加以下配置來覆蓋原有的配置,約定大于配置,走的就是我們這里配置的端口。
配置完畢后,啟動就是下圖所示的結果。
LoadBalancer
集成LoadBalancer
<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-loadbalancer</artifactId>
</dependency>
Spring Cloud LoadBalancer 是Spring Cloud中負責客戶端負載均衡的模塊,其主要原理是通過選擇合適的服務實例來實現負載均衡。
客戶端負載均衡:就是負載均衡算法由客戶端提供,默認是輪詢負載均衡,就是每個服務被依次調用。
我們多此訪問我們項目的接口,可以從控制臺中發現,三個用戶服務的控制臺中各有一條SQL查詢信息,說明每個都被調用了一次。
http://localhost:10200/api/order/findOrderByOrderId/101
LoadBalancer流程
Spring Cloud LoadBalancer的底層采用了一個攔截器【LoadBalancerInterceptor】,攔截了RestTemplate發出的請求,對地址做了修改。
執行流程說明:
-
通過 LoadBalancerInterceptor 請求攔截器攔截我們的 RestTemplate請求:http://ssgw-cloud-user/api/user/findUserByUserId/1
-
獲取請求的url,然后,從請求的url中獲取服務提供方的主機名稱(ssgw-cloud-user)
-
然后,調用LoadBalancerClient中的execute方法,將服務提供方的名稱傳遞過去
-
在LoadBalancerClient的choose方法中通過ReactiveLoadBalancer.Factory從Nacos注冊中心中獲取服務列表以及負載均衡算法實例對象
-
通過ReactiveLoadBalancer從服務列表中選擇一個服務實例地址,然后,發起遠程調用
源碼跟蹤
首先我們進入到 LoadBalancerInterceptor 的 intercept 方法,可以看到我們調用遠程服務的uri和服務名稱serviceName。
緊接著進入到 LoadBalancerClient 的 execute 方法,這個方法主要來處理服務id和用戶請求,我們主要看他的 choose 方法。
我們從choose方法可以看出來,我們的負載均衡器是我們在配置文件中配置的 NacosLoadBalancer 負載均衡器。
緊接著調用負載均衡器的 choose 方法,從服務列表中選擇一個服務實例對象。
如果我們注釋掉配置文件中的集成nacos的負載均衡算法,我們可以得到負載均衡器變成了默認的RR負載均衡器也就是輪詢調度負載均衡器(RoundRobinLoadBalancer)。
自定義負載均衡算法
詳細注釋在代碼中都有,這里不多贅述。
public class CustomLoadBalancerConfiguration {/*** @param environment: 用于獲取環境屬性配置,其中LoadBalancerClientFactory.PROPERTY_NAME表示該負載均衡器要應用的服務名稱。* @param loadBalancerClientFactory: 是Spring Cloud中用于創建負載均衡器的工廠類,通過getLazyProvider方法獲取ServiceInstanceListSupplier對象,以提供可用的服務列表。* ServiceInstanceListSupplier:用于提供ServiceInstance列表的接口,可以從DiscoveryClient或者其他注冊中心中獲取可用的服務實例列表。* @return*/@BeanReactorLoadBalancer<ServiceInstance> randomLoadBalancer(Environment environment,LoadBalancerClientFactory loadBalancerClientFactory) {String name = environment.getProperty(LoadBalancerClientFactory.PROPERTY_NAME);return new RandomLoadBalancer(loadBalancerClientFactory.getLazyProvider(name, ServiceInstanceListSupplier.class), name);}
}
使用自定義負載均衡算法
這里使用的是 RestTemplate 來遠程調用其他的服務接口(后期會換成 OpenFeign),所以我們在 RestTemplateConfiguration 類上面加上 @LoadBalancerClients 注解來指定我們要調用哪個服務實例,指定使用我們自定義的負載均衡算法來進行調用。
@Configuration
@LoadBalancerClients(value = {@LoadBalancerClient(name = "ssgw-cloud-user", configuration = CustomLoadBalancerConfiguration.class)
})
public class RestTemplateConfiguration {@Bean@LoadBalancedpublic RestTemplate restTemplate() {return new RestTemplate();}
}
結語
至此我們就完成了我們的主題《SpringCloud服務拆分:Nacos服務注冊中心 + LoadBalancer服務負載均衡使用》,更多的細節和使用方法還等著我們去探索,加油吧👍!
——👦[作者]:向陽256
——?[更新]:2025.5.8
——🥰本人技術有限,如果有不對指正需要更改或者有更好的方法,歡迎到評論區留言。