基于云原生应用平台实现应用服务可造性

2019-05-22 09:27刘琦
无线互联科技 2019年5期
关键词:应用服务

刘琦

摘 要:随着容器技术的快速发展,应用服务的支撑框架已从原先的物理机、云计算虚拟机到目前的基于Kubernetes的容器平台。基于容器平台的云原生应用通过应用本身的弹性、动态扩张实现可造性(resiliency)。文章从平台支持和应用本身的改造两方面说明云原生应用可造性的实现方式。

关键词:云原生应用;应用服务;可造性

1 云原生应用平台研究背景

云计算时代,各类云计算平台如雨后春笋般出现在各个企业中,虽然在服务类型和平台功能上有所差异,但是他们本质都是一样,均是一种资源的服务模式。云平台的快速发展,衍生了一系列云平台产品。随着大规模的互联网应用不断在云计算平台上遇到挑战,新的应用架构模式呼之欲出,在众多的实践和方法论中,云原生应用是其中的佼佼者,主要包含容器化、容器的动态编排和微服务。

2 云原生应用平台介绍

Kubernetes是Google开源的容器集群管理系统,构建在Docker技术之上,为容器化的应用提供资源调度、部署运行、服务发现动态伸缩等一系列完整功能,它最大的优点是可以显著提升整个集群的总CPU利用率,所以成为众多容器调度框架中最受欢迎的调度模式。云原生应用平台是基于Kubernetes实现的,在完全兼容Kubernetes、Docker 技术的基础上,提高大规模容器集群管理的便捷性。

2.1 使用场景

2.1.1 大型复杂系统

原本小而简单的应用会随着长时间使用变得臃肿,在大型复杂系统中,应用越大,启动时间越长,修复bug和实施新功能也就愈发困难且耗时颇多,从而影响开发和交付的敏捷性,大大降低了生产效率。面对数据中心规模大、应用数量多,技术架构多样,但运维人力有限的问题,将运维复杂度和应用规模解耦是可行的解决思路。从运维系统的角度出发,随着应用越来越复杂,必须引入相应的平台化手段进行解耦,避免有限的运维人力与不断扩大的数据规模之间的矛盾。

云原生应用平台通过微服务架构重新构建复杂的应用,将单体式应用从不同纬度拆分成多个微服务,每个微服务的内容使用一个Docker镜像管理。在功能不变的情况下,应用拆分成了多个可管理的服务,每个单体的服务容易理解、开发和维护。不同的服务也可以由不同的团队来开发,开发团队可自由选择开发技术和程序语言等,每个服务又可獨立部署、独立扩展。

2.1.2 业务频繁升级

庞大且复杂的应用的另一问题是难以进行持续部署更新,而目前的发展趋势要求应用可以在单日内多次将修改推送到生产环境。对于传统应用而言,更新应用的某个部分,必须重新部署整个应用,更新周期被无限拉长,漫长的启动时间更是雪上加霜,此外,由于不能完全预见修改的影响,用户不得不提前进行大量人工测试,使得持续部署变得不可能。实现快速迭代首先需要开发独立,如果一单体应用由几百人开发一个模块,将可能出现代码提交冲突频发、人员过多而难以沟通解决的情况。团队规模越大,冲突概率则越大。

当应用被拆分成不同的模块,每个模块由10个人左右进行维护时,首先可大幅降低代码冲突的概率,当技术冲突发生时也更容易解决。每个模块对外提供接口,其他依赖模块无需关注具体的实现细节,只需要保证接口正确。适合需要快速上线、频繁更新升级的业务。

云原生应用平台通过持续集成、持续交付、持续运维,极大提高软件的发布效率。持续集成强调开发人员提交了新代码之后,立刻进行构建、(单元)测试,便于确定新代码和原有代码能否正确地打包集成在一起。持续交付在持续集成的基础上,将集成的代码部署到预发布环境和现网环境上。而持续运维则通过各种自动化工具实现了整个应用在运行过程中的托管。通过以上3项功能实现应用全生命周期管理。

2.1.3 功能持续扩展

应用要实现快速迭代,首先需要上线独立。如果没有拆分微服务,每次上线都将面临各类挑战。当修改某个小功能时,因为依赖其他模块而造成的模块耦合、互相依赖,使得整体应用上线的复杂度更高、风险更大、周期更长。

当服务拆分后,在接口稳定的情况下,不同的模块可以独立上线。上线的次数增多,单次上线的需求列表变小,可随时回滚,风险降低,周期缩短,影响面小,从而加快迭代速度。对于需要接口升级的部分,可采取灰度的方式,先做接口新增,而非原接口变更,并通过注册中心监控接口调用情况,确保原接口不再使用再进行删除。

