架构五要素

前言

  一直以来工作中都是基于一个组件一个系统在思考,没有形成系统体系化的思维。最近一年多吵吵闹闹终于定型了整个PAAS系统,目前正处于上线阶段。加上最近作为面试官面试了不少70后名校毕业的架构师,发现有很多人还是停留在我以前的一个状态。资深的人员面试,我一般不问细节,只问架构原理。虽然我知道他们说的那些东西,也知道他们已经到了能说出来但是没有办法表达,当然我知道他的状态是清楚的,只是表达不清楚,因为我经历过这一切。由术上升到道是很多架构师短板,可能一般架构师做一个组件一个独立系统没有问题,但是一旦牵扯到跨系统交互,往往就无所适从。今天我就从个人角度聊一聊架构,解构术背后的道。

架构定义

  架构的英文是Architecture,在Wikipedia上,架构是这样定义的:
Architecture (Latin architectura, from the Greek ἀρχιτέκτων arkhitekton”architect”, from ἀρχι- “chief” and τέκτων “builder”) is both the process and the product of planning, designing, and constructing buildings and other physical structures。
从这个定义上看,架构好像是一个过程,也不是很清晰。为了讲清楚这个问题,我们先来看看为什么会产生架构。

为什么产生架构

  想象一下,在早期,每个人都完全独立生活,衣食住行全部都自己搞定,整个人类都是独立个体,老死不相往来。为了解决人类延续问题,自然而然男女群居出现,这个时候出现了分工,男人和女人所做事情有一定分工,但是人每天生活的基本需求没有发生变化,还是衣食住行等生活必需品。

  一旦分工配合作为生存整体,力量就显得强大多了。有些人种田厉害,有些人制作工具厉害,有些地方适合产出粮食,有些地方适合产出棉花等,就自然形成了人的分群,地域的分群。当分工发生后,每个人的生产力都得到了提高,因为做的都是每个人擅长的事情。整体人群的生产力和抵抗环境能力都得到增强。为什么呢?因为每个人的能力和时间都是有限的,并且因为人的结构限制,人同时只能专心做好一件事情,这样不得已导致了分工的产生。既然分工发生了,原来由一个人干生存所必需的所有的事情,就变成了很多不同分工的角色合作完成这些事情,这些人必须要通过某些机制合在一起,让每个人完成生存所必需的事情,这实际上也导致了交易的发生。

  在每个人都必须自己完成所有生活必须品的生产的时候,是没有架构的。一旦产生分工,把所有的事情切分,然后由不同角色的人来完成,最后再通过交易,使得每个个体都拥有生活必须品,而不需要每个个体都做所有的事情,只需要每个个体做好自己擅长的事情,并具备一定的交易能力即可。

  这实际上就形成了社会的架构。那么怎么定义架构呢?以上面这个例子为例,把一个整体(完成人类生存的所有工作)切分成不同的部分(分工),由不同角色来完成这些分工,并通过建立不同部分相互沟通的机制,使得这些部分能够有机的结合为一个整体,并完成这个整体所需要的所有活动,这就是架构。由以上的例子,也可以归纳出架构产生的动力:

  1. 必须由人执行的工作
  2. 每个人的能力有限
  3. 每个人的时间有限
  4. 人对目标系统有更高的要求
  5. 目标系统的复杂性使得单个人完成这个系统不可能

  当这5个条件同时成立,一定会产生架构。从这个层面上来说,架构是人类发展过程中,由懵懵懂懂的,被动的去认识这个世界,变成主动的去认识,并以更高的效率去改造这个世界的方法。

架构方法

  上面说了架构定义以及为什么需要架构。那如何做架构呢?一般来说我总结有如下步骤:

  1. 根据要解决的问题,对目标系统的边界进行界定。
  2. 对目标系统按某个原则的进行切分。切分的原则,要便于不同的角色,对切分出来的部分,并行或串行开展工作,一般并行才能减少时间。
  3. 对这些切分出来的部分,设立沟通机制。
  4. 根据3,使得这些部分之间能够进行有机的联系,合并组装成为一个整体,完成目标系统的所有工作。

架构要素

  架构中一般需要考虑5个核心要素,分别是性能、可用性、伸缩性、扩展性和安全性这5个架构指标。

1.性能

  性能是互联网项目必须首要考虑的核心指标,不然难以应对突发的流量洪峰冲击。一个打开缓慢的网站会导致严重的用户流失,很多时候网站性能是网站架构升级优化的触发器。当然优化站点性能的手段也很多,一般来说主要有以下几个方面:

1) web前端性能优化:
1. 浏览器访问优化
  1. 减少http请求。 (避免建立太多通讯链路。如将js、css、图片文件尽可能合并,避免太多请求。同时,对于系统的后端请求也尽可能进行合理的设计,来避免出现太多交互)
  2. 使用浏览器的缓存。http头设置Cache-Control和Expires。js文件名比如可以带时间戳。一旦有更新则更新时间戳,否则缓存;同时尽量避免同一时间更新大量静态资源。
  3. 对静态资源进行压缩。
  4. css放置在页面最上方,js放下最下面。以提前进行css渲染。同时避免js带来的页面阻塞。但需要case by case。比如页面dom节点需要依赖js生成,则可视情况改变文件位置。
  5. 减少cookie传输。同时让静态资源有独立域名,发送静态资源请求时候不发送cookie,以此减少传输代价,cookie可以通过document.cookie获取。
2. CDN加速。

缓存图片、文件、CSS以及script脚本。但是PC上的CDN加速效果要好于移动端。经过调研发现,last-mile的延迟越高,CDN的相对有效性越差。

3. 反向代理。

