@gaoxiaoyunwei2017
2017-12-10T18:56:15.000000Z
字数 3443
阅读 650
闫强
在过去的一年中,服务网格(Service Mesh)已经演变成为云原生堆栈的重要组成部分。像Paypal,Lyft,Ticketmaster和CreditKarma这样的高流量公司都已经为其生产应用添加了ServiceMesh。并且,今年1月,用于云原生应用的开源ServiceMesh-Linkerd成了为CNCF的官方项目。但是到底什么是ServiceMesh呢?为什么突然受到关注?
在本文中,我将给给出义ServiceMesh的定义,通过分析在过去十年中应用架构的变迁来追踪分析它的变化。同时,我也会区分ServiceMesh与之相关但不同的概念,包括API网关,EdgeProxies(边缘代理)和ESB(企业服务总线)。最后,我将介绍erviceMesh的发展方向,以及分写随着云原生应用的发展,这个概念将会发生什么变化。
ServiceMesh是用于处理服务到服务通信的专用基础设施层,它负责为现代云原生应用的复杂服务拓扑可靠地传递请求。在实践中,ServiceMesh通常被实现为与应用程序代码一起部署的轻量级网络代理数组,而应用程序不需要知道它的存在(但是外界也存在不同的看法)。
ServiceMesh作为单独层的概念与云原生应用的兴起有关。在云原生模型中,单个应用程序可能包含数百个服务;每个服务可能有数千个实例;并且这些实例中的每一个都可能处于不断变化的状态,因为它们是使用诸如Kubernetes之类的编排器动态地调度的。世界上的服务交流不仅非常复杂,同时也是运行时行为的基本组成部分。合理管理使用ServiceMesh,对于确保端到端的性能和可靠性至关重要。
ServiceMesh是一个网络模型,它位于TCP/IP以上的抽象层。它假设底层的L3/L4网络是存在的,并能够从点到点传送字节(它还假设这个网络与环境的其他方面一样是不可靠的,因此,ServiceMesh也必须能够处理网络故障)。
在某些方面,ServiceMesh类似于TCP/IP。正如TCP栈抽象出在网络端点之间可靠传递字节的机制,ServiceMesh抽象了在服务之间可靠地传递请求的机制。像TCP一样,ServiceMesh不关心实际的有效载荷或它的编码方式。应用程序具有高级目标(“从A发送到B”),并且ServiceMesh的工作(如TCP)是在处理过程中发生任何故障时完成此目标。
与TCP不同,ServiceMesh具有超越“仅仅使其工作”的重要目标:它提供了统一的应用范围点,用于将可视性和控制引入运行时的应用程序。ServiceMesh的明确目标是将服务通信从不可见,隐含的基础设施领域转移为生态系统的一等公民———可以在其中进行监控,管理和控制。
在云原生应用中可靠地传递请求可能非常复杂。像Linkerd这样的ServiceMesh可以通过各种强大的技术来管理这种复杂性:断电,延迟感知负载平衡,最终一致性(“咨询”)服务发现,重试和最后期限。这些功能必须一起工作,并且这些功能之间的相互作用以及它们运行的复杂环境可能相当微妙。
例如,当通过Linkerd向服务发出请求时,简化的事件时间表如下:
1. Linkerd应用动态路由规则来确定请求者所需要的服务。请求是否应该路由到生产或Staging环境的服务?在本地数据中心或云中的服务?使用正在测试的服务的最新版本,还是在生产过程中被测试的较旧版本?所有这些路由规则都是可动态配置的,并且可以在全局和任意一个流量片上应用。
2. 找到正确的目的地后,Linkerd将从相关的服务发现端点检索相应的实例池,这可能有好几个。如果这个信息与Linkerd在实践中观察到的信息有所不同,Linkerd会根据信息来源做出决定。
3. Linkerd根据各种因素选择最有可能返回快速响应的实例,包括其对最近请求的延迟时间的观察。
4. Linkerd尝试将请求发送到实例,记录结果的延迟和响应类型。
5. 如果实例关闭,无响应或无法处理请求,则Linkerd会在另一个实例上重试该请求(但只有当知道请求是幂等时)。
6. 如果实例一直返回错误,则Linkerd将其从负载平衡池中排除,以便稍后重新进行重试(例如,一个实例可能会发生暂时失败)。
7. 如果请求的截止时间已过,Linkerd将主动将请求做失败处理,而不是再次尝试添加负载。
8. Linkerd以度量和分布式跟踪的形式捕获上述行为的各个方面,这些跟踪被发布到集中度量系统。
当然,这只是简化版本,Linkerd还可以发起和终止TLS,执行协议升级,动态转移流量,并在数据中心之间进行故障转移!
要注意这些功能旨在提供点向弹性和应用范围的弹性。大型分布式系统无论其架构如何,都具有一个典型的特征:它们为小型本地化故障提供了许多机会,从而可能演变为全系统的灾难性故障。ServiceMesh必须设计为通过减少负载来防止这些恶性演变,并在底层系统接近其极限时让其快速失败。
ServiceMesh并不是一项新的功能,而是功能位置的转变。Web应用程序一直不得不管理服务通信的复杂性,ServiceMesh模型的起源可以追溯到过去十五年来这些应用的发展。
考虑2000年时中型Web应用程序的典型架构:三层应用程序。在这个模型中,应用程序逻辑,Web服务逻辑和存储逻辑都是一个单独的层。层之间的沟通虽然复杂,但范围有限———毕竟只有两跳。没有“Mesh”,但是在每层的代码之间处理跳数有通信逻辑。
当这种架构方式被推到扩展性非常高的场景时,它开始破裂了。像Google,Netflix和Twitter这样的公司面临着巨大的流量需求,实现了云原生方案的前身:应用层被分解为许多服务(有时称为“微服务”),层级成为拓扑。在这些系统中,广义通信层变得强相关,但通常采用“胖客户端”的形式-Twitter的Finagle,Netflix的Hysterix和Google的Stubby就是这样的例子。
在许多方面,像Finagle,Stubby和Hysterix这样的库是第一个ServiceMesh。虽然它们与具体周围环境的细节相关,并且需要使用特定的语言和框架,但它们是用于管理服务到服务通信的专用基础设施,并且(在开源Finagle和Hysterix库的情况下)可以在其公司之外使用。
快进到现代云原生应用。云原生模型将许多小型服务的微服务方法与两个额外的因素相结合:容器(例如,提供资源隔离和依赖关系管理的Docker)和编排层(例如Kubernetes),将底层硬件抽象为同质池。
这三个组件允许具有自然机制的应用程序在负载下进行扩展,并能够处理云环境中存在的部分故障。但是,随着数百个服务或数千个服务,以及随时重新安排实例的业务流程层,通过服务拓扑获得单一请求的路径可能非常复杂,并且由于容器使得用不同的语言实现服务变得容易,库的方法已经不再可行了。
这种复杂性和关键性的组合促使需要产生专用层,用于从应用程序代码中分离出服务到服务的通信,并能够捕获底层环境的高度动态性质。这个层就是ServiceMesh。
虽然在云原生生态系统中的ServiceMesh正在迅速增长,但仍然存在有待探索且令人兴奋的路线图。无服务计算(例如亚马逊的Lambda)的要求直接适用于ServiceMesh的命名和链接模型,并且是它在云原生生态系统中角色的自然扩展。服务身份和访问策略的作用在云原生环境中仍然很新鲜,ServiceMesh在此很好的发挥着重要的作用。最后,ServiceMesh,如之前的TCP/IP,将继续被推进到底层基础设施中。正如Linkerd从Finagle这样的系统中演进而来,当前的服务形式作为必须明确添加到云原生堆栈中的单独的用户空间代理,也将继续发展。
ServiceMesh是云原生堆栈的关键组件。Linkerd在推出一年多的时间内,就成为了CNCF的一部分,拥有广泛的贡献者和用户群体。其用户包括了Monzo(英国银行业的颠覆者)到诸如Paypal,Ticketmaster和CreditKarma这样的大型互联网公司,还有像HoughtonMifflinHarcourt这样存在了几百年的公司。