第三章 Nacos Discovery--服務治理

之前我講過 Nacos文章 的內容,想要深入瞭解的 朋友的話,可以去看看 ,我們繼續承接上篇講下去 --> 第二章 : 微服務環境搭建

3.1 服務治理介紹

先來思考一個問題

通過上一章的操作,我們已經可以實現微服務之間的調用。但是我們把服務提供者的網絡地址(ip,端口)等硬編碼到了代碼中,這種做法存在許多問題:

  • 一旦服務提供者地址變化,就需要手工修改代碼
  • 一旦是多個服務提供者,無法實現負載均衡功能
  • 一旦服務變得越來越多,人工維護調用關係困難

那麼應該怎麼解決呢, 這時候就需要通過註冊中心動態的實現服務治理

什麼是服務治理

服務治理是微服務架構中最核心最基本的模塊。用於實現各個微服務的自動化註冊與發現。

  • 服務註冊: 在服務治理框架中,都會構建一個註冊中心,每個服務單元向註冊中心登記自己提供服務的詳細信息。並在註冊中心形成一張服務的清單,服務註冊中心需要以心跳的方式去監測清單中的服務是否可用,如果不可用,需要在服務清單中剔除不可用的服務

  • **服務發現:**服務調用方向服務註冊中心諮詢服務,並獲取所有服務的實例清單,實現對具體服務實例的訪問。

在這裏插入圖片描述
通過上面的調用圖會發現,除了微服務,還有一個組件是服務註冊中心,它是微服務架構非常重要的一個組件,在微服務架構裏主要起到了協調者的一個作用。註冊中心一般包含如下幾個功能:

1. 服務發現:

  • **服務註冊:**保存服務提供者和服務調用者的信息
  • **服務訂閱:**服務調用者訂閱服務提供者的信息,註冊中心向訂閱者推送提供者的信息

2. 服務配置:

  • 配置訂閱: 服務提供者和服務調用者訂閱微服務相關的配置
  • 配置下發: 主動將配置推送給服務提供者和服務調用者

3. 服務健康檢測

  • 檢測服務提供者的健康情況,如果發現異常,執行服務剔除

常見的註冊中心

  • Zookeeper

zookeeper 是一個分佈式服務框架,是Apache Hadoop 的一個子項目,它主要是用來解決分佈式應用中經常遇到的一些數據管理問題,如:統一命名服務、狀態同步服務、集羣管理、分佈式應用配置項的管理等。

  • Eureka

    Eureka是Springcloud Netflix中的重要組件,主要作用就是做服務註冊和發現。但是現在已經閉源

  • Consul

Consul是基於GO語言開發的開源工具,主要面向分佈式,服務化的系統提供服務註冊、服務發現和配置管理的功能。Consul的功能都很實用,其中包括:服務註冊/發現、健康檢查、Key/Value存儲、多數據中心和分佈式一致性保證等特性。Consul本身只是一個二進制的可執行文件,所以安裝和部署都非常簡單,只需要從官網下載後,在執行對應的啓動腳本即可。

  • Nacos

Nacos是一個更易於構建雲原生應用的動態服務發現、配置管理和服務管理平臺。它是 Spring Cloud Alibaba 組件之一,負責服務註冊發現和服務配置,可以這樣認爲nacos=eureka+config

3.2 nacos簡介

Nacos 致力於幫助您發現、配置和管理微服務。Nacos 提供了一組簡單易用的特性集,幫助您快速

實現動態服務發現、服務配置、服務元數據及流量管理。
從上面的介紹就可以看出,nacos的作用就是一個註冊中心,用來管理註冊上來的各個微服務。

3.3 nacos實戰入門

接下來,我們就在現有的環境中加入nacos,並將我們的兩個微服務註冊上去。

3.3.1 搭建nacos環境

第1步: 安裝nacos

下載地址: https://github.com/alibaba/nacos/releases
下載zip格式的安裝包,然後進行解壓縮操作

第2步: 啓動nacos

#切換目錄
cd nacos/bin
#命令啓動
startup.cmd -m standalone

第3步: 訪問nacos

打開瀏覽器輸入http://localhost:8848/nacos,即可訪問服務, 默認密碼是nacos/nacos

在這裏插入圖片描述

3.3.2 將商品微服務註冊到nacos

接下來開始修改shop-product 模塊的代碼, 將其註冊到nacos服務上

1 在pom.xml中添加nacos的依賴

 <!--nacos客戶端-->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>

