SpringCloud服務架構搭建 (eurekaServer註冊中心+eurekaClient服務提供者+feign服務消費者+ribbon服務消費者+Hystrix斷路器)

1 , 首先搭建eureka server 註冊中心

1 .1 創建springboot項目 , 選擇相關的組件 eureka-server , 下面是我的pom文件

<?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.1.2.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.eureka.server</groupId>
    <artifactId>eureka-server</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>eureka-server</name>
    <description>Demo project for Spring Boot</description>

    <properties>
        <java.version>1.8</java.version>
        <spring-cloud.version>Greenwich.RC2</spring-cloud.version>
    </properties>

    <dependencies>
        <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>
        </repository>
    </repositories>

</project>

 

1.2 下面是項目的啓動類

/****
 * EurekaServer 服務註冊中心
 */
@SpringBootApplication
@EnableEurekaServer
public class EurekaServerApplication {

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

}

這裏的核心主要是增加 @EnableEurekaServer註解 .

 

1.3 application.yml配置文件

server:
  port: 8761
eureka:
  instance:
    hostname: localhost
  client:
    ##防止自己被註冊
    registerWithEureka: false
    ##獲取註冊列表
    fetchRegistry: false
    serviceUrl:
      defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/

 

運行這個服務 , 這樣註冊中心就搭建好了 , 瀏覽器直接訪問http://localhost:8761/

因爲還沒有服務註冊到註冊中心 ,所以目前application列表是空的 .

 

2 , 第二步 , 創建服務提供者 eureka-client

2.1 和之前一樣 , 先新建一個springboot項目 ,選定好相關的組件 , 這裏主要有

web , eureka-client , 下面是我的完整的pom文件

<?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.1.2.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>eureka.client</groupId>
    <artifactId>eureka-client</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>eureka-client</name>
    <description>Demo project for Spring Boot</description>

    <properties>
        <java.version>1.8</java.version>
        <spring-cloud.version>Greenwich.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-client</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>
        </repository>
    </repositories>

</project>

 

2.2 application.yml配置文件

eureka:
  client:
    serviceUrl:
      defaultZone: http://localhost:8761/eureka/
server:
  port: 8762
spring:
  application:
    name: service-hi

這裏主要是配置註冊中心的地址 , 和服務名稱

 

2.3 新建一個控制器 Controller

@RestController
public class TestController {

    @Value("${server.port}")
    String port;

    @RequestMapping("/hi")
    public String home(@RequestParam String name) {
        return "hi " + name + ",i am from port:" + port;
    }

}

 

2.4 項目啓動類

@SpringBootApplication
@EnableEurekaClient
public class EurekaClientApplication {

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

}

這裏主要就是添加 @EnableEurekaClient 註解

然後直接啓動項目 , 再次刷新註冊中心頁面(全程保持註冊中心服務開啓) , 可以看到服務已經註冊上去了

然後我們直接訪問 http://localhost:8762/hi?name=nickzhang ,可以看到正常的返回數據

hi nickzhang,i am from port:8762

 

3 , 創建服務提供者

3.1 這裏我們先使用 Feign的方式

這裏先簡單的介紹一下什麼事Feign ,有興趣的同學可以深入研究

Feign是一個聲明式的僞Http客戶端,它使得寫Http客戶端變得更簡單。使用Feign,只需要創建一個接口並註解。

它具有可插拔的註解特性,可使用Feign 註解和JAX-RS註解。Feign支持可插拔的編碼器和解碼器。

Feign默認集成了Ribbon,並和Eureka結合,默認實現了負載均衡的效果。

簡而言之:

Feign 採用的是基於接口的註解

Feign 整合了ribbon

 

3.2 準備工作

繼續用上面的工程,eureka-server保持開啓,端口爲8761; 爲了更好的展示 這裏我們打包兩個client服務 ,採用jar包的形式運行 , 端口分別爲8762 、8763. 採用mvn clean install 命令直接打包成jar包 , 記得更改相應的端口 . 然後在cmd中 使用 java -jar XXX.jar 啓動兩個服務

然後刷新註冊中心頁面 , 可以看到兩個服務已經註冊進去了

 

3.3 然後我們創建一個名爲server-feign的springboot工程

