《从零开始学架构》读书笔记(下)
Posted 松松哥、
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了《从零开始学架构》读书笔记(下)相关的知识,希望对你有一定的参考价值。
《从零开始学架构》读书笔记(下)
书接上文
思维导图
高可用架构模式
高可用的理论
CAP
在一个分布式系统(指互相连接并共享数据的节点的集合)中,当涉及到读写操作时,只能保证
一致性(Consistence)
、可用性(Availability)
、分区容错性(Partition Tolerance)
三者中的两个,另外一个必须被牺牲
一致性
对某个指定的客户端来说,读操作保证能够返回最新的写操作数据
可用性
非故障的节点在合理的时间内返回合理的响应(不是错误和超时的响应)
分区容忍性
当出现网络分区(发生丢包、连接中断、拥塞等)后,系统能够继续按预期工作
CAP为什么只能选两个
首先,你肯定是要选P分区容忍性
的,因为网络本身是无法100%可靠的,所以分区是必然的,你也不想网络一点抖动你系统就挂了吧。如果不选分区容忍性
,那么发生分区时,为了保障一致性
,系统要禁止写操作,当发生写操作时返回err,这又和可用性
冲突了,所以理论上你必须选P分区容忍性
。
CP一致性+分区容忍性:前面说了,当发生分区时,为了保障一致性
,要禁止写操作返回err,所以这时候可用性
是不能被满足的,所说CAP只能满足CP。
AP可用性+分区容忍性:为了保障可用性
,发生分区时,底层数据无法同步,必然造成数据的不一致,这时系统还要对外提供服务,所以CAP只能满足AP。
CAP还有一些细节需要注意。
- CAP关注的粒度是数据,而不是整个系统
- CAP是忽略网络延迟的,这就意味着
一致性
是不可能完美实现的 - 正常情况下,可以同时满足CA。分区不存在的时候
可用性
和一致性
是可以同时被满足的 - 分区恢复后,需要为数据的同步做准备
ACID
ACID是数据库管理系统为了保证事务的正确性而提出来的一个理论,包含四个约束:
- 原子性(Atomicity): 一个事务中所有操作,要么全部完成,要么全部不完成,没有中间状态
- 一致性(Consistency): 在事务开始之前和事务结束之后,数据库的完整性没有被破坏
- 隔离性(isolation):允许多个并发事务同时执行
- 持久性(durability): 事务处理结束后,对数据的修改就是永久的,即使系统故障也不会丢失
BASE
BASE是指基本可用(Basically Available)
、软状态(Soft State)
、最终一致性(Eventual Consistency)
。其核心思想是即使无法做到强一致性,但可以采用合适的方式达到最终一致性。现实中很多系统大多都是采用的最终一致性,强一致性常见于金融业务。
- 基本可用:在系统出现故障时,允许损失部分可用性,保证核心业务可用就行,影响范围尽可能小
- 软状态:也就是短时间的数据不一致
- 最终一致性:所有数据副本经过一段时间后,最终能够达到一致的状态
FMEA
FMEA(故障模式与影响分析)又称为失效模式与后果分析等,是一套分析和思考的方法。具体分析方法如下:
- 给出初始的架构设计图
- 假设架构中的某个部件发生故障
- 分析此故障对系统功能造成的影响
- 根据分析结果,判断架构是否需要进行优化
此方法输出的是一份表格,包含功能点、故障模式、故障影响、严重程度、故障原因、故障概率、风险程度、已有措施、解决措施和后续规划。总结来说就是一份分析报告,列出系统的薄弱点,并提出改进措施,很可能改进之后又会引入新的薄弱点,所以需要不断更新。除此之外也可以当成一份运维手册来看,当发生故障时看看这份表上有没有相应的补救措施。
存储高可用
存储高可用本质都是将数据复制到多个节点,通过冗余来实现高可用。这类方案都要面对的一个问题是复制延迟和中断导致的数据不一致。任何一个存储高可用方案,都要想清楚以下几点:
- 数据是怎么复制的
- 各个数据节点的职责是什么,是单纯备份还是对外提供服务还是二者兼有
- 如何面对复制延迟
- 如果面对复制中断
主备复制
主机对外提供服务,通过复制通道将数据复制到备机,备机不对外提供服务。发生故障时需要将客户端的请求转到备机上。
缺点是如果主机永久挂了,对于复制延迟和中断造成的数据缺失没啥好的解决方案。由于备机不提供服务,平时会造成资源浪费。
优点就是比较简单,适用于内部管理系统。
主从复制
跟主备复制类似,但是备机是可以对外提供读服务的。
优点就是机器资源得到有效利用,主机挂了,读操作不受影响
缺点就是如果延迟比较高,写完立即读可能读到旧数据。也比较复杂,需要将不同的操作发给不同的机器
适应于论坛新闻类的业务,读多写少,影响范围可以控制
主备倒换和主从倒换
无论是上面哪种模式,发生故障时都要进行角色的转换。需要有状态的判断机制和倒换策略。例如:
- 状态是怎么传递的
- 传递的内容是什么?是心跳?还是包含了当前负载状态?
- 什么时候进行转换?没心跳转换?还是延迟高就转换?
- 转换手段是什么?人工or自动?
- 故障节点恢复后,数据冲突怎么解决?永远不恢复,缺失的数据怎么办?
根据状态传递渠道的不同,常见的主备倒换架构有三种形式:
- 互连式:主备互联。这里操作空间很大,怎么连?单向还是双向?万一通道本身出问题,那备机可就自己决定变成主机了
- 中介式:主备机分别向中介机发生信息,中介来决定角色。这种模式要简单很多,但是也要注意中介本身挂了的情况
- 模拟式:备机假装成客户端,向主机发请求,请求异常自己升级为主机。实现比互连简单,但是仅依靠响应信息决策还是有点草率
数据集群
当一台节点存储不下全部数据时,上面的两种方案就用不了了,就要上数据集群了,把数据分散到各个节点上。此方案的复杂点在于如何将数据分配到不同的服务器上,设计时需要考虑以下几点:
- 均衡性:各个节点的数据大小是均衡的
- 容错性:部分节点故障时,需要将原来分配给故障节点的数据分区分配给其他节点
- 可伸缩性:需要扩容时,能够自动迁移数据
既然数据分散到各个节点,那避免不了的问题就是分布式事务
。目前分布式事务算法非常多,但再多的算法也不能彻底解决问题,极端情况下还得看人工。目前常用的分布式事务算法有:
- 2PC: 二阶段提交。分为请求阶段和提交阶段。缺点比较明显,存在同步阻塞、状态不一致和单点故障问题
- 3PC: 三节点提交。分为提交判断、准备提交和提交执行三个阶段。解决了单点故障导致的系统阻塞问题,但还是没解决数据不一致问题。
- 消息表:把各个节点的执行情况记录到一张表里,协调者挂了之后新的协调者根据表信息再决定怎么操作,比较复杂。
数据分区
数据分区是指将数据按照一定的规则进行分区,不同分区分布到不同的地理位置上,每个分区存储一部分数据,通过这种方式来规避地理级别的故障。分区规则有很多,你可以选城市分区、国家分区、洲际分区等,一般看业务量决定。同时,即使是数据分区,也要考虑分区数据的备份,万一真发生地理级别的故障,还是要尽可能将数据恢复。一般有以下几种备份规则:
- 集中式:所有分区备份到一个总的数据中心。简单是简单,但是总的数据中心一旦挂掉,也挺头疼。
- 互备式:各个数据分区互相备份。稳定性大大上升,但是拓展性很差,后续增加一个新分区,是放到哪里备份呢?
- 独立式:各个数据分区有自己的数据中心。终极解决方式,但是成本非常高。
计算高可用
计算高可用的主要目的是当部分节点故障时,服务依然能正常对外提供服务。因此和存储高可用的思路是一致的,就是通过冗余来规避风险。这里复杂度主要体现在任务管理方便,即怎么分发任务
和任务执行失败后怎么处理
的问题。架构一般由任务分配器
+计算节点
组成。
常见的计算高可用架构:
- 主备:备机平时不干活,主机故障时开始干活。简单但是故障时需要人工操作,也浪费一定的资源
- 主从:备机平时也干活。缺点是任务分配器会复杂一些
- 对称集群:目前最常见的负载均衡集群方案。各个计算节点没有角色区别,通过分配器均衡任务。
- 非对称集群:计算节点区分角色,不同角色执行不同任务,比较少见。
业务高可用
业务高可用主要实现方式就是异地多活,异地多活又分同城异区
、跨城异地
、跨国异地
,具体采用哪种方案需要根据业务量级以及业务重要程度来选择。另外,核心业务内部也分核心数据和非核心数据,所以在选择方案是也可以根据数据重要程度进行进一步划分。
在发生业务故障时,要使用日志记录并做好用户的补偿,降低影响范围和舆论影响程度。
另外针对接口级别的故障,平时发生的概率比较高,我们一般有以下几种应对方案
- 降级:将某些业务或接口的功能降低,指提供部分功能或完全不提供功能。例如APP的页面数据,可以只提供核心模块的数据。
- 熔断:一般是指依赖的下游故障。熔断需要有应对方案,例如熔断后返回缓存数据等等
- 限流:限流是从用户访问压力的角度来应对。在上线服务时,要设置请求的阈值,超过这个阈值的请求可以被丢弃,避免机器负载过高影响所有用户
可拓展架构
可拓展架构的主要价值在于后续改动时,能尽量降低开发成本,降低改动范围。一般来说,设计方法有很多,但核心思想就是拆分
,怎么拆各有各的说法,你可以面向流程拆分
,也可以面向服务拆分
,也可以面向功能拆分
。
分层架构
这是非常常见的架构模式,例如C/S架构、B/S架构、MVC架构等等。平常设计时也会习惯性进行分层,进行逻辑的划分,降低整体的复杂度。划分的原则也很简单,就是要保证各层之间的差异足够清晰,边界足够明显,可读性高
。
但有个缺点就是可能会发生冗余,有时候你只需要调用最底层的一个接口就好,但是为了维持这个分层架构,不得不层次传递,如果各层之间是网络连接,那网络耗时将会大大增加。
SOA架构
SOA是面向服务的架构,现在在传统大企业里面可能比较容易见到。提出的背景是企业内部的IT系统重复建设且效率低下。例如企业里面有很多独立的系统,财务系统、销售系统、HR系统等等,这些系统都需要进行员工的权限管理,也许都要重复开发该能力。
SOA主要有三个概念:
- 服务:所有业务功能都是一项服务,服务需要对外提供能力,其他系统需要这些能力时,无需重复开发
- ESB:因为各个服务之间是异构的,所以需要ESB来屏蔽各个系统对外提供各种不同的接口方式
- 松耦合:目的是减少各个服务间的依赖和互相影响
SOA的瓶颈就在ESB上,因为所有服务都要通过它来进行通信。
微服务
微服务是大家耳熟能详的老伙计了,在国内的互联网公司,稍微大一点的业务都会采用微服务架构。微服务很容易和SOA混淆,主要区别在于服务粒度不同(SOA粒度比较粗)
、服务通信(SOA使用ESB通信,兼容不同协议,微服务的通信协议是一致的,简单很多)
、服务交付(微服务的交付成本先易后难,微服务越多,越需要更强的管理手段)
、应用场景(SOA适用于改动成本高的企业级系统,微服务适用于快速迭代的互联网系统)
。
采用微服务架构,开发基建一定要跟上,因为随着微服务越来越多,怎么做服务发现,怎么做服务路由,怎么自动部署,怎么排查问题就是实实在在要面对的问题。
那么,微服务要怎么拆分呢,基于什么原则进行拆分?
首先有一个“三个火枪手原则”:
三个火枪手原则:一个微服务三个人负责开发
具体的拆分方法有,可以根据自己的业务特点进行选择:
- 基于业务逻辑拆分
- 基于可拓展性拆分
- 基于可靠性拆分
- 基于性能拆分
关于微服务有很多其他经典的书籍可以学习,后续可以展开写写。
微内核
就是插件式架构,关键技术有:插件管理
、插件连接
和插件通信
。
应用场景有很多,例如促销规则生成系统,内核就是一个计算逻辑,但是很多商品种类可以封装成插件,新增规则时开发成很低。
互联网架构模板
一张图就可以说明了,内容深度不大。
架构的重构
前面我们介绍架构设计原则的时候,有一条原则就是“演化原则”。
演化优于一步到位
现在就是演化的时候了。在演化时,我们要注意:
- 识别当前的主要矛盾
- 换位思考推送项目,你得让对方有利可图,才会配合你演化
- 分阶段演化
读后感
读完收益良多,以前总是觉得架构挺神秘的,奈何没有一个系统的教程入门,网上资料汗牛充栋,根本无从下手,进行系统设计时脑子都是空白的,没有头绪。这本书介绍的挺全面的,很适合扫盲用,适合那些刚接触架构设计的开发人员。
后续可以在这里练练手:系统设计题
从零开始学架构-day04
不得不说我是三天打渔两天晒网,烂泥巴糊不上墙。
烂泥巴开始打渔。
上节跟着大佬学习了,架构的复杂度来源,现在回顾下,确实想不起来了。重新开一遍。
回顾
影响架构复杂度的几大因素,追求高性能,高可用,高拓展既然已经知道了复杂度的来源于这些方面,那我们有什么原则可以直接将这些复杂度化难为简呢? 那这这节课,我们就看下架构的三大原则:合适原则,简单原则,演化原则。
架构的三大原则
合适原则
- 合适原则,合适的意思就是合适呗,选择一个中间件,或者一些框架,或者物理机等,都得合适我们所要设计的系统。
- 还有就是合适原则的宣言是:“合适优于业界领先。”,就针对这个宣言,我在工作中也有遇到过,有些架构师为了追求新的技术而耗费大量的资源去达到只是起了替换作用的工作。我说一个我自己遇到的真是例子:公司一直用的0是关系性数据库mysql,现在公司上了一个新的项目,然后有个新来的团队leader他说选用mongDB来做存储,当时由于公司之前没有使用过,运维团队的维护能力也算是跟不上。最终结果是折腾了一会然后最后还是使用了mysql解决了。这里的没有选择mongDB也就是合适原则了,虽然mongDB有很多优势,且相对来说能符合一些项目需求。但是运维能力跟不上这也是问题的。
- 还有的就是大佬所讲的盲目跟风,我现在就是有这样的情节,一方面为了证明自己走在技术最前沿(装逼呗),一方面是自己学了,赶紧用公司的项目实践一下(真TM的自私,说的就是我)。这都是自己之前不成熟的想法,如果我的领导看到我的文章,如果我下次要新的技术栈我会给你充分的理由的,毕竟我们都是专业的开发人员。
- 之前的微服务就很火吗?但是有多少公司真正的微服务落地成功,这里的成功不是拆成功,而是真正的达到最终的目的,降低成本,提高服务的稳定性和复杂度等等了吗? 现在阿里又要拆中台,不搞了。难道大家又要学阿里合并起来吗?
- 合适是重中之重。不合适的人最终都会分手的。
简单原则
简单原则宣言:“简单优于复杂”。
- 我靠,我的第一反应这不就废话吗?简单优于复杂。是的我的思维方式有点问题,这里的复杂的意思是为了使架构变得精美,无懈可击让架构变得很复杂的意思,其实我个人理解他就是我们所说的:“过度设计”。
- “复杂”在制造领域代表先进,在建筑领域代表领先,但在软件领域,却恰恰相反,代表的是“问题”。
- 软件领域的复杂性体现在两个方面:
-
结构复杂:
- 组成复杂系统的组件数量更多;
- 同时这些组件之间的关系也更加复杂。
-
看看下面的物理架构图够复杂吧,其实再我们很多系统都没有必要这么全,下面的物理架构图也算是现在的主流设计了吧。相当全。但是我们的系统需要这么全吗???
-
我们再来看看如果这么复杂了会出哪些问题呢?
- 组件越多,就越有可能其中某个组件出现故障 必然事件
- 某个组件改动,会影响关联的所有组件,不需要缓存,你加了缓存,改了缓存那肯定影响系统的一致性问题
- 定位一个复杂系统中的问题总是比简单系统更加困难。有了缓存,到底是数据库没有没出海㷣事缓存没有刷新呢?
-
- 简单这件事情 不管是在架构设计,还是在我们写代码的时候都有用到,比如设计模式中的kiss原则,不是打kiss的kiss,是keep Simple yourself 或者 Keep It Simple, Stupid!的意思保证简单单一。生活中我们也应该这样。不然会让我们很累
演化原则
演化原则宣言:“演化优于一步到位”。
- 之前一个老师傅讲的一句话: “我们先简单开发(不过度设计),后面结构什么慢慢迭代重构优化”,这是我在上家公司最后一个项目的架构师说的。这也许就本着演化原则来的,希望我没有充分解读。哈哈哈
- 不高深的讲世间万物都是一步一步演化而来的,没有什么是一生下来就是完美的。生物的进化等等等,所以软件架构设计其实更加类似于大自然“设计”一个生物,通过演化让生物适应环境,逐步变得更加强大:
- 软件架构设计同样是类似的过程:
- 首先,设计出来的架构要满足当时的业务需要。这是必然不然会被产品经理“砍死”!
- 其次,架构要不断地在实际应用过程中迭代,保留优秀的设计,修复有缺陷的设计,改正错误的设计,去掉无用的设计,使得架构逐渐完善。这也是重构的作用之一,重构也是迭代开发中很重要的一步。
- 第三,当业务发生变化时,架构要扩展、重构,甚至重写;代码也许会重写,但有价值的经验、教训、逻辑、设计等(类似生物体内的基因)却可以在新架构中延续。
总结
- 主要聊了架构的三大原则:
- 合适原则
- 简单原则
- 演化原则
- 这也是我们生活的原则,选择合适的,做事简单点,不要着急,一步一步的脚踏实地前进。
以上是关于《从零开始学架构》读书笔记(下)的主要内容,如果未能解决你的问题,请参考以下文章