Zipkin是 Twitter 的一个开源项目,基于 Google Dapper实现。使用它来收集各个服务器上请求链路的跟踪数据,及时地发现系统中出现的延迟问题,找出系统的性能瓶颈。
完整代码:
https://github.com/Justin02180218/micro-kit
配置文件
zipkin:
url: "http://zipkin-server:9411/api/v2/spans"
service_name: "user-service"
reporter:
timeout: 5
batch_size: 1000
batch_interval: 3
max_backlog: 10000
在hosts中配置zipkin-server域名
config.go
type ZipkinConfig struct {
Url string `json:"url" yaml:"url"`
ServiceName string `json:"service_name" yaml:"service_name"`
Reporter struct {
Timeout int `json:"timeout" yaml:"timeout"`
BatchSize int `json:"batch_size" yaml:"batch_size"`
BatchInterval int `json:"batch_interval" yaml:"batch_interval"`
MaxBacklog int `json:"max_backlog" yaml:"max_backlog"`
}
}
pkg/tracers
在 pkg 下新建目录 tracers,创建 zipkin.go 文件:
代码如下:
// 创建 Reporter
func NewZipkinReporter(zipkinCfg *configs.ZipkinConfig) reporter.Reporter {
return zipkinhttp.NewReporter(
zipkinCfg.Url,
zipkinhttp.Timeout(time.Duration(zipkinCfg.Reporter.Timeout)*time.Second),
zipkinhttp.BatchSize(zipkinCfg.Reporter.BatchSize),
zipkinhttp.BatchInterval(time.Duration(zipkinCfg.Reporter.BatchInterval)*time.Second),
zipkinhttp.MaxBacklog(zipkinCfg.Reporter.MaxBacklog),
)
}
// 创建 Tracer
func NewZipkinTracer(serviceName string, reporter reporter.Reporter) *gozipkin.Tracer {
zEP, _ := gozipkin.NewEndpoint(serviceName, "")
tracerOptions := []gozipkin.TracerOption{
gozipkin.WithLocalEndpoint(zEP),
}
tracer, err := gozipkin.NewTracer(reporter, tracerOptions...)
if err != nil {
fmt.Println(err)
return nil
}
return tracer
}
func Zipkin(tracer *gozipkin.Tracer, name string) endpoint.Middleware {
return zipkin.TraceEndpoint(tracer, name)
}
func MakeHttpServerOptions(zipkinTracer *gozipkin.Tracer, name string) []http.ServerOption {
zipkinServiceTrace := zipkin.HTTPServerTrace(zipkinTracer, zipkin.Name(name))
options := []http.ServerOption{zipkinServiceTrace}
return options
}
func MakeHttpClientOptions(zipkinTracer *gozipkin.Tracer, name string) []http.ClientOption {
zipkinClientTrace := zipkin.HTTPClientTrace(zipkinTracer, zipkin.Name(name))
options := []http.ClientOption{zipkinClientTrace}
return options
}
func MakeGrpcServerOptions(zipkinTracer *gozipkin.Tracer, name string) []grpc.ServerOption {
zipkinServiceTrace := zipkin.GRPCServerTrace(zipkinTracer, zipkin.Name(name))
options := []grpc.ServerOption{zipkinServiceTrace}
return options
}
func MakeGrpcClientOptions(zipkinTracer *gozipkin.Tracer, name string) []grpc.ClientOption {
zipkinClientTrace := zipkin.GRPCClientTrace(zipkinTracer, zipkin.Name(name))
options := []grpc.ClientOption{zipkinClientTrace}
return options
}
endpoint层
修改book-rpc-endpoint.go,以library-user-service为例,其他微服务相同。
func MakeFindBooksEndpoint(instance string, tracer *gozipkin.Tracer) endpoint.Endpoint {
conn, err := grpc.Dial(instance, grpc.WithInsecure())
if err != nil {
fmt.Println(err)
return nil
}
findBooksEndpoint := grpctransport.NewClient(
conn, "book.Book", "FindBooksByUserID",
encodeGRPCFindBooksRequest,
decodeGRPCFindBooksResponse,
pbbook.BooksResponse{},
tracers.MakeGrpcClientOptions(tracer, "grpc-transport-findBooks")...,
).Endpoint()
return findBooksEndpoint
}
transport层
修改user_transport.go,以library-user-service为例,其他微服务相同。
func NewHttpHandler(ctx context.Context, endpoints *endpoint.UserEndpoints, tracer *gozipkin.Tracer) *gin.Engine {
r := utils.NewRouter(ctx.Value("ginMod").(string))
e := r.Group("/api/v1")
{
e.POST("register", func(c *gin.Context) {
kithttp.NewServer(
endpoints.RegisterEndpoint,
decodeRegisterRequest,
utils.EncodeJsonResponse,
tracers.MakeHttpServerOptions(tracer, "transport-register")...,
).ServeHTTP(c.Writer, c.Request)
})
......
}
}
修改 main.go
以 library-user-service 为例,其他微服务相同。
reporter := tracers.NewZipkinReporter(config.Conf.ZipkinConfig)
defer reporter.Close()
tracer := tracers.NewZipkinTracer(config.Conf.ZipkinConfig.ServiceName, reporter)
findBooksEndpoint := endpoint.MakeFindBooksEndpoint
grpcClient := registers.GRPCClient(config.Conf, findBooksEndpoint, tracer, logger)
hystrix.ConfigureCommand("Find books", hystrix.CommandConfig{Timeout: 1000})
grpcClient = circuitbreakers.Hystrix("Find books", "book-rpc-service currently unavailable")(grpcClient)
grpcClient = tracers.Zipkin(tracer, "grpc-endpoint-findBooks")(grpcClient)
......
userEndpoints := &endpoint.UserEndpoints{
RegisterEndpoint: tracers.Zipkin(tracer, "endpoint-register")(ratelimit(endpoint.MakeRegisterEndpoint(userService))),
FindByIDEndpoint: tracers.Zipkin(tracer, "endpoint-findByID")(ratelimit(endpoint.MakeFindByIDEndpoint(userService))),
FindByEmailEndpoint: tracers.Zipkin(tracer, "endpoint-findByEmail")(ratelimit(endpoint.MakeFindByEmailEndpoint(userService))),
FindBooksByUserIDEndpoint: tracers.Zipkin(tracer, "endpoint-findBooks")(ratelimit(endpoint.MakeFindBooksByUserIDEndpoint(userService))),
HealthEndpoint: tracers.Zipkin(tracer, "endpoint-health")(ratelimit(endpoint.MakeHealthEndpoint(userService))),
}
启动 Zipkin
使用 Docker 启动 zipkin
docker pull openzipkin/zipkin
docker run -d -p 9411:9411 --name zipkin openzipkin/zipkin
启动服务,通过网关访问 library-user-service 微服务的 findBooksByUserID 接口。
在浏览器地址栏输入:http://zipkin-server:9411/
点击 "RUN QUERY" 按钮
继续点击第一行的 "SHOW" 按钮
下一篇文章,我们在各个微服务中加入服务监控功能。
完整代码:
https://github.com/Justin02180218/micro-kit
更多【分布式专辑】【架构实战专辑】系列文章,请关注公众号