第三章 微服務之間的調用 + 服務發現 + 負載均衡 + retrofit通信

来源:http://www.cnblogs.com/java-zhao/archive/2016/06/01/5545599.html
-Advertisement-
Play Games

微服務與微服務之間通信。 一、通信協議 我們選用的通信協議是http,其實現工具是retrofit。 特點:實現簡單,但是速度相較於tcp協議是慢一些 如果對速度要求很高,可以使用tcp協議,實現產品可選用mina2/netty 特點:實現簡單,但是速度相較於tcp協議是慢一些 二、服務路由 說明: ...


微服務與微服務之間通信。

一、通信協議

  • 我們選用的通信協議是http,其實現工具是retrofit
    • 特點:實現簡單,但是速度相較於tcp協議是慢一些
  • 如果對速度要求很高,可以使用tcp協議,實現產品可選用mina2/netty

 

二、服務路由

說明:不使用netflix的ribbon做服務路由,自己來實現。

實現思路:

  1. 拉取可用服務列表(服務發現)serverList
    • 緩存到本地guava cache中去,以後每隔10min從consulServer拉取一次(原本打算這樣做),但是consulServer自己通過gossip協議會將服務數據廣播給consulClient,每次獲取伺服器列表的時候,都是直接從本地agent(即consulClient)獲取。
  2. 使用配置好的路由演算法選出其中1台,執行邏輯

補充:當第二步執行邏輯超時或出錯了,我們可以從剩下的機器中再選一臺做,這樣的失敗重試可以通過"while(true)+局部計數器"的形式來實現。(這裡暫時不做)

 

三、實現(由於代碼改動比較大,列出完全版的代碼)

  • framework:基本框架模塊
  • myserviceA-server:myserviceA提供的服務邏輯
  • myserviceA-client:對server進行封裝,提供介面,供其他微服務(service)或者gateway或者app使用
  • myserviceB-server:myserviceB提供的服務邏輯
  • myserviceB-client:同myserviceA-client

1、framework

1.1、pom.xml

 1 <?xml version="1.0" encoding="UTF-8"?>
 2 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 3     xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
 4 
 5     <modelVersion>4.0.0</modelVersion>
 6 
 7     <parent>
 8         <groupId>org.springframework.boot</groupId>
 9         <artifactId>spring-boot-starter-parent</artifactId>
10         <version>1.3.0.RELEASE</version>
11     </parent>
12 
13     <groupId>com.microservice</groupId>
14     <artifactId>framework</artifactId>
15     <version>1.0-SNAPSHOT</version>
16 
17     <properties>
18         <java.version>1.8</java.version><!-- 官方推薦 -->
19     </properties>
20 
21     <!-- 引入實際依賴 -->
22     <dependencies>
23         <dependency>
24             <groupId>org.springframework.boot</groupId>
25             <artifactId>spring-boot-starter-web</artifactId>
26         </dependency>
27         <!-- consul-client -->
28         <dependency>
29             <groupId>com.orbitz.consul</groupId>
30             <artifactId>consul-client</artifactId>
31             <version>0.10.0</version>
32         </dependency>
33         <!-- consul需要的包 -->
34         <dependency>
35             <groupId>org.glassfish.jersey.core</groupId>
36             <artifactId>jersey-client</artifactId>
37             <version>2.22.2</version>
38         </dependency>
39         <dependency>
40             <groupId>com.alibaba</groupId>
41             <artifactId>fastjson</artifactId>
42             <version>1.1.15</version>
43         </dependency>
44         <!-- 引入監控工具,包含health檢查(用於consul註冊) -->
45         <dependency>
46             <groupId>org.springframework.boot</groupId>
47             <artifactId>spring-boot-starter-actuator</artifactId>
48         </dependency>
49         <!-- 引入lombok,簡化pojo -->
50         <dependency>
51             <groupId>org.projectlombok</groupId>
52             <artifactId>lombok</artifactId>
53             <version>1.16.8</version>
54             <scope>provided</scope>
55         </dependency>
56         <!-- 引入swagger2 -->
57         <dependency>
58             <groupId>io.springfox</groupId>
59             <artifactId>springfox-swagger2</artifactId>
60             <version>2.2.2</version>
61         </dependency>
62         <dependency>
63             <groupId>io.springfox</groupId>
64             <artifactId>springfox-swagger-ui</artifactId>
65             <version>2.2.2</version>
66         </dependency>
67         <!-- retrofit -->
68         <dependency>
69             <groupId>com.squareup.retrofit</groupId>
70             <artifactId>retrofit</artifactId>
71             <version>1.9.0</version>
72         </dependency>
73     </dependencies>
74 
75     <build>
76         <plugins>
77             <plugin>
78                 <groupId>org.springframework.boot</groupId>
79                 <artifactId>spring-boot-maven-plugin</artifactId>
80             </plugin>
81         </plugins>
82     </build>
83 </project>
View Code

