Bilgin Lbryam
原文
关键要点
微服务架构依然是分布式系统最流行的架构风格。但Kubernetes和云原生运动大规模的重新定义了应用设计和开发的某些方面。
云原生平台,服务的可见性还不够。一个更基本的前提是通过健康检查,信号的响应以及声明所需消耗的资源等使微服务自动化
在后Kubernetes时代,使用诸如Hystrix熔断等库解决网络营运问题已经完全被Service Mesh技术取代。
微服务必须设计成可恢复,多维度幂等性。
现代开发者必须很熟练的使用编程语言实现业务功能,同时也要对云原生技术相当熟练以便实现非功能性基础架构级别的需求
微服务的炒作是始于一系列关于组织架构,团队大小,服务大小,抛弃并重写服务而不是修复它以及避免单元测试等极端思想。以我的经验,这些思想许多被证明是错误的,不实用的,或者至少不是普遍适用的。如今,对剩下的许多原则和实践的定义亦是如此空泛和松散以至于虽然它们都是对的但多年以来却对实践没什么意义。
在Kubernetes诞生之前就被采纳的微服务架构现在依然是最流行的分布式架构风格。但Kubernetes和云原生运动大规模的重新定义了应用设计和开发的某些方面。在这篇文章,我想置疑一些最初的微服务思想并且承认一个事实:在后Kubernetes时代,这些思想已经不再和当初一样重要了。
服务不仅可观察还需自动化
可观察性从最初开始就是微服务的基本原则。这条原则对分布式系统普遍适用。今天(尤其是在Kubernetes上)可观察性的大部分功能都是平台级开箱即用的,比如健康检查,CPU和内存消耗。对应用程序最小的要求就是把log以JSON格式输出到控制台。然后,平台就可以监控资源消耗,进行请求跟踪,收集各类指标数据,错误率等而无需大量的服务级别的开发工作。
云原生平台,服务的可见性还不够。一个更基本的前提是通过健康检查,信号的响应以及声明所需消耗的资源等使微服务的自动化。它几乎可以把所有的应用装入容器并运行。但是创建能够被云原生平台自动化及有效编排的容器化应用需要遵循某些规则。遵循这些原则和模式可确保容器在许多容器编排引擎上表现得像一位云原生好公民,能很好地以自动化的方式被编排,伸缩和监控。
我们是希望平台可以侦测到服务异常然后按声明恢复到一致状态,而不是希望观察服务里头发生了。不管是截止进入服务实例的流量,重启及伸缩服务,还是迁移服务到健康的宿主机,重试失败的请求,或其他,这些都不重要。假如服务是自动化的,所有的动作都会自动发生,而我们仅仅需要描述想要的状态,而不是去发现问题,然后响应。一个服务应该是可观察的,但也是可以通过平台调整,不需要人工干预。
智能平台,智能服务,职责合理分工
从SOA架构转向微服务架构,“智能终端和哑管道”的概念是另外一个基础的关于服务间交互的转变。微服务的世界里,服务不依赖于中心化的智能路由层的存在,而是依赖处理某些平台级特性的职能端点。这是通过把传统的ESB某些功能植入微服务中,并改用不包含业务逻辑元素的轻量协议来达到的。
当这种使用如Hystrix库在不可靠的网络实现服务间交互的方式还很流行的时候,现在,在后Kubernetes时代,它已经完全被Service Mesh技术取代了。有趣的是,Service Mesh甚至比传统的ESB更智能。它可以实现动态路由、服务发现、基于时延,响应类型和监控指标负载均衡以及分布式跟踪,重试和超时等你所想到的。
Service Mesh和ESB不同的是,使用Service Mesh,不需要中心化的路由层,每个微服务典型地都会有自己的路由——一个Sidecar容器和一个额外的中心管理层一起执行代理逻辑。更重要的而是,管道(或者说是平台本身和Service Mesh)不拥有任何业务逻辑;它们纯碎关注基础架构问题,让服务关注业务逻辑。如下图所示,其代表从ESB到微服务的演化,以适应动态及不可靠的云环境。
从服务的另外一方面看,我们注意到云原生不仅仅影响端点和服务的交互。Kubernetes平台(包括使用的其他额外技术)负责资源管理,编排,部署,配置管理,伸缩,服务交互等。我想最好将其称之为各自具有合理职责的智能平台和智能服务,而不再称之为“智能代理和哑端点”。它不仅是关于端点,而是一个完整的平台,为聚焦业务功能的服务提供基础架构方方面面的的自动化。
为故障更为恢复设计
运行在本质上不可靠的基础架构和网络构成的云原生应用环境中的微服务必须处理故障。对于这点没有问题。但由平台捕获并处理的故障越来越多,余下的需要服务本身捕获的故障就少了。因而我们需要考虑服务故障恢复设计,比如多维度的幂等性。
容器技术,容器编排系统和Service Mesh能够侦测许多故障并恢复。如:死循环——CPU共享;内存泄漏及内存不足——健康检查;磁盘独占(磁盘猪)——配额管理;Fork 炸弹——进程限制;隔板和进程隔离——内存限制;基于服务发现的延迟和像响应,重试,超时,自动伸缩等。更不用说,随着转向无服务器模式,服务仅仅只要几毫秒来处理单个请求,对垃圾收集,线程池及资源泄露的关注也越来越少了。
平台可以处理这些故障甚至更多,可以把你的服务想象成一个黑盒子,能够多次启动和停止——服务对于重启是幂等的。你的服务可以多次伸缩——你的服务是无状态的,能安全的伸缩。假设收到请求将最终会timeout——保证端点幂等性。假设发送请求可能临时性失败,平台将会为你重试——保证你所使用的服务幂等性。
为了适合云原生环境的自动化,服务必须:
重启是幂等的
伸缩是幂等的
幂等的生产者(服务可以处理请求的重入)
幂等的消费者(服务或者mesh可以重试请求)
如果你的服务在上述动作被多次重复执行时保持行为一致,那么当故障发生时,平台能够帮助恢复你的服务,而无需人工干预。
最后,需要记住的是,所有由平台提供的故障恢复都仅仅是局部优化。Christian Posta说得好,确保分布式系统中应用的安全性和正确性仍然是应用本身的责任。整体业务流程级别的思维(可能跨越多个服务)对设计一个整体稳定的系统是必须的。
混合式开发职责
越来愈多的微服务原则由Kubernetes和其外围项目来实现并作为功能提供。因此,开发者必须很熟练的使用编程语言实现业务功能,同时也要对云原生技术相当熟练以便实现非功能性基础架构级别的需求,完整实现一个功能。
业务需求和基础架构(运维,跨功能需求以及系统质量属性)之间的界限一直是模糊的,不可能你只考虑一方面,而期望其他人去考虑另外一方面。 比如,假如你在Service Mesh这一层实现重试的逻辑,你就必须确保被使用的服务在业务逻辑和其内的数据库层的幂等性。假如你在Service Mesh层使用timeout,你就必须服务使用者timeout和服务内部timeout的同步。假如你需要实现一个重复运行的服务,那么你必须配置一个Kubernetes 任务来完成每一次的临时执行。
继而,服务一部分功能将作为业务逻辑在服务内部实现, 而另一部分由平台实现。使用对的工具做对的事是好的职责隔离的做法,技术的激增极大的提高了整体的复杂性。即便实现一个简单业务逻辑需求的服务都要求对分布式技术栈具有良好的理解,因为职责分布在不同的层。
Kubernetes已证明可以扩展到数千节点,上万pod以及每秒百万级事务。但是它能收缩回去吗?关于你的应用的大小和复杂度的阈值或者被证明会合理引入“云原生”复杂性的临界点是多少对我来说还不清楚。
结论
有趣的是,我们看到微服务运动如何激发大家如此多的动力采用如Docker和Kubernetes等容器技术。起初,是微服务实践推进这些技术发展,现在Kubernetes定义微服务架构的原则和实践。
就目前的情况来看,我们不久将会接受函数模型(注:ServerLess, 如AWS Lambda?)是有效的微服务原语,而不会认为它是微服务的反模式。我们没有充分置疑云原生技术对中小型案例的实用性和适用性,反而是兴奋的有些手足无措。
Kubernetes从EBS和微服务中学到了很多,正因为如此,它成为了最终的分布式系统平台。它是定义分布式系统架构风格的技术,而不是相反。这是好是坏,只有时间可以证明。