《从0开始学架构》–笔记

第2篇 架构是什么

系统 泛指由一群有关联的个体组成,根据某种规则运作,能完成个别元件不能单独完成的工作的群体(能力)。

从逻辑的角度拆分系统后,得到的单元就是“模块”,从物理的角度拆分系统后,得到的单元就是“组件”。划分模块的主要目的是职责分离,划分组件的主要目的是单元复用。

框架是组件规范,提供基础功能的产品。软件架构指软件系统的“基础结构”,创造这些基础结构的准则,以及这些结构的描述。框架关注的是“规范”,架构关注的是“结构”。

软件架构指软件系统的顶层结构:
* 架构需要明确系统包含哪些“个体”,个体可以是 子系统、模块、组件等。
* 架构需要明确个体的运作和协作的规则。
* 顶层结构可以更好地区分系统和子系统。

自话:软件架构确定了系统中应该包含哪些个体,以及个体之间应该如何协作,以提供某种能力,从而实现系统的价值。

第2篇 架构设计的历史背景

“模块”“对象”“组件”本质上都是对达到一定规模的软件进行拆分,区别只是在于随着软件的复杂度不断增加,拆分的粒度越来越粗,拆分的层次越来越高。

第3篇 架构设计的目的

架构设计的主要目的是为了解决软件系统复杂度带来的问题。

架构设计首先要分析系统的复杂度所在,然后针对这些复杂度进行设计、制定方案。

第4篇 复杂度来源:高性能

软件系统中高性能带来的复杂度主要体现在两方面,一方面是单台计算机内部为了提高性能带来的复杂度;另一方面是多态计算机集群为了高性能带来的复杂度。

第5篇 复杂度来源:高可用

系统的高可用本质都是通过“冗余”来实现的,方法是增加机器。

高性能增加机器的目的在于“提升”处理性能,高可用增加机器的目的在于“冗余”处理单元。

存储高可用的难点不在于如何备份数据,而在于如何减少或者规避数据不一致对业务造成的影响。

高可用状态决策:无论是计算高可用还是存储高可用,其基础都是“状态决策”,即系统能够判断当前状态是正常还是异常,如果出现异常就要采取行动来保证高可用。

决策方式:
* 独裁式:所有冗余的个体向一个独立的决策主体上报状态信息,决策者进行决策。问题在于决策者本身是个单点。
* 协商式:两个独立的个体通过交流信息,然后根据规则进行决策,最常用的协商式决策就是主备决策。难点在于两者的信息交换出现问题时如何决策。
* 民主式:指多个独立的个体通过投票的方式来进行决策。缺陷是脑裂:原来统一的集群因为连接中断,造成两个独立分隔的子集群,每个子集群单独进行选举,选出两个决策者。解决方法是要求“投票节点数必须超过系统总结点数一半”。

第6篇 复杂度来源:可扩展性

可扩展性是指为了应对将来需求变化而提供的一种扩展能力。

设计具备良好可扩展性的系统,有两个基本条件:正确预测变化、完美封装变化。

预测变化的复杂性在于:不能每个设计点都考虑可扩展性、不能完全不考虑可扩展性、所有的预测都存在出错的可能性。

设计具备良好可扩展性的系统,有两个思考角度:从业务维度,对业务深入理解,对可预计的业务变化进行预测;从技术维度,利用扩展性好的技术,实现对变化的封装。

应对变化的常见方案一是将“变化”封装在一个“变化层”,将不变的部分封装在一个独立的“稳定层”。
方案二是提炼出一个“抽象层”和一个“实现层”,抽象是文档的,实现可根据具体业务需要定制开发,加入新的功能时,只需要增加新的实现,无需修改抽象层。

举例:设计一个支付网关对接不同的支付机构,为业务系统提供支付能力。每家支付机构的通信方式、请求/响应格式都是不一样的,但基本参数都是四要素信息(银行卡号、预留手机号、姓名、身份证号)、扣款金额等,扣款结果一般就是成功/失败/等通知,因此可以抽象出统一的接口,对接不同支付机构的具体实现类实现这个接口、完成具体的调用逻辑,当要对接新的支付机构时只需要添加一个实现类;业务系统只需访问这个统一的接口。

第7篇 复杂度来源:低成本、安全、规模

低成本是架构设计的一个约束条件,不是首要目标,本质上与高性能/高可用冲突。