2.1.4 应用并发量大、稳定、高可用

可靠性是传统应用难以解决的问题之一。由于所有模块都运行在同一进程中,任何模块中的一个bug,例如内存泄漏都可能影响到整个进程。此外,由于应用中的所有实例都是唯一,这个bug将影响整个应用的可用性。

并发性是另一个问题。对于并发量不大的系统而言,进行云原生化的驱动力较低,如果只有少量的用户在线,多线程即可解决问题。然而对于存在突发性访问高峰,有明显波峰和波谷的应用而言,云原生化不仅可大幅提高其可用性,还可以实现热备和双活等特性。

2.2 核心功能

云原生应用平台为客户提供了一套完整的云原生应用服务,可提供容器服务、资源管理与编排、多租户镜像仓库、应用部署、应用全生命周期管理、持续集成以及应用常用通用组件,例如智能网关、基础账号体系支撑等功能。主要可以实现这六大特性:以应用驱动资源、多语言集成、一键式部署、快速发布更新、弹性伸缩、持续稳定。

云原生平台的主要功能包含以下方面。

2.2.1 资源统一纳管

(1)虚拟机、物理机混合管理:云原生应用平台容器平台能进行统一资源管理和调度,打通物理机、虚拟机,使之互相通信,协同工作。基于云原生应用平台创建的k8s集群,可实现基于IP地址手动添加虚拟机、物理机资源节点。提供对虚拟机或物理节点完善的管理功能,可以方便直观地获取主机监控信息以及主机信息等,包括CPU、内存、I/O。

(2)存储资源管理:云原生应用平台提供对存储节点完善的管理功能,容器应用通过持久卷实现状态存储,后台使用Ceph存储集群,云原生应用平台支持存储节点动态添加,可以方便直观地获取存储节点监控信息,包括CPU、内存、I/O。

(3)异构IaaS层资源接入:云原生应用平台异构实现对接多种异构IaaS,统一其接口及资源模型,可以实现在不同IaaS部署标准的Kubernetes集群。支持同时接入虚拟机CPU、虚拟机GPU、物理机CPU、物理机GPU 4种类型的资源管理。

(4)多集群、多租户隔离:云原生应用平台采用多集群、多租管理模型和租户的资源配额管理,严格实现多租户资源/服务的安全隔离。集群(Cluster)为物理隔离单位,实现物理资源隔离。租户(Tenant)为逻辑隔离单位,实现虚拟资源的逻辑隔离。如一个公司可创建多个集群,并在集群中配置多个租户,通过用户组、用户和权限对各个集群、租户的安全性进行隔离和控制。同时也能实现配额管理,为避免单一租户过量占用资源,可通过K8s集群中的租户管理实现资源配额,主要包括CPU和内存资源限制,同时也可以限制容器资源的创建。

2.2.2 集群自动化部署

云原生应用平台容器平台提供K8s集群的自动化部署。可实现部署过程中每一个步骤的自动化,在整个生命周期(包括部署在内)中把必须的人工干预降低到最小。

2.2.3 多租户镜像仓库

(1)多租户镜像管理:云原生应用平台提供对容器镜像的统一管理,内容包括镜像名称、版本,从软件包的镜像构成,以及镜像打包的统一规范流程,其主要功能包括:镜像全生命周期管理,镜像版本管理,安全扫描以及镜像仓库访问控制。

(2)镜像仓库访问控制:镜像仓库实现多租户访问控制,用户可以使用并修改被绑定租户中的镜像。

2.2.4 应用商店及一键式部署

(1)标准应用包管理:可以直接通过配置文件和容器镜像,对应用包进行管理,包括版本、配置文件、脚本等。

(2)大量PaaS、SaaS服务:为用户提供大量常用应用模板,包含成熟的PaaS服务,开源的服务(MySQL、Redis等),实现应用一键式部署

(3)自动化部署、升级:该平台为各种业务配置合适的资源进行安装部署,并支持應用的更新、升级、扩容、伸缩、卸载等。为各种业务配置合适的资源进行安装部署,并支持业务的更新、升级、扩容、伸缩、卸载等,其支持业务包括:无状态应用、有状态应用、多镜像联调部署模型。

(4)通过平台可以实现对应用的调度策略,以容器为最小运行单位实现应用的不同调度策略,包括:①应用(容器)间的亲和/反亲和性调度,不同的业务调度部署在相同或不同节点中。②应用与节点的亲和/反亲和性调度,应用的容器调度部署到指定的或与指定不同的节点中。

2.3 平台架构

在数字化转型的过程中,针对应用上云的需求,云原生应用平台结合原有的技术沉淀,为警务服务创建了一套云原生应用支撑平台。在基础实施和应用层面解决了警务应用在数字化转型中所面临的痛点,帮助客户采用云原生技术实现应用架构转型升级和高效管理。平台架构如图1所示。

