采用云原生技术开发,你需要懂的事项

在容器云平台运维中,我们常被应用服务的低级错误所困扰,本文直击痛点,强调“预则立”思维,逐一剖析采用云原生技术在开发阶段需要懂的事项。云原生应用的成功,始于开发阶段对需求、架构、部署和运行环境等的深度理解以及应用架构可扩展性、高可用、可观测性、安全等的前瞻性设计,本文为追求稳定性与敏捷性平衡的技术团队,提供了一份可贵的务实指南。

在运维容器云平台的过程中,经常会被应用服务的一些低级错误搞的很无语,不得不一再提醒研发人员关注服务设计、架构和实现逻辑,关注部署场景和特性需求等。我一直强调:不懂运维就做不好开发,应用运行和操作系统、运行环境、IO、网络、存储、部署架构等密切相关,不是仅仅懂开发语言或开发框架API就够了(所以真正的SRE其价值远远高于普通研发工程师价值),以终为始,具备运维视角是保障应用设计可部署、可观测、可扩展、稳健高可用等的关键。

在采用微服务、容器等云原生技术开发应用过程中,需要提前考虑应用部署、运行、日志、可观测和故障处理等问题。首先就需要认识到和理解云原生技术特点和适用场景。

1、理解云原生技术特点和适用场景

我们所常说的云原生技术包括容器、微服务、DevOps 、ServiceMesh 、持续交付等,通常采用微服务架构来设计实现应用,部署运行在容器中,通过Kubernetes 进行调度和管理,以DevOps 和持续交付等实现编译测试部署等流程自动化,以ServiceMesh 等实现监控和链路跟踪等。服务运行容器中,需要对容器的特性和适用场景有深入的理解才能用好容器。容器通过容器镜像实现了运行环境一致性,从而可以敏捷分发和弹性扩展。也正是基于云原生容器等这些特点,其适用场景是敏捷、频繁变更、动态扩缩容等场景。理论上说,容器是不稳定的,其特点就是动态弹性,变化是常态 。它通过多实例高可用、多集群多数据中心部署、负载均衡等机制实现动态稳定。到目前为止,依然有很多单位和人员把容器当虚拟机在用,失去了容器的轻量、弹性等特点和优势。若把容器当虚拟机用,既无法发挥容器的特点优势,也往往无法获得稳定性,甚至会因为量的增加和多层封装导致运维复杂化。

微服务架构的目的是解决庞大的单体系统难以变更的问题,通过拆分、分布式松耦合、服务自治等,满足敏捷变更需求。如果微服务运行在容器中,则在设计实现之初就需要考虑服务的部署架构和部署要求。

2、云原生应用和服务部署要求

微服务和容器结合带来很大便利,但需要认识到,微服务架构不是解决所有软件问题的良药,一些场景微服务架构并不一定合适,因此也出现了有人贬低微服务架构,重新捡起单体应用架构等情况。时移事移,不同场景需求不一样,如果死搬硬套,肯定是不合适的。所以我也一再强调要理解云原生容器、微服务等技术特点和适用场景,才能更好地设计和开发出满足业务需求的应用软件。

采用微服务架构的云原生应用在设计开发之初就需要考虑如何部署问题,应用是部署在虚拟机?还是部署在容器中?是否需要利用容器的特性?还是把容器当虚拟机使用?等等。其实,业务需求直接就决定了服务架构选型、设计模型、交互模式、监控可观测方式、部署架构等(这也是我强调基于需求做架构治理的关键所在)。部署要求和部署架构也往往影响着微服务拆分的粒度。微服务拆分的粒度合适、功能范围定义的合理,才能体现出微服务架构的优势(减少依赖和交互、提升自治能力)。比如说日志组件,整体可以是一个独立、自治的微服务组件,但它本身可能由多个服务组件组成(例如logappenders、layouts 、filters等),这些组件可分布式部署,也可整体部署为一个微服务组件。再例如消息组件,其本质是为了满足分布式应用之间的交互,因此需要提供Pub -Sub 、Req - Res、send -Listener 等多种同步和异步交互模型。不同的部署要求和部署架构,对组件中服务接口的交互设计实现就会有差别。最简单的是单体部署在一起,无需通过网络交互,效率最高,安全性、稳定性最好,但扩展性、弹性可能就差。因此,部署需求和架构往往影响着微服务的拆分和设计,需要在设计之初基于需求考虑这些问题。

3、微服务容器化和服务注册发现

在容器云或云原生PaaS环境中,微服务或服务的注册发现需要厘清楚。

首先,采用微服务开发框架如SpringCloud 等有自己的注册发现组件如Eureka 等,其和Kubernetes内的容器服务的注册发现机制(Service)是不一样的。部署在容器中的微服务也是容器服务(从业务角度,也是业务服务),因此往往混淆在一起,很多厂商单独弄了个微服务治理工具,搞的异常复杂化。有必要单独部署微服务治理工具吗?完全没必要,甚至服务开发的时候都不需要实现服务注册发现代码,部署在Kubernetes之后,生成Service就自动在Kubernetes 实现了注册,所以如果容器化部署,根本不需要考虑微服务框架服务注册发现问题,只需要关注和实现服务逻辑就可以了。

其次是服务暴露的问题,Service是Kubernetes内部对象(作用域是Kubernetes集群内),要想从Kubernetes外部访问,就需要通过NodePort 、Ingress、 Load balancer 等机制把服务暴露出去,多个集群高可用往往还需要单独部署API网关或负载均衡器。这些都和Eureka 等组件没有任何关系,因此对于容器云平台和云原生PaaS来说,无需部署Eureka等组件。那Eureka等能用在什么地方?可用于单个应用内部或者微服务应用非容器化部署,作为其自身服务的注册发现组件,方便应用管理自己的服务组件,但这个Eureka就是应用的一部分了。