服務註冊相關

1.2、com.microservice.com.microservice(啟動類)

 1 package com.microservice;
 2 
 3 import org.springframework.boot.SpringApplication;
 4 import org.springframework.boot.autoconfigure.SpringBootApplication;
 5 
 6 import com.microservice.consul.ConsulRegisterListener;
 7 
 8 import springfox.documentation.swagger2.annotations.EnableSwagger2;
 9 
10 /**
11  * 註意:@SpringBootApplication該註解必須在SpringApplication.run()所在的類上
12  */
13 @SpringBootApplication
14 @EnableSwagger2
15 public class MySpringAplication {
16 
17     public void run(String[] args) {
18         SpringApplication sa = new SpringApplication(MySpringAplication.class);
19         sa.addListeners(new ConsulRegisterListener());
20         sa.run(args);
21     }
22 
23     public static void main(String[] args) {
24     }
25 }
View Code

1.3、com.microservice.consul.ConsulConfig(構建consul單例實例)

 1 package com.microservice.consul;
 2 
 3 import org.springframework.context.annotation.Bean;
 4 import org.springframework.context.annotation.Configuration;
 5 
 6 import com.orbitz.consul.Consul;
 7 
 8 @Configuration
 9 public class ConsulConfig {
10 
11     @Bean
12     public Consul consul(){
13         return Consul.builder().build();
14     }
15 }
View Code

1.4、com.microservice.consul.ConsulProperties(讀取服務註冊信息)

 1 package com.microservice.consul;
 2 
 3 import org.springframework.beans.factory.annotation.Value;
 4 import org.springframework.stereotype.Component;
 5 
 6 import lombok.Getter;
 7 import lombok.Setter;
 8 
 9 @Component
10 @Getter @Setter
11 public class ConsulProperties {
12 
13     @Value("${service.name}")
14     private String servicename;
15     @Value("${service.port:8080}")
16     private int servicePort;
17     @Value("${service.tag:dev}")
18     private String serviceTag;
19     
20     @Value("${health.url}")
21     private String healthUrl;
22     @Value("${health.interval:10}")
23     private int healthInterval;
24     
25 }
View Code

