这是我参与「第五届青训营 」伴学笔记创作活动的第 6 天
Day6
1. 什么是架构
计算机整体结构 与 组件 的抽象
好的架构具有弹性,资源利用率高,维护起来也很方便。
而差的架构就会导致代码的屎山,维护起来也很麻烦。
1.1 单机架构
单机架构有越来越庞大的趋势,因为业务逻辑一般都会增加,而不是删减。
1.2 单体架构/垂直架构
- 垂直切分:把整个业务按照业务逻辑切分
单体架构:引入了负载均衡器(大堂经理),但不同的组件仍然是全栈化的(一个蛋糕师傅需要同时做多种蛋糕):缺点 ==> 爆炸半径大,如果一个师傅的一个步骤出了问题,那么这个师傅所有的蛋糕都做不了。同时,用户对不同种类的蛋糕(不同种类的服务)有不同需求,如果让后台兼顾所有业务逻辑,无法进行定制化和权重负载。
- 垂直应用架构:仍然是基于负载均衡器,但是全栈业务进行了垂直切分,切分为了更细粒度的服务。具体到一个特定的输出。 缺点:这样切分后的业务仍兼顾很多职责。面包师需要 进购原料,发面,制作,烘焙,将蛋糕交给大堂经理售卖。实际上,面包师应当专注于自己的业务逻辑:制作。至于其他的职责,交给其他人来干即可。
软件的迭代过程,就是 不断的迭代,导致单体越来越大,最后再对单体进行切分,切分为垂直应用,乃至微服务
1.3 SOA/微服务架构
服务:可以对外暴露的功能单元。比如上文中的发面,烘焙,进购原料,都可以视为一个服务。这是将业务逻辑的进一步细化。
中心化:在SOA架构中,不同的服务组件需要依赖一套通信标准:ESB,ESB就是服务组件的注册和发现中心,但是ESB是中心化的,也就是所有服务,只要想互通, 必须经过ESB,ESB管理所有服务组件的沟通:有点类似拨号电话时代的电话连线员。那时候的电话线不存在直连,想通信必须经过连线员。
去中心化:每个服务都是老大,可以通过rpc手段,和任意的微服务建立通信
水平切分:在不改变业务逻辑的情况下,添加主机数量。水平切分可以通过增加主机数量,减少单个主机的负载,因为在单个主机进行硬件资源的扩容是很难再进一步的。
挑战:
- 数据一致性:数据一致性基于水平切分,任何东西都有两面性,既然进行了水平切分,那么如何保证水平切分后各服务数据一致?
- 高可用/治理:SOA/微服务的架构,引入了 链路调用成本,这意味着,一旦一个步骤出错,整条链路将阻塞。如何规划链路?如果出错了如何处理?
- 解耦:每个服务都占据一个主机,每个服务都有自己的依赖环境和调用链。不仅要准备好依赖环境,要想测试,整条链路的环境都要准备好。运维:听我说谢谢你
2. 企业级后端架构
蛋糕店面临的问题(如何进行架构?)
云计算的四个概念:Iaas,PaaS,SaaS,FaaS
2.1 云计算
这里的计算不是动词,而是名词,代表计算资源,这里的云则是形容词,代表"云上的" 。计算资源包括哪些,在后面会进行讨论。那么云计算的含义就是 将计算资源上云,没有能力搭建大型workstation或者机房的用户也可以轻易获得计算资源
IaaS我们购买的阿里云服务器就是IaaS。为什么我们没有主机,就可以获取硬件的基础设施?多亏了虚拟化技术和隔离技术,使得云开发商,可以把他们的硬件资源的一部分隔离出来,给我们。为什么要把硬件资源拱手让人? 现在硬件资源发展太快,导致硬件资源使用率比较低,如果不给别人,无法挖掘最大效益(资本家压榨工人) 。简单理解,IaaS就是让我们直接具有了一台物理意义上的机器,有cpu,有内存,有网卡。而这台计算机是云上的。那么,如果不使用IaaS,我们想拥有一个计算机,就需要自己搭机房,数据中心了。类似我们的面包店老板是买一个面包店,还是租一个。
PaaS光有了硬件资源,没有操作系统还是白扯,硬件资源好像毛坯房,而硬件资源+操作系统才是住房。如果使用PaaS,我们将直接获得可以运行软件的一套设施。类似我们的vmvare实际上就是一个paas。而如果不使用PaaS,我们需要自己安装系统。
SaaS就太熟悉了,我们用的app就是SaaS,使用SaaS,我们直接使用别人设计好的软件进行开发。比如短信验证码服务,第三方接口,或者第三方库,应该都是SaaS的范畴。(我们这一方叫调库侠,而所谓的调库侠,正是享受到了SaaS)
FaaS这个概念有些模糊,不知道我们使用的各种框架算不算FaaS。因为框架和调库的最大区别是,框架需要进行一定的开发。进一步的leetcode等oj平台,实际上就提供了FaaS
2.2 云原生
云原生,全称云原生计算。顾名思义,这是云计算经过一定时间发展后的一个产物。
云原生的特点还是集中在 云以及 计算资源上。而原生则指的是对这些计算资源的进一步管理。
2.2.1 弹性计算资源
云原生应当提供弹性资源服务。
也就是说:把计算资源以云的形式,提供给用户,这类似上面说到的
SaaS。这也是现在的一种趋势,之前是给你一个平台,你自己去开发,但是有些小公司没有开发成本,只能租别人的,所以云服务商干脆提供 现成服务给你使用,你交钱就行。当然,计算资源的表现为高性能的cpu,甚至是gpu服务器,这类的计算资源一般可能提供给机器学习,或者作为超算等使用。当然需要氪金就多一些了。
2.2.2 弹性存储资源
同样,云平台可以提供高性能存储服务
以华为云平台为例,使用OBS服务,可以免去了配置数据中心以及数据库的步骤,直接对数据进行CRUD
还可以是非结构化的数据,比如大数据下的用户消费记录,这样的记录用mysql存储显然是不适合的。但是OBS的出现,使得我们不用关注究竟应该用啥来存储,反正用人家现成的就行。。还有诸如元数据,这类map结构,数据小而精,也有自己的存储结构。以及nosql。
如果手搭这么多东西,不仅麻烦人力物力,一旦配置不当,还有被脱库的风险。安全永远是最容易被忽视的,而用云平台的服务可以尽量避免这些情况。
2.2.3 devops
前面用了好多云平台的资源,那么问题也随之而来
如何管理这些资源?
如果是采取传统运维,那么将造成运维黑洞。一个单体上线有时候都麻烦不断,更何况成百上千的微服务上线?而测试又怎么进行?起码要保证调用链路全上线才行!
因此devops的出现,解决了这些问题。devops主要突出一个自动化,自动集成,自动部署。中途自动化的运行测试案例。devops不仅是一个解决方案,更贯彻整个开发流程。这也需要架构师在设计阶段进行细腻的考虑。
2.2.4 微服务架构
HTTP:好处
- 可以对外提供端点(无论是pc端,还是客户端都可以使用,手机电脑均可用,数据一般采取json,具有易读性和可理解性)。这些端点主要提供给用户调用(总不能每次用户想获取一个服务,都得手动建立一个tcp请求,那浏览器是干啥的)
- 缺点:采取http协议,数据包比较大,消费额外的网络开销。
rpc:好处
- 性能自然是响当当的,基于tcp,不需要那些额外的http报文头,而且使用rpc数据一般都是二进制的,不是json的,二进制可以进一步减少网络io。
- 很多rpc框架具有完备的服务治理功能:超时咋办?网络断了咋办?
缺点
- 一般数据采取二进制,可理解性差(对于开发人员,都不知道传了个啥,想debug还得反序列化一下)
所以一般的设计就是,最外层负载均衡器对外提供http端点,然后将请求路由到网关。在网关以及各微服务之间,通过rpc通信。
至于rpc或者http通信的底层实现,借助框架即可。这不是我们开发人员考虑的。
2.2.5 服务网格(mesh)
在服务网格下,不同的容器不直接通过rpc通信,而是进一步的引入了service Mesh。那么不同的组件,如何知道通信对象呢?服务网格的控制层,提供了服务发现机制,这个控制层通过服务发现,可以控制不同容器的数据面互通。
在这里,我们似乎看到了中心化的服务发现中心和配置中心,这和作为中间件的服务发现中心有什么区别呢
在微服务设计中,服务发现器实际上也是一个微服务,这意味着,他是去中心化的。也就是微服务之间直接通信,不经过一个manager。那么中心化又有什么好处呢?中心化的服务发现器,不仅可以进行服务发现,还可以收集不同容器的运行情况,进行动态权重调整。在后面会叙述这个特性。
3. 企业级后端架构的挑战
- 利用率无法占满:导致有一部分计算资源空闲。看起来无可厚非,但是,在云原生环境下,几乎每个服务都占有一定计算资源,而一旦利用率占不满,用这个空闲率去乘云原生主机,整体硬件空闲将是一个很大数字。而物理资源又是有限的,我们不能无限制的建立主机,搭机房,所以只能提高利用率
- 利用率无法预测:量化利用率是很难的问题,故没有很好的方法来提高利用率
3.1 离在线资源并池
这里主要应用到了一个量化指标:离在线业务的特点。
在线业务必须要对数据进行持久化,所以是IO密集的,而且需要立即返回结果,是实时性的。
离线业务通常就是对持久化的数据进行数据分析,进行推荐系统算法运行,而且不需要立即把结果返回给用户。可能用户刷了一天抖音,才把主页养成自己的xp。这就是离线数据分析系统经过计算后,隔了好久才返回结果。
因此基于潮汐的特点,就可以对离在线资源进行并池。
如何隔离资源?
离在线资源通常都是xx线程,可以通过
cgroup的方式,隔离线程对硬件的使用。
3.2 自动扩缩容
有了解决办法,我们总不能手动进行cgroup隔离吧?
所以需要自动化的进行扩缩容。
那么一定需要一个指标来扩缩容。最显著的指标就是:cpu利用率,内存利用率。如果cpu利用率较高,我们可以扩大离线资源池,减少在线资源池。
难点:如何量化io指标。我们知道,io越高表示在线资源越多。但是如果我们用QPS来描述,那么得到的结果是不具备信服力的。所以当前业界也在对如何量化io指标进行探讨。
能量化 ==> 能建立模型 ==> 能用数学表达式解决 ==> 能编程实现。
3.3 亲和性部署
我们知道,rpc是需要网络开销的,如果服务A依赖服务B,而且是强亲和性的依赖。比如我们确定了B服务几乎每次都会调用到A1主机上的A服务,我们就可以把A1和B部署在同一台主机:可以通过进程间通信(IPC)框架,来避免网络io。进程间通信就要看ipc的实现了,大体上就是通过共享内存通信。要是通过本地套接字也无所谓,反正不走网卡。
3.4 流量治理
提高可用性,如果调用链路中的一个服务崩了,我们不能让整个链路都崩了。
3.5 cpu水位负载均衡
我们之前提到的,中心化的服务发现器优势来了
如果是中间件的服务发现器,比如nacos,eureka这种,只能提供静态的权重。
比如宿主机B是一个老牌的CPU,而B1则是最新的intel core i9,那我们就需要给B1多一点权重。但是如果是中间件,只能手动并静态配置。而使用中心化的服务发现器,可以通过拉取宿主机CPU的指标,进行流量调度:有能力的多干,没能力的少干。
4. 后端架构实战:蛋糕店
还是水位负载均衡,即根据CPU能力进行负载均衡。
4.1 问题提炼
我们要设计一个能够进行CPU水位负载均衡的架构。
流量调度器需要获取各微服务的CPU信息(型号,cpu利用率,几个核,外频多少,倍频多少等等等)。
那么浏览器调度器进行分析,就会对不同的水平架构微服务进行权重均衡。。
4.1 自适应静态权重
只需要让微服务自己把微服务信息发送给注册中心即可。
- 如果流量超标,还要多劳多得吗? ==> 紧急回滚:如果流量多了,就别多劳多得,小心忙不过来。发生这种情况,应该可以及时调整权重,以达到自适应。
4.2 自适应系统alpha
这种方式,类似操作系统的权重调度(nice值)。一个静态 + 动态值。
这样,决策中心决策的是 根据cpu值的动态权重
- 如果调度器发现流量异常,将采取静态权重,舍弃动态权重
- 决策中心可以通过配置中心获取 哪些服务采取cpu水位负载均衡。
缺点
- 决策中心只管你能力如何,不管你请求如何。比如QPS=1000,权重也是9:1,QPS=10000000(双十一),权重也是9:1,那么必然会导致直接崩盘了。因此进一步的优化点就是,让决策中心可以判断机器的实时负载
4.3 自适应系统beta
这个版本比上个版本多了一个上报rpc指标的过程。
这样,决策中心可以及时的看到宿主机的网络io状况。如果发现请求太多,导致了延迟剧增,那么决策中心会进行权重调整。
4.4 自适应系统release(发布版)
这个版本把rpc指标的报表过程进行了服务拆分。
由于每个应用在rpc调用过多时,上传的报表也越来越多,因此需要引入消息队列,避免直接把分析引擎或者时序数据库打崩了。
那么这下决策中心终于可以同时分析cpu性能,和io请求,最后确定出最适合的动态权重了。
我们可以发现:
需求先行会导致组件越来越大,最后变成一个大单体,这时候就不得不进行服务切分。
异常情况也是,会导致组件越开发越大,越迭代越大,然后一切的一切还是微服务。