Develop RPC Server & RPC Client

Dubbo-go Quick Start

Based on the Triple protocol defined by Dubbo, you can easily write browser and gRPC compatible RPC services that run on both HTTP/1 and HTTP/2 simultaneously. The Dubbo Go SDK supports defining services using IDL or programming language-specific methods and provides a lightweight API for publishing or invoking these services.

This example demonstrates the RPC communication pattern based on the Triple protocol. The example uses Protocol Buffer to define the RPC service and demonstrates the processes of code generation, service publishing, and service access.

Sample source: dubbo-go-samples/helloworld.

Prerequisites

Since we are using Protocol Buffer, we first need to install the relevant code generation tools, including protoc, protoc-gen-go, and protoc-gen-go-triple.

  1. Install protoc

    Check the Protocol Buffer Compiler Installation Guide

  2. Install protoc plugins

    Next, we install the plugins protoc-gen-go and protoc-gen-go-triple.

    go install google.golang.org/protobuf/cmd/protoc-gen-go@latest
    
    git clone --depth 1 https://github.com/apache/dubbo-go.git
    (cd dubbo-go/tools/protoc-gen-go-triple && go install .)
    

    Make sure protoc-gen-go and protoc-gen-go-triple are in your PATH. You can verify this with which protoc-gen-go and which protoc-gen-go-triple. If either command does not work, run:

    [ -n "$(go env GOBIN)" ] && export PATH="$(go env GOBIN):${PATH}"
    [ -n "$(go env GOPATH)" ] && export PATH="$(go env GOPATH)/bin:${PATH}"
    

    protoc-gen-go-triple is now maintained in the dubbo-go repository under tools/protoc-gen-go-triple. Install it from that directory, and keep the generated *.triple.go files in sync when you change the .proto service definition.

Quick Run Example

Download Example Source Code

We maintain a series of dubbo-go usage examples in the apache/dubbo-go-samples repository to help users quickly learn how to use dubbo-go.

You can download the example zip file and unzip it, or clone the repository:

git clone --depth 1 https://github.com/apache/dubbo-go-samples.git
cd dubbo-go-samples/helloworld

Run Server

Run all the following commands from the helloworld root directory. Start the server with:

go run ./go-server/cmd/main.go

Use cURL to verify that the server has been started correctly:

curl \
  --header "Content-Type: application/json" \
  --data '{"name":"Dubbo"}' \
  http://localhost:20000/greet.GreetService/Greet

The response is:

{"greeting":"Dubbo"}

Run Client

Open another terminal, return to the helloworld root directory, and start the client:

cd dubbo-go-samples/helloworld
go run ./go-client/cmd/main.go

The logs include the following response (prefixes such as the timestamp, log level, and call site vary by environment):

Greet response: hello world

This is a complete development process of a dubbo-go RPC communication service.

Source Code Explanation

Next, we will explain the source code of the dubbo-go-samples/helloworld example.

Define Service

The example uses Protocol Buffer (IDL) to define the Dubbo service.

syntax = "proto3";

package greet;
option go_package = "github.com/apache/dubbo-go-samples/helloworld/proto;greet";

message GreetRequest {
  string name = 1;
}

message GreetResponse {
  string greeting = 1;
}

service GreetService {
  rpc Greet(GreetRequest) returns (GreetResponse) {}
}

proto/greet.proto declares the GreetService service and defines the Greet RPC, its GreetRequest request, and its GreetResponse response.

Generate Code

Before running the server or client, generate the code with protoc-gen-go and protoc-gen-go-triple from the helloworld root directory:

protoc \
  --go_out=. \
  --go_opt=paths=source_relative \
  --go-triple_out=. \
  --go-triple_opt=paths=source_relative \
  ./proto/greet.proto

After the command completes, the proto directory has the following structure:

proto/
├── greet.proto
├── greet.pb.go
└── greet.triple.go

