0. 简介
0.1 目录
0.2 引言
针对不同环境和目标的客户和服务可以通过不同的机制进行通信。根据协议,它可以是同步的或异步的。
同步通信-请求响应方法
在同步通信中,需要一个预定义的源服务地址,确切地将请求发送到何处,并且该服务(主叫方和被叫方)目前都应已启动。尽管协议可能是同步的,但I/O操作可以是异步的,其中客户端不必等待响应。这是I/O和协议的区别。 Web API通用的通用请求-响应方法包括REST,GraphQL和gRPC。
异步通讯
在异步通信的情况下,呼叫者不必具有被呼叫者的特定目的地。一次处理多个使用者变得相对容易(因为服务可能会增加使用者)。此外,如果接收服务关闭,则消息将排队,然后在接收服务打开时继续处理。从松散耦合,多服务通信以及应对部分服务器故障的角度来看,这尤其重要。这些是使微服务倾向于异步通信的决定性因素。诸如MQTT,STOMP,AMQP之类的异步协议由Apache Kafka Stream,RabbitMQ之类的平台处理。
理解何时何地使用同步模型与异步模型是设计有效的微服务通信的基础性决策。
作者:Morgan Yong
链接:https://zhuanlan.zhihu.com/p/302599305
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
同步通信与HTTP协议紧密相关,SpringCloud采用HTTP协议进行同步通信。本文介绍了SpringCloud关于同步通信的重要组件和软件。
0.3 思考
-
如何解决微服务间的服务通信问题?
-
TTP REST方式:使用HTTP协议进行数据传输,JSON格式(SpringCloud使用HTTP协议进行数据传输
-
RPC方式:远程过程调用,二进制
-
-
为什么大多数服务间通信组件使用HTTP协议而不是RPC?
OSI:物理层 -> 数据链路层 -> 网络层 -> 传输层(RPC) -> 会话层 -> 表示层 -> 应用层(HTTP)
RPC性能比HTTP好,但是RPC要求两个服务必须使用同一种编程语言,如Dubbo(高性能RPC远程接口调用框架)就要求调用和被调用服务都是用Java编写,这使得其他语言都不能使用该框架,局限性非常大。
HTTP: 应用层协议,使用HTTP Rest方式,使用JSON作为传输数据的格式进行通信;高度解耦,效率低
RPC: 传输层协议,直接使用对象二进制方式传递数据,耦合度高,效率高。代表:Dubbo
-
如何在Java代码中发起一个HTTP请求?(来进行微服务间通信)
- Spring框架提供了一个HttpClient对象
RestTemplate
(不是SpringCloud的一个组件,就是一个对象而已,相当于Java中的浏览器),发起一个http请求(让它模拟浏览器,可以发起GET
,POST
…)
- Spring框架提供了一个HttpClient对象
-
实现服务间通信(案例)
服务注册中心:Consul
客户端:用户服务(USERS),订单服务(ORDERS)
-
服务间通信需要解决的问题
- 使用哪种方式通信? – HTTP(SpringCloud); RPC(Dubbo)
- 服务调用的负载均衡? – Ribbon(Netflix)…
1. RestTemplate
1.0 简介
-
RestTemplate是Spring提供的用于访问Rest服务的客户端,RestTemplate提供了多种便捷访问远程Http服务的方法,能够大大提高客户端的编写效率。
-
RestTemplate是Spring用于同步client端的核心类,简化了与http服务的通信,并满足RestFul原则,程序代码可以给它提供URL,并提取结果。默认情况下,RestTemplate默认依赖jdk的HTTP连接工具。当然你也可以 通过setRequestFactory属性切换到不同的HTTP源,比如Apache HttpComponents、Netty和OkHttp。
-
RestTemplate能大幅简化了提交表单数据的难度,并且附带了自动转换JSON数据的功能
关于RestTemplate的详情这里不介绍,只是作为一个工具在这里使用,为了突出该工具在微服务间通信时的不足,进而介绍其他组件。
1.1 案例
实现用户服务和订单服务的服务间通信
这里以用户服务为例:
-
创建项目
springcloud_04_users
-
pom.xml
引入依赖:<dependencies> <!--springboot--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!--consul--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-consul-discovery</artifactId> </dependency> <!--actuator--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency> </dependencies>
-
application.properties
配置用户服务
server.port=8888 spring.application.name=USERS
订单服务:
server.port=9999 spring.application.name=ORDERS
-
开发入口类
@SpringBootApplication @EnableDiscoveryClient // public class UsersApplication { public static void main(String[] args) { SpringApplication.run(UsersApplication.class, args); } }
从Spring Cloud Edgware开始,
@EnableDiscoveryClient
或@EnableEurekaClient
可省略。只需加上相关依赖,并进行相应配置,即可将微服务注册到服务发现组件上。 -
登陆consul UI界面查看服务是否注册成功
-
简单为两个服务个字添加一个Controller,实现一个demo:
此时两个服务想要通信(获取对方数据),必须通过URLhttp://localhost:8888/user或者http://localhost:9999/orderf,发起HTTP请求。要实现这一点,上面已经提到,Spring为我们封装了一个HttpClient对象
RestTemplate
,这个对象有HTTP的GET
,POST
…方法,具体用法:OrderController
@RestController public class OrderController { private static final Logger log = LoggerFactory.getLogger(OrderController.class); @GetMapping("order") public String demo() { log.info("Oder demo running ..."); return "order demo OK!"; } }
UserController
@RestController public class UserController { private static final Logger log = LoggerFactory.getLogger(UserController.class); @GetMapping("user") public String invokeDemo() { log.info("User demo running ..."); RestTemplate restTemplate = new RestTemplate(); String orderResult = restTemplate.getForObject("http://localhost:9999/order", String.class); log.info("订单服务调用成功:{}", orderResult); return "调用Order服务成功,结果为: " + orderResult; } }
1.2 问题
RestTemplate restTemplate = new RestTemplate();
String orderResult = restTemplate.getForObject("http://localhost:9999/order", String.class);
现有的直接使用RestTemplate的方式实现服务间通信存在什么问题?
- 没有把服务注册中心利用起来
- 调用服务的主机地址和端口直接写死在url中,无法实现集群的负载均衡
- 被调用服务的请求路径写死在代码中,倘若路径发生变化不利于后期维护
- 不能自动转换响应结果为对应的对象(可由Feign/OpenFeign解决)
解决RestTemplate的负载均衡问题?
a. 自定义负载均衡的策略(最简单的策略,随机
b. 使用SpringCloud提供组件Ribbon来解决负载均衡调用(推荐)
2. Ribbon
Spring Cloud Ribbon是一个基于HTTP和TC