Appearance
RPC、服务调用与 OpenFeign
系统一旦从单体走向多服务,马上就会碰到一个非常现实的问题:一个服务怎么调用另一个服务。
这就是服务调用主线。
很多人一提到 RPC,又会马上联想到 Feign,但这两个词并不是完全等价的。
这篇文章重点讲:
RPC到底是什么- HTTP 调用和 RPC 调用是什么关系
OpenFeign在 Spring Cloud 里扮演什么角色- 它解决什么问题
- 服务调用里真正要注意的工程边界是什么
1. RPC 到底是什么
RPC 是 Remote Procedure Call,即远程过程调用。
直接看成:让你像调用本地方法一样去发起远程服务调用。
这里最重要的不是“像方法调用”,而是:一次调用跨了进程、跨了机器、跨了网络。
所以 RPC 真正解决的是:服务和服务之间如何建立一套更稳定、更统一的调用模型。
2. 为什么服务调用不能简单理解成“发个 HTTP 请求”
当然,很多服务调用底层确实是 HTTP。
但企业开发真正要处理的,不只是“能不能打通”,还包括:
- 服务地址怎么发现
- 调用接口怎么声明
- 超时怎么控制
- 失败怎么重试或熔断
- 请求头、鉴权、链路信息怎么透传
所以服务调用主线更适合直接记成:远程调用 = 协议 + 发现 + 序列化 + 超时 + 容错 + 治理。
3. RPC 和 HTTP 是什么关系
这部分特别容易混。
更稳妥的理解是:
RPC是一种调用模型- HTTP 是一种传输协议
RPC 可以基于 HTTP 实现,也可以基于其他协议实现。
所以不要把 “RPC” 和 “HTTP” 讲成非此即彼的关系。
4. OpenFeign 到底是什么
OpenFeign 可以理解成 Spring Cloud 生态里一种声明式的 HTTP 客户端。
它最核心的价值是:把远程 HTTP 调用从手写请求代码,变成接口声明式调用。
你可以直接把它理解成:用接口描述远程服务,再由框架帮你生成调用实现。
5. 为什么很多项目喜欢用 Feign
如果不用 Feign,服务调用代码经常会散成这样:
- 手动拼 URL
- 手动处理请求头
- 手动序列化和反序列化
- 每个调用方都自己写一套 HTTP 模板代码
而 Feign 解决的是:把远程服务调用接口化、声明化。
6. 一个最基本的 Feign 示例
例如订单服务要调用库存服务:
java
/**
* 声明库存服务的远程调用客户端。
*/
@FeignClient(name = "stock-service")
public interface StockClient {
/**
* 调用库存服务执行扣减。
*
* @param request 扣减库存请求体,包含商品 ID 和扣减数量
*/
@PostMapping("/stocks/deduct")
void deduct(@RequestBody DeductStockRequest request);
}业务层里可以直接注入:
java
/**
* 下单服务示例,演示业务层如何通过 Feign 客户端发起远程调用。
*/
@Service
public class OrderService {
private final StockClient stockClient;
/**
* 注入库存服务客户端。
*
* @param stockClient 用于调用库存服务的 Feign 客户端
*/
public OrderService(StockClient stockClient) {
this.stockClient = stockClient;
}
/**
* 创建订单,并同步通知库存服务扣减库存。
*
* @param command 下单命令,包含商品和数量等信息
*/
public void createOrder(CreateOrderCommand command) {
stockClient.deduct(new DeductStockRequest(command.getProductId(), command.getCount()));
}
}这个例子最想表达的是:调用方不再自己拼 HTTP 请求,而是通过接口方法表达远程调用。
7. @FeignClient 到底在做什么
@FeignClient 是 Feign 主线里最核心的注解。
它解决的是 告诉 Spring 这不是一个普通接口,而是一个远程服务调用接口。
常见属性包括:
| 属性 | 作用 |
|---|---|
name | 服务名 |
url | 直接指定调用地址 |
path | 统一前缀路径 |
configuration | 指定自定义配置 |
fallback / fallbackFactory | 指定降级处理 |
例如:
java
/**
* 声明用户服务的远程调用客户端,并指定统一路径和降级实现。
*/
@FeignClient(
name = "user-service",
path = "/users",
fallback = UserClientFallback.class)
public interface UserClient {
/**
* 按用户 ID 查询用户信息。
*
* @param id 用户主键 ID
* @return 查询到的用户信息
*/
@GetMapping("/{id}")
UserDTO getById(@PathVariable Long id);
}8. Feign 为什么经常和注册发现一起出现
因为在微服务环境里,调用方通常不会写死一个 IP 地址。
更常见的做法是:按服务名发起调用,再由注册发现体系找到可用实例。
所以 Feign 和注册中心经常配套出现,本质原因是:
- Feign 解决“怎么声明调用”
- 注册发现解决“服务实例在哪”
9. Feign 只是“更优雅的 HTTP”吗
从表面上看是这样,但工程上还不止。
因为 Feign 常常还会和下面这些能力协同:
- 负载均衡
- 超时配置
- 重试
- 熔断和降级
- 请求拦截器
- 日志和链路透传
所以更适合直接记成:Feign 是声明式服务调用入口,但真正可用的企业级调用链,还需要治理能力一起配合。
10. 常见注解和扩展点
| 注解 / 组件 | 作用 |
|---|---|
@EnableFeignClients | 开启 Feign 客户端扫描 |
@FeignClient | 标记远程调用接口 |
RequestInterceptor | 统一拦截请求,透传 token / traceId |
fallback | 指定调用失败时的兜底实现 |
例如启动类:
java
/**
* 开启 Feign 客户端扫描的应用启动类。
*/
@SpringBootApplication
@EnableFeignClients
public class OrderApplication {
}例如统一透传请求头:
java
/**
* Feign 调用链上的公共配置。
*/
@Configuration
public class FeignConfig {
/**
* 为每次 Feign 调用统一追加请求头。
*
* @return 一个会向请求模板写入来源标识的拦截器
*/
@Bean
public RequestInterceptor requestInterceptor() {
return template -> template.header("X-Source", "order-service");
}
}11. fallback 到底在解决什么问题
远程调用一定要接受一个现实:下游服务可能随时失败、超时或不可用。
这时 fallback 解决的是:当远程调用失败时,系统有没有一个可控的兜底行为。
例如:
java
/**
* 用户服务调用失败时的降级实现。
*/
@Component
public class UserClientFallback implements UserClient {
/**
* 当远程调用失败时,返回一个兜底的用户对象。
*
* @param id 用户主键 ID
* @return 降级后的默认用户信息
*/
@Override
public UserDTO getById(Long id) {
return new UserDTO(id, "unknown");
}
}但要注意:fallback 不是让你把失败隐藏掉,而是让失败行为更可控。
12. RPC / Feign 这条线真正容易出问题的地方是什么
真正的问题通常不是“接口能不能调通”,而是:
- 超时时间设得不合理
- 重试把下游打得更重
- 失败没有隔离,故障扩散
- DTO 设计混乱,服务边界模糊
- 把同步调用链拉得太长
所以企业里要注意的是:远程调用最难的部分不是语法,而是边界、超时、容错和依赖关系设计。
13. RPC、Feign 和 Dubbo 这类框架怎么区分
这部分也很常被问到。
可以直接这样理解:
RPC是大类概念Feign更偏 Spring Cloud 里的声明式 HTTP 调用Dubbo更偏专门的 RPC 框架体系
Feign 是企业微服务里很常见的一种调用方式,但它不等于整个 RPC 世界。
14. 工程上最容易混的几个边界
14.1 误区一:Feign 就是 RPC 的全部
不是。
Feign 只是服务调用体系里一种常见实现方式。
14.2 误区二:服务调用成功率低,只要加重试就行
不一定。
下游已经过载时,重试反而可能放大问题。
14.3 误区三:远程调用看起来像本地方法,就可以按本地方法心态设计
这是非常危险的。
远程调用的本质始终是:有网络、有序列化、有超时、有失败。
15. 一句话总结
RPC / 服务调用这条线,本质上是在解决多服务之间如何建立统一、可治理的远程调用模型;而 OpenFeign 在 Spring Cloud 里最重要的价值,是把 HTTP 服务调用声明式化,但真正要把它用好,仍然要把注册发现、超时、容错和调用边界一起设计好。