可以提供七层负载均衡(http请求进行均衡策略),并且可以提供静态资源的缓存,请求转发,防止网络攻击等。比较流行的有nginx。

2) 应用服务器性能优化:

  应用服务本身优化,一般来说有如下方法:

1. 分布式缓存

  站点性能优化优先考虑的是使用缓存。一般来说,存入cache的数据的读写比在2:1以上,而且应该是热点数据。需要考虑如果采用缓存则可能带来的数据短期内的不一致,或者如果实时更新缓存可能带来的性能和资源开销。需要考虑cache一旦失效,大量请求直接命中DB可能带来的服务性能雪崩。所以可以对cache采用集群化部署,以此避免丢失过多数据造成服务压力陡增。对于热点数据考虑进行缓存的预热加载。比如高峰期来临前,先将热点数据提前存入缓存,以此提高高峰期的服务性能。为了避免恶意攻击,一直query不存在的数据,导致cache无法命中而频繁访问DB,可以将不存在的数据也进行缓存并定期清理。同时有机制对恶意请求进行识别和封禁。分布式缓存应该去中心化并集中管理,通过不同实例间的互不通信和同构来保证可扩展性,并降低系统复杂度。

2. 异步化

  任何可以晚点做的事情都应该晚点再做,通过分布式消息队列来实现削峰的目的,通过业务配合技术来解决问题。比如12306的排队。

3. 集群

  采用集群也是服务虚拟化的一个体现,用以避免单点问题,同时提供更加高可用,高性能的服务。

4. 代码优化

  多线程中,如果是密集型计算,线程数不宜超过CPU核数。如果是IO处理,则线程数=[任务执行时间/(任务执行时间-IO等待时间)] * CPU核数。除此之外,我们应该将对象设计成无状态对象,多采用局部对象,适当将锁细化。

  进行资源复用。比如采用单例模式,比如采用连接池。

  合理设置JVM参数,以最大程度避免不合理的full gc。

3) 数据库层优化:

  数据库层其实是最脆弱的一层,一般在应用设计时在上游就需要把请求拦截掉,数据库层只承担“能力范围内”的访问请求,所以,我们通过在服务层引入队列和缓存,让最底层的数据库高枕无忧。但是如果请求激增,还是有大量的查询压力到MySQL,这个时候就要想办法解决MySQL的瓶颈了,这时候可用使用索引、缓存、SQL性能优化以及读写分离等手段,还可以使用NoSQL数据库来优化数据模型、存储结构等

4) 衡量网站性能的指标:

  站点压测一般考虑响应时间,并发数,qps,95线,99线,cpu和内存负载。

2.安全

  互联网是开放的,任何人在任何地方都可以访问网站。网站的安全架构就是保护网站不受恶意访问和攻击,保护网站的重要数据不被窃取。安全的5个要素:机密性、完整性、可用性、可控性和可审查性。

3.可用性

  大型网站几乎都承诺7x24小时可用,但事实上任何网站都不可能达到完全的7x24可用,总会有一些故障时间,扣除这些故障时间就是网站的总可用时间,这个时间换算成网站的可用性指标,以此衡量网站的可用性。衡量一个系统架构设计是否满足高可用的目标,就是假设系统中任何一台或者多台服务器宕机时,以及出现各种不可预期的问题时,系统整体是否依然可用。

  一般就三个手段:冗余、集群化、分布式。

  网站高可用的主要手段就是冗余,应用部署在多台服务器上同时提供服务,数据存储在多台服务器上相互备份,任何一台服务器都不会影响应用的整体可用,通常的实现手段即把多台服务器通过负载均衡设备组成一个集群,任何一台服务器宕机,只需把请求切换到其他服务器就可实现应用的高可用,但是一个前提条件是:应用服务器上不能保存请求的会话信息,否则服务器宕机,会话丢失,即使将用户请求转发到其他服务器上也无法完成业务处理。

4.扩展性

  扩展性(Extensibility)指对现有系统影响最小的情况下,系统功能可持续扩展或提升的能力。表现在系统基础设施稳定不需要经常变更,应用之间较少依赖和耦合,当系统增加新功能时,不需要对现有系统的结构和代码进行修改,这个没啥好说。扩展性依赖于前期良好的架构设计。合理业务逻辑抽象,水平/垂直切割分布式化等等。

  网站可扩展架构的主要手段是事件驱动架构和分布式服务。

  事件驱动架构在网站通常利用消息队列实现,将用户请求和其他业务事件构造成消息发布到消息队列,消息的处理者作为消费者从消息队列中获取消息进行处理。通过这种方式将消息产生和消息处理分离开来,可以透明地增加新的消息生产者任务或者新的消息消费者任务。

  分布式服务则是将业务和可复用服务分离开来,通过分布式服务框架调用。新增产品可以通过调用可复用的服务实现自身的业务逻辑,而对现有产品没有任何影响。可复用服务升级变更的时候,也可以通过提供多版本服务对应用实现透明升级,不需要强制应用同步变更。

5.伸缩性

  所谓伸缩性,是指通过不断向集群中加入服务器的手段来缓解不断上升的用户并发访问压力和不断增长的数据存储需求。衡量架构伸缩性的主要标准就是:是否可以用多台服务器构建集群,是否容易向集群中添加新的服务器。加入新的服务器后是否可以提供和原来的服务器无差别的服务。集群中可容纳的总的服务器数量是否有限制。伸缩性主要考虑业务切分,需要考虑将业务做水平横向分离和垂直纵向分离。
(1)横向分离:将不同的业务模块分离部署,实现系统的伸缩性;
(2)纵向分离:将业务处理流程上的不同部分分离部署,实现系统的伸缩性;

坚持原创技术分享,您的支持将鼓励我继续创作!