1. 程式人生 > >SpringCloud(二)服務註冊與發現

SpringCloud(二)服務註冊與發現

離上一篇微服務的基本概念已經過去了幾個月,在寫那篇部落格之前,自己還並未真正的使用微服務架構,很多理解還存在概念上。後面換了公司,新公司既用了SpringCloud也用了Dubbo+Zookeeper,就像上一篇文章說的,當一個服務是面向外部或者是直接提供給前端呼叫的,那麼就使用SpringCloud,而一些內部公用的,比如一些特定服務(如傳送簡訊),就使用Dubbo+Zookeeper,因為他在內部呼叫更像呼叫接一個介面,效率也會比較高,而一些模組型的功能,我們則使用SpringCloud。

在已經存在了成熟的開發框架後,微服務本身也沒什麼技術難點,架構思想才是最重要的,要在不斷的實踐中去探索,廢話不多說,來學習SpringCloud的技術。

一、SpringCloud技術棧

SpringCloud是一套完整的分散式微服務架構,我們可以去官網上看下整體的架構圖

 SpringCloud基於SpringBoot提供了一套微服務解決方案,包括服務註冊與發現,配置中心,全鏈路監控,服務閘道器,負載均衡,熔斷器等元件,除了基於NetFlix的開源元件做高度抽象封裝之外,還有一些選型中立的開源元件。

而SpringBoot並沒有重複製造輪子,它將目前各家公司開發的比較成熟、經得起實際考驗的服務框架組合起來,通過SpringBoot風格進行再封裝遮蔽掉了複雜的配置和實現原理,最終給開發者留出了一套簡單易懂、易部署和易維護的分散式系統開發工具包。

SpringCloud提供了全家桶式技術解決方案,對我們使用者來說是極其簡單的。但是要學會SpringCloud的前提那必定要學會SpringBoot。

瞭解完整體的架構圖後,就來進行一個個的技術棧的學習,學習的網站推薦:

Spring Cloud中國社群:http://springcloud.cn/

Spring Cloud中文網: https://www.springcloud.cc/

二、服務註冊與發現

一般架構的開發過程中,我們也會去呼叫一些外部服務,這個時候都是直接去呼叫,沒有服務註冊與發現的概念。但在微服務架構中,我們會按照模組將系統分為多個微服務,而且每個服務我們會做成叢集,那這些服務的數量是很大的,這些服務之間可能會被前端直接呼叫,也有可能互相呼叫,而且呼叫關係十分複雜。

每個服務例項的網路位置(IP與埠)資訊,而且這些服務有可能會下線(奔潰),也有可能擴容,那這個時候服務之間相互去記錄這些資訊肯定是非常麻煩的,這個時候我們需要一個服務的治理元件。

在定義服務治理之前,我們可以類比一個場景,就是我們工作大樓的物業,公司入駐這棟大樓,就會在物業處註冊自己的一些資訊,並且交物業費,那這個物業管理類似服務治理。公司相當於一個一個服務,當外面的人想要找到公司提供服務時,可以去物業處瞭解我們的資訊,然後再找到我們,而本身不需要記錄我們公司的資訊,因為他記不想記住這麼多資訊,而且就算記了,我們公司資訊也可能會改變,比如破產倒閉了,或者又發展壯大換了地方了。我們定時向物業交管理費,一旦我們不交物業費了,那物業就認為我們不在這裡了,那其他人在來找也當做公司不存在了,Eureka的服務註冊與發現就有點類似這種場景。

Spring Cloud 封裝了 Netflix 公司開發的 Eureka 模組來實現服務註冊和發現,Eureka 採用了 C-S 的設計架構。Eureka Server 作為服務註冊功能的伺服器,它是服務註冊中心(物業管理)。而系統中的其他微服務(公司),使用 Eureka 的客戶端連線到 Eureka Server,並維持心跳連線(交物業費)。這樣系統的維護人員就可以通過 Eureka Server 來監控系統中各個微服務是否正常執行。Spring Cloud 的一些其他模組(訪問人員)就可以通過 Eureka Server 來發現系統中的其他微服務,並執行相關的邏輯。

Eureka包含兩個元件:Eureka Server和Eureka Client

Eureka Server提供服務註冊服務各個節點啟動後,會在EurekaServer中進行註冊,這樣EurekaServer中的服務登錄檔中將會儲存所有可用服務節點的資訊,服務節點的資訊可以在介面中直觀的看到。

EurekaClient是一個Java客戶端,用於簡化Eureka Server的互動,客戶端同時也具備一個內建的、使用輪詢(round-robin)負載演算法的負載均衡器。在應用啟動後,將會向Eureka Server傳送心跳(預設週期為30秒)。如果Eureka Server在多個心跳週期內沒有接收到某個節點的心跳,EurekaServer將會從服務登錄檔中把這個服務節點移除(預設90秒)。

