1. 程式人生 > 程式設計 >SpringBoot+Eureka實現微服務負載均衡的示例程式碼

SpringBoot+Eureka實現微服務負載均衡的示例程式碼

1,什麼是Eureka,什麼是服務註冊與發現

Spring Boot作為目前最火爆的web框架。那麼它與Eureka又有什麼關聯呢?

  1. Eureka是Netflix開源的一個RESTful服務,主要用於服務的註冊發現。
  2. Eureka由兩個元件組成:Eureka伺服器和Eureka客戶端。Eureka伺服器用作服務註冊伺服器。
  3. Eureka客戶端是一個java客戶端,用來簡化與伺服器的互動、作為輪詢負載均衡器,並提供服務的故障切換支援。
  4. Netflix在其生產環境中使用的是另外的客戶端,它提供基於流量、資源利用率以及出錯狀態的加權負載均衡。

2,先建立一個Eureka-Server服務註冊中心


這裡需要用到spring-cloud的Eureka模組,他是一個服務的註冊和發現模組

如圖我們先new一個Spring-boot工程引入Eureka Server




Next>>>>Finish完成

我們來看看構建好的Eureka-Server的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>
  <groupId>com.eureka</groupId>
  <artifactId>server</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  <packaging>jar</packaging>
  <name>server</name>
  <description>Demo project for Spring Boot</description>
  <parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.0.2.RELEASE</version>
    <relativePath/> <!-- lookup parent from repository -->
  </parent>
  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
    <java.version>1.8</java.version>
    <spring-cloud.version>Finchley.RC2</spring-cloud.version>
  </properties>
  <dependencies>
    <!-- 引入的Eureka-server -->
    <dependency>
      <groupId>org.springframework.cloud</groupId>
      <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
    </dependency>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-test</artifactId>
      <scope>test</scope>
    </dependency>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-autoconfigure</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>
    </dependencies>
  </dependencyManagement>
  <build>
    <plugins>
      <plugin>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-maven-plugin</artifactId>
      </plugin>
    </plugins>
  </build>
  <repositories>
    <repository>
      <id>spring-milestones</id>
      <name>Spring Milestones</name>
      <url>https://repo.spring.io/milestone</url>
      <snapshots>
        <enabled>false</enabled>
      </snapshots>
    </repository>
  </repositories>
</project>

我們看到這裡與普通的Spring-boot專案不同的是,這裡引用了一個Eureka-Server包。

那麼我們怎麼使用它呢,怎麼啟動它呢?

這裡只需要啟動一個註解就可以啦,我們在Spring-Boot工程的啟動類上加>>>>>> @EnableEurekaServer

程式碼如下:

package com.eureka.server;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
/**
 * 啟動一個服務註冊中心
 */
@EnableEurekaServer
@SpringBootApplication
public class ServerApplication {
 
  public static void main(String[] args) {
    SpringApplication.run(ServerApplication.class,args);
  }
}

差點忘了,我們還需要配置application.yml

Eureka是一個高可用的元件,每一個例項註冊之後需要向註冊中心傳送心跳包,在預設情況下erureka server也是一個eureka client,必須要指定一個 server。

eureka server的配置檔案appication.yml:

server:
 port: 8081 #服務註冊中心埠號
eureka:
 instance:
  hostname: 127.0.0.1 #服務註冊中心IP地址
 client:
  registerWithEureka: false #是否向服務註冊中心註冊自己
  fetchRegistry: false #是否檢索服務
  serviceUrl: #服務註冊中心的配置內容,指定服務註冊中心的位置
   defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/

我們來啟動一下吧


我們在瀏覽器上輸入http://127.0.0.1:8081/飛機直達


我們可以看到它的視覺化介面

細心的朋友會發現,這裡沒有發現服務???No instance available

why? 因為我們還沒有服務向註冊中心註冊服務,所以找不到啊

3,先建立一個Eureka-Client客戶端也就是服務提供者

客戶端在向註冊中心它會提供一些元資料,例如主機和埠,URL,主頁等。Eureka server 從 每 個client例項接收心跳訊息。 如果心跳超時,則通常將該例項從註冊server中刪除。