The generated files have different responsibilities:

  • greet.pb.go is generated by the standard protoc-gen-go plugin. It primarily contains Protobuf messages such as GreetRequest and GreetResponse, together with their encoding and decoding code.
  • greet.triple.go is generated by protoc-gen-go-triple. It primarily contains Triple server registration, the client proxy, and RPC invocation code, including RegisterGreetServiceHandler and NewGreetService.

After changing proto/greet.proto, rerun the command above to update both generated files.

Implement Service

Next, add the business logic. GreetTripleServer implements the generated greet.GreetServiceHandler interface:

type GreetTripleServer struct{}

func (srv *GreetTripleServer) Greet(ctx context.Context, req *greet.GreetRequest) (*greet.GreetResponse, error) {
	resp := &greet.GreetResponse{Greeting: req.Name}
	return resp, nil
}

Start Server

Create a Server and register the GreetTripleServer implementation with RegisterGreetServiceHandler. The Server listens on port 20000:

package main

import (
	"context"

	_ "dubbo.apache.org/dubbo-go/v3/imports"
	"dubbo.apache.org/dubbo-go/v3/protocol"
	"dubbo.apache.org/dubbo-go/v3/server"
	"github.com/dubbogo/gost/log/logger"

	greet "github.com/apache/dubbo-go-samples/helloworld/proto"
)

type GreetTripleServer struct{}

func (srv *GreetTripleServer) Greet(ctx context.Context, req *greet.GreetRequest) (*greet.GreetResponse, error) {
	resp := &greet.GreetResponse{Greeting: req.Name}
	return resp, nil
}

func main() {
	srv, err := server.NewServer(
		server.WithServerProtocol(
			protocol.WithPort(20000),
			protocol.WithTriple(),
		),
	)
	if err != nil {
		logger.Errorf("failed to create server: %v", err)
		return
	}

	if err := greet.RegisterGreetServiceHandler(srv, &GreetTripleServer{}); err != nil {
		logger.Errorf("failed to register greet service handler: %v", err)
		return
	}

	if err := srv.Serve(); err != nil {
		logger.Errorf("failed to serve: %v", err)
		return
	}
}

Access Service

The simplest way is to use an HTTP/1.1 POST request to access the service, passing the parameters as standard JSON format in the HTTP payload. Here is an example using a cURL command:

curl \
    --header "Content-Type: application/json" \
    --data '{"name": "Dubbo"}' \
    http://localhost:20000/greet.GreetService/Greet

You can also use a Dubbo client to request the service. First, obtain the service proxy from the generated code in the greet package, specify the server address, and initialize it. Then you can initiate an RPC call.

package main

import (
	"context"
	"time"

	"dubbo.apache.org/dubbo-go/v3/client"
	_ "dubbo.apache.org/dubbo-go/v3/imports"
	"github.com/dubbogo/gost/log/logger"

	greet "github.com/apache/dubbo-go-samples/helloworld/proto"
)

func main() {
	cli, err := client.NewClient(
		client.WithClientURL("127.0.0.1:20000"),
	)
	if err != nil {
		logger.Errorf("failed to create client: %v", err)
		return
	}

	svc, err := greet.NewGreetService(cli)
	if err != nil {
		logger.Errorf("failed to create greet service: %v", err)
		return
	}

	ctx, cancel := context.WithTimeout(context.Background(), time.Second)
	defer cancel()

	resp, err := svc.Greet(ctx, &greet.GreetRequest{Name: "hello world"})
	if err != nil {
		logger.Errorf("failed to greet: %v", err)
		return
	}
	logger.Infof("Greet response: %s", resp.Greeting)
}

This is the basic working principle of dubbo-go RPC!

After the basic unary call is working, the same generated Triple client and server also support server streaming, client streaming, bidirectional streaming, request metadata, response headers and trailers, filters, health checks, timeouts, retries, and OpenAPI exposure. Continue with the RPC framework guides for these capabilities.

More Content

More Features of RPC Framework

Learn about Streaming communication models, configuring timeout durations, passing headers, and more framework configurations.

Governance capabilities such as service discovery

Learn how to use dubbo-go to develop microservices, incorporating service discovery, observability, traffic control, and more service governance capabilities.