《架构师》期刊摘要(2015年)一

一、架构应该是从简单到复杂,不断演变的一个过程。工程师思维驱动人们去开发一个理想化的系统。然而最好的架构却通常不是最理想的架构,而是最适合的架构。我们见过许多因为过度的架构设计而浪费宝贵的时间的案例,更有甚者因为过多不切实际的假想而导致架构迟迟无法落定,这种现象的术语描述,叫做“分析瘫痪”。

    所以优秀的架构应该结合业务目标,在权衡之中寻求一个最优的点。

二、分布式系统在扩展性方面分成四个维度

    1、性能可扩展性:性能无法实现线性扩展,但是尽量使用具有并发性和异步性的组件。具备完成通知功能的工作队列要优于同步连接到数据库。

    2、可用性可扩展:CAP理论表明,分布式系统无法同时提供一致性、可用性和分区容错性的保证。许多大规模web应用程序都为了可用性和分区容错而牺牲强一致性,而后者则依赖于最终一致性来保证。

    3、维护可扩展性:在使用平台、工具监控和更新应用程序时,要尽可能的自动化。

    4、成本可扩展性:在设计一个系统时,要在重用现有组件和完全新开发组件之间进行权衡。

    根据上述内容总结出10个设计原则:

    1、避免单点故障:任何东西都要有两个。这增加了成本和复杂度,但却能在可用性和负载性能上收益。

    2、横向扩展:而不是纵向扩展。

    3、尽量减少应用程序核心所需要完成的工作。(程序职能尽可能的清晰和简单,不要让一个组件承担过多的职能)

    4、API优先:将应用程序视为一个提供API的服务,而且,不假定服务的客户端类型(手机应用、web站点、桌面应用程序)

    5、总是缓存。

    6、提供尽可能新的数据:用户可能不需要立即看到最新的数据,但是最终一致性可以带来更高的可用性。

    7、设计事要考虑维护和自动化:不要低估应用程序维护所需要的时间和工作量。

    8、宁异步,不同步。

    9、努力实现无状态:状态信息要保存在尽可能少的地方,而且要保存在专门设计的组件中。

    10、为故障做好准备:将故障对终端用户的影响最小化。

《高可扩展分布式应用程序的架构原则》(2015年11月)

三、传统架构面临的挑战

    1、稳定性:传统的单体式应用把所有的服务都堆到一起,可能会由于一些不重要的服务出问题而影响系统的核心服务。另外,系统对服务的要求也不一样,分开部署可以减小它们之间的相互影响。

    2、可维护性:多个服务堆积在一起,增加了代码的维护成本。

    3、API的版本迭代:单体应用中,一个系统会对应很多的API,而根据业务的不断迭代,肯定会衍生出很多版本的API,API的升级和维护都需要相应的版本管理。

    4、持续集成:单体式的应用由于比较大,应用内部的依赖非常多,设计的业务逻辑也比较复杂。在CI流程中,如果没有很好的约定的话,失败的次数也会比较多;此外由于代码基比较大,构建时间也会非常长,排查问题困难。

    对微服务的理解:

    1、微服务的概念里,有两个重点,快速发布和解耦。这两点都可以和OO中的架构原则相对应,一个是单一职责,也就是把一件事情最好,一个是关注分离。康威定律说:设计系统的架构,最终产生的设计等同于组织之内、之间的沟通结构。对应到这里,也就是说微服务和公司的组织架构有非常紧密的关系。

    2、微服务革新的软件的生产过程,包括开发、测试和部署各个阶段。但服务的切分并不是要准守单一原则,因为未来的服务不可能完全垂直切分。

    3、首先微服务并不是指代码本身,它包括从代码开发到部署到运维的这一系列的工作流程。其次谈到服务拆分,需要注意的是服务的SLA是不一样的,拆分是需要考虑哪些是以及服务,哪些是二级服务。最底层的服务直接决定了上层服务的稳定性。

    4、服务化就是组件化的一种形式,所有的组件都来源于重构。流程是从上往下写的,写到一定程度时,就会遇到分离、解耦的问题,然后就是组件化,这时才会出现重构。

    5、如康威定律说,系统架构和团队的组织架构有直接的关系。但并不是说为了微服务而调整组织架构,一般是考虑到业务的需求才调整团队的组织架构。团队与团队之间不要有太多的依赖。微服务涉及到你能否快速提供环境的能力、文化的改变、快速部署、监控等多方面的能力,当这些条件都具备之后,再考虑是否微服务。

    服务治理:

    1、有三个需要注意的,一是接口的统一性,如果没有接口规范,那么效率马上就会下降。之前可以像游击队一样打,但是人多了之后,还是像正规军一样战斗力会比较强;二是容错一定要做好,这块可以参考Netflix开源的几个组件。容错如果没有做好,在服务化这样的系统里,很有可能造成雪崩效应,容错的方案也有很多,比如限流、回退、隔离、熔断;三是监控,在微服务出错之后,团队需要快速定位出错的位置和原因。

    2、服务治理,可以选择比较良好的服务框架,比如Dubbo等。

    3、服务方需要指导服务会被多少人调用,被那些业务调用,每个时间点上的状态是怎么样的。另外,阿里的eagleeye和点评的CAT监控系统,支持对服务调用链和依赖关系进行可视化监控,可以参考学习。

    4、微服务中,服务的测试是个非常大的挑战。服务与服务之间会存在依赖,所以环境的搭建可能会涉及到多个团队,这个时候就需要能够快速的部署环境,当然现在比较推荐的方案是容器。(Docker)

    5、微服务,其实对应的是微业务,为了适应业务的多变、面向最终用户的个性化需求。而微服务的力度,很大程度上是取决于完成一项业务所要设计的数据存储所在的区域。微服务的监控,包括业务、应用、系统多个层次,日志、Metrics、调用链、告警等多个维度。

    6、提到监控,大家一般都是从系统、应用等层面去考虑。