3 应用服务可造性

3.1 应用拆分&集成

3.1.1 分拆模式

云原生应用采取有关松散耦合的服务,它采用的是单一职责原则。理论上要将应用分成多个小块,在实际分拆中一般遵守以下规则。按照业务功能分拆:业务功能是指产生价值的最小单位,一组给定业务的功能划分则取决于企业本身的类型,每一个业务功能都可以被看作是一种面向业务,而非技术的服务。

3.1.2 分拆规范

(1)规范一:服务纵向拆分最多3层、两次调用。服务拆分是为了横向扩展,因而应横向拆分而非纵向拆成多层级式。纵向最多拆分3层。

①基础服务层:用于屏蔽数据库、缓存层,提供原子的对象查询接口,封装数据从而实现数据库扩容、缓存替换等。使得数据对上层透明,上层仅调用这一层的接口而不直接访问数据库和缓存。

②组合服务层:这一层调用基础服务层,完成较为复杂的业务逻辑,实现分布式事务也多在这一层。

③对外接口层:调用组合服务层对外提供标准接口。

(2)规范二:仅单向调用、严禁循环调用。服务拆分后,如果服务间的依赖关系复杂(如循环调用),则升级将会变得难以维护。因而层次之间的调用规定如下。

①基础服务层主要做数据库的操作和一些简单的业务逻辑,不允许调用其他任何服务。

②组合服务层可以调用基础服务层,完成复杂的业务逻辑,可以调用组合服务层,不允许循环调用,不允许调用对外接口层服务。

③对外接口层,可以调用组合业务层服务,不允许被其他服务调用。如果出现循环调用,则使用消息队列,将同步调用改为异步调用。

(3)规范三:将串行调用改为并行或异步调用。如有的组合服务需要调用多个外部服务,应考虑如何通过消息队列实现异步化和解耦。对基于Kubernetes的云原生应用,使用消息队列可增强其横向扩展能力。或者通过Kubernetes内服务自带的负债均,这样处理时间会大大缩短(不是多次调用的时间之和,而是调用所需最长时间)。

(4)规范四:接口严格按照REST标准写。以前不同服务接口之间传递往往通过数据结构,从底层一直到上层使用同一个数据结构,或上层的数据结构内嵌底层的数据结构。当数据结构中添加或者删除一个字段的时候,波及的面会非常大。因REST标准在每两个接口之间约定,严禁内嵌和透传。这样接口协议的改变,影响面仅仅在调用方和被调用方,当接口需要更新的时候比较可控,也容易升级。

3.2 应用容器化

3.2.1 应用分析

操作系統:应用运行的操作系统类型和版本,如centos7.2。

运行环境:Java,go,php,python等,以及对应的版本号。

依赖:如openssl,以及对应的版本号。

3.2.2 尽量使用TCP、HTTP协议

服务间接口调用使用非标准协议进行交互(如EJB调用使用t3协议),无法通过负载均衡器进行有效负载。建议服务间接口调用通过TCP和HTTP协议进行交互,这样可使用负载均衡器进行有效负载。

3.2.3 确定域名、端口

每个服务尽量只提供一个服务。

避免使用IP:如果服务需要与其他服务通讯,由于容器IP是不固定的,依赖IP地址将无法实现通讯。建议在程序中尽量使用域名代替IP,并且通过Kubernetes的Service负债均衡,尤其对传统非改造的应用直接搬迁,需要使用这个模式。集群中访问,则使用service的域名方式访问更好。

监听固定端口:对于标准的服务只需提供一个对外服务端口,而有些服务在运行过程中会自己产生一些服务端口对外服务,而且这些端口是随机产生,给管理带来不便。建议在服务设计时尽量使用固定服务端口,并且需要让端口固定下来并体现在集成文档中。

3.2.4 设计好程序启动过程和时间

虽然容器服务本身可以做到“秒级”启动,但是对于程序如何在容器/Kubernetes里启动,需要遵守标准的规范。程序在容器内启动过程大体如图2所示。

Kubernetes提供双重检查:liveness和readiness。容器启动并不代表程序已经可以被访问,因为容器内部程序启动比较费时,如果此时去访问服务则很容易timeout。

Liveness: 确保程序还存活,否则Kubernetes就会重启这个POD。

Readiness: 确保程序已经可以接收流量了,否则不会分发流量给它。

3.2.5 充分利用K8s Deployment & Service

使用Kubernetes的Deployment的方式来部署服务,Deployment会保证服务时刻有一定的副本存活,提高了服务稳定性。其次,Kubernetes的Service可以实现负载的均衡。Kube-DNS可以将Service名解析成具体的ClusterIP。基于Kube-DNS和Service的特性,可以实现服务的注册发现和负载均衡。具体如图3所示。

