进化中的架构-创新互联

目录

创新互联公司专业成都网站设计、成都网站建设、外贸网站建设,集网站策划、网站设计、网站制作于一体,网站seo、网站优化、网站营销、软文平台等专业人才根据搜索规律编程设计,让网站在运行后,在搜索中有好的表现,专业设计制作为您带来效益的网站!让网站建设为您创造效益。

前言

原始分布式

单体架构

烟囱式架构

微内核架构

基于事件的架构

SOA架构

微服务

云原生

背景

如何做

虚拟化

容器编排


前言

随着软硬件技术、行业规模、商业模式等的不断发展,时刻对软件提出新的要求,这就是架构进化的源动力。

原始分布式

背景

在很久以前,计算机刚经历了从大型机向以微型机的蜕变,逐渐开始面向商业企业中的生产设备、家庭、个人娱乐设备。此时的微型计算机系统通常具有 16 位寄存器、不足 5MHz 时钟频率的处理器,不超过1MB的大内存和64KB单段偏移地址。

计算机硬件性能很差,已直接妨碍到了在单台计算机上软件能够达到的大规模。为突破硬件算力限制,人们寻找使用多台计算机共同协作来支撑同一套软件系统运行的可行方案。

如果你不能想象当时的场景,不妨对比一下51单片机的性能:8位的cpu、12MHz时钟频率、KB级别内存大小。

51单片机
51单片机开发板
为51单片机编写的代码
为51单片机编写的代码

结果

受限于当时的条件,以失败而告终

成果

  • NCA一种远程服务调用规范
  • 提出基于TCP/IP的RPC
  • AFS分布式存储实现
  • 远程调用不是透明的,底层面临的各种问题没办法做到透明,需要让上层感知到
  • 发明UUID,用来表示在rpc中方法的唯一性
单体架构

背景

20 世纪 80 年代,摩尔定律开始稳定发挥作用,微型计算机的性能以每两年即增长一倍的惊人速度提升,硬件算力束缚软件规模的链条很快变得松动,进入了以单台或少量几台计算机即可作为服务器来支撑大型软件运作的单体时代。

实现

会把代码分为三层,即通常提到的MVC,每层各司其职,层与层之间通过接口耦合,对某一层的改动不会影响其它层。在每一层中,还会根据模块不同而划分出不同的目录。

优点

  • 性能好:没有远程调用
  • 部署方便:无需考虑依赖
  • 大规模:支持集群、多机房部署
  • 结构简单:MVC分层、按照功能划分文件夹

缺点

  • 规模过大不利于团队协作
  • 构建缓慢
  • 启动慢
  • 回滚困难
  • 提交冲突过多
  • 发布过于频繁
  • ......

关键缺点:单体架构下所有组件运行在同一个进程下,隔离性差(性能隔离、故障隔离)。在以往的工作中曾发生多次事故,都与隔离性息息相关,比如:

  • 依赖下游某接口的timeout配置时间过长,当下游出现问题未及时返回时,导致连接数过多,最终整体响应缓慢
  • http连接忘记关闭导致协程过多,cpu不能及时调度协程,造成所有接口响应缓慢
  • 某个模块造成cpu使用100%,集群的所有实例反复重启,整体服务不可用

反思

认识到系统会出问题,且不可避免。需要通过拆分服务到不同机器上以获取隔离性、自治性。

在拆分服务这条路上,人们经过了多次尝试,产生了多种架构,今天成熟的微服务架构不是一蹴而就的。

烟囱式架构

只是简单地将单体系统拆开,两个系统之间不要通信,不要共享数据。然而事实上一个公司内的系统之间确实需要通信,需要共享数据,需要建设公共平台。如果强行烟囱,会造成数据孤岛、重复建设等问题。

微内核架构

既然在烟囱式架构中,没有业务往来关系的系统也可能需要共享人员、组织、权限等一些的公共的主数据,那不妨就将这些主数据,连同其他可能被各子系统使用到的公共服务、数据、资源集中到一块,称为微内核。其它子系统/逻辑视为插件集成到微内核中。基于这种思想,决定了插件只能与微内核通信,插件之间的通信没有得到很好的满足。常见的使用场景有IDE、web功能、用于研究目的的OS内核。