2 在主類上添加@EnableDiscoveryClient註解

@SpringBootApplication
@EnableDiscoveryClient
public class ProductApplication

3 在 application.yml中添加nacos服務的地址

spring:
 cloud:
    nacos:
      discovery:
        server-addr: localhost:8848

4 啓動服務, 觀察nacos的控制面板中是否有註冊上來的商品微服務

在這裏插入圖片描述

3.3.3 將訂單微服務註冊到nacos

接下來開始修改shop_order模塊的代碼, 將其註冊到nacos服務上

1. 在pom.xml中添加nacos的依賴

 <!--nacos客戶端-->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>

2. 在主類上添加@EnableDiscoveryClient註解

@SpringBootApplication
@EnableDiscoveryClient
public class OrderApplication

3. 在 application.yml中添加nacos服務的地址

spring:
 cloud:
    nacos:
      discovery:
        server-addr: localhost:8848

4 修改OrderController, 實現微服務調用

    @RestController
    @Slf4j
    public class OrderController {
        @Autowired
        private RestTemplate restTemplate;
        @Autowired
        private OrderService orderService;
        @Autowired
        private DiscoveryClient discoveryClient;

        //準備買1件商品
        @GetMapping("/order/prod/{pid}")
        public Order order(@PathVariable("pid") Integer pid) {
            log.info(">>客戶下單,這時候要調用商品微服務查詢商品信息");
//從nacos中獲取服務地址
            ServiceInstance serviceInstance =
                    discoveryClient.getInstances("service-product").get(0);
            String url = serviceInstance.getHost() + ":" +
                    serviceInstance.getPort();
            log.info(">>從nacos中獲取到的微服務地址爲:" + url);
//通過restTemplate調用商品微服務
            Product product = restTemplate.getForObject(
                    "http://" + url + "/product/" + pid, Product.class);
            log.info(">>商品信息,查詢結果:" + JSON.toJSONString(product));
            
		   Order order = new Order();
		    order.setUid(1);
		    order.setUsername("測試用戶");
		    order.setPid(product.getPid());
			order.setPname(product.getPname());
			order.setPprice(product.getPprice());
			order.setNumber(1);
			orderService.save(order);
			return order;
			
	 }
}

DiscoveryClient是專門負責服務註冊和發現的,我們可以通過它獲取到註冊到註冊中心的所有服務

5 啓動服務, 觀察nacos的控制面板中是否有註冊上來的訂單微服務,然後通過訪問消費者服務驗證調用是否成功
在這裏插入圖片描述

3.4 實現服務調用的負載均衡

3.4.1 什麼是負載均衡

通俗的講, 負載均衡就是將負載(工作任務,訪問請求)進行分攤到多個操作單元(服務器,組件)上進行執行。
根據負載均衡發生位置的不同,一般分爲服務端負載均衡和客戶端負載均衡。
服務端負載均衡指的是發生在服務提供者一方,比如常見的nginx負載均衡
而客戶端負載均衡指的是發生在服務請求的一方,也就是在發送請求之前已經選好了由哪個實例處理請求。
在這裏插入圖片描述
我們在微服務調用關係中一般會選擇客戶端負載均衡,也就是在服務調用的一方來決定服務由哪個提供者執行。

3.4.2 自定義實現負載均衡

1 通過idea再啓動一個shop-product 微服務,設置其端口爲8082

在這裏插入圖片描述

2 通過nacos查看微服務的啓動情況

在這裏插入圖片描述

3 修改shop-order 的代碼,實現負載均衡

@RestController
@Slf4j
public class OrderController {


    @Autowired
    private RestTemplate restTemplate;

    @Autowired
    private OrderService orderService;

    @Autowired
    private DiscoveryClient discoveryClient;


        //準備買1件商品
       @GetMapping("/order/prod/{pid}")
        public Order order (@PathVariable("pid") Integer pid){
            log.info(">>客戶下單,這時候要調用商品微服務查詢商品信息");
//從nacos中獲取服務地址
//自定義規則實現隨機挑選服務

            List<ServiceInstance> instances = discoveryClient.getInstances("serviceproduct");
            int index = new Random().nextInt(instances.size());
            ServiceInstance serviceInstance = instances.get(index);
            String url = serviceInstance.getHost() + ":" +
                    serviceInstance.getPort();
            log.info(">>從nacos中獲取到的微服務地址爲:" + url);
//通過restTemplate調用商品微服務
            Product product = restTemplate.getForObject("http://" + url +
                    "/product/" + pid, Product.class);
            log.info(">>商品信息,查詢結果:" + JSON.toJSONString(product));
            Order order = new Order();
            order.setUid(1);
            order.setUsername("測試用戶");
            order.setPid(product.getPid());
            order.setPname(product.getPname());
            order.setPprice(product.getPprice());
            order.setNumber(1);
            orderService.save(order);
            return order;
        }
    }

