Junedayday Blog

六月天天的个人博客

0%

五分钟技术小分享 - 2022Week03

2022-01

2022-01-17 CNCF-gRPC

今天,我们一起来看CNCF的 Remote Procedure Call - RPC 模块中最具代表性的项目 - gRPC。

gRPC官网的定义很简洁,重点强调了其高性能的特点:

A high performance, open source universal RPC framework.

我们再看一段官方更详细的描述:

gRPC is a modern open source high performance Remote Procedure Call (RPC) framework that can run in any environment. It can efficiently connect services in and across data centers with pluggable support for load balancing, tracing, health checking and authentication. It is also applicable in last mile of distributed computing to connect devices, mobile applications and browsers to backend services.

除了高性能,这里还提到了两个重要特性:

  • 插件化的支持:负载均衡、tracing、健康监测、认证等
  • 最后一公里:将手机app、浏览器与后端服务器的联通

第一点体现出了gRPC的高度可扩展性。这里的插件化不仅体现在上面列举的这些具体功能,甚至像序列化的方案、底层通信的协议,都可以做到快速替换与迭代。

第二点在实际生产上应用的case并不多,仍需要大量的实践与经验沉淀后,才建议大家尝试。目前,绝大多数的gRPC通信都是发生在后端服务之间。

接下来,我们来谈谈官网列举的四个特性:

Simple service definition

gRPC采用Protocol Buffers进行定义,从整体来说阅读体验确实是比较简洁的,但在实际工程中仍存在两个问题:

  1. 迁移成本大:gRPC没有提供从很多历史RPC解决方案中迁移的途径,如Thrift等,完全是另起炉灶,这对有历史包袱的团队来说很难接受;
  2. 配套开发工具缺失:高频使用Protocol Buffers的朋友都有了解,主流IDE对pb文件的错误提示和文件格式化都有缺失,很多问题都无法在coding的过程中实时提示,而是需要运行二进制命令protoc后才能了解。

Start quickly and scale

快速启动 - 强调的是通过Protocol Buffers生成的代码,可以在各语言内用简洁的代码就可运行(这部分与各语言强相关)

快速扩容 - 这个特性需要与Kubernetes的能力结合。

Works across languages and platforms

跨语言与平台的特性,非常依赖背后的生态 - 需要大量的工作去兼容多语言,也要兼顾性能、稳定性等问题。

所以,这不仅仅是技术上的问题,更需要社区、资金等复杂因素的支持。

Bi-directional streaming and integrated auth

  • 双向流式通信 - 这点是gRPC的核心特性,体现出了与其它RPC方案的差异
  • 集成认证功能 - Auth是gRPC插件化生态中的重要一环,这部分其实与服务网格的功能存在一定的重叠

2022-01-18 CNCF-Envoy

作为云原生Service Mesh代表性的产品之一,Envoy占据了大壁江山。

Envoy is an L7 proxy and communication bus designed for large modern service oriented architectures.

  1. 定位:L7 代理和通信总线
  2. 重点服务对象:SOA面向服务架构(也完全适用于微服务架构)

核心理念:

The network should be transparent to applications. When network and application problems do occur it should be easy to determine the source of the problem.

网络应对应用程序透明。当网络和应用程序出现问题时,应该很容易地确定问题根源。

文档资料:

我们依旧挑选三个核心特性展开:

Out of process architecture 进程外架构

进程外架构,其实就是一种微服务理念的体现,它的利与弊也是和微服务强相关的。

优点很直观 - Envoy可以支持多语言,也可以独立于业务快速迭代与发展。

而弊端在官网上没有体现,最关键的一点是:性能损耗。作为一种side-car模式,Envoy是在本机内、进程间进行通信,远远地比进程内调用的压栈、出栈更花时间。

Service discovery and dynamic configuration 服务发现和动态配置

很多运维同学都会拿Envoy去对比Nginx,确实在很多特性上,两者有很大的相似之处。但在这个特性上,Envoy有得天独厚的优势。

以一个常见的动态负载均衡为例,nginx需要结合consul template来实现,还需要对应用程序做一定的侵入。而Envoy可以与Kubernetes完美契合,大幅度减少维护成本。

Best in class observability 最佳的可观察性

Envoy 的最主要目标是使网络透明,而最佳的可观测性往往会从OpenTelemetry推荐的三点入手:Metrics、Logging、Tracing。

Envoy提供了大量的插件,一方面保证了Envoy内部的问题清晰明了,同时也能快速地协助定位到应用侧的问题。

2022-01-19 CNCF-Contour

作为CNCF中的控制平面的主打产品,Contour的知名度远不如Google的Istio。但由于种种原因,Istio并没有被捐献给云原生基金会,于是CNCF就孵化了Contour。

定义

Contour is an open source Kubernetes ingress controller providing the control plane for the Envoy edge and service proxy. Contour supports dynamic configuration updates and multi-team ingress delegation out of the box while maintaining a lightweight profile.

三大特性

  • Envoy Inside
  • Flexible Architecture
  • TLS Certificate Delegation

从定义与三个特性的描述里,我们很难真实地感受到Contour的特点。

今天我将换一个角度:从控制平面与数据平面进行分析。如果我们能清楚地认识到这两者的定义与边界,那么会对云原生的Service Mesh理念,以及Envoy、Contour、Istio等产品有更深的理解。

这篇博客的定义很具有参考意义:

  • 控制平面 - 通过配置和控制消息来组织编排网络的逻辑,并下发给数据平面
  • 数据平面 - 以 Sidecar 的形式与应用部署在一起,承载其流量的发送与接收

控制平面的关键功能就是控制与管理,重点对象是配置信息

