当前位置:   article > 正文

知识分享系列二:云原生技术_容器云原生技术

容器云原生技术

云原生技术

本文系统地介绍了云原生技术的产生背景、主要技术,以及云原生技术助力降本增效的案例。云原生涉及的内容较广,本文的深度不会很深,停止在知道是什么的层面,希望本文能帮助初接触云原生的读者加深理解,如有不对之处也烦请不吝赐教。全文篇幅较大,有些太过细节的内容已经用方框标注,如果不感兴趣可以跳过,不影响理解。


目录

一、产生背景

二、主要技术

2.1 容器技术

2.1.1 容器与虚拟化

2.1.2 容器应用架构

2.1.3 容器引擎架构

2.1.4 Namespace与Cgroups

2.2 容器编排

2.2.1 K8S主要功能

2.2.2 K8S系统架构

2.2.3 Pod原理与调度

2.2.4 K8S存储方案

2.2.5 应用编排管理

2.2.5.1 工作负载Workload

2.2.5.2 服务访问

2.2.5.3 应用监控管理

2.3 微服务

2.3.1 诞生背景

2.3.2 微服务设计约束

2.3.2.1 微服务个体约束

2.3.2.2 微服务与微服务之间的横向关系

2.3.2.3 微服务与数据层之间的纵向约束

2.3.2.4 全局视角下的微服务分布式约束

2.3.3 云原生微服务典型架构

2.3.3.1 第一代微服务架构

2.3.3.2 第二代微服务架构

2.3.3.3 第三代微服务架构—服务网格

2.3.3.4 第四代微服务架构—多运行时微服务架构

2.4 Service Mesh技术

2.5 Serverless

2.5.1 Serverless主要技术

2.5.1.1 FaaS(Function as a Service,函数即服务)

2.5.1.2 BaaS(Backend as a Service,后端即服务)

2.5.2 Serverless应用场景举例

2.5.2.1 场景一:应用负载有显著的波峰波谷

2.5.2.2 场景二:基于事件的数据处理

2.5.3 Serverless的劣势

2.5.3.1 不适合长时间运行应用

2.5.3.2 完全依赖于第三方服务

2.5.3.3 缺乏调试和开发工具

2.5.3.4 构建复杂

2.6 云原生中间件

2.7 DevOps

2.7.1 持续集成(CI)

2.7.2 持续交付(CD)

2.7.3 持续部署

2.7.4 DevOps

三、企业案例

3.1 阿里云云原生相关产品

3.2 数禾科技AI模型Serverless容器化

3.3 智联招聘升级为云原生架构,释放Serverless技术红利

参考文献


一、产生背景

随软件规模的增大、业务模块规模变大、部署环境增多、分布式复杂性增强、版本迭代速度加快,今天的软件构建变得越来越复杂,大量非业务性的事务耗费了大量人力物力。简单总结一下,软件更复杂、迭代需求更快、稳定性要求更高

云计算出现后,云厂商提供了统一的IaaS能力和云服务,大幅提升了企业IaaS层的复用程度,但还远远不够,云计算从工业化应用到如今,已走过十七个年头,大量应用使用云的方式仍停滞在传统IDC时代:

  • 上云的程度仅停留在使用虚拟机代替原来的物理机
  • 使用文件保存应用数据
  • 大量自带的三方技术组件
  • 没有经过架构改造(如微服务改造)的应用上云
  • 传统的应用打包与发布方式

对于如何使用这些技术,没有绝对的对与错,只是在云的时代不能充分利用云的强大能力,不能从云技术中获得更高的可用性与可扩展能力,也不能利用云提升发布和运维的效率,是一件非常遗憾的事情。

为使资源、产品可被不断复用,为能够进一步降低企业运营成本,IaaS以上层的系统也需要被统一,云的时代需要新的技术架构,来帮助企业应用能够更好地利用云计算优势,充分释放云计算的技术红利

  • 2013年,Pivotal公司的Matt Stine首次提出云原生的概念,用于区分为云而设计的应用和云上部属传统应用;
  • 2015年,云原生计算基金会(CNCF)成立,把云原生定义为包括: 容器化封装+自动化管理+面向微服务;
  • 2018年,CNCF又更新了云原生的定义,把服务网格(Service Mesh)和声明式API给加了进来。
  • 在业界的共识是,云原生不是一个产品,而是一套技术体系和方法论,其原则是摒弃传统的运维开发框架,通过容器化和DevOps、微服务架构实现应用【弹性伸缩】和【自动化部署】,充分利用云计算资源实现在最少的空间里做最大的事

作为诞生于云计算时代的新技术理念,云原生拥有传统IDC无法比拟的优势,成为驱动业务增长的重要引擎。综上,云原生架构主要带来了以下提升:

1.快速开发:

  • 非功能特性代码:任何应用都提供两类特性,功能性特性和非功能性特性。功能性特性是真正为业务带来价值的代码,比如如何建立客户资料、如何处理订单、如何支付等等;即使是一些通用的业务功能特性,比如组织管理、业务字典管理、搜索等等也是紧贴业务需求的。非功能性特性是没有给业务带来直接业务价值,但通常又是必不可少的特性,比如高可用能力、容灾能力、安全特性、可运维性、易用性、可测试性、灰度发布能力等等
  • 举例:今天大部分的编程语言中,都有文件、网络、线程等元素,这些元素为充分利用单机资源带了好处,但是却带来了分布式编程的复杂性;因此大量的框架和产品涌现,来解决分布式环境中的网络调用问题、高可用问题、CPU争用问题、分布式存储问题。
  • 提升:在云的环境中,“如何获取存储”变成了若干服务,比如对象存储服务、块存储服务和没有随机访问的文件存储服务。云不仅改变了开发人员获得这些存储能力的界面,还在于云产品在这些OpenAPI或者开源SDK背后把分布式场景中的高可用挑战、自动扩缩容挑战、安全挑战、运维升级挑战等都处理了,应用的开发人员就不用在其代码中处理节点宕机后如何把本地保存的内容同步到远端的问题,也不用处理当业务峰值到来时如何对存储节点进行扩容的问题。这些使得业务代码的开发人员技能栈中,不再需要掌握文件及其分布式处理技术,不再需要掌握各种复杂的网络技术。简化让业务开发变得更敏捷、更快速!

2.自动发布(高度自动化的软件交付)

  • 现象:软件交付的困难在于公司环境到客户环境之间的差异,以及软件交付和运维人员的技能差异,填补这些差异的是一大堆的用户手册、安装手册、运维手册和培训文档。
  • 容器化:容器就像集装箱一样,以一种标准的方式对软件打包,容器及相关技术则帮助屏蔽不同环境之间的差异,进而可以基于容器做标准化的软件交付
  • DevOps基于云原生的自动化软件交付相比较当前的人工软件交付是一个巨大的进步。以微服务为例,应用微服务化以后,往往被部署到成千上万个节点上,如果系统不具备高度的自动化能力,任何一次新业务的上线,都会带来极大的工作量挑战,严重时还会导致业务变更超过上线窗口而不可用。

3.稳定运维(云的可用性与可扩展能力)

以大家最头疼的高可用为例,云产品在多个层面为应用提供了解决方案:

  • 虚拟机时代:当虚机检测到底层硬件异常时,可以自动帮助应用做热迁移,迁移后的应用不需重新启动而仍然具备对外服务的能力,应用对整个迁移过程甚至都不会有任何感知;
  • 容器时代:有时应用所在的物理机是正常的,只是应用自身的问题(比如 bug、资源耗尽等)而无法正常对外提供服务了,容器通过监控检查探测到进程状态异常,从而实施异常节点的下线、新节点上线和生产流量的切换等操作,整个过程自动完成而无需运维人员干预;
  • 云服务时代:如果应用把“有状态”部分都交给了云服务(如缓存、数据库、对象存储等),加上全局对象的持有小型化或具备快速重构能力,那么应用本身会变成更薄的“无状态”应用,再加上云服务本身极强的高可用能力,高可用故障带来的业务中断可降至分钟级;如果应用是N-M的对等架构模式,那么结合Load Balancer产品可获得几乎无损的高可用能力!

二、主要技术

对企业而言,云原生技术能提升应用开发的交付效率,缩短应用上线所需的时间,企业有更多时间和精力进行业务创新。一开始,云原生技术生态主要集中在容器、微服务、DevOps等技术领域,但现在已扩展至底层技术、编排及管理技术、安全技术、监测分析技术以及场景化应用等众多分支,初步形成了支撑应用云原生化构建的全生命周期技术链。

企业业务要想真正的云化,不仅要在基础设施和平台层面实现,而且应用本身也应该基于云的特点进行开发从架构设计、开发方式、部署维护等各个阶段和方面重新设计,构建真正应“云”而生的“云原生应用”。