优缺点

评级分析
1整体灵活性 整体灵活性是指能够快速适应不断变化的环境的能⼒。通过插件模块的松耦合实现,可以将变化隔离起来,并且快速满⾜需求。通常,微内核架构的核⼼系统很快趋于稳定,这样系统就变得很健壮,随着时间的推移它也不会发⽣多⼤改变
2易于部署根据实现⽅式,插件模块能够在运⾏时被动态地添加到核⼼系统中 ( ⽐如,热部署 ),把停机时间减到最⼩
3可测试性插件模块能够被独⽴的测试,能够⾮常简单地被核⼼系统模拟出来进⾏演⽰,或者在对核⼼系统很⼩影响甚⾄没有影响的情况下对⼀个特定的特性进⾏原型展⽰
4性能使⽤微内核架构不会⾃然⽽然地使你的应⽤变得⾼性能。通常,很多使⽤微内核架构的应⽤运⾏得很好,因为你能定制和简化应⽤程序,使它只包含那些你需要的功能模块。JBoss应⽤服务器就是这⽅⾯的优秀⽰例: 依赖于它的插件化架构,你可以只加载你需要的功能模块,移除那些消耗资源但没有使⽤的功能特性,⽐如远程访问,消息传递,消耗内存、CPU的缓存,以及线程,从⽽减⼩应⽤服务器的资源消耗
5伸缩性因为微内核架构的实现是基于产品的,它通常都⽐较⼩。它们以独⽴单元的形式实现,因此没有太⾼的伸缩性。此时,伸缩性就取决于你的插件模块,有时你可以在插件级别上提供可伸缩性,但是总的来说这个架构并不是以构建⾼度伸缩性的应⽤⽽著称的
6易于开发微内核架构需要考虑设计和规约管理,使它不会很难实现。规约的版本控制,内部的插件注册,插件粒度,丰富的插件连接的⽅式等是涉及到这个架构模式实现复杂度的重要因素
基于事件的架构

为了让子系统之间方便通信,人们提出了基于事件的架构。具体就是在系统之间架设一个公共的事件总线,每个系统都可以向其中发布事件,其他系统可以获取并处理这个事件。MQ、内存队列都可以作为总线的实现方式,常见的框架有Spring Integration,RocketMQ...以及一些EventBus实现。

每个系统之间是高度解耦的,平等的,甚至可以起到削峰填谷的作用。但是过多地使用总线,会导致系统之间的逻辑关系变得隐晦。而且在某些对性能有高要求的场景中(例如OS内核),这种架构是不能满足的。

SOA架构

服务拆分已经发展到相对成熟的地步。于是有多个大厂参与,拥有专门的组织管理,针对分布式服务提出完整解决方案的SOA架构就诞生了。它对分布式服务做了方方面面的规定,比如以下:

  • 服务的设计指导
  • 要求采用SOAP协议簇来完成服务发布、发现、治理
  • 使用ESB(Enterprise Service Bus)框架来支持各个服务的通信交互(如MULE)
  • ......

正因为SOA对分布式服务做了方方面面的规定,想要解决所有问题,导致了它过于复杂。没有程序员愿意使用如此复杂的技术。

微服务

背景

微服务作为SOA过于复杂的一个补救措施被提出,将微服务当做SOA的一种扩展。经过多年发展,已经形成一种独立的架构风格。2014年是微服务崛起的一年,列出了微服务的核心特征:

  1. 围绕业务能力构建:康威定律
  2. 分散治理:各管各的,每个团队有权利选择自己的技术
  3. 通过服务来实现独立自治的组件:需要拆分服务
  4. 产品化思维:要关心服务的方方面面,整个生命周期
  5. 数据去中心化:拆分数据库,不仅是指自治独立,而且每个服务看待同一个数据有不同的视角,避免相互响应
  6. 强终端弱管道:采用轻量级的通信
  7. 容错性设计:比如熔断等措施
  8. 演进式设计:服务会改变、废弃。需要对其他服务的影响降到最低
  9. 基础设施自动化:会有更多的服务和部署,需要自动化流程来为开发和运维减负

