Getting started with ttrpc
I believe ttrpc stands for teeny tiny rpc. Don’t quote me on it. Created for low latency environments based off of the famous gRPC. I was introduced by ttrpc in a talk given by a containerD maintainer. Unexpected for you to know how containerD functions to get started with ttrpc. This guide is aimed for developers who know gRPC and would like to get started with ttrpc. Knowledge of gRPC isn’t required, however knowledge of golang and tcp is needed. I will felish out more of this tutorial for newbies to the rpc space soon. Important to note. ttrpc does sacrifice security features to reduce latency. I would not recommend opening up a ttrpc service to the world or external facing clients. I think itβs perfect for air gapped environments or already trusted inter service communication like a cache that runs in/with your service.
Requirements
- Golang gRPC requires 1.6 or higher
- Protoc Make sure you have gRPC installed
1
|
$ go get -u google.golang.org/grpc
|
Also the protoc plugin for Go
1
|
$ go get -u github.com/golang/protobuf/protoc-gen-go
|
A thought out guide Next you will need to install ttrpc plugin for protoc
1
2
3
4
5
|
$ go get github.com/containerd/ttrpc
$ cd $GOPATH/src/github.com/containerd/ttrpc/cmd/protoc-gen-gogottrpc/
$ go install
// verify the binary is $GOBIN
$ ls $GOBIN // you should see 'protoc-gen-gogottrpc'
|
Next create a package in your Go workspace
1
2
|
$ mkdir $GOPATH/src/ttrpc-demo
$ cd $GOPATH/src/ttrpc-demo
|
We’ll create a folder titled βpbβ to write our proto files in
Create a file titled hello.proto in the contents fo the file put
syntax = "proto3";
option go_package = "hello;hello";
service HelloService{
rpc HelloWorld(HelloRequest) returns (HelloResponse);
}
message HelloRequest{
string msg = 1;
}
message HelloResponse{
string response = 1;
}
Now we need to generate our code using the ttrpc plugin we installed earlier. This will create a new directory titled hello with generated code for your service.
1
|
$ protoc -I ../pb/ --gogottrpc_out=plugins=ttrpc:../pb ../pb/*.proto</div>
|
Lets write some server side code. Create a new directory titled server/ttrpc/ and a file titled server.go
1
2
|
$ mkdir -p $GOPATH/src/ttrpc-demo/server/ttrpc
$ touch $GOPATH/src/ttrpc-demo/server/ttrpc/server.go
|
In the server.go file, lets write our service calls
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
|
package main
import (
"context"
"errors"
"fmt"
"net"
"os"
"ttrpc-demo/pb/hello"
"github.com/containerd/ttrpc"
)
const port = ":9000"
func main() {
s, err := ttrpc.NewServer()
defer s.Close()
if err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(1)
}
lis, err := net.Listen("tcp", port)
if err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(1)
}
hello.RegisterHelloServiceService(s, &helloService{})
if err := s.Serve(context.Background(), lis); err != nil {
fmt.Fprintln(os.Stderr, err)
}
}
type helloService struct{}
func (s helloService) HelloWorld(ctx context.Context, r *hello.HelloRequest) (*hello.HelloResponse, error) {
if r.Msg == "" {
return nil, errors.New("ErrNoInputMsgGiven")
}
return &hello.HelloResponse{Response: "Hi How are you"}, nil
}
|
Now lets generate our client side code. Let’s create a new directory and a client.go file
1
2
|
$ mkdir -p $GOPATH/src/ttrpc-demo/client/ttrpc/
$ touch $GOPATH/src/ttrpc-demo/client/ttrpc/client.go
|
Inside client.go β place contents below
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
|
package main
import (
"context"
"fmt"
"net"
"os"
"ttrpc-demo/pb/hello"
"github.com/containerd/ttrpc"
)
const port = ":9001"
func main() {
conn, err := net.Dial("tcp", port)
if err != nil {
fmt.Fprintf(os.Stderr, "Failed to dial: %v \n", err)
os.Exit(1)
}
client := hello.NewHelloServiceClient(ttrpc.NewClient(conn))
serverResponse, err := client.HelloWorld(context.Background(), &hello.HelloRequest{
Msg: "Hello Server",
})
if err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(1)
}
fmt.Fprintln(os.Stdout, serverResponse.Response)
}
|