一起来学SpringColud(一)初始微服务

项目的演变

从个大搜索指数来看,微服务的热度在进入 2017 年后突然爆发,国内各大会议和论坛的相关讨论也如雨后春笋般层出不穷,各大一线互联网公司也纷纷将这一技术引入并在实际业务中落地。

这里选取Dubbo官网的一副图作为分析

一起来学SpringColud(一)初始微服务_第1张图片

从左到右依次为

单一应用=》垂直应用架构=》分布式服务架构=》流动计算架构
单一应用架构
当网站流量很小时,只需一个应用,将所有功能都部署在一起,以减少部署节点和成本。此时,用于简化增删改查工作量的数据访问框架(ORM)是关键。
垂直应用架构
当访问量逐渐增大,单一应用增加机器带来的加速度越来越小,将应用拆成互不相干的几个应用,以提升效率。此时,用于加速前端页面开发的Web框架(MVC)是关键。
分布式服务架构
当垂直应用越来越多,应用之间交互不可避免,将核心业务抽取出来,作为独立的服务,逐渐形成稳定的服务中心,使前端应用能更快速的响应多变的市场需求。此时,用于提高业务复用及整合的分布式服务框架(RPC)是关键。
流动计算架构
当服务越来越多,容量的评估,小服务资源的浪费等问题逐渐显现,此时需增加一个调度中心基于访问压力实时管理集群容量,提高集群利用率。此时,用于提高机器利用率的资源调度和治理中心(SOA)是关键。

在开聊微服务之前,我先要你和介绍下单体应用。如果你不知道单体应用的痛,那也不会深刻理解微服务的价值。

一起来学SpringColud(一)初始微服务_第2张图片

这里所说道的服务呢其实就是相应业务的逻辑代码,当网站流量很小时,只需一个应用,将所有功能都部署在一起,减少了部署节点和成本。这样而来呢,容易测试,容易部署,同时也会带来一些问题,开发效率低,代码维护难,如果代码出现转接,会导致后来人不知如何下手,同样呢,构建也是很头疼的一件事,小小的错误也要把所有代码重新构建一遍,稳定性和扩展性也会受到影响,可能代码中出现问题,导致整合项目崩溃,无法满足高并发下的业务需求。

想要解决上面这些问题,服务化的思想也就应运而生。

什么是服务化?

这里我就不谈一些官方的、教条主义的概念了。在我看来,用通俗的话来讲,服务化就是把传统的单机应用中通过 JAR 包依赖产生的本地方法调用,改造成通过 RPC 接口产生的远程方法调用。一般在编写业务代码时,对于一些通用的业务逻辑,我会尽力把它抽象并独立成为专门的模块,因为这对于代码复用和业务理解都大有裨益。

在过去的项目经历里,我对此深有体会。以微博系统为例,微博既包含了内容模块,也包含了消息模块和用户模块等。其中消息模块依赖内容模块,消息模块和内容模块又都依赖用户模块。当这三个模块的代码耦合在一起,应用启动时,需要同时去加载每个模块的代码并连接对应的资源。一旦任何模块的代码出现 bug,或者依赖的资源出现问题,整个单体应用都会受到影响。

为此,首先可以把用户模块从单体应用中拆分出来,独立成一个服务部署,以 RPC 接口的形式对外提供服务。微博和消息模块调用用户接口,就从进程内的调用变成远程 RPC 调用。这样,用户模块就可以独立开发、测试、上线和运维,可以交由专门的团队来做,与主模块不耦合。进一步的可以再把消息模块也拆分出来作为独立的模块,交由专门的团队来开发和维护。

可见通过服务化,可以解决单体应用膨胀、团队开发耦合度高、协作效率低下的问题。

SOA vs 微服务

微服务是SOA的传承,但一个最本质的区别就在于Smart endpoints and dumb pipes,或者说是真正的分布式的、去中心化的。Smart endpoints and dumb pipes本质就是去ESB,把所有的“思考”逻辑包括路由、消息解析等放在服务内部(Smart endpoints),去掉一个大一统的ESB,服务间轻(dumb pipes)通信,是比SOA更彻底的拆分。

微服务的提出

微服务是一种架构风格,一个大型复杂软件应用由一个或多个微服务组成。系统中的各个微服务可被独立部署,各个微服务之间是松耦合的。每个微服务仅关注于完成一件任务并很好地完成该任务。在所有情况下,每个任务代表着一个小的业务能力。

