学习笔记—微服务—技术栈实践(3)—微服务之间的相互调用

微服务之间的相互调用

  服务多了,端口IP自然也就多了,用传统的带上IP和端口的HTTP进行Request甚至用更久远的UDP来进行通信,显然是不合理的。

  尤其是对于微服务架构来说,很多功能需要调用多项服务才能完成,这时候,服务之间如何相互调用就成为了一个相当关键的问题,

  首先,如果直接采用RestTemplate的方式进行服务之间的通信怎么样呢?

  如下代码所示:

1
2
3
4
@Bean
public RestTemplate getRestTemplate(){
return new RestTemplate();
}
1
2
3
4
5
6
7
8
9
@Autowired
private RestTemplate restTemplate;

@GetMapping("/test")
public String test(){
String url = "http://localhost:8081/test";
String result = restTemplate.getForObject(url, String.class);
return result;
}

  这种方式虽然可行,但是代码显得有些冗余,而且如果需要调用多个服务,那么代码就会显得十分混乱,相当于是做了一个硬编码,IP地址等都有了,如果服务提供方的地址端口发生了变化,该怎么做呢?当然是手动修改代码,如果有多个实例呢?通过Nginx实现服务的负载均衡?显然是不美丽的?实例增加了呢?所以,问题是很多的。

  因此,SpringCloud提供了一个叫做OpenFeign的组件,这个组件非常好用。

  可以简化RestTemplate的调用,使得代码看起来更加简洁。更为重要的是,通过OpenFeign,可以解决很多的上述的问题,具体在后文中进行实践与分析。

Restful风格的调用

  在了解OpenFeign之前,首先需要对于Restful风格的调用做了解。

  所谓RESTful调用就是基于REST(Representational State Transfer)架构风格的网络服务调用方式。主要用于 Web 服务之间的通信,强调资源的表示、状态转移和无状态通信。

  对于RESTful架构来说,一个核心的概念是资源(Resource),所有的内容都被视为资源,比如用户、订单、文件等等,通常会通过URL来标识,比如/user/1就表示ID是1的用户,/order/12就表示ID为12的订单。

  另外,RESTful API 使用 HTTP 动词来定义对资源的操作。比如GET是获取资源,POST是创建资源、PUT是创建新资源、DELETE是删除等等。

  比如,GET /user/1就是获取用户为1的资源信息。

  RESTful 服务是无状态的,即每个请求都是独立的,不依赖于之前的请求。所有需要的信息(如认证信息、资源标识等)都应包含在每个请求中。

  RESTful API 会以不同的表现形式返回资源,如 JSON、XML 等。客户端通过解析这些表现形式,获取资源的状态。

  RESTful 调用使用 HTTP 状态码来表示操作的结果:

  200 OK:请求成功,返回资源。

  201 Created:请求成功,并创建了一个新的资源。

  400 Bad Request:请求无效,服务器无法理解请求的内容。

  401 Unauthorized:请求需要身份验证。

  403 Forbidden:服务器拒绝请求。

  404 Not Found:请求的资源不存在。

  500 Internal Server Error:服务器内部错误。

  总结来说,RESTful 调用是一种简洁、直观的 API 设计风格,基于 HTTP 协议,通过标准的 HTTP 方法和状态码,清晰地定义资源的操作。可以说,RESTful是如何通过HTTP进行WEB服务设计的一种最佳实践。

HTTP和Feign

  Feign是对RESTful API的客户端的封装调用,帮助开发者更轻松地和RESTful服务进行交互。
  HTTP 和 Feign 之间的关联和区别主要体现在它们用于服务通信的方式上。HTTP 是底层的网络协议,而 Feign 是一个基于 HTTP 的声明式 Web 服务客户端。

  Feign基于HTTP协议发出请求处理响应,但是简化了 HTTP 请求的代码。Feign 允许开发者通过声明式的方式定义接口,而不用手动处理底层 HTTP 请求的细节。

  所以,简单的说,Feign的本质就是在HTTP之上进行了一层封装,简化了开发工作。

  做个HTTPClient发送HTTP请求和通过Feign发送请求的对比:

