golang Tchannel-Thrift 用法

Posted by 聪少 on 2018-05-14

hey guys,你没看错我又来了!!上篇是说thrift,本篇是tchannel-thrift用法!why!因为jaeger Agent和Collector之间通信使用的是tchannel!(你没想错!我又逮着tchannel源码看了好久,才发现原来是uber开发的一套rpc框架!!!(>﹏<))

Tchannel

设计目的

  • 容易用多种语言实现,尤其是 JS 和 Python。

  • 高性能转发路径。中间件可以快速做出转发决策。

  • 请求/回复模型不再按顺序,慢速请求不会堵在队列前头,阻止后续的快速请求。

  • 大型请求/响应,可能/必须分成碎片成片,逐步发送。

  • 可选 checksums.

  • 可用于在端点之间输送多种协议,例如 HTTP+ JSON 和 Thrift。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
struct HealthCheckRes {
1: bool healthy,
2: string msg,
}

service Base {
void BaseCall()
}

service First extends Base {
string Echo(1:string msg)
HealthCheckRes Healthcheck()
void AppError()
}

service Second {
void Test()
}
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
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
package main

import (
"bufio"
"errors"
"fmt"
"log"
"net"
"os"
"runtime"
"strings"
"time"

tchannel "github.com/uber/tchannel-go"
gen "github.com/uber/tchannel-go/examples/thrift/gen-go/example"
"github.com/uber/tchannel-go/thrift"
)

func main() {
var (
listener net.Listener
err error
)

if listener, err = setupServer(); err != nil {
log.Fatalf("setupServer failed: %v", err)
}

if err := runClient1("server", listener.Addr()); err != nil {
log.Fatalf("runClient1 failed: %v", err)
}

if err := runClient2("server", listener.Addr()); err != nil {
log.Fatalf("runClient2 failed: %v", err)
}

go listenConsole()

// Run for 10 seconds, then stop
time.Sleep(time.Second * 10)
}

func setupServer() (net.Listener, error) {
tchan, err := tchannel.NewChannel("server", optsFor("server"))
if err != nil {
return nil, err
}

listener, err := net.Listen("tcp", ":0")
if err != nil {
return nil, err
}

server := thrift.NewServer(tchan)
server.Register(gen.NewTChanFirstServer(&firstHandler{}))
server.Register(gen.NewTChanSecondServer(&secondHandler{}))

// Serve will set the local peer info, and start accepting sockets in a separate goroutine.
tchan.Serve(listener)
return listener, nil
}

func runClient1(hyperbahnService string, addr net.Addr) error {
tchan, err := tchannel.NewChannel("client1", optsFor("client1"))
if err != nil {
return err
}
tchan.Peers().Add(addr.String())
tclient := thrift.NewClient(tchan, hyperbahnService, nil)
client := gen.NewTChanFirstClient(tclient)

go func() {
for {
ctx, cancel := thrift.NewContext(time.Second)
res, err := client.Echo(ctx, "Hi")
log.Println("Echo(Hi) = ", res, ", err: ", err)
log.Println("AppError() = ", client.AppError(ctx))
log.Println("BaseCall() = ", client.BaseCall(ctx))
cancel()
time.Sleep(100 * time.Millisecond)
}
}()
return nil
}

func runClient2(hyperbahnService string, addr net.Addr) error {
tchan, err := tchannel.NewChannel("client2", optsFor("client2"))
if err != nil {
return err
}
tchan.Peers().Add(addr.String())
tclient := thrift.NewClient(tchan, hyperbahnService, nil)
client := gen.NewTChanSecondClient(tclient)

go func() {
for {
ctx, cancel := thrift.NewContext(time.Second)
client.Test(ctx)
cancel()
time.Sleep(100 * time.Millisecond)
}
}()
return nil
}

func listenConsole() {
rdr := bufio.NewReader(os.Stdin)
for {
line, _ := rdr.ReadString('\n')
switch strings.TrimSpace(line) {
case "s":
printStack()
default:
fmt.Println("Unrecognized command:", line)
}
}
}

func printStack() {
buf := make([]byte, 10000)
runtime.Stack(buf, true /* all */)
fmt.Println("Stack:\n", string(buf))
}

type firstHandler struct{}

func (h *firstHandler) Healthcheck(ctx thrift.Context) (*gen.HealthCheckRes, error) {
log.Printf("first: HealthCheck()\n")
return &gen.HealthCheckRes{
Healthy: true,
Msg: "OK"}, nil
}

func (h *firstHandler) BaseCall(ctx thrift.Context) error {
log.Printf("first: BaseCall()\n")
return nil
}

func (h *firstHandler) Echo(ctx thrift.Context, msg string) (r string, err error) {
log.Printf("first: Echo(%v)\n", msg)
return msg, nil
}

func (h *firstHandler) AppError(ctx thrift.Context) error {
log.Printf("first: AppError()\n")
return errors.New("app error")
}

func (h *firstHandler) OneWay(ctx thrift.Context) error {
log.Printf("first: OneWay()\n")
return errors.New("OneWay error...won't be seen by client")
}

type secondHandler struct{}

func (h *secondHandler) Test(ctx thrift.Context) error {
log.Println("secondHandler: Test()")
return nil
}

func optsFor(processName string) *tchannel.ChannelOptions {
return &tchannel.ChannelOptions{
ProcessName: processName,
Logger: tchannel.NewLevelLogger(tchannel.SimpleLogger, tchannel.LogLevelWarn),
}
}

OK! See you!