golang Tchannel-Thrift 用法

Mon May 14, 2018

800 Words|Read in about 2 Min
Tags: tchannel   rpc   thrift   other   golang  

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

Tchannel

设计目的

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

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

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

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

  • 可选 checksums.

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

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()
}
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!

See Also

Mon May 14, 2018

800 Words|Read in about 2 Min
Tags: tchannel   rpc   thrift   other   golang