三大角色:

  • Eureka Server 提供服務註冊和發現。

  • Service Provider服務提供方將自身服務註冊到Eureka,從而使服務消費方能夠找到。

  • Service Consumer服務消費方從Eureka獲取註冊服務列表,從而能夠消費服務。

三、構建

瞭解了概念,我們現在來實踐一下,因為還會學習更多的的元件,那麼我們建立工程也是從整體來建立,還要了解的一點是,我們現在做的是微服務專案,那其實這些微服務就是一個個獨立的專案,這些專案可以是完全分開的,跟之前的模組概念是不一樣的。

3.1 建立整體專案

直接先建立一個名為spring-cloud-learn 的資料夾,這個資料夾是為了放各個工程的,然後通過idea 開啟這個資料夾,然後在這個資料夾下面建立一個資料夾:spring-cloud-learn-parent

 然後在這個資料夾下增加一個pom.xml檔案:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.0.2.RELEASE</version>
    </parent>
    <groupId>com.yuanqinnan</groupId>
    <artifactId>spring-cloud-learn-parent</artifactId>
    <version>1.0.0-SNAPSHOT</version>
    <packaging>pom</packaging>
    <properties>
        <!-- Environment Settings -->
        <java.version>1.8</java.version>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
        <!-- Spring Settings -->
        <spring-cloud.version>Finchley.RELEASE</spring-cloud.version>
    </properties>
    <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>
        </dependencies>
    </dependencyManagement>
    <build>
        <finalName>spring-cloud-learn-parent</finalName>
        <!-- 資原始檔配置 -->
        <resources>
            <resource>
                <directory>src/main/java</directory>
                <excludes>
                    <exclude>**/*.java</exclude>
                </excludes>
            </resource>
            <resource>
                <directory>src/main/resources</directory>
            </resource>
        </resources>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-resources-plugin</artifactId>
                <configuration>
                    <delimiters>
                        <delimit>$</delimit>
                    </delimiters>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

將這個專案手動託管成maven專案,這個專案是用於管理依賴的,管理一些公共的依賴,就是一些簡單的依賴,需要主要以的是SpringCloud的版本很讓人頭疼,他不僅有數字,還有字母,這些字母是倫敦地鐵站的開頭字母。

3.2 建立服務註冊中心

主要的專案建立完成之後,我們來建立一個用於服務註冊的專案,建立過程與spring-cloud-learn-parent相同,也是建立一個資料夾spring-cloud-learn-eureka,然後在資料夾下增加pom.xml檔案,然後再手動託管

 

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <parent>
        <groupId>com.yuanqinnan</groupId>
        <artifactId>spring-cloud-learn-parent</artifactId>
        <version>1.0.0-SNAPSHOT</version>
    </parent>
    <artifactId>>spring-cloud-learn-eureka</artifactId>
    <packaging>jar</packaging>
    <dependencies>
        <!--eureka-server服務端 -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
        </dependency>
    </dependencies>

</project>

然後再按照maven的目錄結構來建立目錄

 然後建立一個啟動類,這些都是Springboot專案中的知識,然後再增加一個啟動類,上面增加@EnableEurekaServer

@EnableEurekaServer
@SpringBootApplication
public class EurekaApplication {
    public static void main(String[] args) {
        SpringApplication.run(EurekaApplication.class, args);
    }
}

然後增加配置檔案application.yml

spring:
  application:
    name: spring-cloud-learn-eureka

server:
  port: 8761

eureka:
  instance:
    hostname: localhost
  client:
    #表示是否將自己註冊到Eureka Server,預設為true。
    registerWithEureka: false
    #表示是否從Eureka Server獲取註冊資訊,預設為true。
    fetchRegistry: false
    serviceUrl:
      #設定與Eureka Server互動的地址,查詢服務和註冊服務都需要依賴這個地址。預設是http://localhost:8761/eureka ;多個地址可使用 , 分隔
      defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/

需要注意的配置都寫在上面了,很好理解,這個時候我們可以啟動專案了:

這個時候相當於已經建立好註冊中心了,也就是Eureka Server,那現在再來建立服務提供者

3.3 建立服務提供者

按照上面建立註冊服務的方式我們再建立一個部門服務提供者,pom.xml檔案:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <parent>
        <groupId>com.yuanqinnan</groupId>
        <artifactId>spring-cloud-learn-parent</artifactId>
        <version>1.0.0-SNAPSHOT</version>
    </parent>

    <artifactId>spring-cloud-learn-provider-dept</artifactId>
    <packaging>jar</packaging>
    <dependencies>
        <!-- Spring Boot Begin -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <!-- Spring Boot End -->

        <!-- Spring Cloud Begin -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
        </dependency>
        <!-- Spring Cloud End -->
    </dependencies>

</project>

配置檔案:

spring:
  application:
    name: spring-cloud-learn-provider-dept

server:
  port: 8762

eureka:
  client:
    serviceUrl:
      #服務註冊地址
      defaultZone: http://localhost:8761/eureka/

然後建立啟動類:

@EnableEurekaClient
@SpringBootApplication
public class ProviderDeptApplication {
    public static void main(String[] args) {
        SpringApplication.run(ProviderDeptApplication.class, args);
    }
}

啟動時idea會彈出此對話方塊,選擇第一個這個時候我們可以方便的管理多個啟動服務

@Configuration
public class RestTemplateConfiguration {

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

然後我們需要建立一個service,用來請求服務,這裡呼叫的地方指定了服務名稱,不用管ip 地址與埠

@Service
public class DeptService {
    @Autowired
    private RestTemplate restTemplate;

    public String sayHi(String message) {
        //這裡指指定了服務名稱,不用管ip 地址與埠
        return restTemplate.getForObject("http://SPRING-CLOUD-LEARN-PROVIDER-DEPT/hi?message=" + message, String.class);
    }
}

然後建立一個controller,給前端介面呼叫

@RestController
public class DeptController {
    @Autowired
    private DeptService deptService;

    @RequestMapping(value = "hi", method = RequestMethod.GET)
    public String sayHi(@RequestParam String message) {
        return deptService.sayHi(message);
    }
}

 啟動成功後,重新整理Eureka 服務可以看到服務已經註冊上來了,這裡的紅色提示是指Eureka 服務只部署了一臺,不具備高可用,後面我們再來部署叢集

 不過這個時候服務者沒有提供確切的服務,新增一個方法

@RestController
public class DeptController {
    @Value("${server.port}")
    private String port;

    @RequestMapping(value = "hi", method = RequestMethod.GET)
    public String sayHi(@RequestParam(value = "message") String message) {
        return String.format("Hi,your message is : %s i am from port : %s", message, port);
    }
}

這裡為了後面顯示叢集效果,我們返回埠號

3.4 建立服務消費者

上面的註冊中心和提供者都已建好,那現在來建立一個消費者,我們使用Ribbon,先不用管這個,依然按照上面的建立方式再建立一個工程,pom.xml檔案:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <parent>
        <groupId>com.yuanqinnan</groupId>
        <artifactId>spring-cloud-learn-parent</artifactId>
        <version>1.0.0-SNAPSHOT</version>
    </parent>

    <artifactId>spring-cloud-learn-consumer-dept-ribbon</artifactId>
    <packaging>jar</packaging>

    <dependencies>
        <!-- Spring Boot Begin -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-tomcat</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <!-- Spring Boot End -->

        <!-- Spring Cloud Begin -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
        </dependency>
        <!-- Spring Cloud End -->
    </dependencies>

</project>

配置檔案:

spring:
  application:
    name: spring-cloud-learn-consumer-dept-ribbon
server:
  port: 8764

eureka:
  client:
    serviceUrl:
      defaultZone: http://localhost:8761/eureka/

啟動項:

@EnableDiscoveryClient
@SpringBootApplication
public class ConsumerDeptRibbonApplication {
    public static void main(String[] args) {
        SpringApplication.run(ConsumerDeptRibbonApplication.class, args);
    }
}

這個服務我們稍微要給一個配置,因為我們要呼叫服務提供者,會使用到RestTemplate呼叫方式,新增一個配置項,這裡面還有一個負載均衡功能,用起來也很簡單

@RestController
public class DeptController {
    @Autowired
    private DeptService deptService;

    @RequestMapping(value = "hi", method = RequestMethod.GET)
    public String sayHi(@RequestParam String message) {
        return deptService.sayHi(message);
    }
}

這樣消費者就算完成了,我們可以訪問這個消費者了,這個消費者呼叫的是提供者的方法

 

 這樣就已經完成了服務的註冊中心開發,提供者開發及消費者開發,用起來非常簡單,這裡我們看到有@LoadBalanced這個註解,但是服務只有一個,所有沒有效果,我們可以再啟動一個提供者,這裡我們可以直接修改埠號再啟動,只要注意修改一個地方的配置

 

 我們把提供者的埠號改成8763,再啟動一次

 

 這裡啟動了兩個提供者,我們重新整理下注冊中心:

 

 增加了一個服務,但是消費者是感受不到的,然後我們在多次重新整理消費者,可以看到兩個服務在輪訓呼叫,這裡我們就實現了負載均衡:

 

 使用這些元件就是這麼簡單,這裡只是做了最簡單的微服務註冊與發現,未做服務中心叢集,後面我們將再深入的學習。

&n