Reddit是个社交新闻站点,其用户(也叫redditors)能够浏览并且可以提交因特网上内容的链接或发布自己的原创或有关用户提交文本的帖子。其他的用户可对发布的链接进行高分或低分的投票,得分突出的链接会被放到首页。Reddit的工程师团队以及产品复杂度在过去三年急剧上升。能有这样的提升,是因为在Reddit后端基础架构上进行了很多优化改进。一个主要的改进方面就是采用了面向服务的架构,其中最重要的部分是改进了服务发现与服务通信。随着服务数据的增长,服务之间的交互以及遗传系统变得越来越复杂。和在单个应用程序中进行功能调试以及模块调用不同,工程师现在需要深入到多服务之间的RPC请求。和关注于异常处理、错误输入这些通常问题不同,工程师现在需要更加关注客户端请求行为以及如何通过重试机制、熔断以及细粒度路由控制来进行适当防御。最近,我们选择Envoy作为我们L4/L7的服务代理,用以努力解决开发与维护稳定产品服务过程中日益增长的需求。本文主要内容包括:
网格化:Reddit服务发现基础
自从我们开始从原有整体应用服务中分离功能并构建新服务,Reddit后端基础架构就一直使用Airbnb的SmartStack作为基本的Service Mesh。选择SmartStack的原因是它的设计以及使用场景非常符合我们的架构体系,使用它能够让我们很自然地转变成面向服务的基础架构。对这个架构进行简要的了解有助于理解我们最终是如何迁移到Envoy以及如何降低任务本身的难度。今天,我们大多数服务都跑在AWS AutoScaling Groups中的EC2实例上,每天服务的扩缩容都是通过SmartStack的Nerve组件进行服务注册。Nerve是一个Ruby进程,作为sidecar运行在每个实例中,并将实例注册到中央ZooKeeper集群,而服务应用自身负责健康检查并决定是否进行注册。我们大多数服务都使用了Baseplate[1]这个开发框架,它提供了一些共享工具,例如health-check接口[2]用以直接对接Nerve,而对服务开发人员是透明的。基本的Service Mesh还包括服务发现,用来给上游客户端服务提供新的可用下游服务。和Nerve类似,Synapse也是运行在每个实例中的Ruby进程,用来管理服务端点的服务发现。Synapse从ZooKeeper中获取Nerve推送的服务注册列表,将服务端点入口写入本地HAProxy的配置文件。HAProxy同样作为sidecar进程运行,负责请求代理以及下游服务流量负载均衡。
当我们大部分服务架构不断更新时,Reddit中SmartStack的部署几乎不需要进行更新,还稳定运行了3年的时间。服务注册组件Nerve还作为内部工具,用来检查AWS实例是否健康以及监控新主机的引导过程。尽管SmartStack稳定且成熟,但是我们不断演进的系统开始触达它立即可用的局限性,因此我们决定调研评估Service Mesh生态,并确定是否能够使用新技术替换SmartStack。网格演进:迁移到Envoy
随着这些年我们服务架构的演变,在SmartStack方面我们遇到几个痛点,主要是在于它对单个组件缺乏控制。Nerve和Synapse只接受静态配置,因此任何服务注册更新(例如添加或者删除服务),都需要Puppet配置的改变和更新。Synapse对接HAProxy写配置功能只提供一些基本的路由定义,而我们有一些通过HAProxy观察流量的上层需求,但它无法理解我们主要的内部协议Thrift。服务之间的行为复杂性不断加深,我们了解到开发人员被迫在应用程序代码中完成复杂的通信行为。每个应用程序都开始在代码中管理下游服务的重试处理、超时、熔断,有时甚至一个相同的端点需要接收来自4到5个上游客户端的不同行为。我们知道这种方式是不可扩展的,我们需要像网络代理一样在一个共享的网络层管理这些通信行为。既然我们确定了Service Mesh的目标,我们就需要找到最适合Reddit的方案。我们评估了很多代理和网格化方案,主要是关注如下几个方面:
性能:避免增加性能瓶颈,任何在代理层的性能损失都需要通过相当大的功能增益来弥补。我们主要是考虑的是资源利用率以及网络延迟。我们网格化方案是在每台机器上以sidecar方式运行代理,所以我们需要的方案是能够在每台机器以及网络的每一跳上运行。
功能:所有方案选项中最大的区分点就是代理是否支持L7层的Thrift协议。Thrift是我们服务内部使用的主要RPC协议,如果在service mesh中不支持这种行为控制,那和我们现在使用HAProxy进行基本的TCP负载均衡差别不大。我们将在下一小节讨论这一点。
集成和扩展性:还有个核心要求是实用的工具能够进行奉献或与请求集成,并且能够扩展开箱即用的功能。网络代理需要能够随着Reddit的服务需求和开发人员的功能请求而演变。
Envoy以及它的生态系统满足了我们迁移方案的所有需求。虽然我们需要完全改变服务发现栈以及在生产环境中使用新的流量代理,但是Envoy的低占有率和可扩展性(特别是支持Thrift过滤器)为我们基础架构的改进提供了重大的机会。下面我们将介绍Envoy的部署方案以及在实际生产环境中的使用过程。替换HAProxy:使用Envoy的第一步
前文提到过,HAProxy作为服务流量代理部署在Reddit的SmartStack中,只是它只能管控L4层的流量,而使用Envoy最大的不同就是它能够为我们管控L7层的流量。虽然现在HTTP和gRPC都特别成熟,但Reddit的服务主要是使用Thrift,所以我们首先要确定的就是Envoy能够支持Thrift。在那时,Turbine Labs刚刚宣布他们将支持Envoy并为Envoy开发产品,我们注意到他们正在为Envoy做贡献,所以我们去和他们协商在Envoy中合作开发支持Thrift。四个月后,Envoy能够较好地支持Thrift,引入了Thrif代理、路由、请求/响应指标以及速率限制。与此同时,我们内部主要致力于为生产服务部署和运行Envoy奠定基础。 由于内部服务通信不依赖这一层,我们在改变系统某一部分时必须小心翼翼,更不用说整个系统。经过深思熟虑,我们决定首先使用Envoy替代HAProxy作为基本的TCP代理,然后仍然使用Nerve和Synapse负责服务注册和服务发现。这就意味着我们只会替换系统的一小部分,也意味着我们将不会使用Envoy的动态发现服务。为了解决这个问题,我们在Synapse中为Envoy的配置写了一个配置生成器 ConfigGenerator[3]插件,同时也写了一些额外的配置脚本,使用Envoy的热重启机制[4]来管理它。这项工作使我们能够保持大部分服务发现系统的完整性,同时仍然将Envoy投入生产环境,这反过来又为迁移本身提供了很大的灵活性。我们能够一次为每个服务回滚代理变更,并在每台服务器上通过更改应用程序配置来管理使用Envoy端点与下游服务进行通信。在迁移过程中,我们并行运行HAProxy和Envoy用于监听不同的端口,使用Synapse管理它们的配置。这让我们能够为客户端迁移每个服务,观察行为并且在出现任务问题时进行即使回滚,同时,还能够通过HAProxy的配置来审计Envoy的配置。经过两个月,我们为每个服务部署了Envoy,替代HAProxy向下游服务发送请求,监控并确保没有任务行为以及性能的差异。
迁移过程也不是一帆风顺,在我们定制化Synapse与Envoy的集成以及它的静态配置管理上出现过一些问题。Envoy的网络连接处理(尤其是热重启机制)与HAProxy有很大的不同,所以在我们应用程序连接控制代码中引发了一些非预期的错误。不过问题不大,没有影响迁移过程,Envoy也稳定运行了将近4个月。在性能方面,与HAProxy相比,Envoy对我们的服务延迟没有产生可衡量的影响。HAProxy仍然作为sidecar运行,用来应对节日期间的紧急流量需求,而且我们的工程师人力有限,所以我们还不能衡量资源利用率对我们主机的影响。不过,Envoy在网络层面为我们提供了更丰富的可观察性,特别是我们在一些内部服务开启Thrift过滤器。感谢过滤器机制,在不需要修改应用程序代码的情况下,Envoy开始提供我们之前无法获取的请求/响应指标。这些小而重要的提升以及整体的稳定性让我们在2019年Service Mesh路线上充满信心。下一步
随着Envoy在代理层面以及L4层流量管理的成功实施,我们将在2019年的前一段时间巩固运营工具,以便开始真正利用Envoy的控制功能。我们计划部署Envoy的发现服务API,该API由集中式配置存储支持,可以为我们的Envoy部署带来动态配置管理,也给开发人员提供接口在每个服务上管理这些配置。同时,对于内部服务我们会更多使用Kubernetes,所以Envoy部署部分在2019年早期将得到更多的开发,比较有意思的地方是我们会利用Envoy的路由管理工具将服务迁移到Kubernetes。最后,虽然Envoy目前应用于我们的大多数后端服务通信,但我们仍然将AWS ELB用于一些外部入口点,并使用HAProxy作为Reddit核心后端应用程序的主要外部负载平衡器和路由管理。在边缘上运行Envoy将提供更多的可观察性和服务路由控制,我们希望在继续将服务从整体中分离出更小且更易于管理的服务时,能够进行复杂的请求管理操作,例如遮蔽入站流量和边缘流量转移。2018年Reddit在生产环境中实施Envoy是一项艰巨的任务,如果没有大量的内外部支持就不可能做到这一点。我们要感谢Envoy社区建立和维护大量软件,以及Turbine Labs(尤其是Mark McBride,TR Jordan和Stephan Zuercher)为Envoy的Thrift功能奠定基础。如果没有整个工程团队的内部支持,尤其是u/alienth,u/cshoesnoo,u/NomDeSnoo和u/spladug,Envoy也不可能在Reddit成功实施。我们将继续围绕Reddit的网络可观察性和控制进行开发,请持续关注。相关链接:
https://github.com/reddit/baseplate
https://baseplate.readthedocs.io/en/stable/cli/healthcheck.html
https://github.com/airbnb/synapse/tree/master/lib/synapse/config_generator
https://blog.envoyproxy.io/envoy-hot-restart-1d16b14555b5
原文链接:https://redditblog.com/2018/12/18/envoy-proxy-at-reddit/基于Kubernetes的DevOps实践培训
基于Kubernetes的DevOps实践培训将于2019年5月10日在上海开课,3天时间带你系统掌握Kubernetes,学习效果不好可以继续学习。本次培训包括:容器特性、镜像、网络;Kubernetes架构、核心组件、基本功能;Kubernetes设计理念、架构设计、基本功能、常用对象、设计原则;Kubernetes的数据库、运行时、网络、插件已经落地经验;微服务架构、组件、监控方案等,点击下方图片或者点击阅读原文了解详情。