1
2
3
4
5
6
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("http://example.com/users/1"))
.build();
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
1
2
3
4
5
6
7
8
public interface UserClient {
@RequestLine("GET /users/{id}")
User getUserById(@Param("id") Long id);
}

// Feign 客户端构造
UserClient client = Feign.builder().target(UserClient.class, "http://example.com");
User user = client.getUserById(1);

最后,用一个图解来解释RESTful API、HTTP和Feign之间的关系:

1
2
3
4
5
6
7
8
9
10
11
12
           RESTful API
(设计规范,基于HTTP)

|
+------------------------+
| HTTP 协议 |
+------------------------+
↑ ↑
| |
Feign 客户端 HttpClient等
(封装了HTTP调用) (直接调用HTTP)

OpenFeign

  OpenFeign是SpringCloud的一个组件。他的中心思想在于通过提供一种声明式、注解驱动的接口化服务调用方式,极大地简化了微服务架构中的RESTful API调用以及服务间通信的复杂性。它使得开发者可以聚焦于业务逻辑本身,如同调用本地方法一样便捷地调用远程服务,而不必深陷于HTTP请求细节的实现。

  OpenFeign有以下主要特点:

  1. 声明式HTTP客户端:通过定义接口和注解,可以轻松地发起HTTP请求,并自动处理响应。
  2. 支持Spring MVC注解:可以直接使用Spring MVC的注解,如@GetMapping、@PostMapping等,来定义请求的URL、请求方法、请求参数等。
  3. 支持负载均衡:与Ribbon集成,可以自动实现服务实例的负载均衡。
  4. 支持Hystrix熔断:与Hystrix集成,可以自动实现服务调用的熔断保护。

OpenFeign的简单使用

  首先,需要在pom.xml文件中引入OpenFeign的依赖,如下所示:

1
2
3
4
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>

  然后,在启动类上需要添加上@EnableFeignClients注解,如下所示:

1
2
3
4
5
6
7
@SpringBootApplication
@EnableFeignClients
public class Application {
public static void main(String[] args) {
SpringApplication.run(OrderApplication.class, args);
}
}

  接着,创建一个Feign的客户端接口,通过@FeignClient做注解标记,如下所示:

1
2
3
4
5
@FeignClient("user-service")
public interface UserFeignClient {
@GetMapping("/user/{id}")
User getUserById(@PathVariable("id") Long id);
}

  最后,在需要调用服务的地方,注入UserFeignClient,并调用其方法即可,如下所示:

1
2
3
4
5
6
7
8
9
@Service
public class OrderService {
@Autowired
private UserFeignClient userFeignClient;

public Order getOrderById(Long id) {
// 调用user-service的getUserById方法获取用户信息
}
}

  由此,便实现了对于该服务的一个调用。

  值得一提的是,OpenFeign集成了Ribbon这样一个客户端负载均衡器,使得OpenFeign发起的HTTP请求可以自动地在多个服务实例之间进行一个负载均衡。如果想要自定义这样一个负载均衡策略,则需要引入ribbon再做进一步的操作。

消息中间件

  对于微服务之间的消息通信来说,如果只是靠着OpenFeign这样的http客户端来实现微服务之间的通信,在很多地方是存在缺口的。

  尤其是对于一些高并发、大量甚至海量数据的传递来说,是有问题的,OpenFeign进行服务之间的同步调用,而也需要将耗时长量大的消息放入消息队列做异步的处理也是相当重要的,因此,对于消息中间件的详细使用见后文内容。


学习笔记—微服务—技术栈实践(3)—微服务之间的相互调用
https://gagaducko.github.io/2024/09/09/学习笔记—微服务—技术栈实践-3-—微服务之间的相互调用/
作者
gagaduck
发布于
2024年9月9日
许可协议