1.5、com.microservice.consul.ConsulRegisterListener(ContextRefreshEvent監聽器:用於服務啟動註冊

 1 package com.microservice.consul;
 2 
 3 import java.net.MalformedURLException;
 4 import java.net.URI;
 5 
 6 import org.springframework.context.ApplicationListener;
 7 import org.springframework.context.event.ContextRefreshedEvent;
 8 
 9 import com.orbitz.consul.AgentClient;
10 import com.orbitz.consul.Consul;
11 
12 /**
13  * 監聽contextrefresh事件
14  */
15 public class ConsulRegisterListener implements ApplicationListener<ContextRefreshedEvent> {
16 
17     @Override
18     public void onApplicationEvent(ContextRefreshedEvent event) {
19         Consul consul = event.getApplicationContext().getBean(Consul.class);
20         ConsulProperties prop = event.getApplicationContext().getBean(ConsulProperties.class);
21 
22         AgentClient agentClient = consul.agentClient();
23         try {
24             agentClient.register(prop.getServicePort(), 
25                                  URI.create(prop.getHealthUrl()).toURL(),
26                                  prop.getHealthInterval(), 
27                                  prop.getServicename(), 
28                                  prop.getServicename(), // serviceId:
29                                  prop.getServiceTag());
30         } catch (MalformedURLException e) {
31             e.printStackTrace();
32         }
33     }
34 
35 }
View Code

負載均衡相關

1.6、com.microservice.loadBalancer.ServerAddress(伺服器封裝類)

 1 package com.microservice.loadBalancer;
 2 
 3 import lombok.AllArgsConstructor;
 4 import lombok.Getter;
 5 import lombok.Setter;
 6 
 7 /**
 8  * 這裡只做簡單的封裝,如果需要複雜的,可以使用java.net.InetAddress類
 9  */
10 @Getter @Setter
11 @AllArgsConstructor
12 public class ServerAddress {
13     private String ip;
14     private int port;
15 }
View Code

1.7、com.microservice.loadBalancer.MyLoadBalancer(服務發現+負載均衡

 1 package com.microservice.loadBalancer;
 2 
 3 import java.util.ArrayList;
 4 import java.util.List;
 5 import java.util.Random;
 6 
 7 import org.springframework.beans.factory.annotation.Autowired;
 8 import org.springframework.stereotype.Component;
 9 
10 import com.orbitz.consul.Consul;
11 import com.orbitz.consul.HealthClient;
12 import com.orbitz.consul.model.health.ServiceHealth;
13 
14 /**
15  * 實現思路:
16  * 1、拉取可用服務列表(服務發現)serverList
17  * 2、緩存到本地guava cache中去,以後每隔10min從consulServer拉取一次(這裡這樣做的原因,是因為consul沒有做這樣的事)
18  * 3、使用配置好的路由演算法選出其中1台,執行邏輯
19  */
20 @Component
21 public class MyLoadBalancer {
22     
23     @Autowired
24     private Consul consul;
25     
26     /**
27      * 獲取被調服務的服務列表
28      * @param serviceName 被調服務
29      */
30     public List<ServerAddress> getAvailableServerList(String serviceName){
31         List<ServerAddress> availableServerList = new ArrayList<>();
32         HealthClient healthClient = consul.healthClient();//獲取Health http client
33         List<ServiceHealth> availableServers = healthClient.getHealthyServiceInstances(serviceName).getResponse();//從本地agent查找所有可用節點
34         availableServers.forEach(x->availableServerList.add(new ServerAddress(x.getNode().getAddress(), x.getService().getPort())));
35         return availableServerList;
36     } 
37     
38     /**
39      * 選擇一臺伺服器
40      * 這裡使用隨機演算法,如果需要換演算法,我們可以抽取介面進行編寫
41      */
42     public ServerAddress chooseServer(String serviceName){
43         List<ServerAddress> servers = getAvailableServerList(serviceName);
44         Random random = new Random();
45         int index = random.nextInt(servers.size());
46         return servers.get(index);
47     }
48     
49 }
View Code

說明:

  • 在該類中提供了服務發現的方法;
  • 提供了一個負載均衡演算法(隨機演算法)

retrofit通信相關

1.8、com.microservice.retrofit(通信類)

 1 package com.microservice.retrofit;
 2 
 3 import org.springframework.beans.factory.annotation.Autowired;
 4 import org.springframework.stereotype.Component;
 5 
 6 import com.microservice.loadBalancer.MyLoadBalancer;
 7 import com.microservice.loadBalancer.ServerAddress;
 8 
 9 import retrofit.RestAdapter;
10 
11 @Component
12 public class RestAdapterConfig {
13 
14     @Autowired
15     private MyLoadBalancer myLoadBalancer;
16     
17     /**
18      * 負載均衡並且創建傳入的API介面實例
19      */
20     public <T> T create(Class<T> tclass, String serviceName) {
21         ServerAddress server = myLoadBalancer.chooseServer(serviceName);
22         String endPointUrl = new StringBuilder("http://").append(server.getIp())
23                                                          .append(":")
24                                                          .append(server.getPort()).toString(); 
25         RestAdapter adapter = new RestAdapter.Builder()
26                 .setEndpoint(endPointUrl).build();
27         T tclassInstance = adapter.create(tclass);
28         return tclassInstance;
29     }
30 }
View Code

說明:該類定義了一個泛型方法,在該方法中:首先根據負載均衡選擇一臺伺服器,之後使用RestAdapter指定訪問的伺服器,最後創建出相應的serviceClientAPI介面的實例(具體看下邊)

註意:我們可以設置retrofit使用的http的client,下一節會介紹。

 

2、myserviceA

pom.xml(總pom,引入上邊的framework基礎框架)

 1 <?xml version="1.0" encoding="UTF-8"?>
 2 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 3     xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
 4 
 5     <modelVersion>4.0.0</modelVersion>
 6 
 7     <parent>
 8         <groupId>org.springframework.boot</groupId>
 9         <artifactId>spring-boot-starter-parent</artifactId>
10         <version>1.3.0.RELEASE</version>
11     </parent>
12 
13     <groupId>com.microservice</groupId>
14     <artifactId>myserviceA</artifactId>
15     <version>1.0-SNAPSHOT</version>
16     <packaging>pom</packaging>
17 
18     <properties>
19         <java.version>1.8</java.version><!-- 官方推薦 -->
20     </properties>
21 
22     <modules>
23         <module>server</module>
24         <module>client</module>
25     </modules>
26 
27     <!-- 引入實際依賴 -->
28     <dependencies>
29         <dependency>
30             <groupId>org.springframework.boot</groupId>
31             <artifactId>spring-boot-starter-web</artifactId>
32         </dependency>
33         <dependency>
34             <groupId>com.microservice</groupId>
35             <artifactId>framework</artifactId>
36             <version>1.0-SNAPSHOT</version>
37         </dependency>
38     </dependencies>
39 </project>
View Code

2.1、myserviceA-server

2.1.1、pom.xml

 1 <?xml version="1.0" encoding="UTF-8"?>
 2 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 3     xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
 4 
 5     <modelVersion>4.0.0</modelVersion>
 6     
 7     <parent>
 8         <groupId>com.microservice</groupId>
 9         <artifactId>myserviceA</artifactId>
10         <version>1.0-SNAPSHOT</version>
11     </parent>
12 
13     	   

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 適用場合: 7.3 工廠模式的適用場合 創建新對象最簡單的辦法是使用new關鍵字和具體類。只有在某些場合下,創建和維護對象工廠所帶來的額外複雜性才是物有所值。本節概括了這些場合。 7.3.1 動態實現 如果需要像前面自行車的例子一樣,創建一些用不同方式實現同一介面的對象,那麼可以使用一個工廠方法或簡 ...
  • http://blog.csdn.net/hil2000/article/details/41261267/ 一.我為什麼要學習go語言 當今已經是移動和雲計算時代,Go出現在了工業向雲計算轉型的時刻,簡單、高效、內 置併發原語和現代的標準庫讓Go語言尤其適合雲端軟體開發(畢竟它就是為此而設計的)。 ...
  • 上一篇 從引用傳遞到設計模式 (上) 的文末,提到非虛擬介面 NVI 的實現,即將虛函數聲明為保護型或私有型,藉由模板函數模式來實現 。 園友 @KillU 看的很仔細,提出了一個問題:虛函數是 private 類型,繼承可以麽? 答案是:可以 5 實現權和調用權 <Effective C++> 中 ...
  • 需求描述: 解決過程: 百度一番無果,google一番有了答案。 解決方案: android6.0(api=23)以後直接打開文件,讓系統去判斷如何處理。詳細解決方案見如下地址: http://www.jianshu.com/p/d896a09b9aca 原因分析: http://stackover ...
  • Installation Requirements: Eclipse 4.5 (Mars) or later. Java VM version 8 or later. Gocode and Go oracle. Instructions: For an Eclipse package without ...
  • 這裡來講解一下Java8 新特性中的函數式介面, 以及和Lambda 表達式的關係。看到過很多不少介紹Java8特性的文章,都會介紹到函數式介面和lambda表達式,但是都是分別介紹,沒有將兩者的關係說明清楚,在這裡,把自己的理解整理如下: 一、函數式介面: 函數式介面其實本質上還是一個介面,但是它 ...
  • FastDFS是一個開源的輕量級分散式文件系統,由跟蹤伺服器(tracker server)、存儲伺服器(storage server)和客戶端(client)三個部分組成,主要解決了海量數據存儲問題,特別適合以中小文件(建議範圍:4KB < file_size <500MB)為載體的線上服務。 S ...
  • SOLID 是面向對象設計5大重要原則的首字母縮寫,當我們設計類和模塊時,遵守 SOLID 原則可以讓軟體更加健壯和穩定。那麼,什麼是 SOLID 原則呢?本篇文章我將談談 SOLID 原則在軟體開發中的具體使用。 單一職責原則(SRP) 單一職責原則(SRP)表明一個類有且只有一個職責。一個類就像 ...
一周排行
    -Advertisement-
    Play Games
  • 示例項目結構 在 Visual Studio 中創建一個 WinForms 應用程式後,項目結構如下所示: MyWinFormsApp/ │ ├───Properties/ │ └───Settings.settings │ ├───bin/ │ ├───Debug/ │ └───Release/ ...
  • [STAThread] 特性用於需要與 COM 組件交互的應用程式,尤其是依賴單線程模型(如 Windows Forms 應用程式)的組件。在 STA 模式下,線程擁有自己的消息迴圈,這對於處理用戶界面和某些 COM 組件是必要的。 [STAThread] static void Main(stri ...
  • 在WinForm中使用全局異常捕獲處理 在WinForm應用程式中,全局異常捕獲是確保程式穩定性的關鍵。通過在Program類的Main方法中設置全局異常處理,可以有效地捕獲並處理未預見的異常,從而避免程式崩潰。 註冊全局異常事件 [STAThread] static void Main() { / ...
  • 前言 給大家推薦一款開源的 Winform 控制項庫,可以幫助我們開發更加美觀、漂亮的 WinForm 界面。 項目介紹 SunnyUI.NET 是一個基於 .NET Framework 4.0+、.NET 6、.NET 7 和 .NET 8 的 WinForm 開源控制項庫,同時也提供了工具類庫、擴展 ...
  • 說明 該文章是屬於OverallAuth2.0系列文章,每周更新一篇該系列文章(從0到1完成系統開發)。 該系統文章,我會儘量說的非常詳細,做到不管新手、老手都能看懂。 說明:OverallAuth2.0 是一個簡單、易懂、功能強大的許可權+可視化流程管理系統。 有興趣的朋友,請關註我吧(*^▽^*) ...
  • 一、下載安裝 1.下載git 必須先下載並安裝git,再TortoiseGit下載安裝 git安裝參考教程:https://blog.csdn.net/mukes/article/details/115693833 2.TortoiseGit下載與安裝 TortoiseGit,Git客戶端,32/6 ...
  • 前言 在項目開發過程中,理解數據結構和演算法如同掌握蓋房子的秘訣。演算法不僅能幫助我們編寫高效、優質的代碼,還能解決項目中遇到的各種難題。 給大家推薦一個支持C#的開源免費、新手友好的數據結構與演算法入門教程:Hello演算法。 項目介紹 《Hello Algo》是一本開源免費、新手友好的數據結構與演算法入門 ...
  • 1.生成單個Proto.bat內容 @rem Copyright 2016, Google Inc. @rem All rights reserved. @rem @rem Redistribution and use in source and binary forms, with or with ...
  • 一:背景 1. 講故事 前段時間有位朋友找到我,說他的窗體程式在客戶這邊出現了卡死,讓我幫忙看下怎麼回事?dump也生成了,既然有dump了那就上 windbg 分析吧。 二:WinDbg 分析 1. 為什麼會卡死 窗體程式的卡死,入口門檻很低,後續往下分析就不一定了,不管怎麼說先用 !clrsta ...
  • 前言 人工智慧時代,人臉識別技術已成為安全驗證、身份識別和用戶交互的關鍵工具。 給大家推薦一款.NET 開源提供了強大的人臉識別 API,工具不僅易於集成,還具備高效處理能力。 本文將介紹一款如何利用這些API,為我們的項目添加智能識別的亮點。 項目介紹 GitHub 上擁有 1.2k 星標的 C# ...