依賴的組件主要有feign, eureka ,web . 完整的pom文件代碼如下 :

<?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.1.2.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.server.feign</groupId>
    <artifactId>server-feign</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>server-feign</name>
    <description>Demo project for Spring Boot</description>

    <properties>
        <java.version>1.8</java.version>
        <spring-cloud.version>Greenwich.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-client</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</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>
        </repository>
    </repositories>

</project>

 

3.4 application.yml配置文件

eureka:

client:

serviceUrl:

defaultZone: http://localhost:8761/eureka/

server:

port: 8765

spring:

application:

name: service-feign

 

3.5 配置feign

這裏我們先新建一個 feign接口 ,代碼如下

@FeignClient(value = "service-hi")

public interface SchedualServiceHi {

 

@RequestMapping(value = "/hi", method = RequestMethod.GET)

String sayHiFromClientOne(@RequestParam(value = "name") String name);

 

}

 

這裏@FeignClient(value = "service-hi") 註明client的服務名 (在註冊中心裏是靠服務名識別)

 

3.6 創建Controller控制器

@RestController

public class HiController {

 

@Autowired

SchedualServiceHi schedualServiceHi;

 

@RequestMapping(value = "/hi", method = RequestMethod.GET)

public String sayHi(@RequestParam String name) {

return schedualServiceHi.sayHiFromClientOne(name);

}

 

}

 

3.7 啓動類

@SpringBootApplication

@EnableDiscoveryClient

@EnableFeignClients

public class ServerFeignApplication {

 

public static void main(String[] args) {

SpringApplication.run(ServerFeignApplication.class, args);

}

 

}

 

這裏主要是添加兩個註解 @EnableDiscoveryClient和@EnableFeignClients

到此代碼已經準備好了 , 啓動server-feign服務

然後刷新註冊中心頁面 ,我們可以看到服務已經啓動 並且成功註冊

 

此時 我們多次訪問 http://localhost:8765/hi?name=nickzhang , 仔細觀察 會發現 返回的信息是

hi nickzhang,i am from port:8762

hi nickzhang,i am from port:8763

之間不斷的切換 , 這就說明服務已經正常運行 , 並且實現了負載均衡的功能 ,此時我們請求消費者服務server-feign ,後面是有兩個提供者提供相同的服務.

 

4 , 下面我們使用 ribbon 的方式 實現負載均衡

feign之前的暫時不動 只需關閉 server-feign服務就好了

 

4.1 新建一個springboot項目 , 選擇如下的組件

web , eureka-client , ribbon , 下面是我的完整的 pom代碼

<?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.1.2.RELEASE</version>

<relativePath/> <!-- lookup parent from repository -->

</parent>

<groupId>com.ribbon</groupId>

<artifactId>server-ribbon</artifactId>

<version>0.0.1-SNAPSHOT</version>

<name>server-ribbon</name>

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

 

<properties>

<java.version>1.8</java.version>

<spring-cloud.version>Greenwich.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-client</artifactId>

</dependency>

<dependency>

<groupId>org.springframework.cloud</groupId>

<artifactId>spring-cloud-starter-netflix-ribbon</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>

</repository>

</repositories>

 

</project>

 

4.2 application.yml配置文件

eureka:

client:

serviceUrl:

defaultZone: http://localhost:8761/eureka/

server:

port: 8764

spring:

application:

name: service-ribbon

 

4.3 新建service層 , 並提供一個sayHello方法

public interface CallService {

 

public String sayHello(String name);

 

}

 

實現類

@Service

public class CallServiceImpl implements CallService {

@Autowired

private RestTemplate restTemplate;

 

@Override

public String sayHello(String name) {

return restTemplate.getForObject("http://service-hi/hi?name={1}", String.class, name);

}

}

 

這裏主要關注 getForObject("http://service-hi/hi?name={1}", String.class, name) 方法的使用

{1}是佔位符 , 表示後面的name屬性

 

4.4 新建Controller控制器

@RestController

@RequestMapping("/ribbon")

public class CallController {

 

@Autowired

private CallService callService;

 

@GetMapping("/server-hi/{name}")

public String hello(@PathVariable("name") String name) {

return callService.sayHello(name);

}

}

 

4.5 啓動類