至于微服务如何实现、包含哪些组件、优缺点,这些在网上一搜一大把,这里就不再赘述了。

特点

与SOA对比,强约束 VS 软指导、强一致 VS 自由、规范标准 VS实践标准 ,颇有一点约定大于配置的意思。微服务提出了新的思想,更加自由,但是没有带来具体的东西(规范、协议、指导...)。那么SOA已经解决的分布式问题又重新涌现了出来,以注册中心为例,每个人都能说出两个,但如何选择呢?

服务发现:Eureka、Consul、ZooKeeper、Etcd

远程调用:RMI、Dubbo、gRPC、brpc、JSON-RPC、rest

网关:zuul、gateway

如果要我们从头搭建一个微服务架构,恐怕我们需要对大多数框架都要了解,测试它们之间的兼容性,并编写很多胶水代码。幸运的是,有SpringCloud这种保姆式框架,帮我们做了几乎所有工作,而中大型公司则有专门的团队来维护这一套东西。

尽管微服务已经成功地流行开来,但它却是有史以来最复杂的架构,远程通信、一致性、服务发现、熔断降级、可观测性......每一个都是需要深入了解原理,并在实战中反复磨炼的,否则搭建出来的微服务非常脆弱,流量稍微大一点就车毁人亡了。架构的进化不会停止,而以后的进化将会尽可能消除这些不稳定因素。

云原生

云原生三个字比较抽象,通常是媒体用来对外宣传的用词。要了解云原生,就要先了解背景。在这种背景下,出现了什么问题,采用了什么办法解决。

背景
  • 移动互联网下用户基数很大
  • 以移动端为中心对各行各业的渗透
  • 对软件功能提出新要求:需求变化快、创新多...
  • 对软件开发带来了新的挑战:快速迭代、团队人数膨胀...
  • 互联网公司要努力提供更好的服务,要持续增长以获取更多用户

在以上背景下,一种新的开发模式(软件开发方式)开始流行,特征如下

  • 产品快速迭代,更快的上线速度
  • 系统的高可用,故障时能够自动恢复与回滚
  • 快速解决问题,细致的故障探测和发现
  • 避免雪崩,故障时能自动隔离
  • 系统的弹性伸缩,简便快速的水平扩容
如何做

微服务架构能够满足‘新的开发模式’吗,当然不能!但我们要搞清楚为什么不能。微服务带来了史无前例的复杂性,程序员不仅要关注业务逻辑,还要分心思在各种熔断配置、服务注册这种事情上,如何能做到快速迭代、更快的上线速度、快速定位解决问题?代码直接部署在物理机上,与环境紧密地耦合在一起,发生问题时不仅要排查代码,还要排查环境,如何做到故障快速回滚、快速水平扩容?

以上问题正是云原生要解答的。首先了解以下关键技术:

虚拟化

在一个物理机上运行多个虚拟机(操作系统),每个虚拟机之间相互隔离

有以下两个主要部分

  • 主机H/W体系结构和设备:指指令层(指令层的概念参考《计算机组成-结构化方法》一书,它不仅包含了指令集、还有在这一层次下计算机的视角,既如何操作IO、内存、cpu),它需要支持虚拟化(所有指令必须只能访问当前虚拟机资源)
  • 监控管理软件:hypervisor(通常也叫作virtual machine monitor, VMM),是一类软件的统称,能够建立和管理虚拟机实例

以上是一个最基本的原理图,看下有哪些工业实现

(1)完全虚拟化

VMM充当中间层,其上运行的VM感受不到VMM和其它OS,缺点是性能损耗较大。代表软件有Xen

(2)半虚拟化

需要改造操作系统(下图中淡黄色部分),使其能够与VMM和其它OS通信,互相协作,这样就减轻VMM模拟的负担,性能更高。代表软件有Xen

(3)操作系统层虚拟化

操作系统充当VMM层,内核中包含虚拟化技术模块,模块利用操作系统内核的其他组件做大量工作。 代表软件有KVM、virtualbox

