【微服務】- Nacos - 註冊中心

微服務 - 註冊中心 - Nacos

😄生命不息,寫作不止
🔥 繼續踏上學習之路,學之分享筆記
👊 總有一天我也能像各位大佬一樣
🏆 一個有夢有戲的人 @怒放吧德德
🌝分享學習心得,歡迎指正,大家一起學習成長!

上一次介紹了Nacos的簡介以及簡要理解,這次就來使用Nacos整合SpringCloud Alibaba。
努力剋制自己,拒絕擺爛!

在这里插入图片描述

什麼是服務註冊

服務註冊表是註冊中心的核心,它用來記錄各個微服務實例的資訊,例如微服務的名稱、IP、埠等。服務註冊表提供查詢API和管理API,查詢API用於查詢可用的微服務實例,管理API用於服務的註冊與註銷。提供者將服務註冊到註冊中心,註冊中心會對服務進行實例健康監控,消費者通過註冊中心進行服務發現,在進行服務調用。通常服務調用會使用負載均衡,常見負載均衡有ribbon或者feign。
image

對於註冊中心的理解,可以看一下 CSDN:10分鐘帶你徹底搞懂註冊中心_Apple_Web的部落格-CSDN部落格_什麼是註冊中心

什麼是服務發現

在微服務架構中,整個系統會按職責能力劃分為多個服務,通過服務之間協作來實現業務目標。這樣在我們的程式碼中免不了要進行服務間的遠程調用,服務的消費方要調用服務的生產方,為了完成一次請求,消費方需要知道服務生產方的網路位置(IP地址和埠號)。
image
再看這圖,將每個服務集群都註冊到註冊中心,由其統一管理。在服務中心就會有服務註冊表,在服務實例本身並不記錄服務生產方的網路地址,所有服務實例內部都會包含服務發現客戶端。

1)、在每個服務啟動的時候,服務會向註冊中心(Nacos)註冊服務,上報自己的網路地址(服務名,埠號等)資訊。服務中心就會形成服務註冊表,這是服務發現的核心。它是存儲了所有服務實例的資料庫。
2)、客戶端會定期從服務中心拉取服務註冊表,快取在客戶端。
3)、如果一個服務有許多實例集群,那就需要設置負載均衡策略,從中選出一個來。

在微服務環境中,由於服務運行實例的網路地址是不斷動態變化的,服務實例數量的動態變化 ,因此無法使用固定的配置文件來記錄服務提供方的網路地址,必須使用動態的服務發現機制用於實現微服務間的相互感知。各服務實例會上報自己的網路地址,這樣服務中心就形成了一個完整的服務註冊表,各服務實例會通過服務發現中心來獲取訪問目標服務的網路地址,從而實現服務發現的機制。

實例

在之前已經更新了一篇 【微服務】Nacos初體驗,裡面介紹了Nacos的基礎使用,現在來通過SpringCloud實現一個實例。

創建父工程

創建父級springcloud工程,pom.xml文件如下,這裡需要注意的是版本問題,可以在springcloud-alibaba的開源項目中查看具體地址:版本說明
image

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="//maven.apache.org/POM/4.0.0" xmlns:xsi="//www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="//maven.apache.org/POM/4.0.0 //maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <packaging>pom</packaging>
    <modules>
        <module>service-goods</module>
        <module>service-store</module>
    </modules>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.4.2</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.lyd</groupId>
    <artifactId>spring-cloud-demo</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>spring-cloud-demo</name>
    <description>Demo project for Spring Boot</description>
    <properties>
        <java.version>1.8</java.version>
        <spring-cloud.version>2020.0.1</spring-cloud.version>
        <spring-cloud-alibaba.version>2021.1</spring-cloud-alibaba.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter</artifactId>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-bootstrap</artifactId>
        </dependency>
    </dependencies>
    <dependencyManagement>
        <dependencies>
            <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>
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <excludes>
                        <exclude>
                            <groupId>org.projectlombok</groupId>
                            <artifactId>lombok</artifactId>
                        </exclude>
                    </excludes>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

創建服務

創建一個maven模組,編寫啟動類和bootstrap.yml配置文件
需要在pom添加以下依賴坐標:

  • spring-cloud-starter-alibaba-nacos-discovery:將 Nacos 作為註冊中心,並實現對它的自動配置與服務發現
  • spring-boot-starter-web:web啟動器,為我們提供了嵌入的 Servlet 容器以及 SpringMVC 的依賴,並為 Spring MVC 提供了大量自動配置,可以適用於大多數 Web 開發場景。
<dependencies>
    <dependency>
        <groupId>com.alibaba.cloud</groupId>
        <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
</dependencies>

啟動器類需要添加註解
@EnableDiscoveryClient: 將微服務註冊到服務發現組件上,能夠讓註冊中心能夠發現,掃描到改服務。