从技术的角度,安全可以分为两类:功能上的安全,架构上的安全。

功能安全一般与具体的编码相关,是实现的问题。功能安全是一个逐步完善的过程,往往都是在问题出现之后才能针对性的提出解决方案,也无法预测下一个漏洞在哪里。

架构安全是防止暴力破坏,典型的就是防止DDOS攻击。

规模带来复杂度的主要原因是“量变引起质变”,当数量超过一定的阈值后,复杂度会发生质的变化。
常见的规模带来的复杂度有:功能越来越多,导致系统复杂度指数级上升;数据越来越多,系统复杂度发生质变;

第8篇 架构设计三原则

合适原则:合适优于业界领先。真正优秀的架构都是在企业当前人力、条件、业务等各种约束下设计出来的,能够合理地将资源整合在一起并发挥出最大功效,并且能够快速落地。

简单优于复杂。(复杂分结构复杂和逻辑复杂)

对于建筑,永恒是主题;对于软件,变化才是主题。软件架构需要根据业务发展不断变化。

第10篇 架构设计流程1:识别复杂度

深入研究业务需求、通过“排查法”分析复杂度所在。

第11篇 架构设计流程2:设计备选方案

成熟的架构师需要对已经存在的技术非常熟悉,对已经经过验证的架构模式烂熟于心,然后根据对业务的理解,挑选合适的架构模式进行组合,再对组合的方案进行修改和调整。

备选方案:数量3-5个最佳;差异要比较明显;技术不要只局限于已经熟悉的技术;不宜过于详细而忽略整体设计;

第12篇 架构设计流程3:评估和选择备选方案

列出需要关注的质量属性点,分别从这些质量熟悉的维度去评估每个方案,再综合挑选适合当时情况的最优方案。

常见的方案质量熟性有:性能、高可用、成本、复杂度、安全性、可扩展性、可伸缩性等。

第13篇 架构设计流程4:详细方案设计

详细方案设计就是将方案涉及的关键技术细节确定下来。

架构师不但要进行备选方案设计和选型,还需要对备选方案的关键细节有深入的理解。通过分步骤、分阶段、分系统等方式,尽量降低方案复杂度,方案本身的复杂度越高,某个细节推翻整个方案的可能性就越高,适当降低复杂性,可以减少这种风险。如果方案本身很复杂,采取设计团队的方式来进行设计,防止只有1-2个架构师可能出现思维盲点或经验盲区。;

第14/15篇 高性能数据库集群

读写分离

将读压力分散到集群中的多个节点,但没有分散存储压力。主从复制延迟和分配机制会带来复杂度。

解决主从延迟的常见方法:写操作后的读操作发送给数据库主服务器(和业务强绑定,侵入业务代码);读从机失败后再读一次主机(大量二次读会增加主机读压力);关键业务读写操作全部指向主机,非关键业务采用读写分离。

读写分离的实现一般有两种方式:程序代码封装和中间件封装。
程序代码封装指在代码中抽象一个数据访问层,实现读写操作分离和数据库服务器连接的管理。
中间件封装指的是独立一套系统出来,实现读写操作分离和数据库服务器连接的管理。

读写分离首先需要考虑业务的读写比例。

分库分表

既分散了读压力,又分散了存储压力。

分库带来的问题:join 操作问题,事务问题,成本问题。

水平分表相比垂直分表,引入的复杂性主要体现在:
* 路由:用于确定某条数据所在切分后的子表。常见的路由算法有 范围路由、hash路由、配置路由。
* join 操作
* count 操作
* order by 操作

第17篇 高性能缓存架构

缓存穿透

指缓存没有发挥作用,业务系统虽然去缓存查询数据,但缓存中没有数据,业务系统需要再次去存储系统查询数据。

缓存雪崩

指当缓存失效(过期)后引起系统性能急剧下降的情况。

常见的解决方法有两种:
* 更新锁机制:对缓存更新操作进行加锁保护,保证只有一个线程能够进行缓存更新,未能获取更新锁的线程要么等待锁释放后重新读取缓存,要么直接返回空值或者默认值。
* 后台更新机制:缓存本身的有效期设置为永久,后台线程定时更新缓存。

缓存热点:对于特别热点的数据,可以复制多份缓存副本,将请求分散到多个缓存服务器上,减轻缓存热点导致的单台服务器压力。


欢迎关注我的微信公众号: coderbee笔记,可以更及时回复你的讨论。

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据