微服務與微服務之間通信。 一、通信協議 我們選用的通信協議是http,其實現工具是retrofit。 特點:實現簡單,但是速度相較於tcp協議是慢一些 如果對速度要求很高,可以使用tcp協議,實現產品可選用mina2/netty 特點:實現簡單,但是速度相較於tcp協議是慢一些 二、服務路由 說明: ...
微服務與微服務之間通信。
一、通信協議
- 我們選用的通信協議是http,其實現工具是retrofit。
- 特點:實現簡單,但是速度相較於tcp協議是慢一些
- 如果對速度要求很高,可以使用tcp協議,實現產品可選用mina2/netty
二、服務路由
說明:不使用netflix的ribbon做服務路由,自己來實現。
實現思路:
- 拉取可用服務列表(服務發現)serverList
- 緩存到本地guava cache中去,以後每隔10min從consulServer拉取一次(原本打算這樣做),但是consulServer自己通過gossip協議會將服務數據廣播給consulClient,每次獲取伺服器列表的時候,都是直接從本地agent(即consulClient)獲取。
- 使用配置好的路由演算法選出其中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