《先把平台做扎实,再来微服务吧》(2015年11月)

四、大规模弹性架构的主要设计目标是系统的高可用和高扩展性:根据系统的实际需要,系统自动弹性分配资源。在需求量大,比如峰值的时候,系统自动调配足够的资源;在访问量小,系统自动释放出部分资源,从而实现资源的按需分配。那么大规模弹性架构的基本原理是什么?其主要是利用高性能虚拟化技术,实现计算、存储和网络资源的统一调度和弹性分配。

    1、实现动态部署:为了应对突发峰值访问量或者可能的网络攻击,需要在应用服务器内部部署一些监控程序,由主控程序判断当前整个集群的负载情况,自动增加或者减少服务节点,并且自动部署应用程序,从而从容的应对突增的业务流量。

    2、实现故障自动恢复。当一台物理机损坏时,系统需要自动监测到硬件故障,并且在第一时间内,把云服务器迁移到新的宿主机器上,同时硬盘数据需要保持最后一刻的状态。

《卷首语》(2015年12月)

五、根据负载均衡LB所在位置的不同,目前主要的服务注册、发现和负载均衡方案有三种

    第一种是集中式LB:在服务消费者和服务提供者之间提供一个独立的LB层,此LB通常有专门的软硬件来实现(F5、LVS、Haproxy,nginx等)。LB上有所有服务的地址映射表,通常有运维配置注册,当服务消费放调用某个目标服务时,它向LB发起请求,由LB以某种策略(比如Round-Robin)做负责均衡后将请求转发到目标服务。LB一版具备健康检查能力,能自动摘除不健康的服务实例。服务消费方如何发现LB呢?通常的做法是通过DNS,运维人员为服务配置一个DBS域名,这个域名指向LB。

    集中式LB方案实现简单,容易做到集中式访问控制,这一方案目前还是业界主流。集中式LB的主要问题是单点问题,所有的服务调用流量都经过LB,当服务数量和调用量大的时候,LB容易成为瓶颈;此外,LB在服务消费方和提供方之间增加了一跳(hop),有一定的性能开销。

    第二种是进程内LB方案,针对集中式LB的不足,进程内LB方案将LB的功能以lib库的方式集成到服务消费放进程内(比如JVM内),该方案也被称为软负载或者客户端负载方案。这一方案需要一个服务注册表(Service Registry)配合支持服务自注册和自发现,服务提供方启动时,首先将服务地址注册到服务注册表(同时定期报心跳到服务注册表以表明服务的存活状态,相当于健康检查),服务消费方要访问某个服务时,它通过内置的LB组件向服务注册表查询(同时缓存并定期刷洗、同步)目标服务地址列表,然后以某种负载均衡策略选择一个目标服务地址,最后向目标服务发起请求。这一方案对服务注册表的可用性要求很高,一般采用能满足高可用分布式一致的组件(zookeeper)。

    进程内LB方案是一种分布式方案,LB和服务发现能力被分散到每一个服务消费者进程内部,同时服务消费方和服务提供者之间是直接调用,没有额外开销,性能相对较好。它的问题出现在:1)类库的升级需要协同服务提供方、服务消费方一起进行,推动阻力很大。 2)服务注册中心的可用性需要有较高的保证 3)客户端对服务的均衡策略需要自助开发。

    进程内LB的案例是Netfflix的开元服务框架,对应的组件分别是:Eureka服务注册表,Karyon服务端框架支持服务自注册和健康检查,Ribbon客户端框架支持服务自发现和软路由。另外,阿里开源的Dobbo也采用了类似的机制。

    第三种是主机独立的LB进程方案,该方案是针对第二种方案的不足而提出的一种折中方案,原理和第二种方案基本类似,不同之处是,他将LB和服务发现的功能从进程内移出来,变成朱姐上的一个独立进程,主机上的一个或者多个服务要访问目标服务时,它们都通过同一主机上的独立LB进程做服务发现和负载均衡。(简而言之,就是将LB进程单独部署为每个服务消费方的本地机器上)这种方案也是分布式方案,没有单点问题,一个LB进程挂了只会影响该主机上的服务调用方,服务调用方和LB之间是本地“进程间”调用,性能较好(无网络开销);同时,该方案还简化了服务调用方,不需要为不同的语言开发客户端lib,LB的升级不需要服务调用方改代码;但是它的不足就是部署复杂,环节较多,对问题排查不便。(类似于每个服务消费方的本地部署一个Haproxy、nginx)。

    服务容错:

    当企业微服务化以后,服务之间会有错综复杂的依赖关系,例如,一个前端请求一般会依赖于多个后端服务,技术上称为1->扇出(fan-out),在实际的生产环境中,服务往往不是百分之百的可靠,服务可能会出错或者产生延迟,如果一个应用不能对其依赖的故障进行容错和隔离,那么该应用本身就出在被拖垮的风险中,在一个高流量的网站中,某个单一祸端一旦繁盛延迟,可能在数秒内导致所有应用资源(线程、队列等)被耗尽,造成所谓的雪崩效应(Cascading-failure),严重时可能导致整个网站瘫痪。

    1)电路熔断器模式(Cicuit Breaker Pattern):该模式的原理类似于家里的电路熔断器,如果电路发生短路,熔断器能够主动熔断电路以避免灾难性损失。在分布式系统中应用电路熔断模式后,当目标服务慢或者大量超时时,调用方能够主动熔断,以防止服务被进一步的拖垮;如果情况又好转了,电路又能自动恢复,这就是所谓的弹性容错,系统有自恢复能力。

    正常情况下,电路处于关闭状态,如果调用持续出错或者超时,电路被打开进入熔断状态,后续一段时间内的所有调用都会被拒绝(Fail Fast),一段时间后,保护器会尝试进入版熔断状态,允许少量请求进来尝试,如果调用仍然失败,则继续回到熔断状态,如果调用成功,则回到电路闭合状态。

    2)舱壁隔离模式:该模式像舱壁一样对资源或者失败单元进行隔离,如果一个船舱进水,只损失一个船舱,其他船舱不受影响。线程隔离(Thread isolation)就是船舱隔离模式的一个例子,假定一个应用程序A调用了“S1/S2/S3”三个服务,且部署A的容器共有120个工作线程,采用线程隔离机制,可以给S1/S2/S3的调用各分配40个线程,当S2慢了,给S2分配的40个线程因为慢而阻塞并且最终耗尽,线程隔离可以保证给S1/S2/S3分配的80个线程可以不受影响;如果没有这种隔离机制,当S2慢的时候,120个工作线程会很快全部被对S2的调用耗尽,整个应用程序会全部慢下来。

    3)限流(Rate limiting):服务总有容量限制,没有限流机制的服务很容易在突发流量的时候被冲垮。限流通常指对服务限定并发访问量,比如单位时间内只允许100个并发调用,对超过这个限制的请求要拒绝并回退。

    4)回退(fallback):在熔断或者限流发生的时候,会触发回退机制,回退是系统的弹性恢复能力,常见的处理策略有,直接抛出异常,也成为快速失败(Fail Fast),也可以返回空值或者缺省值,还可以返回备份数据,如果主服务熔断了,可以从备份服务获取数据。

    目前比较主流的微服务框架有Netflix的Karyon/Ribbon,Spring Boot/Cloud,阿里的Dubbo。

    目前比较成熟的“运行时配置管理”组件有Spring Cloud Config。

    Netflix的微服务框架(这些框架已经开源,并集成在了Spring Cloud中):

    1、Eureka:服务注册发现框架。

    2、Zuul:服务网关。

    3、Karyon:服务端框架

    4、Ribbon:客户端框架。

    5、Hystrix:服务容错组件。

    6、Archaius:服务配置组件。

    7、Servo:Metrics组件

    8、Blitz4j:日志组件。

    对于一些打算构建微服务框架体系的公司来说,充分利用或者参考借鉴Netflix的开源微服务组件(或者Spring Cloud),在此基础上进行必要的企业定制,无疑是通向微服务架构的捷径。