3.3 应用无状态化

有状态应用是指在应用内存储状态信息。例如用户在登录后会有一定的会话信息(也就是应用中的session对象)存储在实例中,如果该实例异常停止,该用户的会话信息就会丢失。

建议应用开发时将用户的会话信息保存到缓存(如Redis,Memcached)中,根据用户的唯一标识session_id来对缓存服务器进行存取用户的会话信息,这样会话信息与应用实例分离,实现应用无状态化。

3.4 热数据缓存

热数据指程序在运行过程中经常使用的数据,传统方式是程序在启动时通过数据库加载到程序实例缓存中,提高数据的访问速度,但往往因为加载的数据过多而导致系统启动过慢。

建议程序在设计时将热点数据存放到缓存(如Redis,Memcached)中,在启动时避免执行加载缓存动作,提高程序启动速度,相关热点数据可通过手动或自动方式更新到缓存中,程序通过访问缓存获取相关热点数据。

3.5 有状态数据库

服务必须是松散耦合的,以便部署和独立扩容,尤其当各个服务需要横跨多个服务时。当应用需要从多个服务中查询到数据时,有时需要根据需求和规模对数据库进行复制或分片,不同的服务具有不同的数据存储需求。

服务单独DB:为每个服务配备一个独享的数据库模式,该数据库仅能被其对应服务的API单独访问,而不能被其他服务直接访问到。每个服务应该拥有一个单独的数据库ID,以便它们在独享访问的同时,禁止再访问其他的服务表集。

服务共享DB:服务单独DB是一种理想的微服务模式,只有在新的云原生应用中会用到。但对于采用微服务架构的应用,按服务共享DB的模式虽然有些违背微服务的理念,但对于将传统的单体应用拆分成较小的逻辑块而言是更为适用的。在该模式下,一个数据库可以匹配多个服务,当然至多2~3个,否则会影响到扩容、自治性和独立性。

3.6 网络梳理

对应用容器化后的网络进行规划是另一个重要工作。首先容器平台本身分为管理集群master,计算集群slave以及包含其他日志、监控、镜像仓库等系统服务的集群。可以将管理集群、日志、监控等划入管理IP网段,将计算集群划入业务IP网段,并且对每台主机上安装的组件进行端口规划。

另外,需要根据应用的特性,进行网络模式选择。例如无状态的分布式应用,可以在容器部署时使用bridge模式。需要指定端口的应用,或者对网络性能要求高的应用,更适合使用host网络模式,但使用host模式时,需要进行网络端口资源规划,同样的应用实例只能在一台主机上部署一个,避免端口冲突。

4 云原生应用平台展望

云原生应用,专门为在云平台部署和运行而设计的应用。通过容器化、容器的动态编排和微服务来统一管理应用,实现资源的统一纳管、集群的自动化部署、多租户镜像仓库和应用商店一键式部署,整个平台满足应用运行所需的资源、部署、管理等各个环节,真正可实现应用自动化管理,带来应用开发的新时代。

[参考文献]

[1]BALALAIE A,HEYDARNOORI A,JAMSHIDI P.Microservices architecture enables devops: migration to a cloud-native architecture[J].IEEE Software,2016(3):42-52.

[2]BALALAIE A,HEYDARNOORI A,JAMSHIDI P.Migrating to cloud-native architectures using microservices: an experience report[C].Taormina:European Conference on Service-Oriented and Cloud Computing,2015:201-215.

[3]BREWER E A.Kubernetes and the path to cloud native[C].New York:Proceedings of the Sixth ACM Symposium on Cloud Computing,2015:167.

[4]ROUSSEV V,MCCULLEY S.Forensic analysis of cloud-native artifacts[J].Digital Investigation,2016(16):104-113.

[5]TOFFETTI G,BRUNNER S,BL?CHLINGER M,et al.Self-managing cloud-native applications: design,implementation,and experience[J]. Future Generation Computer Systems,2017(72):165-179.

猜你喜欢
应用服务
加快推进航天强国建设 提升卫星应用服务能力——两会代表委员为航天发展建言献策
全球卫星互联网应用服务及我国的发展策略
高校图书馆微信公众平台应用研究
国家不动产统一登记信息平台构建与应用服务
全力推进不动产登记信息管理基础平台建设与应用服务
地名地址应用服务系统的研究与实现
大数据服务在高考填志愿中服务的心理学意义探讨
智慧校园建设架构与应用服务研究——以安徽工程大学为例
本地应用服务交付平台的功能架构要求研究
全国征集卫星应用服务解决方案