服务架构演进

了解服务架构的历史,并且总结几点规律

服务架构演进

原始分布式时代

“使用多个独立的分布式服务共同构建一个更大型系统的设想与实际尝试,反而要比今天大家所了解的大型单体系统出现的时间更早”

1970-1980,此时8086CPU刚诞生,算力严重不足,此时提出的分布式主要是为了解决算力不足的问题。

OSF开放软件基金会(就是指定Unix系统技术标准的那个基金会)与很多主流的计算机厂商制定了DCE(Distribute Computing Environment)分布式运算环境

DCE较为详细的回答了分布式可能会遇到的问题(服务在哪里?有多少个?出现分区、超时、服务出错怎么办等等)

但是DCE计划破产,原因有两个:

  1. 解决了分布式遇到的问题,但是远程的调用方法,更加耗时耗资源,与原本想利用分布式提高算力的初衷相违背
  2. 开发要求Coder有极高的水平

破产得到一个教训:

某个功能能够进行分布式,并不意味着它就应该进行分布式,强行追求透明的分布式操作,只会自寻苦果

单体系统时代

(Monolithic Application 单体架构,也译作巨石系统)

单体:指的是项目跑在一个进程内,连IPC(进程间调用)都不存在

1980开始,摩尔定律的黄金时代,计算机算力日新月异,单体系统完全可以支撑当时业务的要求。

单体系统可以纵向划分层次,比如最最传统的Controller层、业务层、持久层、数据库

但是随着项目规模的主键庞大,单体系统暴露出一些弊端:

  1. 不隔离:单体系统运行在同一进程内,优点是无需考虑网络问题、对象操作方便;但是如果代码存在缺陷,譬如内存泄漏、线程爆炸、阻塞、死循环等问题,那么就只能停止服务,重启整个项目。
  2. 技术不异构:单体系统往往由同一种语言或技术开发,无法兼容多个语言的优势。
  3. 不允许程序出错:从“追求尽量不出错”,到“出错是必然”的观念转变,要求系统可以自治,出现错误依然可以保持对外提供服务。
  4. 为了性能与算力:单体对外可以接收的流量太小,分布式集群承载力会更大

SOA时代

SOA 架构(Service-Oriented Architecture) 面向服务的架构是一次具体地、系统性地成功解决分布式服务主要问题的架构模式。

简单理解,SOA相比于单体时代,他将子系统进行了拆分,跑在了多个进程内;相比于之后的微服务时代,他的划分粒度并没有那么细致。

SOA就是“不那么微的微服务”

SOA时代也有很多种方案:

  • 烟囱式架构:也叫信息孤岛,子系统之间不允许任何往来
  • 微内核架构:也叫插件式架构,比如浏览器的插件与内核、操作系统与软件之间的关系都属于此类;子系统可以与内核交互,但是子系统之间不允许交流。
  • 事件驱动架构:维护一个事件队列的管道,子系统之间通过事件来进行交互

最终SOA时代迎来了巅峰:SOAP协议:协议规定的十分详细,对开发中譬如服务之间的松散耦合、注册、发现、治理,隔离、编排都有规定

但是SOAP夭折了,原因是SOAP协议规定的过于详细了:

  • 规定十分复杂繁琐,Coder需要了解完整的流程,懂得复杂的概念(脱离了群众)

微服务时代

微服务一开始是SOA的轻量化补救方案,在波兰克拉科夫举行的“33rd Degree Conference”大会后,微服务才真正脱离SOA(作者的观点)

此时的微服务才是我们今天所熟知的微服务:

微服务架构(Microservices):微服务是一种通过多个小型服务组合来构建单个应用的架构风格,这些服务围绕业务能力而非特定的技术标准来构建。

各个服务可以采用不同的编程语言,不同的数据存储技术,运行在不同的进程之中。

服务之间采取轻量级的通信机制和自动化的部署机制实现通信与运维。

