gRPC是一个高性能、开源、通用的RPC框架,面向移动和HTTP/2设计,是由谷歌发布的首款基于Protocol Buffers的RPC框架。
gRPC基于HTTP/2标准设计,带来诸如双向流、流控、头部压缩、单TCP连接上的多复用请求等特性。这些特性使得其在移动设备上表现更好,更省电且节省空间占用。gRPC 1.0版本是2015年面世以后的第一次版本发布,开发者可以把该版本用于生产。API现在也是很稳定的。
Bugsnag(注:一家云端bug监控服务商)每天处理数以亿计的错误信息,为了处理这些数据,考虑优先构建一个可扩展,性能强大的后端系统,并从中学到很多有挑战性的技术。最近,我们推出了新版本的仪表板,这个项目要求扩展系统,来处理服务呼叫的显著增加,这些呼叫是跟踪用户发布和会话所需的。
仪表板的发布在进行中,工程团队将Bugsnag的后端功能分解成称之为管道(pipeline)的微服务体系。将管道扩展到支持发布,意味着增加新的服务,并修改现有服务,也可预见到许多新的服务器和客户端的交互。为了处理上述架构的变化,需要采用一致性的方式来设计,实施和集成企业的服务。Bugsnag是一家多语言的公司,服务是用Java,Ruby,Go和Node.js等多语言编写,因此企业需要一种与平台无关的方法。
本文将介绍为什么我们最终选择了gRPC作为Pipeline的默认通信框架。
达到REST API设计的极限
现有系统传统上使用具有JSON有效载荷的REST API进行同步通信。这种选择是基于占压倒性比例的成熟度、熟悉度和工具的可用性做出的,但是随着跨洲际工程团队的增长,企业需要设计一致的,基于RESTful API的工具。
不幸的是,这感觉就像试图将简单的方法调用变成一个数据驱动的RESTful界面。这满足了RESTful接口的verb,header,URL标识符,资源的URL和有效载荷的神奇组合,并做了一个清洁,简单,看起来几乎不可能实现的功能界面。RESTful有很多规则和解释,在大多数情况下会导致REST ish接口,这需要花费额外的时间和精力来保持其纯度。
最终,考虑到RESTAPI的复杂性,我们找到了替代方案。希望微服务尽可能相互隔离,减少交互和解耦服务。它可以让企业在很短的时间内创造出一个可行的服务,并防止跳过hoops。
评估REST的替代方案
不要轻易选择通信框架。大型组织(如Netflix)可以拥有超过500+个微服务的后端系统。迁移这些服务以取代不充分的服务间通信会花费大量时间,从后勤和财务角度看这很不切实际。花时间从一开始就考虑正确的框架,可以省去很多未来的浪费。
我们花了大量的时间来制定评估标准和研究、选择。Bugsnag到底长什么样子呢?
技术标准
在研究可用选项时,使用了一些特定的标准来评估。要考虑的事情是基于微服务架构的最有效的方法。主要目标是自由地使用通信,消除通信的复杂性,了解每项服务的责任所在。其中的一些技术问题是:
速度 - 对于大量的请求/响应API调用,需要将调用本身的延迟作为性能和用户响应速度的最小因素。延迟的主要组成部分是连接成本,传输成本和消息编码/解码时间。
基础架构兼容性 - 框架在基础架构中扮演的角色如何?主要是关于负载平衡和自动扩展?我们使用托管在Google云端平台上的Kubernetes服务,因此需要框架来兼容这种环境。
开发工具 - 在实现框架时,提供尽可能小的摩擦将会使开发人员更快捷。哪些工具可以帮助编码,本地测试端点,以及单元和集成测试的stubbing/mocking?当事情出错时,我们需要能够看到包括内容在内的请求信息。消息格式等因素也可以使调试更容易依赖于工具,例如JSON消息是人可读的,但是二进制消息将需要额外的努力来解码。
成熟度和采用 - 对于初创公司来说,资源是有限的,需要花费在公司的核心业务上,而不是修复,测试和增强第三方框架。诸如框架的普及,大规模使用的例子,社区的活跃程度以及框架本身的成熟度等因素都是稳定性的良好指标。需要强调的是,选择一个解决具体问题的框架,而并非选择最新最热的。
多平台支持 - 在真正的微服务思维中,使用最适合其目的的语言编写企业的服务,目前包括Java,Ruby,Go和Node。框架是否为现有的语言选择提供了一流的支持,同时提供了用其他语言编写新服务的选项?
代码量 - 框架应该有助于降低工程成本。企业需要编写和维护多少代码才能使其工作?与业务逻辑相比,这是多少样板代码?
安全 - 所有的内部通信都应该被认证和加密。我们需要能够使用所有通信的SSL / TLS(或等价物)。
设计上的考虑,并非都与技术有关
服务API是最重要的接口之一,因为在开发过程中对设置服务期望至关重要。解决服务API的设计是一项艰巨的任务,当不同的团队负责所涉及的不同服务时,该任务会被放大。最大限度地减少由于预期不匹配而浪费的时间和精力,与缩短编码时间一样有价值。由于Bugsnag拥有跨地区的工程团队,因此沟通时间有限。必须通过简化沟通,确保事情不用那么多解释,否则错误很容易产生,事情很容易被拖延。
以下是在选择框架时的一些设计考虑因素:
强类型 - 消息是否是强类型的?如果通过服务边界发送的消息清晰可见,那么可以消除由于类型而造成的设计和运行时错误。
打开解释 - 能够直接从服务API规范生成客户端库,减少了误解的问题。错误条件 - 有一套明确定义的错误代码可以更容易一致地交流问题。
文档 - 服务API应该是易读易懂的。定义服务API的格式应该尽可能清楚,准确地描述端点。
版本控制 - 更改是不可避免的,这是一个很好的选择,在某些时候,服务API将需要修改。所使用的消息传递格式和服务定义可以影响修改API并将其部署到生产的容易程度。是否有明确的路径来增加版本及其相应的库,并推出更改?
微服务最佳实践,为什么可扩展性是重要的
除了上面列出的标准外,还需要选择一个易于扩展的框架。随着微服务的发展,企业需要越来越多的“开箱即用”功能,发展的同时,为系统增加了更多的复杂性。因此企业希望的功能包括:
异常处理 - 在请求级别提供一个处理异常的机制。它允许捕获有关请求的重要上下文元数据,例如发出请求的用户,可以用例外报告。我们使用Bugsnag轻松地监视这些异常。
智能重试 - 在特定条件下重试请求,例如仅在5xx状态码上。这包括支持各种退避策略,如指数退避。
服务发现配置 - 将通信框架连接到流行的服务发现应用程序(如Zookeeper,Eureka或Consul)的选项可以提供一种快速简便的解决方案,以绕过企业的架构来请求路由。
度量、跟踪和日志记录 - 可观察性对于复杂的分布式系统是必不可少的,但是应该小心监视的内容。在服务边界自动收集指标和跟踪信息可以快速回答常见问题,例如“我的服务对请求响应缓慢吗?”以及“请求失败的频率如何?”。
熔断 - 这种模式可以通过自动检测问题和快速失败来防止级联服务故障。也可以由长时间缓慢的请求来触发,以提供响应降级的服务而不是不断地超时。
缓存和批处理 - 通过使用缓存或批处理请求来加速请求。
大多数框架不会提供所有功能,但至少它们应该是可扩展的,以便在需要时添加。
什么是gRPC和协议缓冲区?
没有一个框架是万能的。我们探索的一些选项包括Facebook的Thrift,Apache Hadoop的Avro,Twitter的Finagle,甚至使用JSON模式。
我们的需求更接近于远程程序调用(RPC),给予所需要的细粒度控制。使用RPC的另一个吸引力是使用接口描述语言或IDL。IDL允许以独立于语言的格式描述服务API,将接口与任何特定的编程语言分离。他们可以提供一系列的好处,包括服务API的一个单一的事实来源,并可能被用来生成客户端和服务器代码来与这些服务进行交互。IDL的例子包括Thrift,Avro,CORBA,当然还有ProtocolBuffers。
最后,明确的获胜者是基于协议缓冲区的gRPC。
什么是gRPC?
我们选择了gRPC,因为它满足了我们的功能需求(包括未来的可扩展性),背后的活跃社区以及HTTP / 2框架的使用。
gRPC是由Google开发,设计用于传统的RPC调用。该框架使用最新的网络传输协议HTTP / 2,主要用于通过使用流的单个TCP连接来实现低延迟和多路复用请求。与REST over HTTP / 1.1相比,gRPC非常快速和灵活。
gRPC的性能对于设置管道来处理仪表板发布的大量增加至关重要。此外,HTTP / 2是下一个标准化的网络协议,可以利用为HTTP / 2开发的工具和技术(如Envoy代理),并为gRPC提供一流的支持。由于多路复用流支持,gRPC支持双向通信,不限于简单的请求/响应呼叫。
什么是Protobufs(协议缓冲区)?
Protocol Buffers或protobufs是定义和序列化结构化数据为高效的二进制格式的一种方式,也是由Google开发的。二者的有效结合,也是我们选择gRPC的主要原因之一。
以前有许多与想修复的版本相关的问题。微服务意味着必须不断更新,需要适应并保持向前和向后兼容的接口,protobufs对此非常有用。由于是二进制格式,所以它们也是通过wire快速发送的小型有效载荷。
Protobuf消息使用关联的IDL进行描述,它提供了一个紧凑的,强类型的,向后兼容的格式来定义消息和RPC服务。我们使用最新的proto3规范,并在此处显示protobuf消息的实际示例。
所有字段proto3都是可选的。如果未设置字段,将始终使用默认值。这与字段编号相结合提供了一个API,可以非常抵抗打破变化。通过遵循一些简单的规则,向前和向后兼容性可以成为大多数API更改的默认值。
protobuf格式还允许定义RPC服务本身。服务端点与消息结构共存,在单个protobuf文件中提供RPC服务的自包含定义。对于我们的跨洲际的工程团队来说,这非常有用,他们可以从一个文件中了解服务如何工作,生成客户端并开始使用它。以下是我们的服务之一:
该框架能够生成代码来使用protobuf文件与这些服务进行交互,这是另一个优势,它可以自动生成需要的所有类。这个生成的代码负责消息建模,并提供一个存根类,其中包含与您的服务端点相关的重复方法调用。
支持多种语言,包括C ++,Java,Python,Go,Ruby,C#,Node,Android,Objective-C和PHP。但是,使用protobuf文件维护和同步生成的代码是个问题。我们已经能够通过使用Protobuf文件自动生成客户端库来解决这个问题,会在即将发布的下一篇博客文章中分享更多的内容。
gRPC最好的特性之一是支持中间件模式,被称为拦截器。它允许扩展所有的gRPC实现(这对企业来说很重要),能够轻松访问所有请求,从而实现自己的微服务最佳实践。gRPC还内置了对一系列认证机制的支持,包括SSL / TLS。
gRPC社区
我们正处于gRPC采用的开始阶段,期待社区提供更多的工具和技术。很高兴能够加入这个充满活力的社区,并对未来的项目有一些想法,我们希望看到这些项目是开放源代码或我们自己写的。
gRPC工具的当前状态
gRPC比较新,缺乏可用的开发工具,特别是与经验丰富的REST over HTTP / 1.1协议相比。搜索教程和示例时,这一点尤其明显,因为只有少数有用的信息。二进制格式也使消息不透明,需要努力解码。虽然有一些选择,例如JSON代码转换器可以帮助,但预计需要做一些基础工作,以便为gRPC提供顺畅的开发体验。
我们喜欢用Apiary 来记录外部API。使用服务协议缓冲区(protobuf)文件自动生成交互式文档的等价物,将是理想的有效的内部通信gRPCAPI。protobuf文件的静态分析在运行时能捕获更多的bug。使用Checkstyle作为Java代码,并且把它用作类似于protobuf的文件。自定义拦截器可以提供跟踪,日志记录和错误监视功能。我们希望开源我们的Bugsnag gRPC拦截器,以自动捕获并向Bugsnag报告错误。gRPC的增长和采用
在过去几年中,gRPC的普及度大幅增长,Square,Lyft,Netflix,Docker,Cisco和CoreOS等公司大规模采用。Netflix Ribbon是基于RPC调用使用REST的微服务通信框架的事实标准。今年,他们宣布,由于其多语言支持和更好的可扩展性/可组合性,他们正在向gRPC过渡。该框架最近也于2017年3月加入了CNCF基金会,支持重量级的Kubernetes和Prometheus。gRPC社区非常活跃,与开源gRPC生态系统 列出了许多gRPC激动人心的项目。
另外,gRPC有我们认同的原则
Lyft在转向gRPC方面做了大量的讨论,这与我们的经验非常相似:使用Protocol Buffers和gRPC生成统一的API。值得一试。
gRPC现在还处于初期阶段,存在一些明显的磨合问题,但未来前景光明。总的来说,我们对gRPC如何整合到后端系统非常乐观,并且很高兴见证这个框架的发展。
原文链接: blog.bugsnag.com/ 本文转自:Segmentfault.com
文章末尾固定信息