基于Go技术栈的微服务构建
在大型系统的微服务化构建中,一个系统会被拆分成许多模块。这些模块负责不同的功能,组合成系统,终可以提供丰富的功能。在这种构建形式中,开发者一般会聚焦于大程度解耦模块的功能以减少模块间耦合带来的额外开发成本。同时,微服务面临着如何部署这些大量的服务系统、如何运维这些系统等新问题。
本文的素材来源于我们在开发中的一些佳实践案例,从开发、监控、日志等角度介绍了一些我们基于Go技术栈的微服务构建经验。
开 发
微服务的开发过程中,不同模块由不同的开发者负责,明确定义的接口有助于确定开发者的工作任务。终的系统中,一个业务请求可能会涉及到多次接口调用,如何准确清晰的调用远端接口,这也是一大挑战。对于这些问题,我们使用了gRPC来负责协议的制订和调用。
传统的微服务通常基于http协议来进行模块间的调用,而在我们的微服务构建中,选用了Google推出的gRPC框架来进行调用。下面这张简表比较了http rpc框架与gRPC的特性:
gRPC的接口需要使用Protobuf3定义,通过静态编译后才能成功调用。这一特性减少了由于接口改变带来的沟通成本。如果使用http rpc,接口改变就需要先改接口文档,然后周知到调用者,如果调用者没有及时修改,很可能会到服务运行时才能发现错误。而gRPC的这种模式,接口变动引起的错误保证在编译时期就能消除。
在性能方面,gRPC相比传统的http rpc协议有非常大的改善(根据这个评测,gRPC要快10倍)。gRPC使用http 2协议进行传输,相比较http 1.1, http 2复用tcp连接,减少了每次请求建立tcp连接的开销。需要指出的是,如果单纯追求性能,之前业界一般会选用构建在tcp协议上的rpc协议(thrift等),但四层协议无法方便的做一些传输控制。相比而言,gRPC可以在http header中放入控制字段,配合nginx等代理服务器,可以很方便的实现转发/灰度等功能。
接下来着重谈谈我们在实践中如何使用gRPC的一些特性来简化相关开发流程。
1. 使用context来控制请求的生命周期
在gRPC的go语言实现中,每个rpc请求的个参数都是context。http2协议会将context放在HEADER中,随着链路传递下去,因此可以为每个请求设置过期时间,一旦遇到超时的情况,发起方就会结束等待,返回错误。
ctx := context.Background() // blank context
ctx, cancel = context.WithTimeout(ctx, 5*time.Second)
defer cancel( )
grpc.CallServiveX(ctx, arg1)
相关文章