我们可以将数据平面看作为基础的Nginx服务,它是和底层的应用强相关的,解析相关的数据包并实现路由、负载均衡等功能。但Nginx自身也需要有一定的配置信息,比如说:

  • 数据平面的服务发现中心往往是因服务而异的;
  • 数据平面的超时参数会频繁调整;
  • 在做蓝绿测试时,需要频繁调整流量;
  • 认证相关的设置往往需要统一更新,如证书;

在我看来,控制平面更像是数据平面的配置中心,解决的是高频变化或应用间差异性很大的配置信息,让数据平面更稳定地运行。

从架构层面来说,如果一层解决不了问题,那就再抽象一层。

从具体的工程实践来说,数据平面主要负责的是底层实现,在保证稳定性的情况下更要兼具性能,所以不宜有太多丰富的功能。这时,引入了控制平面,我们可以将很多的配置信息通过界面UI方式进行管理,下发到各个控制平面,然后控制平面再针对性地进行转发到数据平面,就能大幅度地提高整个Service Mesh方案的可维护性。

2022-01-20 CNCF-Emissary-Ingress

Emissary-Ingress是CNCF中又一个与网络相关的项目。这款软件的前身叫作Ambassador。但Ambassador是一款商业软件,为了避免相关的问题,更名为Emissary-Ingress后被捐献给了CNCF。因为网上资料更多的都是Ambassador,下面统一用Ambassador对这款软件进行描述。

CNCF上的定义为:

open source Kubernetes-native API gateway for microservices built on the Envoy Proxy

我们很容易将这个产品与Istio、Envoy混淆起来,那它们之间的区别是什么呢?这里有篇文章,介绍了具体的实践,但我们直接可以从标题中得到关键信息:

  • Ambassador - Edge proxy
  • Istio - service mesh

而Envoy+Contour对标的是Istio,所以不难看出,云原生推荐将Ambassador作为一种边缘网关,更多地是作为整体流量的出入口。如果说service mesh是一种对网络的精细化管理,那么边缘网关更多地是对整体流量的管理。

但在实际使用中,两者有大量的重叠功能,如路由、认证、限速等,而我也没有在网上找到相关的Best Practice,这部分就很需要大家的经验与摸索了。从我的角度来看,更倾向于大家多使用Envoy的特性,毕竟它的生态最成熟。即便后续有了替代品,对方也往往会提供对应的兼容方案。

这里,我引用了一个链接,讲述了微服务网关(Emissary-Ingress定位)与传统企业级网关的差异。

Primary Purpose 主要目标

  • 传统企业级网关 - Expose, compose, and manage internal business APIs
  • 微服务网关 - Expose and observe internal business services

微服务网关相对而言会更轻量级,而且对外以服务的维度呈现。

Publishing Functionality 发布功能

  • 传统企业级网关 - API management team or service team registers / updates gateway via admin API
  • 微服务网关 - Service team registers / updates gateway via declarative code as part of the deployment process

微服务网关更倡导自运维的方式。

Handling and Debugging Issues 处理和Debug问题

  • 传统企业级网关 - L7 error-handling (e.g. custom error page or payload). Run gateway/API with additional logging. Troubleshoot issue in staging environment

  • 微服务网关 - Configure more detailed monitoring. Enable traffic shadowing and / or canarying

微服务网关更强调的是网络侧的更细致化的管理,突出了灵活性。

2022-01-21 谈谈Context在Go程序外的传递

这两天,有个读者跟我讨论了一个关于链路追踪的问题 - 他发现通过context传递的trace-id丢失了。从根本上来说,这涉及到了Context在Go程序外的传递的理解,细想的话很有意思,所以我今天专门拿出来讲讲。

如果你对Go语言有一定的基础,会很习惯地使用Context作为上下文信息的传递:无论是内部函数的调用,还是RPC的调用,这就会产生一种错觉:context的传递是水到渠成的

这位同学的调用链路是 Go程序 - MQ - Go程序,发现context中的trace-id丢失了。

trace-id用于分布式的链路追踪

分析这个问题不难,有很多种思路,但我比较建议大家从底层实现去理解:

  1. context的本质,是一种key-value的数据结构;
  2. 服务之间的调用,本质上是一种网络上的二进制数据的传递,而context信息肯定是保存在其中的
  3. HTTP是一种二进制数据上的协议表达格式,我们常见的RESTful API 的 json数据是填入到body中,但HTTP协议还有很多地方可以保存数据,尤其是HTTP Header。context信息大概率是被保存在Header里的;

Go语言的Client将context封装到Header里,Server将context从Header中解析出来

默认的官方库是不会写直接写的,需要做一层浅封装:

发送前,从ctx中将对应的k-v填入到header;

收到后,从header中提取k-v,写入到context。

要验证一下上面的猜想很简单,我强烈大家用最底层的方式:Wireshark抓包。事实也如我们的预期,Go语言的ctx传递正是用这种方式实现的。而MQ这种第三方组件,往往不会去解析这种特定的Header,所以会发生丢失。

这时,我们有什么样的解决方案呢?

  1. 制定标准。这也是OpenTracing等规范推崇的,对广大的开发者来说非常友好,尤其是跨语言的情况,但这块非常依赖生态,需要大量的SDK,整体来说推进进度比较难。(这就体现了Service Mesh的价值)
  2. 显示传递。相当于把关键信息填到HTTP的body里,对具体代码的实现来说侵入性很强,但不失为中小型公司快速落地的方案;遇到一些不支持标准的第三方软件,我们也往往只能采用这种方式。

Github: https://github.com/Junedayday/code_reading

Blog: http://junes.tech/

Bilibili: https://space.bilibili.com/293775192

公众号: golangcoding

二维码