建立客戶端和服務端差不多,只是啟動註解有點不一樣,還有yml配置檔案




Next>>>Finish完成啦

開啟會發現pom.xml其實和Server註冊中心的類似

<?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>
  <groupId>com.eureka</groupId>
  <artifactId>provider</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  <packaging>jar</packaging>
  <name>provider</name>
  <description>Demo project for Spring Boot</description>
  <parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.0.2.RELEASE</version>
    <relativePath/> <!-- lookup parent from repository -->
  </parent>
  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
    <java.version>1.8</java.version>
    <spring-cloud.version>Finchley.RC2</spring-cloud.version>
  </properties>
  <dependencies>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
      <groupId>org.springframework.cloud</groupId>
      <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
    </dependency>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-test</artifactId>
      <scope>test</scope>
    </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>
    </dependencies>
  </dependencyManagement>
  <build>
    <plugins>
      <plugin>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-maven-plugin</artifactId>
      </plugin>
    </plugins>
  </build>
  <repositories>
    <repository>
      <id>spring-milestones</id>
      <name>Spring Milestones</name>
      <url>https://repo.spring.io/milestone</url>
      <snapshots>
        <enabled>false</enabled>
      </snapshots>
    </repository>
  </repositories>
</project>

怎麼證明它是Client呢

很簡單

在Spring-boot的啟動類上通過註解@EnableEurekaClient 表明自己是一個eurekaclient.

package com.eureka.provider;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import java.util.HashMap;
import java.util.Map;
/**
 * Eureka客戶端
 */
@RestController
@EnableEurekaClient
@SpringBootApplication
public class ProviderApplication {
 
  public static void main(String[] args) {
    SpringApplication.run(ProviderApplication.class,args);
  }
 
 
  /**
   * 假如這個客戶端要提供一個getUser的方法
   * @return
   */
  @GetMapping(value = "/getUser")
  @ResponseBody
  public Map<String,Object> getUser(@RequestParam Integer id){
    Map<String,Object> data = new HashMap<>();
    data.put("id",id);
    data.put("userName","admin");
    data.put("from","provider-A");
    return data;
  }
 
}

雖然加好了@EnableEurekaClient,總感覺差點什麼,對了,配置檔案yml

eureka:
 client:
  serviceUrl: #註冊中心的註冊地址
   defaultZone: http://127.0.0.1:8081/eureka/
server:
 port: 8082 #服務埠號
spring:
 application:
  name: service-provider #服務名稱--呼叫的時候根據名稱來呼叫該服務的方法

我們來啟動看看吧


我們看到這個客戶端已經向註冊中心註冊服務了,那麼我們開啟Eureka-server飛機直達


我們看到我們啟動的服務是不是加進去了呢


我們看到我們的服務是不是加進去了呢。

那麼有人會問,那一大堆飆紅的什麼意思啊。因為註冊的服務都是高可用的,這裡只檢測到一個服務,產生的預警,不影響使用,等下我們啟動多個例項就不會了。

我們先來測試下客戶端的方法是否可用 http://127.0.0.1:8082/getUser?id=1

顯然是沒有問題,那麼我們提供好了服務,sei來消費呢?

下面我們就來建立一個消費者

為了更簡單易懂,我還是一步一步出圖吧。



來,貼上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>

  <groupId>com.eureka</groupId>
  <artifactId>consumer</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  <packaging>jar</packaging>

  <name>consumer</name>
  <description>Demo project for Spring Boot</description>

  <parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.0.2.RELEASE</version>
    <relativePath/> <!-- lookup parent from repository -->
  </parent>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
    <java.version>1.8</java.version>
    <spring-cloud.version>Finchley.RC2</spring-cloud.version>
  </properties>

  <dependencies>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
      <groupId>org.springframework.cloud</groupId>
      <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
    </dependency>

    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-test</artifactId>
      <scope>test</scope>
    </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>
    </dependencies>
  </dependencyManagement>

  <build>
    <plugins>
      <plugin>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-maven-plugin</artifactId>
      </plugin>
    </plugins>
  </build>

  <repositories>
    <repository>
      <id>spring-milestones</id>
      <name>Spring Milestones</name>
      <url>https://repo.spring.io/milestone</url>
      <snapshots>
        <enabled>false</enabled>
      </snapshots>
    </repository>
  </repositories>