《实施微服务,我们需要哪些基础框架?》(2015年12月)

 

六、互联网时代的产品通常有两类特点:需求变化快和用户群体庞大。在这种情况下,如何从系统架构的角度出发,构建灵活、易扩展的系统,快速应付需求的变化;同时,随着用户量的增加,如何

保证系统的可伸缩性、高可用性,成为系统架构师面临的挑战。

    早在1996年,Gartner就提出面向服务架构(SOA)。SOA阐述了“对于复杂的企业IT系统,应按照不同的、可重用的粒度划分,将功能相关的一组功能提供者组织在一起为消费者提供服务”,其目的是为了解决企业内部不同IT资源之间无法互联而导致的信息孤岛问题。

    

    事实上,微服务架构并不是一个全新的概念,其思想与SOA几乎一致,它们之间的主要区别:

    SOA实现                                                      微服务架构实现

    企业级,自顶向下开发                                团队级,自底向上开展

    服务有多个子系统组成                                一个系统被拆分为多个服务

    粒度大                                                       粒度细

    企业服务总线,集中式的服务架构               无集中式总线,松散的服务架构

    集成方式复杂--ESB/WS/SOAP                   集成方式简单---HTTP/REST/JSON

    单体系统架构,相互依赖,部署复杂            服务都能独立部署

    

    由此可见,相对于传统的SOA服务实现方式,微服务更具有灵活性、可实施性以及可扩展性,其强调的是一种独立测试、独立部署、独立运行的软件架构模式。

    

    ThoughtWorks首席科学家马丁-福勒对微服务的一个描述如下:

    “微服务架构师一种架构模式,它提倡将单一应用程序划分为一组小的服务,服务之间互相协调、互相配合,为用户提供最终价值。每个服务运行在其独立的进程中,服务与服务间采用轻量级的通信机制互相沟通(通常是基于HTTP协议的RESTFul API)。每个服务都围绕着具体业务进行构建,并且能够被独立的部署到生产环境、类生产环境等。另外,应该尽量避免统一的、集中式的服务管理机制,对具体的一个服务而言,应根据业务上下文,选择合适的语言、工具对其进行构建”。

    

    总结下来,微服务架构中的核心部分包括如下几点:

    1)小,且专注于做一件事情

    2)独立的进程中

    3)轻量级的通信机制

    4)松耦合、独立部署

    《解析微服务架构(二)微服务架构综述》(2015年8月) 

相关推荐