《凤凰架构》网址:https://icyfenix.cn/
技术方法论
微服务不是银弹
目的:微服务的驱动力
微服务的目的是有效的拆分应用,实现敏捷开发和部署。提高性能一般不是目的。
原则:能够通过扩展硬件的手段解决问题就尽量别使用复杂的软件方法。
理论:硬件的成本能够持续稳定地下降,而软件开发的成本则不可能。
前提:微服务需要的条件
前提一:决策者与执行者都能意识到康威定律在软件设计中的关键作用。
康威定律:系统的架构趋同于组织的沟通结构。
“沟通决定设计”(Communication Dictates Design)
“所有的技术上的决策实际都是政治上的决策”(All Technical Decisions Are Political Decisions)
前提二:组织中具备一些对微服务有充分理解、有一定实践经验的技术专家。
微服务对普通程序员友善的背后,预示着未来的信息技术行业很可能也会出现“阶级分层”的现象。
前提三:系统应具有以自治为目标的自动化与监控度量能力。
Martin Fowler 在《Microservice Prerequisites》中提出的微服务系统的三个技术前提都跟自动化与监控度量有关,分别是:
- 环境预置(Rapid Provisioning):即使不依赖云计算数据中心的支持,也有能力在短时间(原文是几个小时,如今 Kubernetes 重启一个 Pod 只需要数秒到数十秒)内迅速地启动好一台新的服务器。
- 基础监控(Basic Monitoring):监控体系有能力迅速捕捉到系统中出现的技术问题(如异常、服务可用性变化)和业务问题(如订单交易量下降)。
- 快速部署(Rapid Application Deployment):有能力通过全自动化的部署管道,将服务的变更迅速部署到测试或生产环境中。
不论自动化实现了多少层,顶层仍然必须是人,只有人能确保整体运维的连续性,所以永远也无法达到完全的自动化。
微服务自动化的最终目的是构筑一个可持续的生态系统。
自动化需要和系统规模匹配,不是自动化程度越高越好。
前提四:复杂性已经成为制约生产力的主要矛盾
对于小型系统,单体架构就是最好的架构。
只有在业务已经发展到一定的程度,单体架构与微服务架构的生产力曲线已经到达交叉点,此时开始进行微服务化才是有收益的。
长期来看,多数服务的结局都是报废而非演进。
边界:微服务的粒度
识别微服务的边界:方法论 领域驱动设计(Domain-Driven Design,DDD)
DDD 的发明人 Eric Evan 《领域驱动设计:软件核心复杂性应对之道》
Chris Richardson《微服务架构设计模式》
《人月神话》:“为进度给项目增加人力,如同用水去为油锅灭火”(Adding Manpower to A Late Software Project Makes It Later)软件项目中的沟通成本= n×(n-1)/2,n 为参与项目的人数
结论一:微服务粒度的下界是它至少应满足独立——能够独立发布、独立部署、独立运行与独立测试,内聚——强相关的功能与数据在同一个服务中处理,完备——一个服务包含至少一项业务实体与对应的完整操作。
结论二:微服务粒度的上界是一个 2 Pizza Team 能够在一个研发周期内完成的全部需求范围。
治理:理解系统的复杂性
治理就是让产品能够符合预期地稳定运行,并能够持续保持在一定的质量水平上。
静态的治理
两个心理学概念来解释复杂性的来源:
- 复杂性来自认知负荷(Cognitive Load) :在软件研发中表现为人接受业务、概念、模型、设计、接口、代码等信息所带来的负担大小。系统中个体的认知负担越大,系统就越复杂,这点解释了为什么蚂蚁族群和国家的人口可能一样多,但治理国家比治理一群蚂蚁要更复杂。
- 复杂性来自协作成本(Collaboration Cost):在软件研发中表现为团队共同研发时付出的沟通、管理成本高低。系统个体间协作的成本越高,系统就越复杂,这点解释了为什么小饭馆和国家的构成个体都同样是人类,但治理国家比治理一家饭馆要更复杂。
结论:软件规模小时微服务的复杂度高于单体系统,规模大时则相反。这里的原因就是微服务的认知负荷较高,但是协作成本较低。
面向对象编程(OOP)这种以人类观察世界的视角去抽象系统的设计方式是利于降低认知负荷的,但分布式系统提倡面向资源编程
分治”,这既是微服务的基本特征,也是微服务应对复杂性的手段。
发展的治理
架构腐化只能延缓,无法避免。
大型软件的建设是一个不断推倒重来的演进过程,前一个版本对后一个版本的价值在于它满足了这个阶段用户的需要。
先进的生产力都伴随着更高的复杂性,需要有与生产力符合的生产关系来匹配,敏锐地捕捉到生产力的变化,随时调整生产关系。
Neal Ford 《Building Evolutionary Architectures: Support Constant Change》演进式设计
例子:理想的交通工具
演进中的架构
原始分布式时代
UNIX 的分布式设计哲学:保持接口与实现的简单性,比系统的任何其他属性,包括准确性、一致性和完整性,都来得更加重要。
教训:某个功能能够进行分布式,并不意味着它就应该进行分布式,强行追求透明的分布式操作,只会自寻苦果。”-- Kyle Brown
单体系统时代
单体架构(Monolithic)
“单体”只是表明系统中主要的过程调用都是进程内调用,不会发生进程间通信,仅此而已。
小型的单体是合理的,大型的单体才是需要改善的。
缺陷:隔离能力的缺失、难以阻断错误传播、不便于动态更新程序、技术同构。
单体系统很难兼容“Phoenix”的特性,不利于架构的演化。
构筑可靠系统从“追求尽量不出错”,到正视“出错是必然”的观念转变,才是微服务架构得以挑战并逐步开始取代运作了数十年的单体架构的底气所在
SOA 时代
SOA 架构(Service-Oriented Architecture)
面向服务的架构是一次具体地、系统性地成功解决分布式服务主要问题的架构模式。
SOAP 协议
问题:
- 过于精密和复杂:架构复杂度影响业务开发
- 对开发者要求极高
- 背离了 Unix 简单透明的初心
微服务时代
微服务架构(Microservices)
微服务是一种通过多个小型服务组合来构建单个应用的架构风格,这些服务围绕业务能力而非特定的技术标准来构建。各个服务可以采用不同的编程语言,不同的数据存储技术,运行在不同的进程之中。服务采取轻量级的通信机制和自动化的部署机制实现通信与运维。
2014年, Martin Fowler 与 James Lewis 合写的文章《Microservices: A Definition of This New Architectural Term》
特点:
- 围绕业务能力构建(Organized around Business Capability)
- 分散治理(Decentralized Governance)
- 通过服务来实现独立自治的组件(Componentization via Services)
- 产品化思维(Products not Projects)
- 数据去中心化(Decentralized Data Management)
- 强终端弱管道(Smart Endpoint and Dumb Pipe)。
- 容错性设计(Design for Failure)
- 演进式设计(Evolutionary Design)
- 基础设施自动化(Infrastructure Automation)
《Microservices: A Definition of This New Architectural Term》列举了微服务的九个核心的业务与技术特征:
- 围绕业务能力构建:强调技术架构为业务服务,与业务发展阶段匹配;
- 分散治理:允许技术异构。对应团队为其服务的质量负责,同时允许该团队根据自身情况选择语言/框架等异构技术;
- 通过服务来实现独立自治的组件:“服务”而非“组件/类库”,因前者隔离和自治能力好;
- 产品化思维:把“服务”看成“产品”,关注服务的整个生命周期;
- 数据去中心化:不同服务关注同个数据的重点/视角不同,使用统一的数据容易耦合或相互限制;
- 强终端弱管道:管道指通信机制;管道提供基本的通信机制即可,特殊的能力需求由终端/业务服务定制化解决;
- 容错性设计:承认“出错无法避免”,做好自动化备案机制(健康检查、熔断、隔离、自动恢复等);
- 演进式设计:无永生,承认会报废淘汰;做好生命周期管理,各自独立、自治,能更好地反脆弱;
- 基础设施自动化:更多的服务,更频繁的构建、发布、运维;用 CI、CD 等自动化来支持。
微服务 VS SOA:
- 相同:面向服务;
- 不同:强约束 VS 软指导;强一致 VS 自由;规范标准 VS实践标准。
微服务时代充满着自由的气息,微服务时代充斥着迷茫的选择。
有利弊才要权衡,有取舍才要决策。
后微服务时代
后微服务时代(Cloud Native)
从软件层面独力应对微服务架构问题,发展到软、硬一体,合力应对架构问题的时代,此即为“后微服务时代”。
Kubernetes 成为容器战争胜利者标志着后微服务时代的开端,
后微服务时代(云原生时代):软件和基础硬件设置一起解决分布式架构遇到的问题
微服务的到来,也重新抛出了分布式带来的问题。
虚拟化、容器及 K8s 能灵活快速地调动硬件。可基于此,在基础设施层面,解决掉这些问题,从而让业务专注于业务本身。比如,服务网格以边车的形式,几乎业务无感知地解决了网络问题(服务注册/发现、熔断、隔离等)。
无服务时代
无服务架构(Serverless)
如果说微服务架构是分布式系统这条路的极致,那无服务架构,也许就是“不分布式”的云端系统这条路的起点。
Serverless = BaaS + FaaS
- BaaS: 后端即服务,指 DB、MQ、日志、存储、网关等用于支撑业务逻辑运行,但本身无业务含义的技术组件。
- FaaS: 函数即服务,指业务逻辑代码。函数的概念和粒度接近程序编码中的函数,主要区别是无服务中的函数运行在云端,无需考虑算力问题和容量规划。
无服务让开发者需要关注的东西更少了。
- 微服务:需关注弹性伸缩策略、服务间通信、架构、日志、告警等;
- 无服务:无需关注运行时。函数间是平等关系。
(当前)无服务适合场景:短链接、无状态、适合事件驱动的交互形式,比如 Web 网站、定时任务、小程序/App 后台等。
不适合逻辑复杂、依赖服务端状态、响应速度要求较高、长链接等应用,比如网络游戏、直播等。
小结
软件开发的未来,多种架构风格将会融合互补。
We can only see a short distance ahead, but we can see plenty there that needs to be done.
尽管目光所及之处,只是不远的前方,即使如此,依然可以看到那里有许多值得去完成的工作在等待我们。
架构师的视角
访问远程服务
远程服务调用(Remote Procedure Call,RPC)
为了让计算机能够跟调用本地方法一样去调用远程方法
远程服务调用是指位于互不重合的内存地址空间中的两个程序,在语言层面上,以同步的方式使用带宽有限的信道来传输程序控制信息。
三个基本问题:如何表示数据、如何传递数据、如何确定方法
REST 设计风格
面向资源
事务处理
- 原子性(Atomic):在同一项业务处理过程中,事务保证了对多个数据的修改,要么同时成功,要么同时被撤销。
- 隔离性(Isolation):在不同的业务处理过程中,事务保证了各自业务正在读、写的数据互相独立,不会彼此影响。
- 持久性(Durability):事务应当保证所有成功被提交的数据修改都能够正确地被持久化,不丢失数据。
- 一致性(Consistency):保证系统中所有的数据都是符合期望的,且相互关联的数据之间不会产生矛盾。
A、I、D 是手段,C 是目的
“单个服务使用单个数据源”、“单个服务使用多个数据源”、“多个服务使用单个数据源”以及“多个服务使用多个数据源”
ACID 的事务称为“刚性事务”
BASE的事务称为“柔性事务”
BASE :基本可用性(Basically Available)、柔性事务(Soft State)和最终一致性(Eventually Consistent)
透明多级分流系统
指导原则:
- 第一条原则是尽可能减少单点部件,如果某些单点是无可避免的,则应尽最大限度减少到达单点部件的流量。
- 另一条更关键的原则是奥卡姆剃刀原则。能满足需求的前提下,最简单的系统就是最好的系统。
做法:
- 客户端缓存
- 域名解析
- 传输链路
- 内容方法网络
- 负载均衡
- 服务端缓存
缓存并非多多益善,它有收益,也有风险。
分布式的基石
共识算法
Paxos
Paxos 是由Leslie Lamport(就是大名鼎鼎的LaTeX中的“La”)提出的一种基于消息传递的协商共识算法,现已是当今分布式系统最重要的理论基础,几乎就是“共识”二字的代名词。
前提:假设信息可能丢失也可能延迟,但不会被错误传递。
Basic Paxos
Basic Paxos 算法将分布式系统中的节点分为三类:
- 提案节点:称为 Proposer,提出对某个值进行设置操作的节点,设置值这个行为就被称之为提案(Proposal),值一旦设置成功,就是不会丢失也不可变的。请注意,Paxos 是典型的基于操作转移模型而非状态转移模型来设计的算法,这里的“设置值”不要类比成程序中变量赋值操作,应该类比成日志记录操作,在后面介绍的 Raft 算法中就直接把“提案”叫作“日志”了。
- 决策节点:称为 Acceptor,是应答提案的节点,决定该提案是否可被投票、是否可被接受。提案一旦得到过半数决策节点的接受,即称该提案被批准(Accept),提案被批准即意味着该值不能再被更改,也不会丢失,且最终所有节点都会接受该它。
- 记录节点:被称为 Learner,不参与提案,也不参与决策,只是单纯地从提案、决策节点中学习已经达成共识的提案,譬如少数派节点从网络分区中恢复时,将会进入这种状态。
Basic Paxos 的活锁问题,两个提案节点互不相让地争相提出自己的提案,抢占同一个值的修改权限,导致整个系统在持续性地“反复横跳”,外部看起来就像被锁住了一样。
Multi Paxos
新增了选主过程,一个时刻最多一个主提案节点。
这种把共识问题分解为“Leader Election”、“Entity Replication”和“Safety”三个问题来思考、解决的解题思路,即“Raft 算法”,《一种可以让人理解的共识算法》
ZAB 算法与 Raft 算法都被认为是 Multi Paxos 的等价派生实现。
Gossip
Gossip 把网络上所有节点都视为平等而普通的一员,没有任何中心化节点或者主节点的概念,这些特点使得 Gossip 具有极强的鲁棒性,而且非常适合在公众互联网中应用。
达到一致性耗费的时间与网络传播中消息冗余量这两个缺点存在一定对立,如果要改善其中一个,就会恶化另外一个。
Gossip 设计了两种可能的消息传播模式:反熵(Anti-Entropy)和传谣(Rumor-Mongering)
反熵:会同步节点的全部数据,以消除各节点之间的差异,目标是整个网络各节点完全的一致。一致性好,网络开销大。
传谣:以传播消息为目标,仅仅发送新到达节点的数据,即只对外发送变更信息。一致性差,网络开销小。
优势:
- 可扩展性(Scalable)
- 容错(Fault-tolerance)
- 健壮性(Robust)
- 最终一致性(Convergent consistency)
节点间的交互方式主要有三种:Push、Pull 以及 Push&Pull。
不可变基础设施
容器:以封装应用为中心,一个容器封装一个单进程应用
容器编排:通过集群的形式对外提供服务
docker、k8s
以容器构建系统
隔离与协作
k8s计算资源图:
- 容器(Container):延续了自 Docker 以来一个容器封装一个应用进程的理念,是镜像管理的最小单位。
- 生产任务(Pod):补充了容器化后缺失的与进程组对应的“容器组”的概念,Pod 中容器共享 UTS、IPC、网络等名称空间,是资源调度的最小单位。
- 节点(Node):对应于集群中的单台机器,这里的机器即可以是生产环境中的物理机,也可以是云计算环境中的虚拟节点,节点是处理器和内存等资源的资源池,是硬件单元的最小单位。
- 集群(Cluster):对应于整个集群,Kubernetes 提倡理念是面向集群来管理应用。当你要部署应用的时候,只需要通过声明式 API 将你的意图写成一份元数据(Manifests),将它提交给集群即可,而无需关心它具体分配到哪个节点(尽管通过标签选择器完全可以控制它分配到哪个节点,但一般不需要这样做)、如何实现 Pod 间通信、如何保证韧性与弹性,等等,所以集群是处理元数据的最小单位。
- 集群联邦(Federation):对应于多个集群,通过联邦可以统一管理多个 Kubernetes 集群,联邦的一种常见应用是支持跨可用区域多活、跨地域容灾的需求。
韧性与弹性
- Pod 出现故障时,能够自动恢复,不中断服务;
- Pod 更新程序时,能够滚动更新,不中断服务;
- Pod 遇到压力时,能够水平扩展,不中断服务;
资源与控制器是贯穿整个 Kubernetes 的两大设计理念。
容器间网络
持久化存储
K8S的存储设计
Mount 和 Volume
Mount 是动词,表示将某个外部存储挂载到系统中,Volume 是名词,表示物理存储的逻辑抽象
Mount :
- Bind Mount。把宿主机的某个目录(或文件)挂载到容器的指定目录(或文件)下。
- Volume Mount。挂载卷。
从 Bind Mount 到 Volume Mount,实质是容器发展过程中对存储抽象能力提升的外在表现。
静态存储分配
静态存储分配(Static Provisioning)
持久化的 Volume 和非持久化的普通 Volume 两类。
普通 Volume 的设计目标不是为了持久地保存数据,而是为同一个 Pod 中多个容器提供可共享的存储资源,因此 Volume 具有十分明确的生命周期——与挂载它的 Pod 相同的生命周期。
持久化的 Volume 是指能够将数据进行持久化存储的一种资源对象,它可以独立于 Pod 存在,生命周期与 Pod 无关。
PersistentVolume 是由管理员负责提供的集群存储。
PersistentVolumeClaim 是由用户负责提供的存储请求。
动态存储分配
动态存储分配(Dynamic Provisioning)
容器插件
块存储:AWS EBS
文件存储:AWS EFS
对象存储:AWS S3
资源与调度
服务网格
服务网格(Service Mesh)
服务网格是一种用于管控服务间通信的的基础设施,职责是为现代云原生应用支持网络请求在复杂的拓扑环境中可靠地传递。在实践中,服务网格通常会以轻量化网络代理的形式来体现,这些代理与应用程序代码会部署在一起,对应用程序来说,它完全不会感知到代理的存在。
《What's A Service Mesh? And Why Do I Need One?》2016 年 William Morgan
分布式服务的通信演化阶段:
第一阶段:将通信的非功能性需求视作业务需求的一部分,通信的可靠性由程序员来保障。
第二阶段:将代码中的通信功能抽离重构成公共组件库,通信的可靠性由专业的平台程序员来保障。
第三阶段:将负责通信的公共组件库分离到进程之外,程序间通过网络代理来交互,通信的可靠性由专门的网络代理提供商来保障。
第四阶段:将网络代理以边车的形式注入到应用容器,自动劫持应用的网络流量,通信的可靠性由专门的通信基础设施来保障。
第五阶段:将边车代理统一管控起来实现安全、可控、可观测的通信,将数据平面与控制平面分离开来,实现通用、透明的通信,这项工作就由专门的服务网格框架来保障。
服务网格使用数据平面(Data Plane)通信和控制平面(Control Plane)通信来形容这两类流量。
在工业界,数据平面已有 Linkerd、Nginx、Envoy 等产品,控制平面也有 Istio、Open Service Mesh、Consul 等产品。
数据平面
由一系列边车代理所构成,核心职责是转发应用的入站(Inbound)和出站(Outbound)数据包。
三个关键问题:
- 代理注入:边车代理是如何注入到应用程序中的?
- 流量劫持:边车代理是如何劫持应用程序的通信流量的?
- 可靠通信:边车代理是如何保证应用程序的通信可靠性的?
控制平面
Istio 数据平面交互 流量控制 通信安全 可观测性
标签:容器,服务,通信,笔记,架构,Pod,节点,凤凰 From: https://www.cnblogs.com/txtp/p/16745646.html