🚀 gRPC vs Dubbo:RPC框架的巅峰对决!
副标题:Google的黑科技 vs 阿里的国产之光,到底选谁?🤔
2008年,阿里巴巴内部孵化了Dubbo,为解决分布式服务调用问题而生。
2015年,Google开源了gRPC,带来了全新的RPC理念。
2019年,Apache Dubbo发布3.0,全面拥抱云原生。
今天 ,我们就来一场史诗级的对决:gRPC vs Dubbo!
scss
⚔️
gRPC Dubbo
(Google) (Alibaba)
国际范儿 本土化
年轻力壮 成熟稳重
极简主义 功能丰富
📚 基础知识:什么是RPC?
RPC的本质
RPC (Remote Procedure Call) = 远程过程调用
就像打电话 ☎️:
你:喂,帮我查一下订单123的信息
对方:好的,订单123是...(查询)
对方:查到了,金额是100元
你:好的,谢谢!
本地调用 vs 远程调用:
java
// 本地调用:直接方法调用
Order order = orderService.getOrder(123L);
// 远程调用:看起来一样,实际走了网络
Order order = orderServiceRpc.getOrder(123L);
// ↑
// 底层通过网络调用远程服务
RPC的核心要素
markdown
客户端 服务端
↓ ↓
┌──────────┐ ┌──────────┐
│ Stub │ ←────────────────→ │ Skeleton │
└────┬─────┘ └─────┬────┘
│ │
┌────▼─────┐ ┌─────▼────┐
│ 序列化 │ │ 反序列化 │
└────┬─────┘ └─────┬────┘
│ │
┌────▼──────────────────────────────▼────┐
│ 网络传输 (TCP/HTTP) │
└─────────────────────────────────────────┘
🏗️ gRPC:Google的技术结晶
核心特性
1️⃣ 基于HTTP/2
HTTP/1.1的问题:
css
请求1 → [等待] → 响应1
请求2 → [等待] → 响应2
请求3 → [等待] → 响应3
串行处理,效率低下!
HTTP/2的优势:
css
请求1 ─┐
请求2 ─┼→ [并行处理] ┌─→ 响应1
请求3 ─┘ ├─→ 响应2
└─→ 响应3
多路复用,一条连接搞定所有请求!
关键特性:
- ✅ 多路复用(Multiplexing)
- ✅ 头部压缩(Header Compression)
- ✅ 服务端推送(Server Push)
- ✅ 二进制分帧(Binary Framing)
2️⃣ Protobuf序列化
对比其他序列化方式:
java
// JSON (可读,但体积大)
{
"id": 123,
"name": "iPhone 15",
"price": 5999.00
}
// 大小:约 60 bytes
// Protobuf (二进制,体积小)
[0x08, 0x7B, 0x12, 0x09, ...]
// 大小:约 20 bytes (缩小66%!)
定义Protobuf:
protobuf
syntax = "proto3";
message Product {
int64 id = 1;
string name = 2;
double price = 3;
}
service ProductService {
rpc GetProduct(ProductRequest) returns (ProductResponse);
}
生成的代码:
bash
protoc --java_out=. product.proto
生成的Java类自动包含:
- 序列化/反序列化方法
- Builder模式
- 不可变对象
- 完整的类型检查
3️⃣ 四种通信模式
java
public class ProductService extends ProductServiceGrpc.ProductServiceImplBase {
/**
* 1. 简单RPC(Unary RPC)
* 一问一答
*/
@Override
public void getProduct(ProductRequest request,
StreamObserver<ProductResponse> responseObserver) {
Product product = findProduct(request.getId());
ProductResponse response = ProductResponse.newBuilder()
.setProduct(product)
.build();
responseObserver.onNext(response);
responseObserver.onCompleted();
}
/**
* 2. 服务端流式RPC(Server Streaming RPC)
* 一问多答
*/
@Override
public void listProducts(ListRequest request,
StreamObserver<Product> responseObserver) {
List<Product> products = findAllProducts();
for (Product product : products) {
responseObserver.onNext(product); // 多次返回
}
responseObserver.onCompleted();
}
/**
* 3. 客户端流式RPC(Client Streaming RPC)
* 多问一答
*/
@Override
public StreamObserver<OrderItem> createOrder(
StreamObserver<OrderResponse> responseObserver) {
return new StreamObserver<OrderItem>() {
private List<OrderItem> items = new ArrayList<>();
@Override
public void onNext(OrderItem item) {
items.add(item); // 接收多个
}
@Override
public void onCompleted() {
Order order = saveOrder(items);
OrderResponse response = OrderResponse.newBuilder()
.setOrderId(order.getId())
.build();
responseObserver.onNext(response);
responseObserver.onCompleted();
}
@Override
public void onError(Throwable t) {
log.error("创建订单失败", t);
}
};
}
/**
* 4. 双向流式RPC(Bidirectional Streaming RPC)
* 多问多答
*/
@Override
public StreamObserver<ChatMessage> chat(
StreamObserver<ChatMessage> responseObserver) {
return new StreamObserver<ChatMessage>() {
@Override
public void onNext(ChatMessage message) {
// 收到消息立即响应
ChatMessage response = processMessage(message);
responseObserver.onNext(response);
}
@Override
public void onCompleted() {
responseObserver.onCompleted();
}
@Override
public void onError(Throwable t) {
log.error("聊天异常", t);
}
};
}
}
应用场景:
模式 | 场景 | 例子 |
---|---|---|
Unary | 普通API调用 | 查询订单详情 |
Server Streaming | 大数据量返回 | 日志流、消息推送 |
Client Streaming | 大文件上传 | 分片上传视频 |
Bidirectional | 实时通信 | 聊天、游戏 |
4️⃣ 完整示例
1. 定义服务(product.proto):
protobuf
syntax = "proto3";
option java_package = "com.example.grpc";
option java_outer_classname = "ProductProto";
message ProductRequest {
int64 id = 1;
}
message ProductResponse {
int64 id = 1;
string name = 2;
double price = 3;
string description = 4;
}
service ProductService {
rpc GetProduct(ProductRequest) returns (ProductResponse);
rpc ListProducts(Empty) returns (stream ProductResponse);
}
message Empty {}
2. 服务端实现:
java
@GrpcService
public class ProductServiceImpl extends ProductServiceGrpc.ProductServiceImplBase {
@Autowired
private ProductRepository productRepository;
@Override
public void getProduct(ProductRequest request,
StreamObserver<ProductResponse> responseObserver) {
Product product = productRepository.findById(request.getId())
.orElseThrow(() -> new RuntimeException("Product not found"));
ProductResponse response = ProductResponse.newBuilder()
.setId(product.getId())
.setName(product.getName())
.setPrice(product.getPrice())
.setDescription(product.getDescription())
.build();
responseObserver.onNext(response);
responseObserver.onCompleted();
}
}
3. 客户端调用:
java
@Service
public class ProductClient {
private final ProductServiceGrpc.ProductServiceBlockingStub blockingStub;
public ProductClient(ManagedChannel channel) {
this.blockingStub = ProductServiceGrpc.newBlockingStub(channel);
}
public ProductResponse getProduct(Long productId) {
ProductRequest request = ProductRequest.newBuilder()
.setId(productId)
.build();
try {
return blockingStub.getProduct(request);
} catch (StatusRuntimeException e) {
log.error("RPC调用失败: {}", e.getStatus());
throw e;
}
}
}
gRPC的优缺点
优点 ✅
- 性能极高:Protobuf + HTTP/2
- 跨语言:支持10+种语言
- 流式支持:天然支持4种流式模式
- 生态完善:Google背书
缺点 ❌
- 学习曲线陡:需要学Protobuf
- 调试困难:二进制协议不可读
- 浏览器支持差:需要grpc-web
- 国内生态弱:中文资料少
🐘 Dubbo:阿里的开源力作
核心特性
1️⃣ 多协议支持
java
// Dubbo支持多种协议
@Service(protocol = "dubbo") // Dubbo协议(默认)
public class ProductServiceImpl implements ProductService {}
@Service(protocol = "rest") // REST协议
public class UserServiceImpl implements UserService {}
@Service(protocol = "grpc") // gRPC协议(Dubbo 3.0+)
public class OrderServiceImpl implements OrderService {}
Dubbo协议特点:
- 基于TCP长连接
- 单一长连接NIO异步通信
- Hessian2序列化(默认)
- 适合小数据量大并发
2️⃣ 丰富的负载均衡策略
java
@Service(
loadbalance = "random", // 随机
// loadbalance = "roundrobin", // 轮询
// loadbalance = "leastactive", // 最少活跃调用
// loadbalance = "consistenthash" // 一致性Hash
)
public class OrderServiceImpl implements OrderService {
// ...
}
生活比喻 🏪:
随机(Random):
超市有3个收银台
你闭着眼睛随便选一个
轮询(RoundRobin):
erlang
客人按顺序排队
1号台 → 2号台 → 3号台 → 1号台...
最少活跃(LeastActive):
arduino
哪个收银台人少就去哪个
类似"智能排队系统"
一致性Hash(ConsistentHash):
根据你的会员卡号分配固定的收银台
保证同一个人总是去同一个台
3️⃣ 服务治理功能
java
@Configuration
public class DubboConfig {
/**
* 1. 服务降级
*/
@Bean
public ProviderConfig providerConfig() {
ProviderConfig config = new ProviderConfig();
config.setMock("fail:return null"); // 失败返回null
return config;
}
/**
* 2. 服务限流
*/
@Service(
executes = 10, // 服务端最大并发执行数
actives = 5 // 客户端最大并发调用数
)
public class OrderService {}
/**
* 3. 重试机制
*/
@Reference(
retries = 2, // 失败重试2次(总共3次)
timeout = 3000 // 超时时间3秒
)
private UserService userService;
/**
* 4. 异步调用
*/
@Reference(async = true)
private ProductService productService;
public void asyncCall() {
productService.getProduct(123L); // 异步调用
// 获取Future
Future<Product> future = RpcContext.getContext().getFuture();
Product product = future.get(); // 阻塞等待结果
}
}
4️⃣ 注册中心支持
scss
Dubbo支持的注册中心:
├── Zookeeper ⭐⭐⭐ (最常用)
├── Nacos ⭐⭐⭐ (阿里推荐)
├── Consul
├── Etcd
├── Eureka
└── Redis
服务注册流程:
markdown
┌─────────┐ ┌──────────┐
│ Provider│──① 注册服务──→│Zookeeper │
└─────────┘ └────┬─────┘
│
② 订阅服务
│
┌─────────┐ ┌────▼─────┐
│Consumer │←──③ 推送变更──│Zookeeper │
└────┬────┘ └──────────┘
│
④ 直接调用
│
▼
┌─────────┐
│Provider │
└─────────┘
5️⃣ 完整示例
1. 定义接口:
java
public interface OrderService {
/**
* 创建订单
*/
Order createOrder(OrderRequest request);
/**
* 查询订单
*/
Order getOrder(Long orderId);
}
2. 服务提供者:
java
@DubboService(
version = "1.0.0",
timeout = 3000,
retries = 2,
loadbalance = "random"
)
public class OrderServiceImpl implements OrderService {
@Autowired
private OrderRepository orderRepository;
@Override
public Order createOrder(OrderRequest request) {
Order order = new Order();
order.setUserId(request.getUserId());
order.setProductId(request.getProductId());
order.setAmount(request.getAmount());
return orderRepository.save(order);
}
@Override
public Order getOrder(Long orderId) {
return orderRepository.findById(orderId)
.orElseThrow(() -> new RuntimeException("Order not found"));
}
}
3. 服务消费者:
java
@Service
public class OrderClient {
@DubboReference(
version = "1.0.0",
timeout = 3000,
check = false // 启动时不检查服务是否可用
)
private OrderService orderService;
public Order createOrder(Long userId, Long productId, BigDecimal amount) {
OrderRequest request = new OrderRequest();
request.setUserId(userId);
request.setProductId(productId);
request.setAmount(amount);
return orderService.createOrder(request);
}
}
4. 配置文件(application.yml):
yaml
dubbo:
application:
name: order-service
registry:
address: zookeeper://127.0.0.1:2181
protocol:
name: dubbo
port: 20880
provider:
timeout: 3000
retries: 2
consumer:
check: false
timeout: 3000
Dubbo的优缺点
优点 ✅
- 功能丰富:负载均衡、服务治理、监控
- 国内生态好:中文文档完善,社区活跃
- Spring集成好:无缝集成Spring Boot
- 成熟稳定:经过阿里多年考验
缺点 ❌
- 协议老旧:Dubbo协议基于TCP
- 跨语言弱:主要支持Java
- HTTP支持差:REST协议性能一般
- 学习成本高:配置项多,概念复杂
⚔️ 巅峰对决:gRPC vs Dubbo
1️⃣ 性能对比
scss
gRPC Dubbo
序列化 Protobuf Hessian2
协议 HTTP/2 Dubbo(TCP)
编码 二进制 二进制
压缩 gzip Snappy
性能测试结果(QPS):
┌────────────┬─────────┬─────────┐
│ 场景 │ gRPC │ Dubbo │
├────────────┼─────────┼─────────┤
│ 小对象传输 │ 30000 │ 28000 │
│ 大对象传输 │ 25000 │ 22000 │
│ 流式传输 │ 35000 │ N/A │
└────────────┴─────────┴─────────┘
结论:gRPC略胜一筹!
实际测试代码:
java
@SpringBootTest
public class PerformanceTest {
@Test
public void testGrpcPerformance() {
int count = 10000;
long start = System.currentTimeMillis();
for (int i = 0; i < count; i++) {
grpcClient.getProduct(123L);
}
long end = System.currentTimeMillis();
System.out.println("gRPC: " + count + " requests in " + (end - start) + "ms");
System.out.println("QPS: " + (count * 1000 / (end - start)));
}
@Test
public void testDubboPerformance() {
int count = 10000;
long start = System.currentTimeMillis();
for (int i = 0; i < count; i++) {
dubboService.getProduct(123L);
}
long end = System.currentTimeMillis();
System.out.println("Dubbo: " + count + " requests in " + (end - start) + "ms");
System.out.println("QPS: " + (count * 1000 / (end - start)));
}
}
2️⃣ 功能对比
功能 | gRPC | Dubbo | 说明 |
---|---|---|---|
协议 | HTTP/2 | Dubbo/REST/gRPC | Dubbo更灵活 |
序列化 | Protobuf | Hessian2/JSON/Protobuf | 都支持多种 |
负载均衡 | 需要自己实现 | ⭐⭐⭐ 内置多种策略 | Dubbo完胜 |
服务发现 | 需要第三方 | ⭐⭐⭐ 多种注册中心 | Dubbo完胜 |
服务治理 | 基础 | ⭐⭐⭐ 丰富完善 | Dubbo完胜 |
流式通信 | ⭐⭐⭐ 原生支持 | 不支持 | gRPC完胜 |
跨语言 | ⭐⭐⭐ 10+语言 | Java为主 | gRPC完胜 |
监控 | 需要集成 | ⭐⭐⭐ Admin控制台 | Dubbo完胜 |
3️⃣ 生态对比
gRPC生态
scss
gRPC核心生态:
├── grpc-java (Java实现)
├── grpc-go (Go实现)
├── grpc-web (浏览器支持)
├── grpc-gateway (HTTP转gRPC)
├── grpc-health-probe (健康检查)
└── grpc-ecosystem (生态工具集)
云原生支持:
├── Kubernetes
├── Istio (Service Mesh)
├── Envoy (代理)
└── CNCF项目
Dubbo生态
scss
Dubbo核心生态:
├── dubbo-spring-boot (Spring Boot集成)
├── dubbo-admin (管理控制台)
├── dubbo-monitor (监控)
├── dubbo-samples (示例代码)
└── dubbo-go (Go实现)
阿里生态:
├── Nacos (注册/配置中心)
├── Sentinel (流量控制)
├── Seata (分布式事务)
└── Spring Cloud Alibaba
4️⃣ 使用场景对比
gRPC适合:
- ✅ 微服务间通信(云原生)
- ✅ 跨语言场景(Java/Go/Python混合)
- ✅ 实时流式通信(直播、游戏)
- ✅ 移动端通信(App后端)
- ✅ 高性能要求(金融、广告)
Dubbo适合:
- ✅ Java技术栈(Spring Cloud Alibaba)
- ✅ 国内项目(中文文档完善)
- ✅ 需要丰富的服务治理功能
- ✅ 内部系统(不需要跨语言)
- ✅ 快速上手(Spring集成简单)
🤔 如何选择?
决策树 🌲
markdown
开始选择RPC框架
│
├─ 需要跨语言吗?
│ ├─ 是 → gRPC ⭐⭐⭐
│ └─ 否 ↓
│
├─ 团队主要技术栈是什么?
│ ├─ Java + Spring → Dubbo ⭐⭐⭐
│ ├─ Go/Python/Node → gRPC ⭐⭐⭐
│ └─ 混合 ↓
│
├─ 需要流式通信吗?
│ ├─ 是 → gRPC ⭐⭐⭐
│ └─ 否 ↓
│
├─ 需要丰富的服务治理功能吗?
│ ├─ 是 → Dubbo ⭐⭐⭐
│ └─ 否 ↓
│
├─ 部署在云原生环境(K8s)?
│ ├─ 是 → gRPC ⭐⭐⭐
│ └─ 否 → Dubbo ⭐⭐
│
└─ 团队对新技术的接受程度?
├─ 高 → gRPC
└─ 低 → Dubbo
典型场景推荐
场景1:电商平台
markdown
技术栈:Java + Spring Cloud Alibaba
服务数:100+
团队:50+人
需求:服务治理、监控、降级
推荐:Dubbo ⭐⭐⭐⭐⭐
理由:
1. Spring集成简单
2. 服务治理功能完善
3. Nacos、Sentinel生态协同
4. 中文文档完善,团队上手快
场景2:云原生SaaS平台
markdown
技术栈:Java + Go + Python混合
服务数:50+
团队:30+人
需求:跨语言、高性能、K8s部署
推荐:gRPC ⭐⭐⭐⭐⭐
理由:
1. 跨语言支持好
2. K8s原生支持
3. 性能优异
4. 流式通信能力强
场景3:直播平台
markdown
技术栈:Java + Go
服务数:30+
团队:20+人
需求:实时流式通信、低延迟
推荐:gRPC ⭐⭐⭐⭐⭐
理由:
1. 流式通信天然支持
2. 性能优异
3. 跨语言(Java服务端 + Go推流)
4. HTTP/2优势明显
场景4:传统企业内部系统
markdown
技术栈:Java + Spring Boot
服务数:20+
团队:10+人
需求:稳定、易维护
推荐:Dubbo ⭐⭐⭐⭐
理由:
1. 技术成熟稳定
2. 学习资料丰富
3. 社区活跃
4. 问题容易解决
💡 最佳实践
gRPC最佳实践
java
/**
* 1. 连接池管理
*/
@Configuration
public class GrpcConfig {
@Bean
public ManagedChannel grpcChannel() {
return ManagedChannelBuilder
.forAddress("localhost", 9090)
.usePlaintext()
// 连接池配置
.maxInboundMessageSize(10 * 1024 * 1024) // 10MB
.keepAliveTime(30, TimeUnit.SECONDS) // 保持连接
.keepAliveTimeout(10, TimeUnit.SECONDS)
.build();
}
}
/**
* 2. 优雅关闭
*/
@PreDestroy
public void shutdown() throws InterruptedException {
channel.shutdown().awaitTermination(5, TimeUnit.SECONDS);
}
/**
* 3. 拦截器(类似AOP)
*/
public class LoggingInterceptor implements ClientInterceptor {
@Override
public <ReqT, RespT> ClientCall<ReqT, RespT> interceptCall(
MethodDescriptor<ReqT, RespT> method,
CallOptions callOptions,
Channel next) {
log.info("gRPC调用: {}", method.getFullMethodName());
long start = System.currentTimeMillis();
ClientCall<ReqT, RespT> call = next.newCall(method, callOptions);
return new ForwardingClientCall.SimpleForwardingClientCall<ReqT, RespT>(call) {
@Override
public void start(Listener<RespT> responseListener, Metadata headers) {
super.start(new ForwardingClientCallListener.SimpleForwardingClientCallListener<RespT>(responseListener) {
@Override
public void onClose(Status status, Metadata trailers) {
long end = System.currentTimeMillis();
log.info("gRPC调用完成,耗时: {}ms", end - start);
super.onClose(status, trailers);
}
}, headers);
}
};
}
}
/**
* 4. 错误处理
*/
public Product getProduct(Long productId) {
try {
return blockingStub.getProduct(request);
} catch (StatusRuntimeException e) {
switch (e.getStatus().getCode()) {
case NOT_FOUND:
throw new ProductNotFoundException(productId);
case DEADLINE_EXCEEDED:
throw new TimeoutException("调用超时");
case UNAVAILABLE:
throw new ServiceUnavailableException("服务不可用");
default:
throw new RuntimeException("RPC调用失败", e);
}
}
}
Dubbo最佳实践
java
/**
* 1. 合理设置超时时间
*/
@DubboService(
timeout = 1000, // 默认1秒
methods = {
@Method(name = "createOrder", timeout = 5000), // 特定方法5秒
@Method(name = "queryOrder", timeout = 500) // 查询方法500ms
}
)
public class OrderServiceImpl implements OrderService {}
/**
* 2. 服务分组
*/
@DubboService(group = "production", version = "1.0.0")
public class OrderServiceV1 implements OrderService {}
@DubboService(group = "beta", version = "2.0.0")
public class OrderServiceV2 implements OrderService {}
// 消费者选择版本
@DubboReference(group = "production", version = "1.0.0")
private OrderService orderService;
/**
* 3. 异步调用
*/
@DubboReference(async = true)
private ProductService productService;
@DubboReference(async = true)
private UserService userService;
public void asyncExample() {
// 并行调用
productService.getProduct(123L);
userService.getUser(456L);
// 获取结果
Future<Product> productFuture = RpcContext.getContext().getFuture();
Future<User> userFuture = RpcContext.getContext().getFuture();
Product product = productFuture.get();
User user = userFuture.get();
}
/**
* 4. 泛化调用(动态调用)
*/
public Object genericInvoke(String interfaceName, String method, Object[] args) {
GenericService genericService = new GenericServiceFactory()
.getGenericService(interfaceName);
return genericService.$invoke(method, new String[]{"java.lang.Long"}, args);
}
🎓 面试高频问题
Q1:gRPC为什么性能高?
A:
-
HTTP/2协议:
- 多路复用,减少连接建立
- 头部压缩,减少数据传输
- 二进制分帧,解析更快
-
Protobuf序列化:
- 体积小(比JSON小3-10倍)
- 序列化快(比JSON快20-100倍)
- 强类型,避免运行时错误
-
长连接复用:
- 避免频繁建立连接
- 减少握手开销
Q2:Dubbo如何实现负载均衡?
A:
Dubbo在客户端实现负载均衡:
java
public interface LoadBalance {
/**
* 从多个Provider中选择一个
*/
<T> Invoker<T> select(List<Invoker<T>> invokers, URL url, Invocation invocation);
}
// 随机负载均衡
public class RandomLoadBalance extends AbstractLoadBalance {
protected <T> Invoker<T> doSelect(List<Invoker<T>> invokers, URL url, Invocation invocation) {
int length = invokers.size();
int totalWeight = 0;
// 计算总权重
for (Invoker<T> invoker : invokers) {
totalWeight += getWeight(invoker, invocation);
}
// 随机选择
int offset = random.nextInt(totalWeight);
for (Invoker<T> invoker : invokers) {
offset -= getWeight(invoker, invocation);
if (offset < 0) {
return invoker;
}
}
return invokers.get(0);
}
}
Q3:什么时候选择gRPC,什么时候选择Dubbo?
A:
选择gRPC的场景:
- ✅ 跨语言微服务
- ✅ 云原生/K8s环境
- ✅ 需要流式通信
- ✅ 追求极致性能
- ✅ 移动端通信
选择Dubbo的场景:
- ✅ Java单一技术栈
- ✅ Spring Cloud Alibaba生态
- ✅ 需要丰富的服务治理
- ✅ 团队已熟悉Dubbo
- ✅ 国内项目(文档/社区)
🎉 总结
核心要点 ✨
-
gRPC:
- Google出品,国际化
- HTTP/2 + Protobuf
- 跨语言、高性能
- 云原生首选
-
Dubbo:
- 阿里出品,本土化
- 多协议、多注册中心
- 服务治理丰富
- Java生态最佳
-
选择建议:
- 跨语言 → gRPC
- Java系 → Dubbo
- 云原生 → gRPC
- 服务治理 → Dubbo
记忆口诀 📝
gRPC性能真的高,
HTTP/2加Protobuf。
跨语言支持很强大,
云原生环境最合适。
Dubbo功能很丰富,
服务治理样样全。
Spring集成很简单,
Java项目首选它。
选择框架看场景,
跨语言就选gRPC。
Java栈用Dubbo好,
各有千秋都很棒!
📚 参考资料
最后送你一句话:
"没有最好的框架,只有最适合的框架。"
愿你选对框架,项目顺利! 🚀✨
表情包时间 🎭
erlang
选框架时:
🤔 到底选哪个呢...
用gRPC:
😎 性能杠杠的!
😅 Protobuf有点难...
用Dubbo:
😊 上手真简单!
🤩 功能好丰富!
最终:
🎉 适合自己的就是最好的!