第4步:啓動兩個服務提供者和一個服務消費者,多訪問幾次消費者測試效果

在這裏插入圖片描述

3.4.3 基於Ribbon實現負載均衡

Ribbon是Spring Cloud的一個組件, 它可以讓我們使用一個註解就能輕鬆的搞定負載均衡

第1步:在RestTemplate 的生成方法上添加**@LoadBalanced**註解

 	@Bean
    @LoadBalanced
    public RestTemplate restTemplate() {
        return new RestTemplate();
    }

第2步:修改服務調用的方法

 @RestController
    @Slf4j
    public class OrderController {
        @Autowired
        private RestTemplate restTemplate;
        @Autowired
        private OrderService orderService;

        //準備買1件商品
        @GetMapping("/order/prod/{pid}")
        public Order order(@PathVariable("pid") Integer pid) {
            log.info(">>客戶下單,這時候要調用商品微服務查詢商品信息");
//直接使用微服務名字, 從nacos中獲取服務地址
            String url = "service-product";
//通過restTemplate調用商品微服務
            Product product = restTemplate.getForObject(
                    "http://" + url + "/product/" + pid, Product.class);
            log.info(">>商品信息,查詢結果:" + JSON.toJSONString(product));
            Order order = new Order();
            order.setUid(1);
            order.setUsername("測試用戶");
            order.setPid(product.getPid());
            order.setPname(product.getPname());
            order.setPprice(product.getPprice());
            order.setNumber(1);
            orderService.save(order);
            return order;
        }
    }
Ribbon支持的負載均衡策略

Ribbon內置了多種負載均衡策略,內部負載均衡的頂級接口爲
com.netflix.loadbalancer.IRule, 具體的負載策略如下圖所示:

在這裏插入圖片描述
在這裏插入圖片描述

們可以通過修改配置來調整Ribbon的負載均衡策略,具體代碼如下

service-product: # 調用的提供者的名稱
  ribbon:
    NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule

3.5 基於Feign實現服務調用

3.5.1 什麼是Feign

Feign是Spring Cloud提供的一個聲明式的僞Http客戶端, 它使得調用遠程服務就像調用本地服務一樣簡單, 只需要創建一個接口並添加一個註解即可。

Nacos很好的兼容了Feign, Feign默認集成了 Ribbon, 所以在Nacos下使用Fegin默認就實現了負載均衡的效果。

3.5.2 Feign的使用

1 加入Fegin的依賴

       <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>

2 在主類上添加Fegin的註解

@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients//開啓fegin的客戶端
public class OrderApplication {

    public static void main(String[] args) {
        SpringApplication.run(OrderApplication.class);
    }

3 創建一個service, 並使用Fegin實現微服務調用

@FeignClient("service-product")//聲明調用的提供者的name
public interface ProductService {
//指定調用提供者的哪個方法
//@FeignClient+@GetMapping 就是一個完整的請求路徑 http://serviceproduct/product/{pid}
    @GetMapping(value = "/product/{pid}")
    Product findByPid(@PathVariable("pid") Integer pid);
}

4 修改controller代碼,並啓動驗證


    @RestController
    @Slf4j
    public class OrderController {
        @Autowired
        private OrderService orderService;
        @Autowired
        private ProductService productService;

        //準備買1件商品
        @GetMapping("/order/prod/{pid}")
        public Order order(@PathVariable("pid") Integer pid) {
            log.info(">>客戶下單,這時候要調用商品微服務查詢商品信息");
//通過fegin調用商品微服務
            Product product = productService.findByPid(pid);
            log.info(">>商品信息,查詢結果:" + JSON.toJSONString(product));
            Order order = new Order();
            order.setUid(1);
            order.setUsername("測試用戶");
            order.setPid(product.getPid());
            order.setPname(product.getPname());
            order.setPprice(product.getPprice());
            order.setNumber(1);
            orderService.save(order);
            return order;
        }
    }

5 重啓order微服務,查看效果

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章