微服务追求的是更加自由的架构风格,摒弃了几乎所有 SOA 里可以抛弃的约束和规定。

因此对于服务的注册发现、跟踪治理、负载均衡、故障 隔离、认证授权、伸缩扩展、传输通信、事务处理每一个过程都由很多个框架可以选择。

仅一个服务间远程调用问题,可以列入解决方案的候选清单的就有:RMI(Sun/Oracle)、Thrift(Facebook)、Dubbo(阿里巴巴)、gRPC(Google)、Motan2(新浪)、Finagle(Twitter)、brpc(百 度)、Arvo(Hadoop)、JSON-RPC、REST,等等;

仅一个服务发现问题,可以选择的就 有:Eureka(Netflix)、Consul(HashiCorp)、Nacos(阿里巴巴)、ZooKeeper(Apac he)、Etcd(CoreOS)、CoreDNS(CNCF),等等。

对于“拧螺丝”的程序员来说,微服务无疑是友善的,有多种选择。

但是对于架构师来说,需要承担选择对应技术的风险(一般都会选择团队熟悉的技术)

后微服务时代

后微服务时代(Cloud Native 云原生):

从软件层面独立应对微服务架构问题,发展到软、硬合力应对架构问题的时代。

虚拟化技术与容器化技术:Docker与K8s

与Spring Cloud从应用层面相比,k8s在基础设施层面也解决了一些类似的问题:

Kubernetes Spring Cloud
弹性伸缩 Autoscaling N/A
服务发现 KubeDNS / CoreDNS Spring Cloud Eureka
配置中心 ConfigMap / Secret Spring Cloud Config
服务网关 Ingress Controller Spring Cloud Zuul
负载均衡 Load Balancer Spring Cloud Ribbon
服务安全 RBAC API Spring Cloud Security
跟踪监控 Metrics API / Dashboard Spring Cloud Turbine
降级熔断 N/A Spring Cloud Hystrix

但是k8s解决问题的粒度比较粗,对于应用层与基础设施边缘的问题难以精细化处理。

为了解决这一问题,引入了服务网格(service mesh)边车代理模式(Sidecar Proxy)

无服务时代

无服务的愿景是让开发者只需要纯粹地关注业务,不需要考虑技术组件,后端的技术组件是现成的,可以直接取用,没有采购、版权和选型的烦恼;不需要考虑如何部署,部署过 程完全是托管到云端的,工作由云端自动完成;

无服务以简单为卖点:只设计两块内容:后端设施与函数

  • 后端设施:一类用于支撑业务逻辑运行,但本身无业务含义的技术组件(比如数据库、消息队列、日志、存储,等等),这些后端设施都运行在云中,无服务中称其为“后端即服务”(Backend as a Service,BaaS 后端即服务)
  • 函数:非常接近于编码角度的函数,但区别在于其运行在云端,不必考虑算力问题(需要考虑费用问题),被称为“函数即服务”(Function as a Service,FaaS)。

比如腾讯微信小程序的云开发,就属于是函数即服务的典型。

总结

服务器架构这么多年的迭代,我们会发现一些规律规律:

  • 简单替代复杂:比如原始分布时代的DCE与SOA时代的SOAP协议,都是典型的复杂设计,都被淘汰,人们都喜欢使用封装好复杂细节的轮子,而不是使用八股文去写APP。
  • 为了分布式而追求分布式,结果只会灭亡:对于比较小的项目,我们完全没必要上分布式、或者上微服务,只是增加麻烦
  • “尽量避免错误”“出错是必然”的观念转变:我们的目标不应该是不犯错,而是犯错后依然能提供服务
  • 面对发展遇到的问题,总是软件到硬件的去解决问题:总是先用软件去解决,在硬件性能提高后,再使用硬件补充软件的不足,然后遇到问题再先用软件解决,依次反复。
  • 服务架构发展的目标:上帝的归上帝,凯撒的归凯撒,业务与技术完全分离,远程与本地完全透明