1. 程式人生 > >微服務之服務生產與消費

微服務之服務生產與消費

服務生產與消費
Eureka 服務治理體系中有 3 個核心角色:服務註冊中心、服務提供者、服務消費者。服務注
冊中心及服務提供者,在前面已做介紹。
本隨筆主要介紹 Eureka 服務治理體系中的服務消費,以 Spring Cloud 服務呼叫中的
Ribbon+RestTemplate 方式為主。

什麼是 Ribbon
Ribbon 是 Netflix 釋出的開源專案,主要功能是提供客戶端的軟體負載均衡演算法,將 Netflix 的
中間層服務連線在一起。Ribbon 客戶端元件提供一系列完善的配置項如連線超時,重試等。
簡單的說,就是在配置檔案中列出 Load Balancer(簡稱 LB)後面所有的機器,Ribbon 會自動
的幫助你基於某種規則(如簡單輪詢,隨即連線等)去連線這些機器。我們也很容易使用
Ribbon 實現自定義的負載均衡演算法。

Ribbon 的負載均衡策略

1. 簡單輪詢負載均衡
  以輪詢的方式依次將請求排程不同的伺服器,即每次排程執行 i = (i + 1) mod n,並選出第
  i 臺伺服器。
2. 隨機負載均衡
  隨機選擇狀態為 UP 的 Server。
3. 加權響應時間負載均衡
  根據相應時間分配一個 weight,相應時間越長,weight 越小,被選中的可能性越低。
4. 區域感知輪詢負載均衡
  複合判斷 server 所在區域的效能和 server 的可用性選擇 server。

實現原理

 

一個服務註冊中心,eureka server,埠為 8761。
micro-service 工程跑了兩個副本,埠分別為 8082、8083,分別向服務註冊中心註冊。

micro-client 埠為 8081,向服務註冊中心註冊。
當 micro-client 通過 restTemplate 呼叫 micro-service 的 hello 介面時,因為用 ribbon 進行了負
  載均衡,會輪流的呼叫 micro-service:8082 和 8083 兩個埠的 hello 介面。

 

程式碼實踐

使用之前Eureka 實踐中建好的註冊中心,之前我們已經建好了服務生產者,現在在服
務生產者中新增介面,以方便服務消費者進行呼叫。

配置服務生產者

1. 新增 ServiceController 類:

package com.example.controller;

import
org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/**
* Created by Administrator on 2018/11/8.
*/

@RestController
public class ServiceController {
@RequestMapping("hello/{name}")
public String hello(@PathVariable String name) {
return name + " say hello Eureka from port:8082";
}

}


2. 參照該服務生產者再建立一個副本,服務埠改為 8083,關鍵程式碼如下:
(application.yml)
# HTTP (Tomcat) port
server:
port: 8083
spring:
application:
name: micro-service
eureka:
client:
service-url:
defaultZone: http://localhost:8761/eureka/

(ServiceController)
package com.example.controller;

import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/**
* Created by Administrator on 2018/11/8.
*/
@RestController
public class ServiceController {
@RequestMapping("hello/{name}")
public String hello(@PathVariable String name) {
return name + " say hello Eureka from port:8083";
}
}



建立服務消費者
1. 在 IDEA 中建立一個 Spring Cloud 工程(服務消費者),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>

<groupId>com.example</groupId>
<artifactId>demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>

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

<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.3.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>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</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>Camden.SR7</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>


</project>


2. application.yml 配置

# HTTP (Tomcat) port
server:
port: 8081
spring:
application:
name: micro-client
eureka:
client:
service-url:
defaultZone: http://localhost:8761/eureka/
# application parameters
app:
service-url: http://MICRO-SERVICE/


3. 編寫啟動類,在啟動類上新增@SpringBootApplication @EnableDiscoveryClient 註解,宣告
 這是一個 Eureka Client。


   ControllerApplication 類:

package com.example;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;

@SpringBootApplication
@EnableDiscoveryClient
public class EurekaConsumerApplication {

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


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


4. 通過@LoadBalanced 註解,呼叫 netflix 的 ILoadBalancer 實現客戶端負載均衡。然後通過
  CallHelloService、CallHelloController 這兩個類去呼叫服務提供者提供的 hello 介面,關鍵程式碼
     如下:

  

package com.example.Service;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

/**
* Created by Administrator on 2018/11/8.
*/

@Service
public class CallHelloService {

@Value("${app.service-url}")
private String appServiceUrl;

@Autowired
private RestTemplate restTemplate;

public String callHello(String name) {
// 是一個 http client
ResponseEntity result = restTemplate.postForEntity(appServiceUrl + "hello/" + name, null, String.class);
return (String) result.getBody();
}
}






package com.example.Controller;


import com.example.Service.CallHelloService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

/**
* Created by Administrator on 2018/11/8.
*/

@RestController
public class CallHelloController {
@Autowired
private CallHelloService callHelloService;

@GetMapping("hello")
public String hello(String name) {
String result = callHelloService.callHello(name);
return result;
}
}

結果驗證
1. 訪問 http://localhost:8761/,如下圖所示:



2. 然後通過如下方式呼叫服務消費者可看到如下介面:

3. 重新整理頁面,測試負載均衡,出現如下介面表示負載均衡配置成功:



注:在整個測試過程中 ,注意所有springboot啟動類在專案中的位置(如下)


否則會出現以下情況