加入收藏 | 设为首页 | 会员中心 | 我要投稿 武汉站长网 (https://www.027zz.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 综合聚焦 > 移动互联 > 应用 > 正文

从单体到分布式到云原生--技术要点及实现

发布时间:2022-10-28 14:01:22 所属栏目:应用 来源:网络
导读: 本文阐述应用系统的演讲过程,将软件应用的几个阶段分别描述并展开讨论了相关实现的技术要点和关键技术,整体上梳理了软件系统架构演讲的路线及相关考量。了解各个类型的应用适应的场景,相

本文阐述应用系统的演讲过程,将软件应用的几个阶段分别描述并展开讨论了相关实现的技术要点和关键技术,整体上梳理了软件系统架构演讲的路线及相关考量。了解各个类型的应用适应的场景,相关技术的优势和不足,在设计应用系统所需做的权衡和取舍。

1单体应用

单体应用Monolith,是最早出现的应用形态,通常将所有功能都在一个项目中实现。

适应场景

在计算机系统早期,计算能力有限,也没有分布式技术,只能是单体应用形态。

在一个项目的早期,单体应用也是适合的,通常在这个阶段,无论是用户量和业务都是较少的,单体应用足够支撑业务了。而且通常项目早期人力资源投入不大,单体应用的复杂度小,少量的人员投入就可以完成,工期也短,能更早的验证业务方向是否可行。

一些简单功能的应用,也完全可以使用单体应用架构,减少引入不必要的复杂性和更多的资源开销。

技术要点

单体应用更多的就是应用加上后端数据库,应用直接运行在OS上或者运行在web容器里面。开发和调试根据不同的开发语言使用不同的工具。

日志记录和监控也较为单一,本身没有过多的复杂性,重点在业务复杂度。

优缺点

优点:

复杂度可控:单体应用的所有业务都在一个项目中,开发和调试和定位问题方便。

可靠性高:不存在外部依赖和调用,业务流程简单清晰,业务可靠性高。

部署维护方便:单体应用没有相关依赖,部署维护方便。

性能有保障:不设计跨应用、跨主机、跨网络等调用,没有延时和不确定性,应用业务的性能有保障。

资源消耗低:不需要使用共享存储,数据及状态不需要与其他实例或者应用同步,所需要的资源低。

缺点:

扩展性差:单体应该所有的功能都在一起,无法根据其性能瓶颈点来扩展,只能整体扩展,而整体扩展对单体应用来说存在很多问题,比如状态同步,数据共享等等如果在一开始就没有考虑,会导致其无法简单的整体扩展。

代码可维护性低:所有业务代码都凑在一起,当业务堆积多了后,代码会比较臃肿,业务相互交织,不方便维护。

2分布式系统

随着计算机技术的不断发展,以及业务需求的变化,需要处理的业务越来越复杂,数量也越来越大。计算机硬件随着摩尔定律不断提升,在这个时期软件技术也得到了长足的发展,不断的匹配业务需求。硬件的发展支撑了复杂度不断增加的业务实现,虽然硬件的发展速度很快,高端硬件的成本也很高,而且硬件的发展还是没有跟上业务的需求。一方面为了满足不断爆发式增长的业务需求,另一方面为了降低硬件成本,软件开始走上分布式系统架构的道路。

分布式架构能平衡业务需求与成本,在业务可接受的范围内,通过分布式系统设计实现,将业务系统运行在普通的硬件上。

适应场景

分布式系统适合处理单体应用存在性能问题的场景,单体应用受限于资源和处理效率难以应对大量的业务处理请求,典型的场景就是大型业务服务,比如搜索引擎,比如电信业务系统,尤其是随着互联网的发展,用户量和业务复杂度相比以前都有大的增长,有的甚至是爆发式增长,单体应用甚至单个服务器都无法承载业务,稍具规模的互联网服务都要使用分布式架构,利用多个服务器的计算和存储能力才能满足业务需要,到今天大家常见的互联网业务系统几乎都是分布式架构的。当然,单体应用并没有消亡,在某些场景下其仍然具有生命力。分布式系统更适合处理大规模业务和大数据量的场景。

技术要点

分布式技术发展到今天,其核心要点仍然是:松耦合,数据/状态一致性,扩展性,高可用。这些核心要点也是分布式设计中的难点。

松耦合

分布式架构意味着系统/业务会由多个进程来完成,通常为了满足处理能力的需要,这些进程会分布在不同的服务器/虚拟机上,这就意味着需要他们之间需要相互通信,进程间通信技术分为同步和异步,RPC/Rest和队列是这两种形态的典型代表,根据业务需要来选择合适的进程间交互形式。为了更好的解耦系统,异步化设计是一个不错的选择。RPC框架有较多的代表:Thrift, GRPC,dubbo等都是较为代表性的产品,异步化涉及主要实现是通过MQ来做的,常用的MQ有:kafka, rabbitmq, rocketmq等。而微服务则是分布式系统松耦合发展的一个典型设计理念,微服务对应用系统按业务拆分,每个业务单独开发和部署。

扩展性

分布式系统本身是为了应对单体应用的性能瓶颈,将业务拆分为不同的进程,分配不同的硬件资源确实可以提高处理能力,但资源是有限的,自然就延伸出来需要将进程运行更多的副本来提升处理能力的场景。在这种场景下,为了让多个实例均衡处理请求,负载均衡技术就成为必要了(如nginx,haproxy等,也有LVS),此外,为了减少和避免业务请求在负载均衡的情况下在不同副本实例上处理不一致的情况,无状态设计就成为了这类应用的设计原则,为了将状态持久化在所有进程副本都能访问的地方,数据库/共享存储/KV缓存中间件这些都是为持久化业务状态提供了解决方案,能够保证数据/状态的一致性,支持系统的扩展性。常用的数据库有RDBMS(mysql,postgresql)和NoSQL数据库(mongodb,cassandra,hbase等),对于访问时延敏感的一般将数据存在内存缓存中,如redis, memcache等。

微服务及治理

为了更好的解耦系统,最小化各个业务的故障对其他业务的影响,出现了微服务理念。微服务将复杂业务拆分为单一的业务,单独实现和演进,与其他服务的交互通过接口或者消息队列来完成,这样就实现了系统的松耦合。但微服务将系统拆分为众多的独立服务也带来了复杂性,首先就是这些服务的发现与寻址,服务相互调用就得知道系统里面有哪些服务、地址信息等,然后服务相互之间的调用,也需要有隔离措施,一是防止服务被疯狂调用超出服务的处理能力,另一个是当某一个服务发送故障,能隔离该故障对其他服务的影响,这就涉及内部流量的治理,因为衍生出服务治理的概念和手段。服务治理较为常用的有spring cloud,dubbo等。提供了服务注册与发现,配置中心,流量控制等功能,方便用户对服务进行管理。

日志监控

同时在分布式架构下,一个业务需要通过多个进程来处理,如何方便的追踪一个业务的日志,以及业务处理的性能问题出在什么位置,这就涉及到了链路追踪和日志监控的领域。链路追踪常用的方案有skywalking, pinpoint,zipkin,cat等,很多都符合OpenTracing标准。除了链路追踪,通过prometheus的可以采集各类应用运行指标,这个都包含在应用性能管理APM领域。Prometheus+Grafana则是当前最为主流的整体监控方案,包含主机和应用监控。日志监控主流的方案是ELK来做集中日志系统,通过集中日志查看和定位问题。

持久化

在分布式环境下,还有一个较为麻烦的问题就是持久化方案。因为进程是分散的,并且做了无状态涉及,那么始终还是要有地方来存储和提供状态和数据的。如果是大量的数据,通常使用使用数据库或者分布式文件系统来存储,通过这些组件本身的高可用方案来保证数据的高可用,如果数据量不大而且是时延敏感的通常是使用内存数据库或者KV缓存来保障数据的可共享访问和高可用,但内存方案的成本较高,要根据需要选用。还以一种方式就是分布式存储,比如块存储,这种方案是将组件的应用程序和数据存储分开,将数据存储在分布式块存储上,应用死掉后在其他地方重建继续使用原来的块存储即可恢复原来的状态。

常用的分布式块存储有ceph,分布式文件系统有cephfs,glusterfs,nfs,hdfs等,还有对象存储等。具体的需要根据业务的特点来选择使用,每种都有其适应场景。

高可用

分布式环境下,扩展性也带来了可用性的问题,高可用也是分布式环境下重点和难点。分布式系统从设计之初就需要考虑各层的高可用方案。接入层,应用层,缓存层,持久化层都需要设计好相应的高可用方案。接入层通常考虑接入点的高可用,接入点通常是负载均衡器,这里硬件解决方案可以用F5这种及其配套的高可用方案,而软件方案则使用Nginx/HAproxy等,这部分的高可用大多都是通过keepalived来实现的,该方案也比较成熟,只是受限于网络环境,通常公有云网络中不支持这种方式,需要用公有云的LB产品,其保障了高可用性。私有化部署的时候,要么硬件方案自带,要么通过keepalived。应用层通常通过无状态设计,部署多个实例来实现高可用,其本质上是将状态交给缓存层或者持久化层来保存。缓存层,一般都用通用的组件如redis、memcache来实现,依赖组件本身的高可用方案,持久化层一般是使用数据库、分布式文件系统等,其高可用方案也是各个组件自己的。

API网关

在分布式环境中,API网关也是一项重要的技术组件。分布式系统多为平台型系统,少不了与其他业务系统的交互,通常业务系统间交互使用API接口。API网关和服务治理都有对接口流量进行控制的功能,通常来说API网关主要用于南北向流量的管控,注意用于控制与外部系统交互的流量,而服务治理更多的是对内部接口流量进行控制,主要管控东西向流量。

API网关一般具备认证、接口访问频次控制、熔断限流、路由及协议转换、负载均衡、缓存策略等功能,这些功能能有效的控制外部系统接入,保障系统本身不会被外部访问导致崩溃,也能及时隔离错误。API网关也可以用于内部服务网关。API网关在应用升级发布时可以配合支持蓝绿发布,动态升级应用,也可以通过配置支持在线A/B测试。

常用的API网关有KONG, APISIX等开源产品。公有云都有各自的相关产品。

优缺点

优点:

可扩展性:分布式系统解决了应用性能扩展的问题,可以方便的增加系统处理能力和容量。

系统解耦:分布式一个重要的特点就是系统解耦合,实现了系统业务和依赖的拆分。

高可用:分布式系统因为可以通过多副本的部署方式,保障系统始终处于可以提供服务的状态。

缺点:

系统复杂度大大提升:分布式系统不管是在设计还是部署升级,以及运维方面,对开发设计和运维人员都是很大的挑战。

故障定位不便:分布式系统的定位相对复杂,一是因为运行多个实例,需要找到问题发送的实例,二是很多异步化设计,并不能直观的找到问题,需要借助各类日志来确定故障点。

开发难度增大:在开发分布式应用时需要注意状态在多实例的情况下该如何合理的处理,异步化设计如何保障状态的一致性。

部署方案复杂:部署方案要考虑服务编排,整个链路的高可用方案,系统的平滑升级方案等等。

3云原生应用

云原生是随着分布式架构发展到微服务阶段,容器技术出现消除了各个应用运行环境的差异,K8S这种基于容器技术的编排系统能很好的承载和处理微服务的复杂度,DevOps的理念使得开发交付一体化和自动化,从而使得用户可以方便的在各种环境(公有云,私有云)可以方便的构建和运行可以弹性扩展的应用。

技术要点

云原生不是一个产品,是一套技术体系和方法论。云原生基金会(CNCF)致力于培育和维护一个厂商中立的开源生态系统,维护了云原生生态的Landscape(landscape.cncf.io/),是云原生最佳实践的集合。

因而云原生有几个核心点:容器技术及服务编排系统,微服务,DevOps持续交付。

容器技术

容器技术的出现,抹平了开发环境与测试环境和生产环境的差异,将应用所需要的运行环境及依赖全部打包成 镜像一起发布,不需要处理复杂的环境依赖,可以高效的发布和升级,体现了不可变基础设施的理念。容器技术目前主要使用docker,镜像仓库主要有docker registry和Harbor,包管理工具主要有Helm。

K8S编排系统及相关技术栈

编排系统主要用来调度运行服务的容器实例,目前K8S已经成为行业统一的标准编排系统。编排系统提供了服务注册与发现(K8S使用etcd和CoreDNS来实现的),服务负载均衡,应用实例(Pod)数量的保持,应用实例(Pod)的自动扩缩容,滚动升降级,配置中心(configMap),安全(secret、service account、namespace及网络隔离、权限控制等),外部流量接入(ingress/nodeport)等功能。

网络

k8s的内部网络方案有多种,用的较多的方案都是overlay方案,也就是在主机网络上虚拟一层网络,拥有自己的IP段与主机网络不冲突。当然也有使用underlay网络方式的(即容器的IP地址网段与主机共用),根据需要来使用。

K8S提供了CNI来支持各种网络方案,常见的网络方案有flannel, canal,calico,weave等。用户也可以实现CNI接口来使用自己的网络方案。每种网络方案都有其适应场景,目前用的较通用的有flannel的vxlan模式, calico的ip-ip模式等。

存储

容器是可以随时创建和删除的,那么对于使用了存储的容器,就不能方便的在集群中创建和销毁。在云原生场景下,就需要有对应的存储方案,能够支持在任意位置都能方便的访问存储。这也就是说在K8S环境下使用的存储本身就要求是分布式的,并且是高可用的。存储分为文件存储,块存储,对象存储。文件存储包含各类FS如glusterFS, CephFS等,块存储方案有 Ceph, Longhorn, OpenEBS 和 Rook等,对象存储有S3/Swift/OSS等。

K8S对存储进行了抽象,使用PV来关联具体的存储实现并指定容量大小应用性能管理,PV需要先创建再使用,开发人员需要自己创建PV,后来又使用PVC来解耦存储系统的具体实现,PVC会根据申明的空间大小去自动匹配合适的PV,这种情况也是要运维或者管理人员先创建好一批通用的PV,开发人员不管具体的PV,再后来出现了StorageClass,使用StorageClass的时候需要先在集群中创建好与后端存储实现相关的provisioner,K8S自带了很多provisioner,可以直接使用,创建storageclass并指定使用的provisioner,并配置后端存储实现的具体参数即可。

K8S也定义了CSI,用户可以实现CSI固定的接口规范,使用自己开发的存储实现。

监控

监控在分布式系统中就占据着重要的位置,如果没有适当的监控手段,是无法把握整个系统的状态的。在K8S环境下监控尤为重要,K8S早期的Heapster对pod资源进行监控,后面统一到Metrics-server上,这个主要是对Pod计算资源进行监控,并且获取实时的值,用于对Pod进行扩缩容的自动控制。

除此之外,对Node,各个组件以及Pod内进程的监控主流方案是通过prometheus+grafana+alertManager来实现的。包含了K8S环境和非K8S环境,但是目前的链路级的监控还是会使用分布式时代的解决方案,也有通过服务网格来支持的。

日志

在k8s集群中一个个Pod的去看日志几乎是不可能的,通过EFK(Elasticsearch+fluentd+kibana)的集中日志方案对日志进行采集和分析极大方便了对问题跟踪定位,也有轻量级的Loki日志方案在使用。

服务网格

服务网格(serivce mesh)是K8S生态中的服务治理方案,主要是对各个Pod之间的流量进行可视化和控制,当前主流方案是istio+enovy的方式,在Pod里面部署sidecar对流量进行转发和控制。

Serverless

无服务器框架通常是指用户将一段代码逻辑放在云端,由事件触发其运行,平时不会运行也不消耗任何资源,用户不需要租赁和管理服务器,目前使用最广泛的有AWS的Lambda。

基于K8S构建无服务器框架,目前使用的有knative,kubeless等开源产品,也有一些商业产品。

DevOps持续交付

DevOps是微服务背景下一套开发和运维最佳实践,通过自动化的工具支持,开发人员自己开发代码并打包成镜像交付,自己部署和维护镜像,运维人员更多的专注与维护基础设施。

DevOps是一整套工具和流程的集合,实现了高效发布。改变了以前应用更新周期长的问题,配合API网关等可以实现随时发布新的版本,升级的频次由以前的按月/周变为按天了,甚至一天内也可以实现多次发布。

自动构建

自动构建是只从开发人员提交代码开始,相关工具便自动开始编译自测试打包,生成相应的运行包,可以是jar包、二进制文件或者docker镜像。在K8S的环境里面构建甚至包含了版本管理工具包的构建,如helm charts,在自动构建时会构建出相关环境的helm包。

通常自动构建会使用到的工具如gitlab, jenkins等,代码质量工具如sonar等,docker应用则包含镜像管理工具如harbor和包管理工具Helm等。

自动测试

自动化测试是DevOps中最为重要的质量控制手段和效率提升方式。自动化测试通常是在自动构建完成后,将相关的包部署到测试环境中,通过自动化框架对产品进行功能或者性能测试。自动化测试的覆盖率越高,产品质量越有保障。

自动化测试的工具也比较多,通常有robot,jmeter等工具来编写自动化用例,配合Jenkins等来控制自动化测试的运行。

自动化测试用例通常需要花费较多时间和人力来编写用例,这个需要衡量和根据实际情况调整以适合自身情况。

自动发布

自动发布是指经过测试验证的产品,自动部署到相关环境中去,一般在开发和测试环境中使用较多,在部署生产环境的时候建议还是在流程中建议先通过人工确认在进行自动部署。

优缺点

优点

云原生作为分布式架构和微服务发展的一个里程碑,解决了分布式里面一些非常重要的问题,其中受益最大的就是系统的扩展性,真正意义上实现了对系统应用的弹性扩缩容,通过K8S的metrics-server对应用使用的资源进行实时测量根据定义的策略对应用实例数量进行控制。

同时云原生将一些通用的分布式和微服务的能力抽象出来,下沉到K8S平台这一层,作为平台的基本能力提供,极大的降低了分布式应用开发难度。如服务负载均衡、分布式存储、配置中心(configMap)等能力,在分布式环境下都是需要自己来实现或者集成三方组件来完成。

便于升级和回退,云原生基于k8s的应用管理能力,将应用打包为镜像通过K8S运行,升级和回退都是对镜像及运行实例操作,因为环境和依赖都打包到镜像里面了,可以避免众多的环境和依赖相关问题。可以方便的进行部分升级回退,只升级指定的服务。

方便流量控制,可以方便的进行A/B测试,金丝雀发布等。

环境隔离,能将不同项目运行在同样的K8S集群上,并且实现项目之间的隔离。

缺点

在K8S环境下,应用封装在pod里面,需要熟悉k8s环境下的调试方法、日志查看方式等,另外K8S本身自己有一层网络,不能像直接部署在主机上那样方便直接调试定位问题。

部署和运维的复杂度更高,除了应用本身外首先需要部署好K8S及相关组件,也需要对其进行相应的运维和故障定位恢复。

使用的资源略多,尤其是对于主机资源要求较少的应用,上一套K8S及相关组件就显得比较重,不适合这种小场景使用,小场景也有miniKube这类项目来支撑。

对于有状态的组件,如数据库等中间件,高可用状态需要开发对应的Operator来支持,对这部分暂时还没有更为便捷的方式来处理,也导致生产环境中很多这类中间件仍然选择运行在主机上。

(编辑:武汉站长网)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!