微服务的概念源于2014年3月Martin Fowler和James Lewis所写的一篇文章“Microservices”(http://martinfowler.com/articles/microservices.html)。尽管“微服务”这种架构风格没有精确的定义,但其具有一些共同的特性,如围绕业务能力组织服务、自动化部署、智能端点、对语言及数据的“去集中化”控制等等。

微服务架构的思考是从与整体应用对比而产生的,是一种架构风格。根据论文中的概述呢,大概有以下几点。

  • 一系列微小的服务共同组成
  • 跑在自己的进程里
  • 每个服务为独立的业务开发
  • 独立部署
  • 分布式的管理

由此可见,微服务化给服务的发布和部署,以及服务的保障带来了诸多好处。

简单的微服务架构

微服务听上去是不错,听上去好像都不错,具体怎么落地啊?这需要回答下面几个问题:

  • 客户端如何访问这些服务?
  • 服务之间如何通信?
  • 这么多服务,怎么找?
  • 服务挂了怎么办?

这么多服务,怎么找?

在微服务架构中,一般每一个服务都是有多个拷贝,来做负载均衡。一个服务随时可能下线,也可能应对临时访问压力增加新的服务节点。服务之间如何相互 感知?服务如何管理?这就是服务发现的问题了。一般有两类做法,也各有优缺点。基本都是通过zookeeper等类似技术做服务注册信息的分布式管理。当 服务上线时,服务提供者将自己的服务信息注册到ZK(或类似框架),并通过心跳维持长链接,实时更新链接信息。服务调用者通过ZK寻址,根据可定制算法, 找到一个服务,还可以将服务信息缓存在本地以提高性能。当服务下线时,ZK会发通知给服务客户端。

  • 客户端做:优点是架构简单,扩展灵活,只对服务注册器依赖。缺点是客户端要维护所有调用服务的地址,有技术难度,一般大公司都有成熟的内部框架支持,比如Dubbo。
  • 服务端做:优点是简单,所有服务对于前台调用方透明,一般在小公司在云服务上部署的应用采用的比较多

一起来学SpringColud(一)初始微服务_第3张图片

客户端如何访问这些服务?

通常,一个大系统里会有很多职责单一的微服务,如果门户系统或移动 APP 来调用这些微服务的 API 时,至少要做好两件事

  • 由统一的入口来调用微服务的 API
  • API 鉴权

我个人认为呢,是是为前台(通常是移动应用)提供后台服务的聚合,提供一个统一的服务出口,解除他们之间的耦合,不过API Gateway也有可能成为单点故障点或者性能的瓶颈。

一起来学SpringColud(一)初始微服务_第4张图片

服务之间如何通信?

因为所有的微服务都是独立的Java进程跑在独立的虚拟机上,所以服务间的通行就是IPC(inter process communication),已经有很多成熟的方案。现在基本最通用的有两种方式

  • 同步调用
    • REST(JAX-RS,Spring Boot)
    • RPC(Thrift, Dubbo)
  • 异步消息调用(Kafka, Rabbitmq)

一般同步调用比较简单,一致性强,但是容易出调用问题,性能体验上也会差些,特别是调用层次多的时候。RESTful和RPC的比较也是一个很有意 思的话题。一般REST基于HTTP,更容易实现,更容易被接受,服务端实现技术也更灵活些,各个语言都能支持,同时能跨客户端,对客户端没有特殊的要 求,只要封装了HTTP的SDK就能调用,所以相对使用的广一些。RPC也有自己的优点,传输协议更高效,安全更可控,特别在一个公司内部,如果有统一个 的开发规范和统一的服务框架时,他的开发效率优势更明显些。就看各自的技术积累实际条件,自己的选择了。

而异步消息的方式在分布式系统中有特别广泛的应用,他既能减低调用服务之间的耦合,又能成为调用之间的缓冲,确保消息积压不会冲垮被调用方,同时能 保证调用方的服务体验,继续干自己该干的活,不至于被后台性能拖慢。不过需要付出的代价是一致性的减弱,需要接受数据最终一致性;还有就是后台服务一般要 实现幂等性,因为消息发送出于性能的考虑一般会有重复(保证消息的被收到且仅收到一次对性能是很大的考验)。最后就是必须引入一个独立的broker,如 果公司内部没有技术积累,对broker分布式管理也是一个很大的挑战。不过呢幸好我们有棒棒哒 springColud。
一起来学SpringColud(一)初始微服务_第5张图片

这么多服务,服务挂了怎么办?

举个例子,把所有鸡蛋放在一个篮子里,一荣俱荣,一损俱损。而分布式最大的特性就是网络是不可靠的。通过微服务拆分能降低这个风险,不过如果没有特别的保障,结局肯定是悲剧性的。我们刚遇到一个线上故障就是一个很不起眼的SQL计数功能,在访问量上升时,导致数据库load彪高,影响了所在应用的性能,从而影响所有调用这个应用服务的前台应用。所以当我们的系统是由一系列的服务调用链组成的时候,我们 必须确保任一环节出问题都不至于影响整体链路。相应的手段有很多

  • 重试机制
  • 限流
  • 熔断机制
  • 负载均衡
  • 降级(本地缓存)

微服务架构的优点

微服务架构有很多重要的优点。首先,它解决了复杂性问题。它将单体应用分解为一组服务。虽然功能总量不变,但应用程序已被分解为可管理的模块或服务。这些服务定义了明确的RPC或消息驱动的API边界。微服务架构强化了应用模块化的水平,而这通过单体代码库很难实现。因此,微服务开发的速度要快很多,更容易理解和维护。

其次,这种体系结构使得每个服务都可以由专注于此服务的团队独立开发。只要符合服务API契约,开发人员可以自由选择开发技术。这就意味着开发人员可以采用新技术编写或重构服务,由于服务相对较小,所以这并不会对整体应用造成太大影响。

第三,微服务架构可以使每个微服务独立部署。开发人员无需协调对服务升级或更改的部署。这些更改可以在测试通过后立即部署。所以微服务架构也使得CI/CD成为可能。

最后,微服务架构使得每个服务都可独立扩展。我们只需定义满足服务部署要求的配置、容量、实例数量等约束条件即可。

微服务架构的缺点和挑战

实际上并不存在完美的架构,微服务架构也会给我们带来新的问题和挑战。其中一个就和它的名字类似,微服务强调了服务大小,但实际上这并没有一个统一的标准。业务逻辑应该按照什么规则划分为微服务,这本身就是一个经验工程。有些开发者主张10-100行代码就应该建立一个微服务。虽然建立小型服务是微服务架构崇尚的,但要记住,微服务是达到目的的手段,而不是目标。微服务的目标是充分分解应用程序,以促进敏捷开发和持续集成部署。

微服务的另一个主要缺点是微服务的分布式特点带来的复杂性。开发人员需要基于RPC或者消息实现微服务之间的调用和通信,而这就使得服务之间的发现、服务调用链的跟踪和质量问题变得的相当棘手。

微服务的另一个挑战是分区的数据库体系和分布式事务。更新多个业务实体的业务交易相当普遍。这些类型的事务在单体应用中实现非常简单,因为单体应用往往只存在一个数据库。但在微服务架构下,不同服务可能拥有不同的数据库。CAP原理的约束,使得我们不得不放弃传统的强一致性,而转而追求最终一致性,这个对开发人员来说是一个挑战。

微服务架构对测试也带来了很大的挑战。传统的单体WEB应用只需测试单一的REST API即可,而对微服务进行测试,需要启动它依赖的所有其他服务。这种复杂性不可低估。

微服务的另一大挑战是跨多个服务的更改。比如在传统单体应用中,若有A、B、C三个服务需要更改,A依赖B,B依赖C。我们只需更改相应的模块,然后一次性部署即可。但是在微服务架构中,我们需要仔细规划和协调每个服务的变更部署。我们需要先更新C,然后更新B,最后更新A。

部署基于微服务的应用也要复杂得多。单体应用可以简单的部署在一组相同的服务器上,然后前端使用负载均衡即可。每个应用都有相同的基础服务地址,例如数据库和消息队列。而微服务由不同的大量服务构成。每种服务可能拥有自己的配置、应用实例数量以及基础服务地址。这里就需要不同的配置、部署、扩展和监控组件。此外,我们还需要服务发现机制,以便服务可以发现与其通信的其他服务的地址。因此,成功部署微服务应用需要开发人员有更好地部署策略和高度自动化的水平。

一起来学SpringColud(一)初始微服务_第6张图片

这里有一个图非常好的总结微服务架构需要考虑的问题,包括:

  • API Gateway
  • 服务间调用
  • 服务发现
  • 服务容错
  • 服务部署
  • 数据调用

一起来学SpringColud(一)初始微服务_第7张图片

总结

  • 对于大的互联网公司,微服务架构是血液,是习惯,每家公司都有自己的套路和架构,细节有不同,但是核心理念是通的。
  • 对于一般的公司而言,实践微服务有非常大的技术挑战,于是乎才有了这么多IT供应商考虑这里的商机。微服务比较适合未来有一定的扩展复杂度,且有 很大用户增量预期的应用,说人话就是新兴的互联网公司。创业初期,不可能买大量的机器或者很贵的机器,但是又必须考虑应对成功后的巨量的用户,微服务架构 成了最好的选择。

你可能感兴趣的:(一起来学SpringColud)