package com.lyd.demo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
/**
 * @author: lyd
 * @description: 啟動類
 * @Date: 2022/9/20
 */
@EnableDiscoveryClient
@SpringBootApplication
public class GoodsApplication {
    public static void main(String[] args) {
        SpringApplication.run(GoodsApplication.class, args);
    }
}

在bootstrap.yml文件上編寫一些配置
修改埠號,服務名字等。ephemeral:表示註冊的實例的屬性,默認是true

server:
  port: 8000
spring:
  application:
    name: service-goods
  cloud:
    nacos:
      server-addr: 127.0.0.1:8848
      discovery:
        ephemeral: false # false為永久實例,true表示臨時實例開啟,註冊為臨時實例

在View/Tool Windows 下面有個services可以打開查看服務,有時候會有提示打開,在添加springboot就行。
image
通過右鍵copy Configuration 可以賦值多個實例,在VM-options中寫 -Dserver.port=????來配置新的實例的埠號
image
運行啟動,就會吧服務註冊到nacos註冊中,此時可以在nacos網頁中查看。
image
這裡能夠顯示服務的集群、狀態等資訊,也可以進行其他操作。
接下來編寫服務的一些具體模擬業務,在讓服務之間相互調用。

編寫模擬api

在service-store中有這麼一個控制類,通過/api/store/id返回訪問的埠和一個integer數值

package com.lyd.demo.controller;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.HashMap;
import java.util.Map;
/**
 * @author: lyd
 * @description: api
 * @Date: 2022/9/21
 */
@RestController
@RequestMapping("/api/store")
public class StoreController {
    @Value("${server.port}")
    private String currentPort;
    @GetMapping("/{id}")
    public Map<String, Object> getStoreNum(@PathVariable String id) {
        Map<String, Object> map = new HashMap<>();
        map.put("port", currentPort);
        map.put("num", 10);
        return map;
    }
}

在server-goods服務中需要有一個實體類,模擬請求的數據實體。

package com.lyd.demo.entity;
import lombok.Data;
/**
 * @author: lyd
 * @description: 商品實體類
 * @Date: 2022/9/21
 */
@Data
public class GoodsDto {
    private Long uid;
    private Integer number;
    private String name;
    private String code;
    private String size;
    private Double price;
    private String currentPort;
    private String serverPort;
}

編寫控制類,暴露api介面,等下就是調用這個介面,並且通過RestTemplate.getForObject來進行服務間的調用,在此需要導入負載均衡策略的坐標。並且可以在啟動器中注入bean,開啟負載均衡。

<!--負載均衡-->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-loadbalancer</artifactId>
</dependency>

在啟動類中去注入bean並且加上註解@LoadBalanced

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

具體控制類程式碼如下:
注意URL是//service-store/api/store/通過服務名來的,這樣restTemplate就能使用負載均衡策略。

package com.lyd.demo.controller;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.lyd.demo.entity.GoodsDto;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
import java.util.Map;
/**
 * @author: lyd
 * @description: api
 * @Date: 2022/9/21
 */
@RestController
@RequestMapping("/api")
public class GoodsController {
    @Autowired
    private RestTemplate restTemplate;
    @Value("${server.port}")
    private String currentPort;
    @GetMapping("/{uid}")
    public GoodsDto getGoodsNum(@PathVariable String uid) throws JsonProcessingException {
        GoodsDto goodsDto = new GoodsDto();
        goodsDto.setUid(1L);
        goodsDto.setName("筆記型電腦");
        goodsDto.setCode("note:1");
        goodsDto.setSize("A6");
        goodsDto.setPrice(5.88);
        // 向service-store服務請求數據
        String object = restTemplate.getForObject("//service-store/api/store/" + uid, String.class);
        ObjectMapper objectMapper = new ObjectMapper();
        Map map = objectMapper.readValue(object, Map.class);
        Integer number = (Integer) map.get("num");
        String port = (String) map.get("port");
        goodsDto.setNumber(number);
        goodsDto.setCurrentPort("請求的埠:" + port);
        goodsDto.setServerPort("當前的埠:" + currentPort);
        return goodsDto;
    }
}

啟動Nacos伺服器後就可以啟動這些服務,為了模擬負載均衡的效果,store服務實例就複製了兩個
image

啟動之後訪問://localhost:8000/api/1 就可以看到輸出的結果,每次輸出的請求埠都不一樣。
image
image

今天算是挺坎坷的,之前用來啟動若依框架的nacos伺服器不知為什麼就不能用了,於是搞了好久乾脆重新安裝一個Nacos伺服器,最後才成功。

👍創作不易,可能有些語言不是很通暢,如有錯誤請指正,感謝觀看!記得點贊哦!👍