操作系统层虚拟化
virtualbox

(4)容器

容器技术其实属于操作系统层虚拟化,但这里拿出来单独讲,因为它是云原生的一个重要组成部分。容器,一种轻量级的虚拟化,提供单机上的隔离。最初作为隔离环境使用,现在作为软件分发的载体。代表软件有docker。

容器的实现依赖linux提供的以下功能

(a)隔离目录:最开始使用unix系统提供的chroot命令,进程只能访问指定目录

(b)隔离访问:nameSpace

(c)隔离资源:cpu时间、内存大小、磁盘速度

虚拟化总结

这里讲的只是计算资源的虚拟化,广义上虚拟化还包括存储虚拟化、网络虚拟化......

我们关注的是虚拟出来的OS,而不是物理机。虚拟机已经是单纯的软件了,但从业务上看,它仍属于硬件(基础设施)的范畴。优点如下:

  • 提供隔离环境
  • 成本降低。比如一个应用无法利用物理机的性能,而直接在物理机上部署多个应用会有依赖、网络、权限等冲突。使用虚拟化技术的隔离、可迁移特点,实现动态负载,支持做细粒度控制
  • 灵活性。抽象了计算资源,提供api来供软件按需创建、管理虚拟机。这意味着硬件可以由软件定义,带来了灵活性
  • 提供基础。使用OpenStack构建Iaas时,底层技术就是虚拟化

需要重点关注容器,容器是操作系统层面虚拟化,它提供单机级别的环境隔离,而且非常轻量级,启动/停止速度快,占用资源少。我们的应用以及依赖环境运行在容器中,换句话说,使用容器封装了应用和环境,这样不仅让我们对具体的环境解耦,而且对上层提供了统一接口,为接下来k8s登场提供了基础。

容器编排

上面已经使用容器封装了单个进程,但是一个分布式应用需要多个容器协作,通过集群的方式对外服务,实现这个目标的过程就是容器编排。目前k8s在编排框架中占据主导地位。

k8s设计思想

(a)隔离与协作

容器封装代表了隔离,但是两个容器之间存在交互的需求。针对交互的频繁或者依赖的多少,划分为普通非亲密、亲密协作、超亲密协作

  1. 普通非亲密:一般通过网络交互
  2. 亲密协作:被调度到同一个机器上,共享本地磁盘方式协作
  3. 超亲密协作:多个容器划分到同一个pod中,共享以下
    1. UTS 名称空间:所有容器都有相同的主机名和域名
    2. 网络名称空间:所有容器都共享一样的网卡、网络栈、IP 地址,等等。因此,同一个 Pod 中不同容器占用的端口不能冲突
    3. IPC 名称空间:所有容器都可以通过信号量或者 POSIX 共享内存等方式通信
    4. 时间名称空间:所有容器都共享相同的系统时间

上面提到了pod这里解释一下,它相当于组的概念,是虚拟的,不对应任何实物。一个pod下可以有多个容器,调度时以pod为基本单位(pod下所有容器一定会被调度在同一个机器上)

可以看到上面有pod、node...层层嵌套

  • 容器(Container)
  • 生产任务(Pod)
  • 节点(Node):代表一台机器,可以是物理机,可以是虚拟机
  • 集群(Cluster):多个主节点+多个工作节点组成一个集群
  • 集群联邦(Federation)

(b)韧性与弹性

我们希望得到一个健壮的系统,能够抵御意外与风险:pod以外终止、流量突增、软件崩溃。k8s能够帮助程序员以最小的代价实现容错。

假设有一个由数十个 Node、数百个 Pod、近千个 Container 所组成的分布式系统,要避免系统因为外部流量压力、代码缺陷、软件更新、硬件升级、资源分配等各种原因而出现中断,作为管理员,你希望编排系统能为你提供何种支持?

k8s将工业中控制回路的思想迁移到软件中,如下图所示

控制回路