@SpringBootApplication

@EnableEurekaClient

public class ServerRibbonApplication {

 

public static void main(String[] args) {

SpringApplication.run(ServerRibbonApplication.class, args);

}

 

@Bean

@LoadBalanced

public RestTemplate restTemplate(){

return new RestTemplate();

}

 

}

這裏的主要操作是裝載 RestTemplate Bean對象 , 注意添加 @LoadBalanced 註解

 

下面我們啓動 ribbon服務 . 然後刷新註冊中心頁面 我們可以看到服務已經註冊上去了 .

此時我們直接訪問 http://localhost:8764/ribbon/server-hi/nickzhang ,發現返回信息也是在

hi nickzhang,i am from port:8762

hi nickzhang,i am from port:8763

之間不斷切換的 , 到這裏位置 ,我們成功的使用ribbon實現負載均衡 .

 

5 , 加入Hystrix斷路器

5.1 在這裏也簡單介紹下 hystrix , 以及爲什麼要使用 , 有興趣的同學可以深入的研究一下

在微服務架構中,根據業務來拆分成一個個的服務,服務與服務之間可以相互調用,在Spring Cloud可以用RestTemplate+Ribbon和Feign來調用。爲了保證其高可用,單個服務通常會集羣部署。由於網絡原因或者自身的原因,服務並不能保證100%可用,如果單個服務出現問題,調用這個服務就會出現線程阻塞,此時若有大量的請求涌入,Servlet容器的線程資源會被消耗完畢,導致服務癱瘓。服務與服務之間的依賴性,故障會傳播,會對整個微服務系統造成災難性的嚴重後果,這就是服務故障的“雪崩”效應。

爲了解決這個問題,業界提出了斷路器模型。

 

Netflix開源了Hystrix組件,實現了斷路器模式,SpringCloud對這一組件進行了整合。

在微服務架構中 , 部分服務如果出現故障,會導致連鎖故障。當對特定的服務的調用的不可用達到一個閥值(Hystric 是5秒20次) 斷路器將會被打開

斷路打開後,可用避免連鎖故障,fallback方法可以直接返回一個固定值。

 

5.2 配置Hystrix斷路器

這裏是在之前的ribbon服務中加入hystrix

前面的操作保持不變 , 註冊中心依然持續運行 , 測試負載均衡的 8762和 8763 服務依然保持運行

feign服務停止 , 對ribbon的代碼進行改造 ,具體步驟如下

 

5.2.1 首先我們在pom文件中加入hystrix組件

<dependency>

<groupId>org.springframework.cloud</groupId>

<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>

</dependency>

 

5.2.2 CallServiceImpl中加入相關注解和斷路器調用方法

@Service

public class CallServiceImpl implements CallService {

 

@Autowired

private RestTemplate restTemplate;

 

@Override

@HystrixCommand(fallbackMethod = "error")

public String sayHello(String name) {

return restTemplate.getForObject("http://service-hi/hi?name={1}", String.class, name);

}

 

/***

* 斷路調用方法

* @param name

* @return

*/

public String error(String name) {

System.out.println("調用斷路方法 - error >>>>>>>>>>");

return "hi," + name + ",sorry,error!";

}

}

 

5.2.3 啓動類改造

啓動類上 只需要添加 @EnableHystrix 註解即可

 

然後我們啓動服務 .

訪問 http://localhost:8764/ribbon/server-hi/nickzhang , 正常情況下 , 我們可以看到 依然和之前一樣 是在

hi nickzhang,i am from port:8762

hi nickzhang,i am from port:8763

之間交替切換顯示的 .

此時 我們停掉 8762 服務.

 

再多次訪問 http://localhost:8764/ribbon/server-hi/nickzhang

這次我們只看到 僅僅返回了 hi nickzhang,i am from port:8763

多次嘗試訪問後 可以發現 出現了

hi,nickzhang,sorry,error!

的返回信息 , 這就是因爲斷路器發揮了作用 .

 

到此我們的服務搭建順利完成 . 源代碼鏈接

鏈接:https://pan.baidu.com/s/1awrOmZTHGVhiQqfULe2l-w

提取碼:pt4h

 

 

 

 

 

 

 

 

 

 

 

 

 

 

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