1.Nacos 簡介
發音: /nɑ:kəʊs/
全稱:Name and Config Service,nacos 是其首字母的拼寫。
Nacos 的核心功能 = 服務注冊 + 動態配置
可以理解為 Nacos = SpringCloud Eureka + SpringCloud Config
2.什么是服務發現
服務消費者怎么找到服務提供者的機制就是服務發現。
3.實現服務發現機制需要解決很多的問題
健康檢查:
問題:服務實例故障了,無法主動注銷自己的信息怎么辦?
方案:通過心跳機制進行健康檢查,注冊中心刪除無心跳的實例信息
本地緩存:
問題:每次服務調用之前都查詢注冊中心,性能差、不可靠,怎么辦?
方案:本地緩存、定時更新(定時查詢服務列表、服務注冊中心主動推送)
數據同步:
問題:注冊中心集群中各個節點的數據如何同步?
方案:強一致性,例如 ZooKeeper。弱一致性,例如 Eureka。
4.Nacos 特征與優勢
5.Nacos環境搭建
官網文檔:https://nacos.io/zh-cn/docs/quick-start.html
下載地址:https://gitee.com/mirrors/Nacos、https://github.com/alibaba/nacos/releases
Spring Boot 2.3.x:https://github.com/alibaba/nacos/releases/tag/1.4.1
windows安裝方式
選擇 nacos-server-1.4.1.zip 進行下載
解壓進入到 C:\Software\nacos-server-1.4.1\bin 目錄
雙擊 startup.cmd 一閃而過代表失敗,注意Java環境是否安裝和配置。
瀏覽器訪問:http://127.0.0.1:8848/nacos
用戶名和密碼都是nacos
服務注冊(linux)
curl -X POST 'http://127.0.0.1:8848/nacos/v1/ns/instance?serviceName=nacos.naming.serviceName&ip=20.18.7.10&port=8080'
服務發現(linux)
curl -X GET 'http://127.0.0.1:8848/nacos/v1/ns/instance/list?serviceName=nacos.naming.serviceName'
使用 Postman
File => Import => Raw test
粘貼curl命令
6.服務提供者和消費者整合Nacos
6.1 provider(服務提供者)
6.1.1 加依賴
<dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> </dependency>
6.1.2 加注解
package com.example.serviceprovider; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.client.discovery.EnableDiscoveryClient; @SpringBootApplication // 加注解(開啟服務發現) @EnableDiscoveryClient public class ServiceProviderApplication { public static void main(String[] args) { SpringApplication.run(ServiceProviderApplication.class, args); } }
6.1.3 改配置
server: port: 8081 spring: application: name: service-provider
# 添加 nacos 地址 cloud: nacos: discovery: server-addr: localhost:8848 namespace: 23ffbc32-5bde-4451-9683-c346220fa282 group: g1 cluster-name: beijing
6.1.4 創建測試接口
package com.example.serviceprovider; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; @RestController public class TestController { @GetMapping("hello") public String hello(@RequestParam String name){ return "hello " + name; } }
6.2 consumer(消費者)
6.2.1 加依賴
<dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> </dependency>
6.2.2 加注解
package com.example.serviceprovider; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.client.discovery.EnableDiscoveryClient; @SpringBootApplication // 加注解(開啟服務發現) @EnableDiscoveryClient public class ServiceConsumerApplication { public static void main(String[] args) { SpringApplication.run(ServiceConsumerApplication.class, args); } }
6.2.3 改配置
server: port: 8082 spring: application: name: service-consumer cloud: nacos: discovery: server-addr: localhost:8848
6.2.4 配置 RestTemplate
package com.example.serviceprovider; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.client.RestTemplate; @Configuration public class ConsumerConfig { @Bean public RestTemplate restTemplate(){ return new RestTemplate(); } }
6.2.5 發起服務調用
package com.example.serviceprovider; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.cloud.client.ServiceInstance; import org.springframework.cloud.client.loadbalancer.LoadBalancerClient; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.client.RestTemplate; import java.net.URI; @RestController public class TestController { // 引入 RestTemplate @Autowired RestTemplate restTemplate; // 引入 LoadBalancerClient @Autowired LoadBalancerClient loadBalancerClient; @GetMapping("hello") public String hello(@RequestParam String name) { String result = ""; // 根據服務名獲取服務實例 ServiceInstance serviceInstance = loadBalancerClient.choose("service-provider"); // 發起調用 URI uri = serviceInstance.getUri(); result = restTemplate.getForObject(uri + "/hello?name=test", String.class); // 返回結果 return result; } }
7.Nacos 服務領域模型
namespace :命名空間ID
group:組
cluster-name:集群
Nacos 三層數據模型:NameSpace, Group, Service
Nacos 服務領域模型:NameSpace, Group, Service,Cluster, Instance
8.負載均衡與權重
負載均衡的類型
服務端負載均衡:如nginx 根據負載均衡策略選擇某個實例轉發請求
客服端負載均衡:根據自己實現的負載均衡策略選擇
8.1 provider(服務提供者),使用配置的服務端口號
package com.example.serviceprovider; import org.springframework.beans.factory.annotation.Value; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; @RestController public class TestController { @Value("${server.port}") Integer port; @GetMapping("hello") public String hello(@RequestParam String name){ return "hello " + name + " " + port; } }
8.2 consumer(消費者),使用負載均衡注解
package com.example.serviceprovider; import com.netflix.loadbalancer.IRule; import com.netflix.loadbalancer.RandomRule; import org.springframework.cloud.client.loadbalancer.LoadBalanced; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.client.RestTemplate; @Configuration public class ConsumerConfig { // 使用負載均衡注解 @LoadBalanced @Bean public RestTemplate restTemplate(){ return new RestTemplate(); } }
服務調用
package com.example.serviceprovider; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.client.RestTemplate; @RestController public class TestLBController { @Autowired RestTemplate restTemplate; @GetMapping("/testlb") public String testlb(@RequestParam String name){ String result = "";
result = restTemplate.getForObject("http://service-provider/hello?name=" + name, String.class); return result; } }
負載均衡策略
SpringBoot 配置文件修改負載均衡策略
package com.example.serviceprovider; import com.netflix.loadbalancer.IRule; import com.netflix.loadbalancer.RandomRule; import org.springframework.cloud.client.loadbalancer.LoadBalanced; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.client.RestTemplate; @Configuration public class ConsumerConfig { @LoadBalanced @Bean public RestTemplate restTemplate(){ return new RestTemplate(); } // 負載均衡策略 @Bean public IRule iRule(){
return new RandomRule();
} }
8.3 自定義基於權重的負載均衡策略的方法
服務消費者中實現基於權重的負載均衡策略
package com.example.serviceprovider; import com.alibaba.cloud.nacos.NacosDiscoveryProperties; import com.alibaba.cloud.nacos.ribbon.NacosServer; import com.alibaba.nacos.api.naming.NamingService; import com.alibaba.nacos.api.naming.pojo.Instance; import com.netflix.client.config.IClientConfig; import com.netflix.loadbalancer.AbstractLoadBalancerRule; import com.netflix.loadbalancer.BaseLoadBalancer; import com.netflix.loadbalancer.Server; import org.springframework.beans.factory.annotation.Autowired; public class NacosWeightRule extends AbstractLoadBalancerRule { // 引入 NacosDiscoveryProperties @Autowired private NacosDiscoveryProperties nacosDiscoveryProperties; // 重寫 choose 方法 @Override public Server choose(Object o) { // 獲取服務提供者的名字 // 拿到 nacos 的命名服務對象 // 通過 nacos 的命名服務根據權重獲取實例 // 封裝 server 對象,返回 BaseLoadBalancer loadBalancer = (BaseLoadBalancer) this.getLoadBalancer(); String name = loadBalancer.getName();
NamingService namingService = nacosDiscoveryProperties.namingServiceInstance(); try { Instance instance = namingService.selectOneHealthyInstance(name); return new NacosServer(instance); }catch (Exception e){ e.printStackTrace(); } return null; } @Override public void initWithNiwsConfig(IClientConfig iClientConfig) { } }
Nacos配置修改權重配置
@Configuration public class ConsumerConfig { @LoadBalanced @Bean public RestTemplate restTemplate(){ return new RestTemplate(); } @Bean public IRule iRule(){ //根據權重的負載均衡策略 return new NacosWeightRule(); } }
9.Nacos集群部署
9.1 創建數據庫和表
使用sql腳本創建數據庫
nacos-server => conf => nacos-mysql.sql
9.2 配置MySQL連接
nacos-server => conf => application.properties
# 表明用MySQL作為后端存儲 spring.datasource.platform=mysql # 有幾個數據庫實例 db.num=1 # 第1個實例的地址 db.url.0=jdbc:mysql://[mysqlIP]/nacos?characterEncoding=utf8&connectTimeout=1000&socketTimeout =3000&autoReconnect=true db.user=[數據庫用戶名] db.password=[數據庫密碼]
9.3 配置集群節點IP端口
nacos-server => conf => application.properties
# nacos01
server.port=8841
# nacos02
server.port=8842
# nacos03
server.port=8843
nacos-server => conf => cluster.conf.example 復制一份 去掉后綴example ,每個集群實例配置,相同配置文件。
server 127.0.0.1:8841; server 127.0.0.1:8842; server 127.0.0.1:8843;
啟動各個nacos
9.4 配置Nginx
nginx.conf 配置文件 include servers/* 意思是加載servers文件夾下所以配置文件,所以進入到servers文件夾 創建 nocos.conf 配置文件,以下是nocos.conf 內容
upstream nacos { server 127.0.0.1:8841; server 127.0.0.1:8842; server 127.0.0.1:8843; }
server { listen 9090; server_name localhost; location /nacos/ { proxy_pass http://nacos; } }