将container、pod、node等都视为资源,为资源附加两个属性:期望状态、实际状态。程序员描述清楚资源的期望状态,由k8s中对应监视这些资源的控制器来驱动资源的实际状态逐渐向期望状态靠拢,以此来达成目的。这种交互风格被称为是k8s的声明式 API

k8s如何使用资源、控制器。举个例子,k8s支持下面三种情况

(1)Pod 出现故障时,能够自动恢复,不中断服务

引入副本集(ReplicaSet)、副本集控制器(ReplicaSet Controller)概念,副本集也是一种资源,它下面包含多个pod,并且由副本集来创建pod。在副本集资源中描述我们期望的数量,那么副本集控制器就会持续监视。如果有pod退出则新启一个,如果有多余则回收。

(2)Pod 更新程序时,能够滚动更新,不中断服务

引入部署(Deployment)与部署控制器概念,’部署‘也是一种资源,由’部署‘来创建副本集,副本集创建pod。在’部署‘中描述我们要的状态,部署控制器就会持续监视,并执行以下步骤:自动创建新副本集,同时逐渐缩减旧副本集,直至升级完成后彻底删除掉旧副本集。

(3)Pod 遇到压力时,能够水平扩展,不中断服务

引入Autoscaling和自动扩缩控制器概念,Autoscaling也是一种资源,能够根据一些指标(内存、cpu、自定义...)自动设置’部署‘资源的描述期望值。当压力来临时,按照Autoscaling→Deployment→ReplicaSet→Pod顺序缩扩容。

k8s除了提供以上特性,还提供了多样的基础设施。什么是基础设施呢?是指支持应用程序的所有软件和硬件,包括操作系统、部署流水线、配置管理,以及支持应用程序生命周期所需的任何系统或软件。这些东西越下沉,越透明,对程序员越不可见,开发效率就会越高。联想一下,在springCloud中,负载均衡、网关、注册中心、链路追踪这些东西是不是需要我们自己来处理,但是在k8s中,它提供了对应的组件,只需配置即可使用,如下图所示

而在基础设施前面加上‘不可变’这个形容词,说的是基础设施最好无状态,才方便我们随时横向扩展。

随着k8s不断发展,还出现了最近几年大火的ServiceMesh(服务网格),它是在pod中注入一个sidecar,由它来挟持我们应用的网络,从而进行管理(熔断、连接数),最终使我们的应用做到透明化的网络调用。

k8s总结

微服务架构带来了巨大的复杂性,而云原生则努力将其下沉隐藏,并提供灵活性和扩展性。k8s提供的故障恢复、滚动更新、自动扩缩等能力,在云原生中常被概括成服务的弹性、可扩展...能够看出k8s的重要程度,所以某些资料甚至说云原生是围绕着k8s来建设的/k8s是云原生时代的操作系统。看下下面官方对云原生的定义,觉得抽象吗?很多名词已经解释过了。

云原生计算基金会(CNCF)2018:

云原生技术有利于各组织在公有云、私有云和混合云等新型动态环境中,构建和运行可弹性扩展的应用。云原生的代表技术包括容器、服务网格、微服务、不可变基础设施和声明式API。
这些技术能够构建容错性好、易于管理和便于观察的松耦合系统。结合可靠的自动化手段,云原生技术使工程师能够轻松地对系统作出频繁和可预测的重大变更

------------------------------------------------------------------------------------------

首次提出云原生的Pivotal公司2017更早:

在我理解,云原生其实是一套解题思路,针对最开始提到的背景问题,给出了具体的可操作方法。如果你不能理解k8s所做工作的重要性,可能是工作年限稍短。以后的文章中将详细讲解底层技术的复杂性,如果把它们赤裸裸暴露给开发者, 将会是巨大的负担。

后续章节:见该专栏的下篇文章

搭建k8s集群​​​​​​​

你是否还在寻找稳定的海外服务器提供商?创新互联www.cdcxhl.cn海外机房具备T级流量清洗系统配攻击溯源,准确流量调度确保服务器高可用性,企业级服务器适合批量采购,新人活动首月15元起,快前往官网查看详情吧


新闻名称:进化中的架构-创新互联
网址分享:http://myzitong.com/article/idsed.html