第三,集群内服务的访问要使用Service ,集群间访问通过暴露的服务API。如果有服务异常,比如说节点维护导致服务被驱逐重启,这需要多实例实现高可用,或者需要能够通过负载均衡器路由到另外集群上的服务。

4、高可用多实例和负载均衡

微服务和容器虽然有很多优势,但数量的累积带来管理和运维的更大复杂性,因此需要实现自动化的持续集成、持续交付、可观测、弹性伸缩、负载均衡等自动化能力。弹性和负载分发通常支撑高可用场景。在高可用场景需求下,也有多种部署方式,例如服务多实例高可用、应用蓝绿部署、应用双活高可用部署等。

服务多实例是指一个服务可以部署多个实例实现高可用。当一个实例出现异常,其他实例可以继续正常运行,从而实现 Kubernetes 集群内实例间的高可用。在kubernetes集群中,提供了Service对象支持多实例高可用。在跨Kubernetes 集群时,就需要集群外的软硬件负载均衡器来实现负载分发。不管是通过nodeport 、ingress或其他方式对外暴露服务,一旦涉及跨集群,往往就必须考虑负载均衡器的使用。在多集群或多集群多数据中心之间,可以通过蓝绿部署、Active-Active 双活部署等方式实现容错或高可用。

一个应用通常包含一到多个服务(从微服务架构视角,可以是微服务组件),每个服务可独立部署和运行在容器中,服务之间通过API交互。这里就涉及了集群内交互还是跨集群交互的问题。一个应用通常不建议出现跨集群的交互,在需要高可用时,可采用应用蓝绿或双活部署,而不是服务级的蓝绿或双活部署。这在日常的管理中是非常重要的一些原则。所以说微服务不是越小越好,而是要基于实际部署需求和变更需求等合理定义服务组件,尽可能减少服务之间的交互,特别是跨集群的交互。所以我也经常提醒一些研发人员,需要考虑将多个小服务合并为一个服务,特别请求量很少的服务 、使用GPU算力的服务、 分时段的业务处理 服务等,要尽可能合并处理请求,减少资源占用, 以提高资源使用效率和运维效率等。

5、多实例弹性伸缩

弹性是云原生容器最大的特性之一,因此绝对不应该拿容器当虚拟机使用、为了容器化而容器化(不建议把历史遗留应用服务不经改造就一股脑容器化)。如果要使用容器的弹性特性,那么服务在设计时就需要考虑服务实例扩容问题。如果服务不支持扩容多实例,也是无法享受容器弹性的优势,所以应用服务的设计和实现模式会影响着其部署和运行模式,在服务设计实现时需要考虑服务的弹性伸缩问题。

在服务弹性伸缩需求场景中,需优先纵向资源伸缩( Request合理, Limit 可2倍或更大 ),减少不必要的实例数(控制横向伸缩) 。服务实例数不是越多越好,要尽可能控制实例数量。基于稳定性与运维复杂度等的权衡,多数场景下,可将单个服务的实例数控制在合理范围内,大多数情况下不建议超过10个实例(只是个人经验和体会,算不得最佳实践和常见实践)。服务实现时需要考虑多线程或线程池等设计,也就是首先要做到单个实例的纵向弹性,而不是动不动就触发实例数量的扩缩容。还有一点,Kubernetes默认使用CPU、MEM作为弹性伸缩的指标是非常不靠谱的,因为这两个指标可能变动比较频繁,特别CPU可能变化很快,存在可能因为错误配置导致集群崩溃(CPU、MEM配置错误触发弹性规则持续创建新实例)。

这里需要提一句,如果使用underlay 网络,将Pod IP对外暴露,虽然方便定位是哪个Pod 的Input /Output 请求,方便防火墙管理等,但也可能使IP泛滥,不便弹性伸缩,管理难度成倍增加等。容器的动态生成销毁也难以通过CMDB 管理。在Pod 少且希望以虚拟机方式使用,是有合理性的,但一旦Pod量增长起来,就不合适了。因此,个人建议采用overlay +Load balancer 方式,合理规划服务粒度和部署架构。

6、日志、链路和可观测

应用服务的日志、链路跟踪和可观测在设计实现时也是需要考虑的,而不是在运行时通过额外工具进行采集。日志、指标、链路跟踪等通常要放在一起规划和定义,因为这些是相互联系的,是实现监控和可观测能力的数据基础。另外我们说可观测是应用自身的可见性和可观察性,通常不是借助外力工具通过采集实现,而是应用服务主动对外暴露相关数据以实现运行时内外部状态、指标数据、访问链路等的可观测。

为了实现统一的日志管理和监控可观测能力,日志、指标等在企业内最好要标准化,每个系统都遵循同样的日志规范和标准,比如日志组件统一维护、日志格式规范、基于场景和安全的日志级别输出规范、日志收集、指标收集、数据动态处理等。运行时的数据往往需要实时进行预处理或计算、统计、滑动时间窗口分析等。这也可能需要专业的SRE来持续关注和优化。原始数据和处理数据都需要按需存储,适时归档等。否则数据的快速增长可能成为一项巨大的压力。

在云原生应用服务研发设计过程有很多的事项都需要提前考虑,预则立嘛。采用云原生容器、微服务等技术设计开发云原生应用的成功,始于开发阶段对需求、架构、部署和运行环境等的深度理解以及应用架构可扩展性、高可用、可观测性、安全等的前瞻性设计。以应用部署和运行目标环境为依托,也是解锁容器弹性、微服务敏捷价值的关键。

请使用浏览器的分享功能分享到微信等