2.1 容器技术

容器作为标准化软件单元,它将应用及其所有依赖项打包,使应用不再受环境限制,可以在不同计算环境间快速、可靠地运行。以前部署应用需要在物理机上装系统、装环境、装依赖项,最后才能部署应用本身,哪怕虚拟机出现后,准备环境和依赖项仍然是件麻烦的事情,不同版本的环境和依赖项还有可能影响稳定性,而容器则很好地解决了以上问题。

2.1.1 容器与虚拟化

  • 虚拟机技术:通过Hypervisor虚拟化物理硬件,并将虚拟化硬件分配给各个虚拟机,每个虚拟机有自己的操作系统(Guest OS),各个Guest OS管理着自己的虚拟硬件,相互间隔离。
  • 容器(container)技术:一种更加轻量级的操作系统虚拟化技术
    • 将应用程序及其运行依赖环境(bin和lib)打包封装成标准化、强移植的镜像
    • 镜像文件通过容器引擎启动成为实例,每个实例都只是宿主系统中的一个进程
    • 容器引擎与宿主机的操作系统内核交互,通过Linux Cgroups分配资源,通过Namespace限制每个容器实例对系统其他资源的访问和可见性(进程能够隔离运行,同时访问各自的系统资源,这个概念是所有容器实现的基础);
    • 通过容器引擎与容器编排调度平台实现容器化应用的生命周期管理。

容器的一个常见用例是在同一主机中拥有同一服务(例如,数据库服务器)的多个副本。每个副本都有独立的资源(文件系统、端口、内存),因此服务不需要处理资源共享,隔离保证故障或有害服务不会影响同一主机或底层系统中的其他服务或容器。

图1  传统、虚拟机、容器部署模式比较

  • 容器的优势:虚拟机中包含操作系统,调度与资源占用都比较重,而容器仅包含应用运行所需的文件,基于操作系统虚拟化技术共享操作系统内核轻量、没有资源损耗、秒级启动、易于移植、敏捷弹性伸缩,极大提升了系统的应用部署密度和弹性;
  • 虚拟机的优势:虚拟机是OS系统级隔离,而容器是进程级隔离,容器的安全性相对更弱一些,需要一些额外的安全技术或安全容器方案来弥补。

表1 虚拟机和容器技术对比

对比项

虚拟机

容器

镜像大小

包含GuestOS,几十G以上

仅包含应用运行的bin/lib,几十M

资源要求

CPU按核分配,内存按G分配

CPU0.x核分配,内存按0.0xG分配

启动时间

分钟级

毫秒/秒级

可移植性

跨物理机器迁移

OS平台迁移

弹性伸缩

VM自动伸缩、CPU/内存手动伸缩

实例自动伸缩、CPU/内存自动在线伸缩

隔离策略

OS、系统级

Cgroups、进程级

2.1.2 容器应用架构

虽然2008年Linux就提供了Linux Namespace视图隔离方案、Cgroups资源管理机制,让应用得以运行在独立沙箱环境中,避免相互间冲突与影响,但标准化与可移植性面临较大挑战;直到Docker容器引擎的开源才很大程度上解决了容器标准化与可移植性问题Docker提出了创新的应用打包规范—Docker镜像,解耦了应用与运行环境,使应用可以在不同计算环境间一致、可靠地运行