</project>

主要是啟動類,裡面內容就豐富啦,都在註釋裡

package com.eureka.consumer;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.context.annotation.Bean;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

import java.util.HashMap;
import java.util.Map;

/**
 * Eureka客戶端-消費者
 */
@RestController
@EnableEurekaClient
@SpringBootApplication
public class ConsumerApplication {

  @Autowired
  RestTemplate restTemplate;

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

  /**
   * 例項化RestTemplate
   * @return
   */
  @LoadBalanced
  @Bean
  public RestTemplate rest() {
    return new RestTemplate();
  }

  /**
   * Rest服務端使用RestTemplate發起http請求,然後得到資料返回給前端----gotoUser是為了區分getUser怕小夥伴暈頭
   * @param id
   * @return
   */
  @GetMapping(value = "/gotoUser")
  @ResponseBody
  public Map<String,Object> data = new HashMap<>();
    /**
     * 小夥伴發現沒有,地址居然是http://service-provider
     * 居然不是http://127.0.0.1:8082/
     * 因為他向註冊中心註冊了服務,服務名稱service-provider,我們訪問service-provider即可
     */
    data = restTemplate.getForObject("http://service-provider/getUser?id="+id,Map.class);
    return data;
  }
}

配置檔案和

eureka:
 client:
  serviceUrl: #註冊中心的註冊地址
   defaultZone: http://127.0.0.1:8081/eureka/
server:
 port: 8083 #服務埠號
spring:
 application:
  name: service-consumer #服務名稱--呼叫的時候根據名稱來呼叫該服務的方法

我們啟動看看效果吧


看看我們的提供者和消費者是不是都進來了

那麼我們看看我們消費者的方法是否可用 飛機直達


哈哈,是不是很神奇

下面介紹個更神奇的東西--實現微服務負載均衡

我們把服務提供者複製一個工程出來,我們再做下小小的修改,看看是否能實現負載均衡。

我們需要修改兩個檔案

一個是啟動類,改了哪些呢?看看就曉得咯

package com.eureka.provider;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;

import java.util.HashMap;
import java.util.Map;

/**
 * Eureka客戶端
 */
@RestController
@EnableEurekaClient
@SpringBootApplication
public class ProviderApplication {

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


  /**
   * 假如這個客戶端要提供一個getUser的方法
   * @return
   */
  @GetMapping(value = "/getUser")
  @ResponseBody
  public Map<String,"provider-B");//改這裡是為了讓大家更能理解它負載均衡的機制
    return data;
  }

}

還有就是yml配置檔案

eureka:
 client:
  serviceUrl: #註冊中心的註冊地址
   defaultZone: http://127.0.0.1:8081/eureka/
server:
 port: 8088 #服務埠號--該埠不要衝突
spring:
 application:
  name: service-provider #服務名稱--呼叫的時候根據名稱來呼叫該服務的方法--名字絕對不能改,改了就訪問不到了

我們來啟動一下吧

看看Eureka-server後臺的效果 ServerA ServerB


這個叫做Service-provider是不是有兩個例項啊

那麼,我們分別訪問一下,看看效果怎麼樣



看到了嗎,8082埠,from是provider-A,8088埠,from是provider-B.

那麼我們訪問消費者的伺服器看看會出現什麼樣的情況呢 飛機直達



一開始是from A,你重新整理一下,誒? 變成 from B了。

說明這個時候兩臺提供者在交替工作,從而達到了一個負載均衡的作用。

來來來,我給你畫個圖


每個微服務都是一個Eureka-Client,我們把每個app(SpringBootApplication)都向註冊中心註冊一個服務。

有時候,某個服務的工作量比較大的時候,我們可以多註冊幾個同名稱的微服務,從而讓他們交替工作,減輕單個服務的壓力。

寫到這裡就結束咯。

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支援我們。