Protocol Overview
This article details specific aspects of the triple in the Dubbo Java implementation, including configuration methods, performance metrics, etc.
Please refer to other parts of the documentation for the triple protocol specification and basic usage. This article elaborates on specific details in the Java implementation of the triple protocol.
Programming Model
When using the triple protocol, developers can define RPC services using either Java Interface
or Protobuf (IDL)
. Both definitions have equal protocol capabilities and only affect the programming experience and serialization methods, with the choice of development model depending on the user’s business background.
Java Interface
Suitable for Dubbo veteran users and development teams without cross-language requirements, with the advantage of low learning costs. Dubbo2 legacy users can switch to this protocol at no cost.
Service definition example:
public interface DemoService {
String sayHello(String name);
}
In this mode, serialization methods can include Hessian, JSON, Kryo, JDK, custom extensions, etc. The experience is similar to the older version of the Dubbo protocol, requiring only a change in one protocol configuration item, making migration from Dubbo protocol to triple smoother.
Please check [advanced studies - communication protocols] for specific examples using Java Interface + Triple protocol.
Protobuf
Defining services using Protobuf (IDL) is suitable for development teams that currently or in the future have cross-language requirements. The same IDL service can be used for Java/Go/Node.js, but it has a higher learning cost.
syntax = "proto3";
option java_multiple_files = true;
package org.apache.dubbo.springboot.demo.idl;
message GreeterRequest {
string name = 1;
}
message GreeterReply {
string message = 1;
}
service Greeter{
rpc greet(GreeterRequest) returns (GreeterReply);
}
Using the protoc compilation plugin provided by Dubbo, the above IDL service definition is precompiled into relevant stub code, which includes the interface definitions required by Dubbo; thus, the subsequent coding differs little, except that the plugin automatically generates the interface definitions compared to the earlier user-defined Java Interface mode.
// Generated by dubbo protoc plugin
public interface Greeter extends org.apache.dubbo.rpc.model.DubboStub {
String JAVA_SERVICE_NAME = "org.apache.dubbo.springboot.demo.idl.Greeter";
String SERVICE_NAME = "org.apache.dubbo.springboot.demo.idl.Greeter";
org.apache.dubbo.springboot.demo.idl.GreeterReply greet(org.apache.dubbo.springboot.demo.idl.GreeterRequest request);
// more generated codes here...
}
The Protobuf mode supports serialization modes of Protobuf Binary and Protobuf JSON. Lastly, please check [advanced studies - communication protocols] for specific examples of Protobuf (IDL) + Triple protocol.
3. Which programming model should I use, and how to choose?
Yes | No | |
---|---|---|
Does the company’s business involve other languages besides Java, and are cross-language scenarios common? | Protobuf | Java Interface |
Are developers in the company familiar with Protobuf and willing to accept the additional costs? | Protobuf | Java Interface |
Is there a need for standard gRPC interoperability? | Protobuf | Java Interface |
Are you a Dubbo2 veteran user wishing to smoothly migrate to the triple protocol? | Java Interface | Protobuf |
Streaming Communication
Streaming Implementation Principles
The Triple
protocol’s streaming mode
From the protocol layer’s perspective,
Triple
is built onHTTP2
, so it inherits all the capabilities ofHTTP2
, including streaming and full-duplex capabilities.From the framework level,
org.apache.dubbo.common.stream.StreamObserver
provides a streaming interface for users, allowing for stream processing of input and output parameters. The framework makes the corresponding interface calls when sending and receiving stream data, ensuring a complete lifecycle for the stream.
Applicable Scenarios
Streaming is a new type of invocation provided by Dubbo3, and it is recommended to use streaming in the following scenarios:
- When interfaces need to send large amounts of data that cannot fit in a single RPC request or response and need to be sent in batches.
- In streaming scenarios, data must be processed in the order sent, with no definite boundaries for the data itself.
- In push scenarios, multiple messages are sent and processed within the same call context.
Streams are divided into three types.
SERVER_STREAM
Server-streaming RPC is similar to Unary RPC, except the server responds to the client’s request and returns a stream of messages. After sending all messages (often multiple), the server sends status information (status code and optional status message) and optional trailing metadata to the client, ending the server stream once all status information is sent. The stream is completed once the client has received all server messages through StreamObserver.
CLIENT_STREAM
Client-streaming RPC is similar to Unary RPC, except the client sends a message stream (often containing multiple messages) rather than a single message. The server responds with a single message (including status details and optional trailing metadata) - typically after receiving all client messages.
BIDIRECTIONAL_STREAM
In bidirectional streaming RPC, the client initiates a method call, and the server receives metadata, method name, and deadline from the client’s call, initiating a complete bidirectional stream channel. The server can choose to return its initial metadata or wait for the client to start streaming messages.
Both the client and server stream processing are application-specific. Since these two streams are independent, clients and servers can read and write messages in any order. For instance, a server may wait until it has received all client messages before sending a message back, or they can play “ping pong” — the server receives a request and then sends a response, and the client sends another request based on the response, etc.
Stream Semantics Guarantee
- Provides message boundaries, allowing for separate message handling
- Strictly ordered, the sending order matches the receiving order
- Full-duplex, sending does not require waiting
- Supports cancellation and timeouts
For specific examples of Streaming, please refer to Streaming communication.
REST Support
By adding annotations to the Java interface, REST-style triple services can be published. A specific code example can be found here.
Stream Semantics Guarantee
Currently, the REST protocol only supports the Java Interface
service definition model, unlike Dubbo and the triple protocol. In REST scenarios, we need to add annotations to the Interface, supporting both Spring MVC and JAX_RS annotations.
If you recall, the triple protocol natively supports cURL access, similar to the access mode of org.apache.dubbo.springboot.demo.idl.Greeter/greet
. By adding the above annotations, additional REST-style access support can be provided for the triple service, such as a GET request for demo/greet
.
Spring Web Annotations
Spring MVC service definition example:
@RestController
@RequestMapping("/demo")
public interface DemoService {
@GetMapping(value = "/hello")
String sayHello();
}
JAX-RS Annotations
JAX-RS service definition example:
@Path("/demo")
public interface DemoService {
@GET
@Path("/hello")
String sayHello();
}
Exception Type Transmission
Business exceptions generated at the Provider end need to be returned as response values to the Consumer client. The consumer can use try catch
to capture possible exceptions:
try {
greeterProxy.echo(REQUEST_MSG);
} catch (YourCustomizedException e) {
e.printStackTrace();
} catch (RpcException e) {
e.printStackTrace();
}
The Dubbo framework will send exception type responses on the provider side according to the following process. Not all business exceptions can be returned as they are; exceptions that cannot be handled will be encapsulated and returned as RpcException
type:
Appendix
Comparison of Protobuf and Java Native Data Types
For users planning to migrate completely from the Java interface to Protobuf, the information here may serve as a reference to understand the limitations that may arise with type migration and whether the Protobuf descriptor language can fully describe Java data types.
This article compares the differences between Protobuf and Java Interface as two IDLs, helping Dubbo protocol developers understand Protobuf and paving the way for transitioning to Triple protocol and Grpc protocol.
1. Data Types
1.1. Basic Types
Protobuf Type | Java Type |
---|---|
double | double |
float | float |
int32 | int |
int64 | long |
uint32 | int[Ref] |
uint64 | long[Ref] |
sint32 | int |
sint64 | long |
fixed32 | int[Ref] |
fixed64 | long[Ref] |
sfixed32 | int |
sfixed64 | long |
bool | boolean |
string | String |
bytes | ByteString |
Note
In Java, unsigned 32-bit and 64-bit integers are represented using their signed counterparts, where the top bit is stored only in the sign bit.
2. Composite Types
2.1. Enum
- Original pb code
enum TrafficLightColor {
TRAFFIC_LIGHT_COLOR_INVALID = 0;
TRAFFIC_LIGHT_COLOR_UNSET = 1;
TRAFFIC_LIGHT_COLOR_GREEN = 2;
TRAFFIC_LIGHT_COLOR_YELLOW = 3;
TRAFFIC_LIGHT_COLOR_RED = 4;
}
- Generated Java code
Enum constants should be in uppercase.
2.2. Arrays
- Original pb code
message VipIDToRidReq {
repeated uint32 vipID = 1;
}
- Generated Java code
Underlyingly, it is actually an ArrayList.
2.3. Collections
PB does not support unordered and unique collections, only uses arrays as a workaround and requires manual deduplication.
2.4. Dictionaries
- Original pb code
message BatchOnlineRes {
map<uint32, uint32> onlineMap = 1; // Online status
}
- Generated Java code
2.5. Nesting
- Original pb code
message BatchAnchorInfoRes {
map<uint32, AnchorInfo> list = 1; // User info map list
}
/*
* The functionality of the corresponding interface: Batch or single retrieval of user info
*/
message AnchorInfo {
uint32 ownerUid = 1 [json_name="uid"]; // User id
string nickName = 2 [json_name="nn"]; // User nickname
string smallAvatar = 3 [json_name="savt"]; // User avatar full path - small
string middleAvatar = 4 [json_name="mavt"]; // User avatar full path - medium
string bigAvatar = 5 [json_name="bavt"]; // User avatar full path - large
string avatar = 6 [json_name="avt"]; // User avatar
}
- Generated Java code
3. Default Field Values
- For strings, the default value is an empty string.
- For bytes, the default value is empty bytes.
- For booleans, the default value is false.
- For numeric types, the default value is zero.
- For enums, the default value is the first defined enum value, which must be 0.
- For message fields, the unset field’s exact value is language-specific. For details, refer to the generated code guide.
4. Overall Structure
Feature | Java Interface | Protobuf | Notes |
---|---|---|---|
Method Overloading | √ | × | |
Generics/Templating | √ | × | |
Method Inheritance | √ | × | |
Nested Definitions | √ | Partially supported | PB only supports nesting of message and enum |
Import Files | √ | √ | |
Nullable Fields | √ | × | |
Multiple Input Parameters | √ | × | PB only supports single input parameter |
Zero Input Parameters | √ | × | PB requires at least one input parameter |
Zero Output Parameters | √ | × | PB requires at least one output parameter |
Input/Output as Abstract Classes | √ | × | PB input/output must be concrete classes |
Input/Output as Interfaces | √ | × | PB input/output must be concrete classes |
Input/Output as Basic Types | √ | × | PB input/output must be structs |
5. Community Resources
- Community homepage: https://developers.google.cn/protocol-buffers/
- Community open source address: https://github.com/google/protobuf
- Relevant JARs in Maven: https://search.maven.org/search?q=com.google.protobuf
Feedback
Was this page helpful?
Yes No
Last modified September 30, 2024: Update & Translate Overview Docs (#3040) (d37ebceaea7)