2016年OCI组织推出了开放容器标准,包括容器运行时标准(runtime spec容器镜像标准(image spec,推动了容器技术的广泛应用。借助容器技术,实现了一个优雅的场景:让开发所需要的灵活性、开放性和运维所关注的标准化、自动化达成相对平衡。如下图,docker应用是一种C/S架构,包括3个部分:

1.Docker ClientDocker的应用/管理员,通过相应的docker命令通过HTTP或REST API等方式与docker daemon实现docker服务使用与管理。

2.Docker Host运行各种docker组件,提供容器服务。其中Docker Daemon负责监听Docker Client的请求并管理docker对象(容器、镜像、网络、磁盘等);Docker Image提供容器运行所需的所有文件;Linux内核中的Namespace负责容器的资源隔离,而Cgroup负责容器资源使用限制,每个容器的文件系统与其他容器是隔离的;容器内的存储层是跟随容器变化的,生命周期同容器保持一致,容器删除,则存储层信息丢失,所以存储东西最好使用存储卷(volume)、绑定宿主目录等方式。

3.Docker Registry容器镜像仓库,负责docker镜像存储管理。可以用镜像仓库如Docker Hub或者自建私有镜像仓库,通过docker push/pull往镜像仓库上传/下载镜像。

所以,Docker运行过程就是Client发送Docker run命令到Docker Deamon,Docker Deamon从本地或镜像仓库获取Docker镜像,然后通过镜像启动运行容器实例。

图2 Docker容器应用架构

2.1.3 容器引擎架构

容器引擎负责容器的生命周期管理与资源管理,2017年4月docker公司将docker项目改名为Moby。Moby容器引擎的内部架构下图:

1.Moby daemon通过HTTP/HTTPSRestful API对外提供容器、镜像、网络与存储的管理。

2.Containerd容器运行时管理引擎,向上提供gRPC调用,实现镜像与容器的基本管理。通过containerd-shim插件模块实现对不同容器运行时模块的创建、动态接管,保障Moby daemon或containerd动态升级时对业务不产生影响。

3.容器运行时RunC基于OCI标准实现,负责容器的配置文件、运行环境与生命周期管理。另外应对Docker容器安全性不足,新推出Kata、gVisor等安全容器技术。

图3 Moby容器引擎架构

2.1.4 Namespace与Cgroups

Linux namespace负责容器的工作空间与资源隔离

容器中namespace通过unshare系统调用来创建,Linux内核提供了7中namespace:

1.PID namespace保障进程隔离,每个容器都以PID=1的init进程来启动;

2.MNT namespace: 保障每个容器都有独立的目录挂载路径;

3.UTS namespace保障每个容器都有独立的主机名或域名;

4.NET namespace保障每个容器都有独立的网络栈、socket和网卡设备;

5.IPC namespace只有在相同IPC命名空间的容器才可以利用共享内存、信号量和消息队列通信;

6.User namespace用于隔离容器中UID、GID以及根目录等,可配置映射宿主机和容器中的UID、GID;

7.Cgroup namespace保障容器中看到的cgroup视图像宿主机一样以根形式来呈现,同时让容器内使用cgroup会变得更安全。

Cgroups对容器进程进行层次化分组,并按组实现资源限制和策略控制

1.Cgroupfs驱动:需要限制CPU或内存使用时,直接把容器进程的PID写入相应的CPU或内存的cgroup;

2.Systemd cgroup驱动:提供cgroup管理,所有的cgroup写操作需要通过systemd的接口来完成,不能手动修改。

Linux内核提供了很多Cgroup控制器,容器中常用的是

1.cpu/cpuset/cpuacct group设置CPU share、cpuacct控制CPU使用率;

2.memory group控制内存使用量;

3.device group控制在容器中看到的device设备,保障安全;

4.freezer group容器停止时Freezer当前容器进程都写入cgroup,进程冻结;

5.blkio group限制容器到磁盘的IOS、BPS;

6.pid group限制容器里面可用到的最大进程数量。

2.2 容器编排

2.2.1 K8S主要功能

Kubernetes已经成为容器编排的事实标准,被广泛用于自动部署,扩展和管理容器化应用。Kubernetes提供了分布式应用管理的核心能力:

  • 容器资源调度:根据应用请求的资源量(CPU、Memory,或者GPU等设备资源),在集群中选择合适的节点来运行应用
  • 应用部署与管理:支持应用的自动发布与应用的回滚,以及与应用相关的配置的管理,也可以自动化存储卷的编排,让存储卷与容器应用的生命周期相关联,此外还有秘钥、监控与日志等;
  • 资源管理:对容器使用的网络、存储、GPU等资源进行管理;
  • 弹性伸缩:Kubernetes可以监测业务上所承担的负载,如果这个业务本身的CPU利用率过高,或者响应时间过长它可以对这个业务进行自动扩容
  • 自动修复与回滚:Kubernetes可以监测集群中所有的宿主机,当宿主机或者OS出现故障,节点健康检查会自动进行应用迁移,Kubernetes也支持应用的自愈,极大简化了运维管理的复杂性
  • 服务发现与负载均衡:通过域名、VIP(虚拟IP)对外提供容器服务,提供DNS和多种负载均衡机制,支持容器化应用之间的相互通信。

2.2.2 K8S系统架构

Kubernetes的控制平面包含四个主要的组件:API Server、Controller、Scheduler以及ETCD,如下图所示:

图4 K8S系统架构

Master的主要组件功能如下:

  • API ServerK8S资源对象的唯一操作入口,接收、校验并处理API请求;Master中所有组件互不相连,都通过API Server 进行消息传送与任务处理;
  • Controller Manager集群管理控制中心,负责集群状态检测与故障恢复等工作。管理多个控制器:Node Controller、Endpoint Controller、Service Account & Token Controller。
  • Cloud Controller Manager负责与云厂商组件相关的控制器交互,如Node Controller、Route Controller、Service Controller、Volume Controller。
  • ETCD负责集群元数据与状态保存。是一个基于RAFT协议的高可用的分布式Key-Value存储系统。
  • Scheduler集群调度器,负责容器调度操作,基于资源与策略等将Pod调度到合适的Node上运行。

Node的主要组件功能如下:

  • Kube-let与API Server交互获取容器Pod创建请求,并转到对应的Container Runtime处理。监控并上报Pod运行情况、镜像与资源状态等。
  • Container Runtime接收Kube-let请求,在OS创建容器的运行时环境。
  • Kube-proxyNode上的网络代理,维护集群服务的网络规则与网络通信。
  • Storage Plugin/Network Plugin负责与外部组件通信,容器存储或网络的配置使用。

2.2.3 Pod原理与调度

Pod是K8S的最小调度以及资源分配单元包含容器运行环境与资源。Pod之间相互隔离。一个Pod运行一个或多个容器,当某些容器间关系非常紧密Tightly coupled(如文件交换、频繁的RPC调用、共享网络或存储等),可在一个Pod运行多个容器方便调度管理。

Pod中可以通过Infra Container共享网络。Infra Container,大小100-200KB,最先启动,并绑定了Pod的唯一IP地址与各种网络资源,Pod内其他容器通过加入Infra Container的Network namespace来实现网络共享。Pod中的多个容器也可以通过挂载相同的共享路径实现存储共享。

Pod中可定义Init Container在应用启动前先启动来执行一次性的辅助任务,比如执行脚本、拷贝文件到共享目录、日志收集、应用监控等,以此将辅助功能与主业务容器解耦,实现独立发布和能力重用。

一个Pod就是一个应用运行实例,可以运行多个Pod实现应用横向扩展。当调度失败或运行失败时,Pod本身没有自恢复能力,需要借助上层的controller来通过采用提前定义好的Pod模板创建Pod,提供Pod重启、重建或迁移能力。

简而言之,Podk8s调度的最小单元一个Pod可以包含1个或多个容器,可以理解为Pod是容器集合,每个Pod通过describe可以看到都有自己的ip地址,Pod内的容器共享相同的ip;Node是一个执行具体工作的机器,它可用是虚拟机也可用是物理机,一个Node上面可以有多个Pod,每个Node都由Master统一管理,关系如下图所示。

图5 Pod和Node的关系示意

K8S调度主要涉及资源调度关系调度,采用两种机制过滤(Filtering)和打分(Scoring)。通过过滤机制选择备用节点,过滤因素包括CPU/内存/存储、Pod与Node匹配、Pod与Pod匹配等;然后将Pod调度到分数最高的节点,打分依据包含亲和性/反亲和性、资源水位等等。完整的调度流程如下:

  • 用户通过UI或CLI提交Pod部署请求时,会首先提交给API Server,然后信息存储到ETCD;
  • Scheduler通过Watch或通知机制获得Pod需要调度的请求,通过过滤和打分机制做出调度决策,并通知API Server调度结果;
  • API Server收到调度结果写入ETCD,并通知响应Node上的Kube-let;
  • Kube-let调用Container Runtime配置其他运行环境,并调用对应的插件去分片存储和网络资源。

2.2.4 K8S存储方案

默认情况下,容器中的磁盘文件是非持久化的,对于运行在容器中的应用来说面临两个问题:

  • 数据非持久:当容器崩溃时,kubelet 会重启它,但是容器中的文件将丢失——容器以干净的状态(镜像最初的状态)重新启动。
  • 数据共享:在Pod中同时运行多个容器时,这些容器之间通常需要共享文件。

Kubernetes Volume解决了以上两个问题。本质上,Kubernetes Volume 是一个目录,当Volume被mount到Pod,Pod中的所有容器都可以访问这个Volume。Kubernetes Volume的生命周期与Pod相同,因此,Volume的生命周期比Pod中运行的任何容器要持久,在容器重新启动时能可以保留数据但当Pod被删除不存在时,Volume也会被卸载(但有些类型的Volume不会删除数据)。在Docker中也有一个Docker Volume的概念,但Docker的Volume只是磁盘中的一个目录,生命周期也不受管理。Kubernetes Volume的涵义比Docker Volume更广,Kubernetes支持许多类型的Volume一个Pod可以同时使用任意类型/数量的Volume。Kubernetes Volume的类型包括:

  • 常规存储:emptyDir、hostPath、local Storage
  • 高级存储:PV(Persistent Volume)/PVC(Persistent Volume Claim)
  • 配置存储:configMap、secret、downwardAPI
  • 云服务商提供的存储:gcePersistentDisk、awsElasticBlockStore、、azureFileVolume、azureDisk、vsphereVolume、
  • 网络存储系统:NFS、CIFS、glusterfs、cephfs
  • 其他:iscsi、fc (fibre channel)、flocker、rbd、gitRepo、projected、Quobyte、PortworxVolume、ScaleIO、StorageOS

下面介绍几个比较重要的类型,其余的详见(http://docs.kubernetes.org.cn/429.html):

1. emptyDir当Pod分配到Node上时,将自动会创建emptyDir,并且只要Node上的Pod一直运行,Volume就会一直存。当Pod(不管任何原因)从Node上被删除时,emptyDir也同时会删除,存储的数据也将永久删除。注:删除容器不影响emptyDir。。

2.hostPath挂载Node上的文件系统到Pod里面去。如果Pod需要使用Node上的文件,可以使用hostPath。

3.local StorageLocal 是Kubernetes集群中每个节点的本地存储(如磁盘,分区或目录),在Kubernetes1.7中kubelet可以支持对kube-reserved和system-reserved指定本地存储资源,Local StorageHostPath的区别在于对Pod的调度上,使用Local Storage可以由Kubernetes自动的对Pod进行调度,而是用HostPath只能人工手动调度Pod,因为Kubernetes已经知道了每个节点上kube-reserved和system-reserved设置的本地存储限制。

4. Persistent VolumePodVolume生命周期解耦,同时通过PVCPersistent Volume Claim)实现职责分离,用户可以在不知道特定云环境的细节的情况下,实现持久化存储。其中,PVC定义业务侧的存储需求,如存储容量、访问模式(独占还是共享、只读还是读写)等,由用户提出;PV是存储的具体实现,分配存储空间,由管理员事先制备,PV是集群之中的一块网络存储,跟Node一样,也是集群的资源,并且不属于特定的namespace,有独立于Pod的生命周期。

  • 静态分配:管理员预先创建分配一些PV,用户端提交Pod与PVC存储需求时,管控组件将PVC与合适的PV绑定到一起,然后提供给Pod使用。这里预先分配的PV很难精确匹配存储需求,可能造成资源浪费。
  • 动态分配:管理员不预先分配PV,只是定义了PV模板StorageClass,说明存储类型,存储插件,回收策略及相关参数,用户端提交Pod与PVC存储需求时,管控组件会根据StorageClass动态创建符合需求的PV,然后绑定到PVC,提供给Pod使用。这里实现了存储按需分配,管理运维也更加简单。

图6 PV存储分配方式

2.2.5 应用编排管理

2.2.5.1 工作负载Workload

K8S中通过工作负载Workload来管理应用部署与发布。需要基于不同的工作负载类型(Deployment、StatefulSet、DaemonSet、Job、CronJob),配置存储卷、容器实例与镜像、实例的数量与弹性伸缩、服务访问方式等。不同负载类型与说明如下表,另外容器中还可以通过ConfigMap、Secret来保持容器中的可变配置与敏感信息。

表2 不同类型工作负载特征

工作负载类型

关键特征

Deployment

管理部署无状态应用。Deployment管理不同版本的ReplicaSetReplicaSet管理相同版本的PodDeployment调整ReplicaSet的终态副本数,控制器会维持实际运行的 Pod数量与期望的数量一致,Pod出故障时可以自动重启或恢复。

StatefulSete

管理部署有状态应用。创建的Pod 拥有根据规范创建的持久型标识符。Pod迁移或销毁重启后,标识符仍会保留,如每个 Pod 有序号,可以按序号创建更新或删除;Pod有唯一网络标志(hostname)或独享的存储PV,支持灰度发布等。

DaemonSet

管理部署每个节点都要运行的任务,如监控、日志收集等,也可以通过标签的方式指定哪些节点运行。

Job

单次任务。可创建一个或多个Pod,监控Pod是否成功运行或终止;根据Pod状态设置重复次数、并发度、重启策略。

CronJob

定时的Job,可以指定运行时间、等待时间、是否并行运行、运行次数限制。

表3 不同类型存储特征

存储类型

关键特征

ConfigMape

存储容器的可变配置(文件、环境变量或命令参数),使容器的配置与运行镜像解耦,保证容器可移植性。可以通过挂载、环境变量或运行命令方式在容器中使用。

Secrete

采用 base-64 编码保存密码、令牌、密等敏感信息。可以通过挂载、环境变量或运行命令方式在容器中使用。

2.2.5.2 服务访问

K8S服务Service提供了功能相同的一组Pod统一抽象入口,定义了服务访问方式与负载均衡,实现前端Client的服务访问与后端Pod上的服务部署解耦。另外可以通过Ingress实现基于HTTP/HTTPS的7层负载均衡,配置转发规则,实现不同URL访问不同的service,支持配置SSL证书。如下表,容器服务支持基于负载均衡、Cluster IP或Node Port方式实现不同场景下的服务访问。

表4 不同服务访问方式

访问方式

说明

公网访问

使用负载均衡模式,分配公网 IP,实现公网访问容器服务;集群外通过域名或IP+服务端口访问;集群内通过服务名+端口访问。适合Web类服务。

集群内访问

使用Cluster IP模式,分配容器内网IP,集群内通过服务名+服务端口访问。适合数据库类服务。

VPC内网访问

使用负载均衡模式,分配VPC子网IP,实现VPC内访问容器服务;集群外通过域名或IP+服务端口访问;集群内通过服务名+端口访问。适合Web类服务。

Node Port访问

提供主机端口映射到容器的访问方式,支持TCPUDP。可以通过IP+主机端口或服务名+服务端口访问服务。

2.2.5.3 应用监控管理

1.就绪探针与存活探针

要保障容器应用的健康稳定运行,需要提供应用的运行状态、资源使用的可观测性与恢复能力。系统通过就绪探针Readiness Probe探测Pod是否处于就绪状态,如果不就绪就切断上层流量,Pod不对外提供服务;通过存活探针Liveness Probe探测Pod是否存活,如果不存活,根据重启策略判断是否需要重新拉起pod。两种探针支持3种探测方式:

  • httpGet发送 http Get 请求来判断,当返回码是 200-399 之间时,应用正常。
  • Exec通过执行容器中的一个命令来判断,如果返回结果 0,容器服务正常。
  • tcpSocket通过容器IP和Port建立TCP 连接,如果连接成功,容器正常。

2.监控告警与日志

K8S监控分为几种类型,如资源监控(CPU、内存、网络)、性能监控(APM应用性能指标)、安全监控(安全策略、越权管理、安全漏洞)、事件监控(正常Normal事件或异常warning事件)。目前K8S采用主流的开源监控标准Prometheus,应用侧只需要实现 Prometheus Client就可以实现数据采集,支持3种数据采集策略:

  • Pull 模式:通过拉模式去拉取对应的数据;但数据声明周期短于数据采集周期时可能漏采。
  • Push模式:通过push gateway进行数据采集,然后Prometheus再通过pull的方式去 push gateway去拉数据。
  • Prometheus on Prometheus通过一个 Prometheus同步数据到另一个Prometheus。

K8S日志也分为几种类型:主机内核日志、运行时Runtime日志、K8S组件日志、业务应用日志。日志通过宿主机文件、容器日志文件或日志标准或错误输出进行采集。目前主流的日志采集呈现方案是ELK,通过 Fluentd采集日志,将数据汇集到 Elasticsearch(或InfluxDB)分析处理,然后再通过 Kibana(或Grafana)做日志展现。

2.3 微服务

2.3.1 诞生背景

过去开发一个后端应用最为直接的方式就是通过单一后端应用提供并集成所有的服务,即单体模式。随着业务发展与需求不断增加,单体应用功能愈发复杂,团队人员也越来越多,应用迭代效率由于集中式研发、测试、发布、沟通模式而显著下滑。为了解决由单体应用模型衍生的过度集中式项目迭代流程,微服务模式应运而生。

微服务模式将后端单体应用拆分为松耦合的多个子应用,每个子应用负责一组子功能。这些子应用称为“微服务”,多个“微服务”共同形成了一个物理独立但逻辑完整的分布式微服务体系。由于微服务架构有下面这几个优势,已经成为云计算时代应用的标准架构:

  • 支持快速上线由于业务组件的自治性和独立性,新的功能和应用能够迅速的发布上线,而不用担心对系统其他功能带来大范围的影响和波及。
  • 支持独立扩容和恢复针对性的对应用中的某些服务进行应用水平扩展冗余部署,解决性能的瓶颈。可以独立替换或恢复微服务中的某个组件。

但也要注意到微服务模型也面临着分布式系统的典型挑战:如何高效调用远程方法、如何实现可靠的系统容量预估、如何建立负载均衡体系、如何面向松耦合系统进行集成测试、如何面向大规模复杂关联应用的部署与运维……

在云原生时代,云原生微服务体系将充分利用云资源的高可用和安全体系,让应用获得更有保障的弹性、可用性与安全性。

2.3.2 微服务设计约束

相较于单体应用,微服务架构的架构转变,在提升开发、部署等环节灵活性的同时,也提升了在运维、监控环节的复杂性。在结合实践总结后,阿里云的《云原生架构白皮书》中总结了设计一个优秀的微服务系统应遵循以下设计约束:

2.3.2.1 微服务个体约束

一个设计良好的微服务应用,所完成的功能在业务域划分上应是相互独立且功能完整的,微服务的“微”并不是为了微而微,而是按照问题域对单体应用做合理拆分。如果当一个微服务修改或者发布时,不应该影响到同一系统里另一个微服务的业务交互

2.3.2.2 微服务与微服务之间的横向关系

在合理划分好微服务间的边界后,主要从微服务的可发现性可交互性处理服务间的横向关系:

可发现性是指当服务A发布和扩缩容的时候,依赖服务A的服务B如何在不重新发布的前提下,如何能够自动感知到服务A的变化,这里需要引入第三方服务注册中心来满足服务的可发现性,特别是对于大规模微服务集群,服务注册中心的推送和扩展能力尤为关键。

可交互性是指服务A采用什么样的方式调用服务B。由于服务自治的约束,服务之间的调用需要采用与语言无关的远程调用协议,比如 REST 协议很好的满足了“与语言无关”和“标准化”两个重要因素,在高性能场景下,基于IDL的二进制协议可能是更好的选择。

伴随着服务链路的不断变长,整个微服务系统也就变得越来越脆弱,因此面向失败设计的原则在微服务体系中就显得尤为重要。对于微服务应用个体,限流、熔断、隔仓、负载均衡等增强服务韧性的机制成为了标配

2.3.2.3 微服务与数据层之间的纵向约束

在微服务领域,提倡数据存储隔离(DSS, Data Storage Segregation)原则,即数据是微服务的私有资产,对于该数据的访问都必须通过当前微服务提供的 API 来访问。如若不然,则造成数据层产生耦合,违背了高内聚低耦合的原则。同时,出于性能考虑,通常采取读写分离(CQRS)手段

同样的,由于容器调度对底层设施稳定性的不可预知影响,微服务的设计应当尽量遵循无状态设计原则,这意味着上层应用与底层基础设施的解耦,微服务可以自由在不同容器间被调度。对于有数据存取(即有状态)的微服务而言,通常使用计算与存储分离方式,将数据下沉到分布式存储,通过这个方式做到一定程度的无状态化。

2.3.2.4 全局视角下的微服务分布式约束

从微服务系统设计一开始,就需要考虑以下因素:

  • 高效运维整个系统,从技术上要准备全自动化的CI/CD流水线满足对开发效率的诉求,并在这个基础上支持蓝绿、金丝雀等不同发布策略,以满足对业务发布稳定性的诉求。
  • 面对复杂系统,全链路、实时和多维度的可观测能力成为标配。伴随着微服务拆分的持续,故障发现时效性和根因精确性始终是开发运维人员的核心诉求。

2.3.3 云原生微服务典型架构

2.3.3.1 第一代微服务架构

第一代微服务架构中,应用除了需要实现业务逻辑之外,还需要自行解决上下游寻址、通讯,以及容错等问题。随着微服务规模扩大,服务寻址逻辑的处理变得越来越复杂,哪怕是同一编程语言的另一个应用,上述微服务的基础能力都需要重新实现一遍

2.3.3.2 第二代微服务架构

在第二代微服务架构中,引入了旁路服务注册中心作为协调者来完成【服务的自动注册和发现】【服务之间的通讯以及容错机制】等服务治理能力开始被模块化,形成服务框架,各个微服务通过封装的SDK引入服务框架。

随着服务框架功能的日益增多,大量孤立的SDK被绑定在业务服务上,导致两方面问题,从而违背了微服务的敏捷迭代原则:

  • 版本升级困难:SDK与业务服务的强依赖性导致想要升级SDK版本变得异常复杂与缓慢;
  • 业务服务难以异构:SDK所支持的语言反向限制了业务服务所能选择的语言,例如 Spring Cloud几乎没有官方的多语言支持。

图7 第一、二代微服务架构

2.3.3.3 第三代微服务架构—服务网格

2016年出现了第三代微服务架构—服务网格,原来被模块化到服务框架里的微服务基础能力,被进一步地从一个SDK演进成为一个独立进程—Sidecar。这个变化使得第二代架构中多语言支持问题得以彻底解决,微服务治理能力演进和业务逻辑迭代彻底解耦,这个架构就是在云原生时代的微服务架构—Cloud Native Microservices

在分布式系统中,应用通常包含业务逻辑、非功能性需求(NFR)和中间件依赖(三方依赖)。在应用程序中,只有业务逻辑才承载具体的业务价值,NFR 和三方依赖是必要的非增值活动,不直接产生业务价值,但是非增值活动耗费开发人员大量的时间和精力,导致业务交付速度慢。在第三代微服务架构中,NFR能力从业务逻辑中抽离出来,下沉到单独的组件中,实现 NFR 与业务逻辑的沉底解耦边车进程(Sidecar)实现了大部分的NFR的能力(如可观测性、熔断、限流、灰度、路由、负载均衡等)

图8 第三代微服务架构

2.3.3.4 第四代微服务架构—多运行时微服务架构

服务网格解决了大部分的NFR的能力,但是三方依赖(如Mysql、Redis、MQ等)与业务逻辑耦合,仍然需要开发人员通过lib库或SDK的方式在业务代码中进行集成,不能让开发纯粹的专注于业务逻辑开发和业务价值交付。三方依赖(分布式能力)是否也可以以 sidecar的方式独立于业务逻辑,并且提供统一的能力抽象,屏蔽底层的组件差异,成为技术架构演进的新方向。

多运行时微服务架构由Red Hat的首席架构师Bilgin Ibryam提出,Bilgin Ibryam梳理总结了分布式应用的各类需求后,将其划分成了生命周期网络、状态以及绑定四种类型,NFR和三方依赖被包含在这四种类型的需求中。

表5 分布式应用的四类需求

需求类型

说明

主要内容

分布式应用

生命周期

即应用从开发态到运行态之间进行打包、部署、扩缩容等需求

打包(Packaging)、健康检查(Healthcheck)、部署(Deployment)、缩扩容(Scaling)、配置(Configuration)、

Kubernetes

网络

分布式系统中各应用之间的服务发现、容错、灵活的发布模式、跟踪和遥测等需求

服务发现(Service discovery

A/B 测试、金丝雀、回滚(A/B testingcanary rollouts

重试、超时、熔断(Retrytimeoutcircuit breaker

安全、可观察性(Point-to-pointpub/sub

服务发现/注册、负载均衡、流量管理

状态

我们期望服务是无状态的,但业务本身一定需要有状态,因此包含对缓存、编排调度、幂等、事务等需求

工作流管理(Workfow mgmt)、幂等性(Idempotency)、时间调度(Temporal scheduling)、缓存(Caching)、应用状态(Application state

数据库、对象存储、块存储

绑定

与外部服务之间进行集成可能面临的交互适配、协议转换等需求

链接(Connectors)、协议转换(Protocol conversion)、消息投递(Message transformation)、消息路由(Message routing)、事务性(Transnationality

事件分发、分布式事务、消息路由

在多运行时微服务架构中,非功能性需求(NFR)和三方库能力彻底与业务逻辑解耦并以独立的sidecar(进程)提供这些能力。开发人员无需关注必要的非增值活动,最大限度的管制业务逻辑实现和业务价值交付。

图9 第四代微服务架构

在多运行时微服务架构中,有两个组件,其中每个组件都是独立的运行时这两个组件都位于同一个主机中,并且在它们之间有可靠的网络。组件之一称为微逻辑(Micrologic,它包含了几乎所有从分布式系统关注点中剥离出来的最小业务逻辑。另一个组件叫Mecha,提供了所有分布式系统功能(生命周期除外,它是平台的功能),Mecha特征如下:

  • Mecha是一个通用、高度可配置、可重用的组件,提供分布式原语作为现成的功能。
  • Mecha的每个实例必须配置成与一个微逻辑组件(边车模型)一起工作,或者配置成与一些组件共享。
  • Mecha不对微逻辑运行时做任何假设。它与利用开放协议和格式(如HTTP/gRPC、JSON、Protobuf、CloudEvents)的多语言微服务或甚至单体系统一起工作。
  • Mecha用简单文本格式(如YAMLJSON)进行声明式配置,这些格式规定了要启用什么功能以及如何把它们绑定到微逻辑端点上。所有这些都是简单的、基于文本的、声明式的、多语言定义的,Mecha可以不需要编码就能实现。Mecha是应用程序级别的分布式原语抽象层

对于特定的API 交互操作,可以为Mecha附加规范,如OpenAPI、AsyncAPI、ANSI-SQL等;对于由多个步骤构成的状态化工作流,可以使用如亚马逊状态编程语言(Amazon State Language)的规范。对无状态集成,可以用类似Camel-K YAML DSL 的方法使用企业集成模式(Enterprise Integration Patterns,简称 EIPs)。

  • 与其依赖于用于不同目的(如网络代理、状态代理、绑定代理)的多个代理,不如有一个提供所有这些功能的Mecha。某些能力的实现(如存储、消息持久性、缓存等)将会有其他的云或自建的服务插入并支持。
  • 关于生命周期管理的一些分布式问题由管理平台(比如,Kubernetes或其他云服务)而不是由使用Open App Model等通用开放规范的Mecha运行时来提供是合理的。

图10 多运行时微服务架构

微服务架构本质上与容器及K8S技术无关,在Java体系的Spring Cloud就提供了诸如网关Zuul组件、Ribbon负载均衡组件、Eureka服务注册组件、LCM扩容组件、Hystrix业务恢复组件。利用Spring Cloud的能力可以实现一套完善的微服务架构。Spring Cloud有大量的java开发人员所拥护,这是它的优势。但是Spring Cloud的劣势很突出,那就是限制编程语言和编程技术

Kubernetes提供了服务注册、配置管理、负载均衡、故障隔离、业务恢复、自动扩容等能力。基于Kubernetes的Paas平台又提供了诸如基础数据服务、网关服务、微服务治理服务等基础服务能力。此外,Kubernetes不限制编程语言,社区活跃、功能稳定。所以微服务与Kubernetes集成会是一个大趋势

2.4 Service Mesh技术

在第三代微服务架构中,Service Mesh技术将那些微服务间的连接、安全、流量控制和可观测等通用功能下沉为平台基础设施,大量非功能性从业务进程剥离到另外进程中,Service Mesh以无侵入的方式实现了应用轻量化。下图展示了 Service Mesh 的典型架构:

图11 Istio架构

2017年发起的服务网格Istio开源项目,清晰定义了数据平面(由开源软件Envoy 承载)管理平面(Istio自身的核心能力)。Istio为微服务架构提供了流量管理机制,同时亦为其它增值功能(包括安全性、监控、路由、连接管理与策略等)创造了基础。

在Istio架构中,Service A调用Service B的所有请求,都被其下的Proxy(在Envoy中是Sidecar)截获,代理完成Service A到Service B的服务发现、熔断、限流等策略,而所有这些策略的总控在Control Plane上配置。

从架构上,Istio可以运行在虚拟机或容器中,Istio的主要组件包括Pilot(服务发现、流量管理)Mixer(访问控制、可观测性)Citadel(终端用户认证、流量加密);整个服务网格关注连接和流量控制、可观测性、安全和可运维性。

虽然相比较没有服务网格的场景多了4个IPC通讯的成本,但整体调用的延迟随着软硬件能力的提升而并不会带来显著的影响,特别是对于百毫秒级别的业务调用而言可以控制在2%以内。从另一方面,服务化的应用并没有做任何改造,就获得了强大的流量控制能力、服务治理能力、可观测能力、49以上高可用、容灾和安全等能力,加上业务的横向扩展能力,整体的收益仍然是远大于额外IPC通讯支出的

服务网格的技术发展上数据平面与控制平面间的协议标准化是必然趋势。大体上,Service Mesh的技术发展围绕着“事实标准”去展开——共建各云厂商共同采纳的开源软件。从数据平面角度,Envoy得到了包括GoogleIBMCiscoMicrosoft、阿里云等大厂的参与共建以及主流云厂商的采纳而成为了事实标准Service Mesh本身也将成为容器服务技术的标配技术组件

2.5 Serverless

微服务在帮助架构解耦的同时,也带来了很多新的挑战,比如运维成本的增加和部署自动化等挑战。即使使用云平台动态管理基础设施,仍然要面临如下现实问题:

    • 基础设施的创建、配置、维护、安全。比如虚拟机的创建、配置,以及出现安全漏洞后对系统、软件的更新等。随着微服务数量增加,维护的基础设施的规模也对应膨胀,造成创建、配置、维护的困难,并带来安全上的风险。
    • 微服务的部署。可能需要定制专门的部署工具去实现零宕机时间部署,或者使用云平台提供的部署服务,但都需要一定的学习、开发和维护成本。
    • 服务的伸缩。云平台虽提供了自动伸缩服务,但其策略往往比较简单。比如,设定使用得最少和最多的虚拟机根据CPU使用率去伸缩,但是总的资源不能超过策略设定的最多虚拟机个数。一旦请求超过最大资源能承载的范围,可能会影响用户的使用体验,甚至服务中断。
    • 基础设施成本。随着微服务的增加,需要创建越来越多的虚拟机/容器来运行这些微服务,为了保证可用性,这些资源会存在一定的冗余,同时利用率不一定会很高。同时,还需要承担容器集群管理工具,如Kubenetes、Mesos等的维护成本。从资源的使用率来讲,在单体应用下,如果应用的某个功能模块需要水平扩展,那么整个应用都得和它一起水平扩展,这是一种资源的浪费。这样的问题在微服务架构下可能同样存在。
    • 上线时间(Time to Market。单体应用的上线时间可能需要半年,打通持续集成流水线的微服务可能只需要两周,然而对于有些领域,需要更快的上线时间。

Serverless,顾名思义就是无服务器架构,也就是说从使用者的角度,看不到服务器的存在,只要使用或者直接部署代码即可。

它与传统架构的不同之处在于,开发者实现的服务端逻辑运行在无状态(Stateless)的暂存计算容器中,它由事件触发, 完全被第三方管理;业务层面的状态则被开发者使用的数据库和存储资源所记录

构建Serverless应用程序意味着开发者可以专注在产品代码上,而无需做复杂的容量规划和手动变配无需管理和操作云端或本地的服务器或运行时无需要关心 CPU、内存等资源的监控和告警。Serverless真正做到了部署应用无需涉及基础设施的建设,自动构建、部署和启动服务

过去是“构建一个框架运行在一台服务器上,对多个事件进行响应”,Serverless则变为“构建或使用一个微服务或微功能来响应一个事件”,做到当访问时,调入相关资源开始运行,运行完成后,卸载所有开销,真正做到按需按次计费

2.5.1 Serverless主要技术

国内外的各大云厂商 Amazon、微软、Google、IBM、阿里云、腾讯云、华为云相继推出Serverless产品,Serverless也从概念、愿景逐步走向落地,在各企业、公司应用开来。Serverless涵盖了很多技术,分为两类:FaaS和BaaS。

2.5.1.1 FaaS(Function as a Service,函数即服务)

FaaS(Function as a Service函数即服务)。开发者实现的服务器端应用逻辑(微服务甚至粒度更小的服务)以事件驱动的方式运行在无状态的临时的容器中,并且这些容器、计算资源都是由第三方管理。使用FaaS后,用户不需要自行供应服务器,也不需要全时运行应用程序

FaaS产品不要求必须使用特定框架或库进行开发。在语言和环境方面,FaaS函数就是常规的应用程序。例如AWS Lambda的函数支持Javascript、Python代码的直接部署,JVM语言(Ruby(JRuby)/Scala/Clojure/Java等)编译成class文件部署。在迁往FaaS的过程中,唯一需要修改的代码是“主方法/启动”代码,其中可能需要删除顶级消息处理程序的相关代码(“消息监听器接口”的实现),可能只需要更改方法签名。

FaaS中的函数可以通过供应商定义的事件类型触发。对于亚马逊AWS,此类触发事件可以包括S3(文件)更新、时间(计划任务),以及加入消息总线的消息(例如Kinesis)。通常函数可以通过参数指定需要绑定到的事件源。大部分供应商还允许函数对传入的Http请求进行响应来触发,通常这类请求来自某种该类型的API网关(例如AWS API网关、Webtask)。

2.5.1.2 BaaS(Backend as a Service,后端即服务)

BaaS(Backend as a Service后端即服务)。严重或完全依赖第三方应用程序/服务(比如云平台)管理服务器端逻辑和状态的应用程序。在其中,开发人员外包Web或移动应用程序的所有服务端方面,仅需自行编写和维护前端。BaaS供应商为服务器上发生的活动提供预编写的软件,例如用户身份验证、数据库管理、远程更新和推送通知(针对移动应用程序),以及云存储和托管。

2.5.2 Serverless应用场景举例

Serverles服务器适合于任何事件驱动的各种不同的用例,这包括移动应用、物联网、基于网络的应用程序和聊天机器人等:

  • 在Web及移动端服务中,可以整合API网关和Serverles服务构建Web及移动后端,帮助开发者构建可弹性扩展、高可用的移动或 Web后端应用服务;
  • 在IoT场景下可高效地处理实时流数据,由设备产生海量的实时信息流数据,通过Serverles服务分类处理并写入后端处理;
  • 在实时媒体资讯内容处理场景里,用户上传音视频到对象存储OBS,通过上传事件触发多个函数,分别完成高清转码、音频转码等功能,满足用户对实时性和并发能力的高要求。
2.5.2.1 场景一:应用负载有显著的波峰波谷

Serverless 应用成功与否的评判标准并不是公司规模的大小,而是其业务背后的具体技术问题,比如业务波峰波谷明显,如何实现削峰填谷。一个公司的业务负载具有波峰波谷时,机器资源要按照峰值需求预估;而在波谷时期机器利用率则明显下降,因为不能进行资源复用而导致浪费。

业界普遍共识是,当自有机器的利用率小于30%,使用 Serverless 后会有显著的效率提升而且,用户无论是自建还是使用普通实例,一般会根据高业务负载购买相关的规格,按固定资源付费。这样在波谷期浪费的资源较多,整体成本较高;如果出现预期外的大业务流量,资源不足又会使业务受损。Serverless 实例能进行快速且独立的扩容和缩容,在快速响应业务变化的同时,合理优化使用成本,助力企业降本增效。

图12 Serverless助力企业降本

对于云服务厂商,在具备了足够多的用户之后,各种波峰波谷叠加后平稳化,聚合之后资源复用性更高。比如,外卖企业负载高峰是在用餐时期,安防行业的负载高峰则是夜间,这是受各个企业业务定位所限的;而对于一个成熟的云服务厂商,如果其平台足够大,用户足够多,是不应该有明显的波峰波谷现象的

2.5.2.2 场景二:基于事件的数据处理

视频处理的后端系统,常见功能需求如下:视频转码、抽取数据、人脸识别等,这些均为通用计算任务,可由函数计算执行。

开发者需要自己写出实现逻辑,再将任务按照控制流连接起来,每个任务的具体执行由云厂商来负责。如此,开发变得更便捷,并且构建的系统天然高可用、实时弹性伸缩,用户不需要关心机器层面问题。

2.5.3 Serverless的劣势

对于企业来说,支持Serverless计算的平台可以节省大量时间和成本,同时可以释放员工,让开发者得以开展更有价值的工作,而不是管理基础设施;另一方面可以提高敏捷度,更快速地推出新应用和新服务,进而提高客户满意度。但是Serverless不是完美的,它也存在一些问题,需要慎重应用在生产环境。

2.5.3.1 不适合长时间运行应用

Serverless在请求到来时才运行,这意味着,当应用不运行的时候就会进入 “休眠状态”,下次当请求来临时,应用将会需要一个启动时间,即冷启动时间。如果应用需要一直长期不间断的运行、处理大量的请求,那么你可能就不适合采用Serverless架构。

2.5.3.2 完全依赖于第三方服务

当采用某云服务厂商的Serverless架构时,就和该服务供应商绑定了,后续再将服务迁到别的云服务商上就没有那么容易了。

2.5.3.3 缺乏调试和开发工具

使用Serverless Framework时,会遇到很明显的问题:缺乏调试和开发工具。虽然serverless-offline、dynamodb-local 等一系列插件使得问题有一些改善。然而,阅读日志系统来说,仍然是一个艰巨的挑战。

每次调试代码的时候,需要一遍又一遍地上传代码;而每次上传的时候,又不能快速地定位问题,还是得借助分级别记录日志、大数据日志分析等技术。

2.5.3.4 构建复杂

Serverless很便宜,但是这并不意味着它很简单,比如AWS Lambda的CloudFormation配置就非常复杂,并且难以阅读及编写(JSON格式)。

2.6 云原生中间件

在云原生的时代,传统中间件技术也演化升级为云原生中间件,云原生中间件主要包括网格化的微服务架构事件驱动技术Serverless等技术的广泛应用,其中网格化(Service Mesh)微服务架构和Serverless前面都讲过了,下面介绍一下事件驱动技术以及云原生技术带来的不同点。

事件驱动技术诞生背景:在单体应用中,我们可以利用关系型数据库的特性去完成事务一致性,但是一旦应用往微服务发展,根据业务拆分成不用的模块,而且每个模块的数据库已经分离开了,这时候,要面对的就是分布式事务了,需要在代码里头完成ACID(原子性、一致性、隔离性、持久性)。1998年,加州大学的计算机科学家 Eric Brewer 提出,分布式系统有三个指标:一致性(Consistency)、可用性(Availability)、分区容错(Partition tolerance),Eric Brewer 说,这三个指标不可能同时做到,这个结论就叫做 CAP 定理。微服务中,P(分区容忍)是必须要有的,这时剩下的C和A就无法同时做到了;此时一般放弃强一致性(C),通过事件驱动实现最终一致性,来保证系统的AP能力。

以电商系统为例,用户下单必须根据库存来确定订单是否成交,下面对比使用事件驱动前后,服务之间的调用的区别。

图13 服务间调用方式对比

未基于事件驱动的服务调用的缺点:

  • 订单服务需同步等待库存服务的返回结果,接口结果返回延误
  • 订单服务直接依赖于库存服务,只要库存服务崩了,订单服务不能再正常运行
  • 订单服务需考虑并发问题,库存最后可能为负

利用事件驱动实现最终一致性:

  • 在订单服务新增订单后,订单的状态是“已开启”,然后发布一个Order Created事件到消息队列上;
  • 库存服务在监听到消息队列Order Created中的消息,将库存表中商品的库存减去下单数量,然后再发送一个Stock Locked事件给消息队列;
  • 订单服务接收到Stock Locked事件,将订单的状态改为“已确认”。

基于事件驱动的服务调用的优点:

  • 订单服务不再直接依赖于库存服务,而是将下单事件发送到MQ中,让库存监听,订单服务能真正的作为一个模块独立运行
  • 解决了并发问题,而且MQ的队列处理效率非常的高。

基于事件驱动的服务调用的缺点:

  • 用户体验改变了,因为使用事件机制,订单是立即生成的,可是很有可能过一会,系统会提醒你没货了。这就像是排队抢购一样,排着排着就被通知没货了。

综上,事件驱动技术是微服务架构中实现最终一致性的重要手段,且一般基于消息队列实现

微服务架构一般包含下列组件:服务注册发现中心配置中心负载均衡容错处理API网关消息队列运行时监控链路跟踪等。云原生中间件最大的技术特点是中间件技术从业务进程中分离,变成与开发语言无关的普惠技术,只与应用自身架构和采用的技术标准有关,比如一个PHP开发的REST应用也会自动具备流量灰度发布能力、可观测能力,即使这个应用没有采用任何服务化编程框架。

【服务注册发现中心】【配置中心】的功能主要致力于解决微服务在分布式场景下的服务发现和分布式配置管理两个核心问题。随着云原生技术的发展,服务发现领域出现了两个趋势,一个是服务发现标准化(Istio,一个是服务下沉(CoreDNS;配置管理领域也有两个趋势,一个是标准化(ConfigMap,一个是安全(Secret

【负载均衡】【容错处理】API网关】交由边车服务完成

【消息队列】是云计算PaaS领域的基础设施之一,主要用于解决分布式应用的异步通信、解耦、削峰填谷等场景。云原生背景下,消息队列提供一种BaaS化的消息使用模式,用户无需预先购买服务器和自行搭建消息队列,也无需预先评估消息使用容量,只需要在云平台开通即用,按消息使用量收费。例如阿里云MaaS(Messaging as a Service)提供的是一站式消息平台,提供业界主流的开源消息队列托管服务,包括Kafka、RabbitMQ、RocketMQ等;也支持多种主流标准协议规范,包括AMQP、MQTT、JMS、STOMP等,以满足微服务、IoT、EDA、Streaming等各种细分领域的需求。

【事件驱动架构】在过去事件驱动架构往往是通过消息队列来实现,事件用消息来传递。进入云计算时代,云厂商提供更加贴近业务的封装,比如Azure提供了事件网格把所有云资源的一些运维操作作为内置事件,用户可以自行编写事件处理程序实现运维自动化;AWS则把所有云资源的操作事件都用SNS的Topic来承载,通过消息做事件分发,用户类似实现WebHook来处理事件。由于事件是异步触发的,天然适合Serverless,所以现在很多云厂商都采用自身的Serverless服务来运行事件负载,包括阿里云Function Compute、Azure Function、AWS Lambda都和事件处理集成。

2.7 DevOps

DevOpsDevelopmentOperations的组合,重视软件开发人员和运维人员的沟通合作,通过自动化流程来使得软件构建、测试、发布更加迅速和可靠。

DevOps与上述的微服务、容器等技术应用没有直接的关系,可以讲,没有微服务和容器等技术,一样可以朝着自动化的构建、测试和发布流程上行进。但是,长久以来,Devops只是在文化上和流程指导上给出了方向,至于落地的方法论和工具链上,并没有很成功,只是在CI/CD流程的个别环节上独立发展出一些比较成功的产品,例如jenkins及一些自动化测试工具。究其原因,还是在软件应用基础架构上,没有完善的技术支撑和技术体系,软件的运行环境千差万别、软件的部署和维护流程千差万别、软件的形态和架构千差万别,Devops落地需要大量定制化,工具链落地难度很大。

在云原生时代,基于容器的微服务架构定义了云原生应用的标准架构;基于容器和Kubernetes的平台提供了云原生应用的标准发布和运行环境,为DevOps的流行提供了土壤。

2.7.1 持续集成(CI)

持续集成(CONTINUOUS INTEGRATION,CI)指的是开发人员频繁的(一天多次的)将所有开发者的工作合并到主干上。这些新提交在最终合并到主线之前,都需要通过编译和自动化测试流进行验证,以保障所有的提交在合并主干之后的质量问题,对可能出现的一些问题进行预警。持续集成的核心在于通过自动化持续集成工具确保新增的代码能够与原先代码正确的集成

持续集成带来的好处:易于定位错误、易于控制开发流程、易于Code Review、易于减少不必要的工作。

图14 持续集成

2.7.2 持续交付(CD)

与持续集成相比,持续交付(CONTINUOUS DELIVERY,CD)的侧重点在于交付,其核心对象不在于代码,而在于可交付的产物。与持续集成相比较,持续交付添加了测试Test->模拟Staging->生产Production的流程,也就是为新增的代码添加了一个保证:确保新增的代码在生产环境中是可用的

持续交付带来的好处:繁琐的部署工作没有了,团队不再需要花费几天的时间去准备一个发布;可以更快的进行交付,这样就加快了与客户之间的反馈环;轻松应对小变更,加速迭代。

图15 持续交付

2.7.3 持续部署

持续部署(CONTINUOUS DEPLOYMENT)指的是通过自动化部署的手段将软件功能频繁的进行交付。从开发人员提交代码到编译、测试、部署的全流程不需要人工的干预,完全通过自动化的方式执行。这一策略加快了代码提交到功能上线的速度,保证新的功能能够第一时间部署到生产环境并被使用。

持续部署带来的好处:发布频率更快,因为不需要停下来等待发布,每一处提交都会自动触发发布流;在小批量发布的时候,风险降低了,发现问题可以很轻松的修复;客户每天都可以看到持续改进和提升,而不是每个月或者每季度,或者每年。

自动实时的部署上线,是最优的解决办法,但持续部署的要求是团队非常成熟,并且上线前是需要经过QA测试的,所以实际情况下很难实现,一般的团队也很难接受,挑战和风险都很大。

2.7.4 DevOps

DevOps不仅包括了CI、CD,还有对于文化氛围的构建。DevOps也即是促使开发人员与运维人员之间相互协作的文化。在DevOps文化指导下,团队中将包含了具有不同技能的人员(开发、测试等),并通过自动化测试与发布的手段,更快、更高质量的生产软件

三、企业案例

3.1 阿里云云原生相关产品

由于精力有限,这里只列举了阿里云在云原生体系下的相关产品。

产品分类

产品名称

产品说明

容器

容器服务Kubernetes ACK

提供高性能可伸缩的容器应用管理能力,支持企业级Kubernetes容器化应用的全生命周期管理。

容器服务Serverless ACK Serverless

通过该产品,您无需管理和维护集群即可快速创建Kubernetes容器应用,并且根据应用实际使用的 CPU 和内存资源量进行按需付费,从而使您更专注于应用本身,而非运行应用的基础设施。

容器计算服务 ACS

K8s为使用界面供给容器算力资源的云计算服务,提供符合容器规范的算力资源。

容器镜像服务 ACR

面向容器镜像、Helm Chart 等符合OCI标准的云原生制品安全托管及高效分发平台。ACR支持全球同步加速、大规模/大镜像分发加速、多代码源构建加速等全链路提效,与容器服务ACK无缝集成,帮助企业降低交付复杂度,打造云原生应用一站式解决方案。

弹性容器实例 ECI

Serverless和容器化的弹性计算服务。您无需管理底层ECS服务器,只需要提供打包好的镜像,即可运行容器,与阿里云容器服务无缝对接并仅为容器实际运行消耗的资源付费。

容器服务Edge ACK Edge

一款提供标准Kubernetes集群云端托管,支持边缘计算资源、业务快速接入、统一管理、统一运维的云原生应用平台,能够帮助您轻松实现云边一体化协同。

分布式云容器平台 ACK One

面向混合云、多集群、分布式计算、容灾等场景推出的企业级云原生平台,支持连接并管理任何地域、任何基础设施上的Kubernetes集群,提供一致的管理和社区兼容的API,支持对计算、网络、存储、安全、监控、日志、作业、应用、流量等进行统一运维管控。

容器服务发行版 ACK Distro

是阿里巴巴针对异构IaaS环境发布的 Kubernetes发行版,使用者可通过阿里云容器镜像服务ACR 免费获取完整内容并获得社区支持。其核心组件经过阿里云容器服务KubernetesACK和阿里巴巴集团业务场景的大规模生产环境验证和安全检查,具备安全性与可靠性。

微服务

企业级分布式应用服务 EDAS

是一个应用PaaS平台,一站式集成微服务、可观测、任务调度等技术;以专业易用的应用全生命周期管理、流量及容量治理等功能,配合业务视角的验收、资源管控与成本优化能力,助力企业应用架构云原生化升级。

微服务引擎 MSE

面向业界主流开源微服务项目, 提供注册配置中心和分布式协调(原生支持 Nacos/ZooKeeper/Eureka)、云原生网关(原生支持 Higress/Nginx/Envoy,遵循 Ingress 标准)、微服务治理(原生支持 Spring Cloud/Dubbo/Sentinel,遵循 OpenSergo 服务治理规范)能力。

应用高可用服务 AHAS

专注于通过多活容灾(简称MSHA)的功能提高应用高可用能力,提供从流量入口、应用层和数据的故障切换以及故障演练等能力,进行云上业务的同城及跨地域的多活建设,提升稳定性。

Service Mesh

服务网格 ASM

是一个统一管理微服务应用流量、兼容Istio的托管式平台。通过流量控制、网格观测以及服务间通信安全等功能,服务网格ASM可以全方位地简化您的服务治理,并为运行在异构计算基础设施上的服务提供统一的管理能力,适用于Kubernetes集群、Serverless Kubernetes集群、ECS虚拟机以及自建集群。

Serverless

函数计算 FC

是一个事件驱动的全托管 Serverless 计算服务,您无需管理服务器等基础设施,只需编写代码并上传,函数计算会为您准备好计算资源,并以弹性、可靠的方式运行您的代码。

Serverless应用引擎 SAE

是一款零代码改造、极简易用、自适应弹性的应用全托管平台。SAE 让您免运维IaaSK8s,秒级完成从源代码/代码包/ Docker镜像部署任何语言的在线应用(如 Web /微服务 /Job任务)到 SAE,并自动伸缩实例按使用量计费,开箱即用日志、监控、负载均衡等配套能力。

DevOps

云效DevOps

企业级一站式研发协同平台。支持公共云、专有云和混合云多种部署形态,通过云原生新技术和研发新模式,助力创新创业和数字化转型企业快速实现研发敏捷和组织敏捷,打造“双敏”组织,实现多倍效能提升。

资源编排服务 ROS

是一种简单易用的云计算资源自动化部署服务。用户可以通过使用Json/Yaml格式的模版描述多个云计算资源(如ECSRDSSLB)的配置、依赖关系等,并自动完成所有云资源在多个不同地域以及多个账户中的部署和配置,实现基础设施即代码。

3.2 数禾科技AI模型Serverless容器化

数禾科技以大数据和技术为驱动,为金融机构提供高效的智能零售金融解决方案,服务银行、信托、消费金融公司、保险、小贷公司等持牌金融机构,业务涵盖消费信贷、小微企业信贷、场景分期等多个领域,提供营销获客、风险防控、运营管理等服务。

随着业务的快速发展,风控模型对AI的需求也随之井喷。如何打造更敏捷的AI计算服务,支撑业务高速增长,同时节省资源成本,是摆在数禾科技面前的一大难题。

经过调研,数禾科技与阿里云云原生团队深度合作,联合打造全新的数禾AI推理服务平台,整个平台基于阿里云 Serverless 容器服务ASK构建,无需购买任何K8s节点即可直接部署推理服务容器应用,也无需对K8s集群进行节点维护和容量规划。同时,根据推理服务的实时请求量动态创建和销毁POD,资源成本大幅下降,服务的可用性也得到了很好的提升。此外,通过ASK Knative服务,有效解决了数禾模型的灰度发布和多版本并存问题,大幅提升了模型迭代上线的效率。

目前,该系统已上线部署数百个AI 模型服务,每天能够提供数亿次查询决策服务,ASK的实时弹性扩展能力帮助数禾节约资源成本约60%,同时平稳地应对了诸多运营活动等突发峰值场景,整个云原生部署和发布系统将数禾的平均部署周期由之前的1天缩短至0.5,有效加速了商业化应用的迭代进程,为金融业务的拓展增长提供了强有力的支撑。

3.3 智联招聘升级为云原生架构,释放Serverless技术红利

在2018年初,智联已经开始了容器化改造,最终实现了业务的快速迁移和扩展等能力。在2021年智联继续深度思考,以自身业务特点出发结合云原生技术优势,确定了Serverless容器混合云是系统进一步演进的最佳技术方案。

智联招聘在业内率先完成全面容器化改造,并与阿里云联合设计“分布式云容器平台 ACK One + IDC统一调度方案”。在应对春招期间高峰流量阶段,通过ACK One统一集群管理,IDC容器集群结合云上资源以及统一可观测性能力、秒级弹性能力,同时兼容线下调度器策略达到成本最优解,有效解决春招期间面临的系统稳定性、资源量预估困难、运维难度大等问题。

使用混合云的方式作为计算平台,不必因为业务突发增长的需求而一次性投入大量资金成本用于采购服务器及扩充机柜。在公共云上可以做到随用随付,对于一些创新业务想做技术调研非常方便,按量付费,大幅减少了试错的成本。在效率方面,借助混合云架构深度集成,方便研发人员完成一站式研发、运维工作,整个持续集成可以做到分钟级。

智联招聘的云原生转型助力了公司的快速变革,云原生架构、DevOps理念的实践,使得智联招聘的开发、测试、运维等工作能够更加协同和高效。此外,云原生架构的高可用性、灵活弹性、自动化特性,也使得智联招聘具备更好的容灾恢复能力和业务可靠性,保证业务在高峰期时能够快速响应和扩展。

参考文献

1.阿里云云原生架构白皮书

2.容器原理架构详解-https://blog.csdn.net/shyeang/article/details/113059045

3.分布式应用多运行时架构-https://cloud.tencent.com/developer/article/1957270

4.微服务架构:利用事件驱动实现最终一致性-https://www.51cto.com/article/604138.html

5.微服务、容器、云原生、Kubernetes、SOA、PaaS平台、Devops 之间的关系-https://zhuanlan.zhihu.com/p/74483850

6. MSE Serverless 正式商用-https://zhuanlan.zhihu.com/p/671148625

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/weixin_40725706/article/detail/563281
推荐阅读
相关标签
  

闽ICP备14008679号