每个程序员都有一个架构师的梦,可理想很丰满,现实很骨感---大部程序员工做中都作着简单的 CRUD,我也不例外。若是就这样还常把“架构”两个字挂在嘴边,估计程序员们都会脸红。但就由于暂时还不能成为架构师,咱们就要放弃成为架构师的梦想了吗?显然不能,掌握架构设计的相关理论是成为架构师的前提,有了方法论能够更好地指导咱们干活。机会老是留给有准备的人的,万一哪天梦想实现了呢?css
为了学习“架构”,我偷偷的看了两本武功秘籍《从 0 开始学架构》《大型网站技术架构》。并从中发现了一些秘密:两本书讲的关于架构的核心内容有不少共同的地方,这说明了什么?说明了架构师是有套路的。掌握了套路并敢于实践,将来并不遥远。html
在理解什么是架构以前,先来看下与它相关的一些词汇:架构、框架、组件、模块和系统。《从0开始学架构》下的一条评论很精炼的总结了它们的定义与区别,摘抄以下:前端
架构是顶层设计; 框架是面向编程或配置的半成品; 组件是从技术维度上的复用; 模块是从业务维度上职责的划分; 系统是相互协同可运行的实体。程序员
软件架构是软件系统的顶层设计,它明确软件系统包括哪些个体:子系统、模块和组件等;同时明确了个体运做和个体之间协做的规则。面试
从机器语言到汇编语言到高级语言、从结构化程序设计方法到到面向对象编程思想到面向接口编程、从单机单进程到单机多进程到分布式集群。每一次语言、编程思想和技术的升级都是为了知足软件规模愈来愈大的须要。而随着软件系统大到必定程度,数据结构与算法再也不构成软件设计的主要问题;当系统组成部分愈来愈多时,整个系统的组织或者说“软件架构”致使了一系列新的问题。而不合理的架构的复杂系统每每面临以下问题:算法
软件架构便应运而生,但因为软件系统的复杂性和多变性,没有一种架构能够知足全部系统的设计需求。它与面向对象编程、软件工程同样,不是软件设计领域的银弹。sql
作任何事情只有明确了目的,才能把握方向,从而制定方案并执行,架构设计也不例外。架构设计的主要目的是为了解决软件系统复杂度带来的问题。小到管理系统大到淘宝、微信,在设计开发过程当中,都须要进行架构设计。而因为软件系统之间的复杂度不一样,架构设计难度也不同,但基本流程都类似,掌握了架构设计的流程,即便简单的对内的工具平台也能玩出花儿来。数据库
架构设计可大可小但不是无关紧要,架构并非高不可攀也别嗤之以鼻。编程
一、架构是为了应对软件系统复杂度而提出的一个解决方案。后端
二、架构即(重要)决策。
三、需求驱动架构,架起分析与设计实现的桥梁。
四、架构与开发成本的关系。
软件架构定义中咱们老是能看到复杂软件这个词,什么是复杂软件呢?大规模网站就是复杂软件的一种,大规模网站架构(其余软件系统也相似)须要考虑的复杂度来源主要以下图所示:
包括高性能、高可用、易扩展、可伸缩、安全性和低成本六个来源。 注:为了更具化的说明软件架构设计本文使用大规模网站做为复杂软件来说解
大部分程序员毕生所学除了用来作业务逻辑开发,大部分技能都是为了解决以上六个问题。咱们看过不少书、写过不少代码、作过不少设计,今天终于在这里找到了作这一切的根源。这颗大型网站架构要素的树能够将你看过绝大部分知识包含进去,是你结构化脑海中知识的根。只要你的知识够丰富,一层层的挂上去,这棵树能够独木成林。这也是是我写这篇文章的目的,并不仅是简简单单的复制和总结。也是想告诉绝大部分程序员:经过这棵树开始结构化你脑海中的知识吧。
一、合适原则:合适优于业界领先。
架构无优劣,但存合适性。“汝之蜜糖,吾之砒霜”;架构必定要匹配企业所在的业务阶段;不要面向简历去设计架构,高大上的架构不等于适用;削足适履与打肿充胖都不符合合适原则;所谓合适,必定要匹配业务所处阶段,可以合理地将资源整合在一块儿并发挥出最大功效,并可以快速落地。
二、简单原则:简单优于复杂
"我没有时间写一封短信,因此只好写一封长信"。其实,简单比复杂更加困难。面对系统结构、业务逻辑和复杂性,咱们能够编写出复杂的系统,但在软件领域,复杂表明的是“问题”。架构设计时若是简单的方案和复杂的方案均可以知足需求,最好选择简单的方案。可是,事实上,当软件系统变得太复杂后,就会有人换一个思路进行重构、升级,将它从新变得简单,这也是软件开发的大趋势。 简单原则是一个朴素且伟大的原则,Google的 MapReduce 系统就采用了分而治之的思想,而背后就是将复杂问题转化为简单问题的典型案例。
三、演化原则:演化优于一步到位
大到人类社会、天然生物,小到一个细胞,彷佛都遵循这一普世原则,软件架构也不例外。业务在发展、技术在创新、外部环境在变化,这一切都是在告诫架构师不要贪大求全,或者盲目照搬大公司的作法。应该认真分析当前业务的特色,明确业务面临的主要问题,设计合理的架构,快速落地以知足业务须要,而后在运行过程当中不断完善架构,不断随着业务演化架构。
架构设计三原则很重要,在设计你的软件系统以前先问问本身这样作架构合适吗?简单吗?可演化吗?
一、识别复杂度
在作软件系统开发的时候不可能一上来就直接敲代码,经常须要进行一些分析。除了功能上的分析,还须要对软件系统复杂度进行分析,这决定了你后续方案的选型。
架构的复杂度来源虽然有六个,但主要复杂度来自于高性能、高可用和易扩展。在讨论架构设计的时候咱们更多的是讨论这三点,本文也不例外。
但架构并不必定任什么时候候都必须知足这三个需求。根据软件系统的不一样,大部分状况下只须要知足其中的一个到两个,不多能用到三个的。
在进行高性能、高可用和易扩展复杂度来源分析的时候最好有指标支撑,好比高性能要达到多少 QPS、高可用要达到几个九、可扩展要扩展到什么程度。千万不要凭本身想象,这样要么将复杂度分析的过于简单,上线后不能知足需求;要么将复杂度分析的过于复杂,致使过分设计,项目迟迟不能上线。
二、设计备选方案
解决高性能、高可用和易扩展三个复杂度来源的成熟的技术方案有不少。好比,高性能的缓存、负载均衡、多路复用,高可用的主备方案、集群方案、异地多活,易扩展的设计模式、架构分层、插件化等。在明确了软件系统的复杂度(三选N)之后就能够按图索骥的找到可选的解决方案。
架构师在设计方案的时候须要注意如下几点,别落入俗套:
这就是为何不少大公司的面试都喜欢问一些开源框架或者软件的源码,他们的目的不在于让你熟悉源码,而是在软件系统架构设计时可以快速的对现有的各类框架进行选型以找出相对合适的。
三、评估和选择备选方案
方案有了,还须要评估和挑选出最合适的方案。这里须要遵照架构设计的三个原则合适、简单和演化,但还会面临如下挑战:
架构师对方案的选择每每存在如下几派:
而正在的备选方案评估以上几派都不靠谱,真正要作的是对各个方案进行 360度环评:**列出咱们须要关注的质量属性点,而后分别从这些质量属性的维度去评估每一个方案,再综合挑选适合当时状况的最优方案。**常见的方案质量属性点有:性能、可用性、硬件成本、项目投入、复杂度、安全性、可扩展性等。根据大家团队对以上各个属性的侧重点,选择最合适的方案。
四、详细方案设计
开始对备选方案进行一个详细的设计,好比各个个体如何运行、个体与个体之间如何协做等。
在这一步的时候可让一线开发来完成细节的填充,架构师作最后的审核便可。一方面下降了架构师的工做量,另外一方面能够培养新人。
咱们从以上内容了解到软件系统设计的发展历史以及架构设计的定义、目的、使命、原则和流程这样一个完整的闭环,为接下来的架构设计实战夯实了理论基础。
高性能是架构设计复杂度来源之一,任何软件系统对高性能都有所要求,只是要求的标准不同。对性能要求越高的软件系统架构设计越复杂,反之越容易。但若是高不能用指标来量化,那便没法进行合理的架构设计和进一步优化。因此高性能的两部分性能指标和性能优化同等重要。
评价大型网站高性能的主要指标以下:
大型网站从前台到后台再到数据可大体分为三个层次,本文分别从三个层次来介绍性能优化所涉及到的技术点,但系统的性能优化方案历来不该该是大而全的,这里只是泛泛而谈。若是这里涉及到的知识点你不曾涉及,建议自行百度,弄懂后挂到脑图树上;若是对涉及到的知识点有着更深的理解,扩充你的脑图树叶。
减小 http 请求:因为一次 http 请求中包含不少有效数据之外的无效数据(好比响应码、header),因此尽可能将屡次 http 请求合并成一个,好比 js 文件与 css 文件合并、小图片合并成一张大图片等。
使用浏览器缓存:不少网站的 css、js、图片这些静态文件更新频率很低,而这些静态文件又须要频繁请求,即可以将它们缓存到浏览器中。经过设置 http 头中的 Cache-Control 和 Expirs 属性,能够设定浏览器缓存,缓存的时间能够是数天或者几个月。(http 协议 header 中各个字段的做用)
启用压缩:在服务器端返回数据之前进行数据压缩,特别是 js/css/html 等文本的压缩,压缩率极高可达 80%。但数据的压缩和解压会给服务器端和浏览器端都形成必定的压力,在设计时须要权衡。(数据压缩算法有哪些)
减小 Cookie 传输:不要将大量的用户数据放在 Cookie 中,一方面不安全,另外一方面会增长网络传输压力。最经常使用作法是将用户数据存储在 Session 中,Cookie 中只须要存入 Session ID 便可。(什么是 Cookie/Session,以及它们之间的区别)
CDN 加速: CDN(Content Distribute Network,内容分发网络)的本质仍然是一个缓存,它通常由网络运营商提供,将数据(通常是静态数据 js、css、图片、文件等)缓存在在离用户最近的地方。(什么是 CDN)
反向代理: 反向代理工做在浏览器和后端服务器之间,它屏蔽了后端服务器的细节。一方面它能够用来进行后端服务器的负载均衡,另外一方面能够缓存静态内容加速网站的访问。(什么是正向代理和反向代理)
使用缓存:缓存在提升性能方面随处可见,从前端到后台。前端前面已经介绍,然后台服务的缓存分为本地缓存和分布式缓存(本地缓存与分布式缓存各自的原理以及它们的优缺点)。
本地缓存可使用简单的 Hash 表实现也可使用开源软件,好比 SpringBoot 下的 Encache。(Hash 定义、如何避免冲突)。
分布式缓存是比较经常使用缓存解决方案,特别是在集群环境。分布式缓存有不少成熟的开源软件,好比 Memcached 和 Redis,因为使用普遍,分布式缓存原理和一些开源软件是面试中的常客。(分布式缓存的原理、Memcached 和 Redis 各自的优缺点,了解缓存中一些经常使用名词:缓存穿透、缓存热点、缓存雪崩等)。
异步操做:异步是提升性能的另外一个手段,也包括本地异步和分布式异步。 本地异步能够用简单的多线程或者线程实现,也能够用成熟的事件框架,好比谷歌的 Guava Eventbus。而本地进程间可使用共享内存实现异步,只是须要在共享内存中实现一个并发安全的本地消息队列。
分布式异步可使用消息队列,消息队列不只能够解耦系统还能够削峰填谷。它是分布式系统异步的终极解决方案,常见的消息队列有 RabbitMQ、MetaQ、Kafka。(消息队列的原理和 RabttiMQ 的优缺点)
使用集群:一台机器的性能再好,整个系统的吞吐量都是有限的。为了支持更大的吞吐量,除了优化代码、提升单机服务器性能,还能够将系统从一台机器部署扩散到多台。所谓的分布式系统都是这种操做,由于只有这样才能破解摩尔定律失效的魔咒。
代码优化:从代码层面来提升性能是程序员必备技能,涉及到的知识点太多,这里只简单的列举一下几点,算是抛砖引玉:
(1)使用多线程、多进程。
(2)充分利用内存。
(3)资源复用:单例和池化技术。
(4)更好的算法和数据结构。
(5)JAVA 虚拟机参数调优以及避免 FULLGC。
(6)合适的 IO 模型和线程/进程模型。
磁盘 IO 优化:使用 SSD 代替机械硬盘,使用 HDFS 代替普通文件系统。 数据库优化:数据库优化是个老生常谈的问题,也是面试中的常客。主要有如下几种优化方法(高性能 Mysql):
(1)增长索引
(2)优化SQL语句
(3)分库分表
(4)读写分离
(5)分布式关系型数据库
(6)使用 Nosql
若是系统不可用,性能再高也没卵用。与高性能同样,高也须要有指标来量化,好比4个9。大型网站的高可用又分为应用高可用、服务高可用和数据高可用。
服务降级:将业务或者接口功能下降,只提供部分功能或者彻底停掉全部功能。常见实现降级方式有:系统后门降级和独立系统降级。
流量限制:降级是故障后的过后处理,而限流是故障前的预防。限流是指只容许可以承受的访问量进来,超出系统系统访问能力的将被放弃。经常使用的限流方式能够分为分类:基于请求限流和基于资源限流。
流量排队:是流量限制的一个变种,限流是直接拒绝用户,排队是让用户等待一段时间。 服务熔断:熔断与降级概念很是容易混淆,降级是为了应对服务自身的故障。熔断的目的是为了应对外部系统故障的状况:主动断开依赖的其余外部的不可用服务,防止形成更多的雪崩效应。
分级管理:根据服务功能的重要性按照等级进行划分,将不一样等级的服务进行隔离,防止非核心服务的故障影响核心服务。
集群 一、多机器部署
二、服务注册与发现
异地多活:
一、同城异区+专线:复杂度低、有用性高、没法应对大灾难(如同城地震、停电)
二、跨城异地:复杂度高、网络延迟高、数据没法强一致性。并不是全部业务都适合。
三、跨国异地:缺点同跨城异地,主要用来:
服务描述:服务描述用来描述服务的如下信息: (1)服务名称 (2)调用服务须要提供的信息 (3)服务调用后返回的数据格式 常见的服务描述包括 RESTFUL API、XML配置以及 IDL 文件三种。
注册中心:经过注册中心进行服务的发布和订阅。微服务分为服务调用者和服务消费者,注册中心是他们沟通的桥梁。
服务框架:提供服务消费者与服务提供者之间进行沟通的约定: (1)服务通讯采用什么协议 (2)数据传输采用什么方式 (3)数据压缩采用什么格式
服务监控:服务监控是了解服务是否可用的重要手段,主要包括三个流程:指标收集、数据处理和数据展现。
服务追踪:除了须要对服务调用状况进行监控以外,你还须要记录服务调用通过的每一层链路,以便进行问题追踪和故障定位。阿里鹰眼
服务治理:服务监控能发现问题,服务追踪可以定位问题所在,而解决问题须要靠服务治理。负载均衡和故障自动转移。
CAP 理论:对于一个分布式计算系统,不可能同时知足一致性(Consistence)、可用性(Availability)、分区容错性(Partition+Tolerance)三个设计约束。CAP 关注的是对数据的读写操做而不是整个系统。CAP最多只能知足三者中的两个,P必须知足,注重一致性则必须是CP(如zookeeper),注重可用性则必须是AP(如eureka)。
ACID:ACID 是数据库系统为了保证事务的正确性而提出来的理论,ACID 包含四个约束:Atomicity(原子性)、Consistency(一致性)、Isolation(隔离性)和 Durability(持久性)。
BASE:BASE+是指基本可用(Basically+Available)、软状态(+Soft+State)、最终一致性(+Eventual+Consistency),核心思想是即便没法作到强一致性(CAP+的一致性就是强一致性),但应用能够采用适合的方式达到最终一致性。
存储高可用方案的本质都是经过将数据复制到多个存储设备,经过数据冗余的方式来实现高可用,其复杂性主要体如今如何应对复制延迟和中断致使的数据不一致问题。所以,对任何一个高可用存储方案,咱们须要从如下几个方面去进行思考和分析:
主备复制:
主从复制:
(1)客户端读复杂度提升,须要感知主从关系并选择一台机器进行读操做。
(2)若是数据复制的延迟比较大,会出现数据不一致的中间态。
(3)故障时须要人工干预。
主主复制:
(1)两台主机均可以进行读写,其中一台故障不影响总体业务。
(2)客户端无需区分角色,能够将读写请求发送到任意一台机器上。
看似完美的主主架构也有众多缺点:
(1)双向复制也并不能保证明时性,若是延迟较高也会存在数据不一致的中间态。
(2)不少数据并不能进行双向复制,好比用户自增 id、库存数据、余额数据等。
主主复制架构对数据设计有严格要求,通常适合那些临时性、可丢失、可覆盖的数据场景。
数据集群:上面介绍的不管是主备/主从/主主都只有一台主机,它们有以下两个缺点:、
(1)主机存储的数据有限。
(2)主机宕机后须要手动恢复。
数据集群由多台机器组成造成一个系统,专门用来存储数据。数据集群又分为数据集中集群和数据分散集群:
(1)数据集中集群:集群中机器上的数据都是同样的,由一台机器进行写而后复制到集群中其余机器。可参考 zookeeper 的原理和架构。
(2)数据分散集群:数据分散在不一样机器上,固然也会备份在几台集群中的机器上。可参考一致性哈希算法和 Amazon 的 Dynamodb 原理以及架构。
数据分区:将数据按照区域进行划分,防止某个区域发生很是大的灾难,好比洪水、地震、海啸等。而每一个区域的数据备份又能够采用上述的主主/主从/主备/集群的方式保证高可用。 数据分区架构复杂度须要从如下方面去考虑:
(1)数据量
(2)分区规则
(3)复制规则:集中式、互备式和独立式
一、网站发布:在柔性的发布过程当中,每次关闭的服务都是集群中的一小部分,并在发布完成后当即能够访问;
二、自动化测试:使用自动测试工具或脚本完成测试;
三、预发布验证:引入预发布服务器,与正式服务器几乎一致,只是没有配置在负载均衡服务器上,外部用户没法访问;
四、代码控制:目前大多数网站采用SVN,分支开发,主干发布模式;另外,目前开源社区普遍采用Git做为版本控制工具,正逐步取代SVN的地位;
(1)用户行为日志收集:服务器端的日志收集和客户端的日志收集;目前许多网站逐步开发基于实时计算框架Storm的日志统计与分析工具;
(2)服务器性能监控:收集服务器性能指标,如系统Load、内存占用、磁盘IO等,及时判断,防患于未然;
(3)运行数据报告:采集并报告,汇总后统一显示,应用程序须要在代码中处理运行数据采集的逻辑;
(1)系统报警:配置报警阀值和值守人员联系方式,系统发生报警时,即便工程师在千里以外,也能够被及时通知;
(2)失效转移:监控系统在发现故障时,主动通知应用进行失效转移;
(3)自动优雅降级:为了应付网站访问高峰,主动关闭部分功能,释放部分系统资源,保证核心应用服务的正常运行;
这个世界惟一不变的是变,与建筑架构不一样,软件系统架构是一个不断演变的过程。若是软件系统从一开始没作好软件架构,遇到每次大的改变都须要重构,将是不能接受的。
可扩展性架构设计方式有不少,但万变不离其踪,全部的可扩展架构的背后基本思想均可以总结为一个字:"拆"。
按照不一样的思路来拆分软件系统,就会获得不一样的架构。常见的拆分思路以下:
更具体的例子:
流程 对应+TCP/IP+四层模型,由于+TCP/IP+网络通讯流程是:应用层 → 传输层 → 网络层 →物理+数据链路层,无论最上层的应用层是什么,这个流程都不会变。
服务 对应应用层的+HTTP、FTP、SMTP+等服务,HTTP+提供+Web+服务,FTP+提供文件服务,SMTP+提供邮件服务,以此类推。
功能 每一个服务都会提供相应的功能。例如,HTTP 服务提供 GET、POST 功能,FTP 提供上传下载功能,SMTP 提供邮件发送和收取功能。
面向流程拆分更像纵向拆分,面向服务拆分更像横向拆分,面向功能拆分是比面向服务更细的拆分。它们之间并非非此即彼的,而是相辅相成的。一个系统的架构既可能用到面向流程拆分也可能用到面向服务拆分,甚至面向功能拆分。
面向流程拆分:分层架构 面向服务拆分:SOA、微服务 面向功能拆分:微内核架构
一、分层架构和 SOA
分层架构:比较常见,最简单的例如将系统分为应用层、服务层和存储层。复杂的软件系统还会分更多的层次。分层架构须要保证各层之间的差别足够清晰,边界足够明显,让人看到架构图后就能看懂整个架构。传统的分层架构:
二、微服务
微服务的英文定义:In short, the microservice architectural style [1] is an approach to developing a single application as a suite of small services, each running in its own process and communicating with lightweight mechanisms, often an HTTP resource API. These services are built around business capabilities and independently deployable by fully automated deployment machinery.
微服务的关键词:small、lightweight 和 automated。 微服务须要的基础设施:
以上种种,几乎涉及了 架构开发的全部知识点,都只是走马观花、点到即止。每一个人所知道知识深度不同,但要想成为一名合格的架构师得现有广度再有深度也不迟,以上总结也算全面的、系统的阐述了一个程序员该掌握的知识点。