微服务全流程分析

转眼已经2020,距离微服务这个词落地已通过去好多年!(我记得2017年就听过这个词)。然而今天我想一想什么是微服务,其实并无一个很好的定义。为何这样说,按照微服务的定义:前端

微服务架构就是将一个庞大的业务系统按照业务模块拆分红若干个独立的子系统,每一个子系统都是一个独立的应用,它是一种将应用构建成一系列按业务领域划分模块的,小的自治服务的软件架构方式,倡导将复杂的单体应用拆分红若干个功能单1、松偶合的服务,这样能够下降开发难度、加强扩展性、便于敏捷开发,及持续集成与交付活动。git

根据这个定义,不难看出其实就是对复杂的业务系通通一作逻辑拆分,保持逻辑上的独立。那么逻辑上独立就是一个服务这样作真的是好吗,如何界定:小、独,还有要作一个事情,完成单一的业务,单一的功能要拆分出来,为了独立而独立会不会致使拆的过细?不一样人有不一样的看法,咱们今天一块儿探讨微服务的过去和将来。web

微服务缘起

在没有微服务以前,咱们最先的架构模式就是 MVC 模式,把业务逻辑分为:表示层,业务逻辑层,数据访问层。MVC模式随着大前端的发展,从一开始的先后端不分离,到如今的先后端分离逐渐演进。这种演进好的一点是剥离了不一样开发语言的开发环境和部署环境,使得开发较为便利,部署更直接。然而问题是:这种模式仍然是单体应用模式,若是有一个改动须要上线,你不得不由于这个改动去考虑更多,由于你没法估量在这么大致量的代码中你的一个改动会不会引起蝴蝶效应。spring

另外很重要的一点就是移动互联网时代的到来,引起了用户数几何倍数暴增,传统的单体应用模式已经没法支撑用户量暴涨的流量冲击,互联网人不得不作出加机器的无赖之举,然而发现有的时候加机器都没法搞定问题,由于逻辑调用过于耦合致使调用链复杂。继而出现精简调用流程,梳理调用路径的举措,因而演变出微服务这个概念。sql

其实在没有微服务这个词出现以前, 咱们也是这样干的,只是干的不完全而已。好比说有一个信贷系统,信贷系统分为贷前,贷中,贷后三步:数据库

在微服务未出现以前,咱们大可能是单体应用,基本上一个工程包含全部,无所不能,因此很臃肿上。述这些模块应该都是在一个工程中,可是按照业务作了代码上的拆分。另外就是 RPC 框架并为横空出世,若是有服务上的拆分,好比不一样部门之间调用对方提供的服务,那么八九不离十确定定义的是HTTP 接口,由于通用。可是某些时候你们又怕 HTTP 接口性能差,关键服务不敢用。编程

微服务出现以后,你们以为按照模块分别部署好像是这么回事,同时默默在内心嘀咕,之前我只用发布一个工程,如今倒好,可能有个改动涉及3个服务,我一个小小的改动就要发布3次,是否是增长了工做量,另外我之前都不用调接口的,如今依赖了一堆别的系统,系统调用这么复杂,万一别的系统有问题,我岂不是就被耽搁了!后端

在这种质疑中你们虽有抱怨可是也没有放弃赶时髦,微服务开展的如火如荼,用户中心独立部署,风控系统单独成型,支付中心全公司统一独立,财务系统再也不各个业务各自为战而是统筹公司各个业务线统一规划。按照业务抽象独立以后,你们发现好像是这么回事,用起来真香。虽然每次须要别的模块的时候就须要找对应模块进行接入,可是业务逻辑上清晰了呀,若是出了问题,不是本身的,那就是别人的,甩锅很方便的(笑)。api

如何作微服务

由于微服务是功能粒度上的拆分,必然致使拆分以后的模块变多。针对模块与模块之间的通讯与维护,又演变出以下问题:浏览器

  • 模块与模块之间如何通讯;
  • 每一个被拆分的微服务如何作负载均衡;
  • 服务如何作注册,如何作发现;
  • 服务之间调用如何作限流,服务调用失败如何作降级,流量异常如何作熔断;
  • 服务调用是否能够作统一的访问控制;

针对这些问题,业界也在发展中慢慢演进出几套通用的框架。理想中微服务框架应该具有这样的能力:

基于上述微服务框架应该具有的能力,咱们来分析目前能够落地的微服务框架的具体实现。

目前国内用的最多的无外乎是两套框架:Dubbo,Spring Cloud。Dubbo你们都很熟悉,从开源到无人维护再到从新冲击Apache顶级项目。可是Dubbo更加准确来讲是一个分布式服务框架,致力于提供高效的RPC远程服务调用方案以及SOA服务治理方案。说白了就是个分布式远程服务调用框架

Dubbo

从Dubbo官网给的图来看Dubbo的总体架构:

模块注解:

  • Provider: 暴露服务的服务提供方
  • Consumer: 调用远程服务的服务消费方
  • Registry: 服务注册与发现的注册中心
  • Monitor: 统计服务的调用次调和调用时间的监控中心
  • Container: 服务运行容器

从上图中不难看出Dubbo功能仍是很明确的:服务注册于发现,服务监控。另外Dubbo也提供服务治理功能:

Dubbo提供了集群容错的能力,在管理后台能够快速的摘除失败的服务。

对于咱们上面提到的一整套微服务应该提供的功能看,Dubbo只是提供了服务注册与服务发现的功能。不能否认在这一项功能中,Dubbo作的是很是优秀的。

Spring Cloud

Spring Cloud 基于 Spring Boot,为微服务体系开发中的架构问题,提供了一整套的解决方案——服务注册与发现,服务消费,服务保护与熔断,网关,分布式调用追踪,分布式配置管理等。

服务注册与发现

目前Spring Cloud 支持的服务注册组件有 Consul,Eureka。Consul 不是 Spring 官方的项目,须要单独部署,Eureka 被 Spring 官方收录,自己属于 Spring Cloud 体系中。

下面列出能够被用做注册中心的组件他们的特性对比:

特性 Euerka Consul Zookeeper etcd
服务健康检查 可配支持 服务状态,内存,硬盘等 (弱)长链接,keepalive 链接心跳
多数据中心 支持
kv 存储服务 支持 支持 支持
一致性 raft paxos raft
cap ap cp cp cp
使用接口(多语言能力) http(sidecar) 支持 http 和 dns 客户端 http/grpc
watch 支持 支持 long polling/大部分增量 全量/支持long polling 支持 支持 long polling
自身监控 metrics metrics metrics
安全 acl /https acl https 支持(弱)
spring cloud 集成 已支持 已支持 已支持 已支持

Consul

Consul 官网中介绍了 Consul 的如下几个核心功能:

  • 服务发现(Service Discovery):提供 HTTP 与DNS 两种方式。
  • 健康检查(Health Checking):提供多种健康检查方式,好比 HTTP 状态码、内存使用状况、硬盘等等。
  • 键值存储(KV Store):能够做为服务配置中心使用,相似 Spring Cloud Config。
  • 加密服务通讯(Secure Service Communication)
  • 多数据中心(Multi Datacenter):Consul 经过 WAN 的 Gossip 协议,完成跨数据中心的同步。

Consul 须要单独部署,而不是与Spring集成的组件。

Eureka

Eureka 是 Spring Cloud NetFlix 默认的服务发现框架,但目前 2.0 版本已闭源,只剩下 1.9 版本的处于维护状态。Eureka 使用尽力而为同步的方式提供提供弱一致的服务列表。当一个服务注册时,Eureka 会尝试将其同步到其余节点上,但不提供一致性的保证。 所以,Eureka 能够提供过期的或是已不存在的服务列表(在服务发现场景下,返回旧的总比什么也不返回好)。

若是在 15分钟内超过85%的客户端节点都没有正常的心跳,那么 Eureka 就会认为客户端与注册中心出现了网络故障(出现网络分区),进入自我保护机制。

此时:

  • Eureka Server 会保护服务注册表中的信息,再也不删除服务。这是因为若是出现网络分区致使其余微服务和该 Eureka Server 没法通讯,Eureka Server 就会断定这些微服务失效,但极可能这些微服务都是健康的。
  • Eureka Server 仍能接受新服务的注册和查询请求,但这些数据不会被同步到其余节点。
  • 当网络恢复时,这个 Eureka Server 节点的数据会被同步到其余节点中。

优势:

Eureka Server 能够很好的应对因网络故障致使部分节点失联的状况,而不会像 ZK 那样若是有一半不可用的状况会致使整个集群不可用。

服务网关

微服务的拆分致使服务分散,若是一个大的业务要对外提供输出,每一个服务单独对外提供调用对接入方不友好而且调用也会很复杂。因此出现了网关,网关主要实现请求的路由转发,负载均衡,统一校验,请求过滤等功能。

目前社区主流的网关有三个:Zuul,Kong,Spring Cloud GateWay。

Zuul

Zuul 是 Netflix 公司的开源项目,Spring Cloud 在 Netflix 项目中也已经集成了 Zuul,依赖名叫:spring-cloud-starter-netflix-zuul。Zuul构建于 Servlet 2.5,兼容 3.x,使用的是阻塞式的 API,不支持长链接,好比 websockets。咱们如今说的 Zuul 指 Zuul 1.x,Netflix 最新的 Zuul 2.x一直跳票,因此 Spring Cloud 在Zuul 2.x没有出的时候依靠社区的力量发展出了新的网关组件:Spring Cloud Gateway。

Zuul 的核心功能就是基于 Servlet 提供了一系列的过滤器:

  • 身份认证与安全:识别每一个资源的验证要求,并拒绝那些与要求不符的请求。
  • 审查与监控:在边缘位置追踪有意义的数据和统计结果,从而带来精确的生产视图。
  • 动态路由:动态地将请求路由到不一样的后端集群。
  • 压力测试:逐渐增长指向集群的流量,以了解性能。
  • 负载分配:为每一种负载类型分配对应容量,并启用超出限定值的请求。
  • 静态响应处理:在边缘位置直接创建部分相应,从而避免其转发到内部集群。

Spring Cloud Gateway

Spring Cloud Gateway 构建于 Spring 5+,基于 Spring Boot 2.x 响应式的、非阻塞式的 API。同时,它支持 Websockets,和 Spring 框架紧密集成,开发体验相对来讲十分不错。SpringCloud Gateway 是基于WebFlux框架实现的,而WebFlux框架底层则使用了高性能的Reactor模式通讯框架Netty。

整体来讲 Spring Cloud Gateway 与Zuul 功能差异不大,最大的出入是在底层性能的提高上。

Zuul 自己是基于 Servlet 容器来实现的过滤,Servlet采用的是单实例多线程的处理方案,Servlet会为每个Request分配一个线程,若是当前线程比较耗时那么会一直等到线程处理完毕才会返回。因此说 Zuul 是基于servlet之上的一个阻塞式处理模型。

同步阻塞模型对于网关这种比较在乎响应耗时和调用频繁的组件来讲,必然会引起一些性能问题,因此Zuul 2已经作出了改良,从Zuul 2开始已经使用Netty。可是不幸的是Spring 官方已经对它的更新频率感到失望因此纵然更新了也没有被选用。

Spring Cloud Gateway 底层基于Webflux。Webflux模式替换了旧的Servlet线程模型。用少许的线程处理request和response io操做,这些线程称为Loop线程。Webflux的Loop线程,正好就是著名的Reactor 模式IO处理模型的Reactor线程,若是使用的是高性能的通讯框架Netty,这就是Netty的EventLoop线程。

因此总体来看,Spring Cloud Gateway 的性能要比目前在用的 Zuul 高。可是Webflux的编程方式可能你们不是很能接收。

服务降级

降级限流在微服务中属于银弹,通常不用,一旦用上那就是拯救宇宙般存在。

目前业界通用的降级限流工具主要有3款:Hystrix,Sentinel,Resilience4j。

Hystrix 的关注点在于以 隔离熔断 为主的容错机制,超时或被熔断的调用将会快速失败,并能够提供 fallback 机制。Hystrix 是元老级别的存在,可是在18年11月 Netflix 官方宣布中止更新(就是这么不靠谱,说跳票就跳票)。虽然中止更新,可是社区又推出了新的替代工具:Resilience4j。

Resilience4j 的模块化作的比较好,将每一个功能点(如熔断、限速器、自动重试)都拆成了单独的模块,这样总体结构很清晰,用户也只须要引入相应功能的依赖便可;另外resilience4j 是针对 Java 8 和函数式编程设计的,API 比较简洁优雅。同时与 Hystrix 相比,Resilience4j 增长了简单的限速器和自动重试特性,使用场景更加丰富。

相比 Hystrix , Resilience4j的优点在于:

  • 针对 Java 8 和函数式编程设计,提供函数式和响应式风格的 API;
  • 增长了 rate limiting 和 automatic retrying 两个模块。其中 rate limiting 引入了简单的速率控制实现,补充了流量控制这一块的功能;
  • 而 automatic retrying 则是封装了自动重试的逻辑,简化了异常恢复的流程。

Resilience4j 属于一个新兴项目,社区也在蓬勃发展。总的来讲,Resilience4j 是比较轻量的库,在较小较新的项目中使用仍是比较方便的,可是 Resilience4j 只包含限流降级的基本场景,对于很是复杂的企业级服务架构可能没法很好地 cover 住;同时 Resilience4j 缺少生产级别的配套设施(如提供规则管理和实时监控能力的控制台)。

Sentinel 一款面向分布式服务架构的轻量级流量控制组件,主要以流量为切入点,从流量控制、熔断降级、系统自适应保护等多个维度来帮助用户保障服务的稳定性。

Sentinel 的核心思想:根据对应资源配置的规则来为资源执行相应的流控/降级/系统保护策略。在 Sentinel 中资源定义和规则配置是分离的。用户先经过 Sentinel API 给对应的业务逻辑定义资源,而后能够在须要的时候动态配置规则。

总体功能对比:

Sentinel Hystrix Resilience4j
隔离策略 信号量隔离(并发线程数限流) 线程池隔离/信号量隔离 信号量隔离
熔断降级策略 基于响应时间、异常比率、异常数 基于异常比率 基于异常比率、响应时间
实时统计实现 滑动窗口(LeapArray) 滑动窗口(基于 RxJava) Ring Bit Buffer
动态规则配置 支持多种数据源 支持多种数据源 有限支持
扩展性 多个扩展点 插件的形式 接口的形式
基于注解的支持 支持 支持 支持
限流 基于 QPS,支持基于调用关系的限流 有限的支持 Rate Limiter
流量整形 支持预热模式、匀速器模式、预热排队模式 不支持 简单的 Rate Limiter 模式
系统自适应保护 支持 不支持 不支持
控制台 提供开箱即用的控制台,可配置规则、查看秒级监控、机器发现等 简单的监控查看 不提供控制台,可对接其它监控系统

从上面的参照看,Sentinel 的功能相对要多一些,可是多并不意味着全部,合适的才是最好的,对于你用不到的功能,简单才是美丽。

统一配置中心

统一配置中心概念的提出也是伴随着微服务架构出现才出现,单体应用的时候全部的配置均可以集成在服务之中,多应用的时候若是每一个应用都持有一份配置可能会有相同配置冗余的状况;若是一共有2000台机器,若是一个配置发生更改,是否要登陆每一台机器从新更改配置呢;另外,更多的配置必然会带来管理上的混乱,若是没有集中管理的地方必然会愈来愈乱。

分布式配置管理的本质基本上就是一种推送-订阅模式的运用。配置的应用方是订阅者,配置管理服务则是推送方。其中,客户端包括管理人员publish数据到配置管理服务,能够理解为添加/更新数据;配置管理服务notify数据到订阅者,能够理解为推送。配置管理服务每每会封装一个客户端库,应用方则是基于该库与配置管理服务进行交互。在实际实现时,客户端库多是主动拉取(pull)数据,但对于应用方而言,通常是一种事件通知方式。

选型一个合格的配置中心,至少须要知足以下4个核心需求:

  • 非开发环境下应用配置的保密性,避免将关键配置写入源代码;
  • 不一样部署环境下应用配置的隔离性,好比非生产环境的配置不能用于生产环境;
  • 同一部署环境下的服务器应用配置的一致性,即全部服务器使用同一份配置;
  • 分布式环境下应用配置的可管理性,即提供远程管理配置的能力。

Diamond

最开始我接触过的配置中心是淘宝的 Diamond,Diamond中的数据是简单的key-value结构。应用方订阅数据则是基于key来订阅,未订阅的数据固然不会被推送。

Diamond是无单点架构,在作更新配置的时候只作三件事:

  • 写数据库
  • 写本地
  • 通知其余机器到数据库拉更新

本地的设计就是为了缓存,减小对数据库的压力。做为一个配置中心,高可用是最主要的需求。如何保持高可用,Diamond持有多层的数据存储,数据被存储在:数据库,服务端磁盘,客户端缓存目录,以及能够手工干预的容灾目录。 客户端经过API获取配置数据按照固定的顺序去不一样的数据源获取数据:容灾目录,服务端磁盘,客户端缓存。

Diamond除了在容灾上作了不少方案,在数据读取方面也有不少特色。客户端采用推拉结合的策略在长链接和短链接之间取得一个平衡,让服务端不用太关注链接的管理,又能够得到长链接的及时性。

使用Diamond的流程:

发布配置:

读取配置:

Diamond server是无中心节点的逻辑集群,这样就能避免单点故障。Diamond的同质节点之间会相互通讯以保证数据的一致性,每一个节点都有其它节点的地址信息,其中一个节点发生数据变动后会响应的通知其余节点,保证数据的一致性。

为了保证高可用,client还会在app端缓存一个本地文件,这样即便server不可用也能保证app可用。Client不断长轮询server,获取最新的配置推送,尽可能保证本地数据的时效性。

Client默认启动周期任务对server进行长轮询感知server的配置变化,server感知到配置变化就发送变动的数据编号,客户端经过数据编号再去拉取最新配置数据;不然超时结束请求(默认10秒)。拉取到新配置后,client会通知监听者(MessageListener)作相应处理,用户能够经过Diamond#addListener监听。

可是Diamond通常用途是作KV存储,若是用来作配置中心,他提供的能力不是太符合。

能够看到早期的配置中心处理的东西仍是比较简单,那个时候业务没有那么复杂,读取配置和更新配置没有那么多花样,持久化存储和本地缓存,长链接更新就能够。可是如今的配置中心随着技术的发展承担的做用可能更多,

Spring Cloud Config

Spring Cloud Config 做为Spring官方提供的配置中心可能比较符合外国人的习惯:

Spring Cloud Config将不一样环境的全部配置存放在git 仓库中,服务启动时经过接口拉取配置。遵循{ServiceID}-{profile}.properties的结构,按照profile拉取本身所需的配置。

当开发者修改了配置项以后,须要结合spring config bus将配置通知到对应的服务,实现配置的动态更新。

能够看到,Spring Cloud Config已经具有了一个配置中心的雏形,能够知足小型项目对配置的管理,但仍然有着不少局限性。配置使用git库进行管理,那么git库的权限如何来判断?不一样环境的安全性也得不到保障。配置的添加和删除,配置项的汇总,也只能经过git命令来实现,对运维人员也并不友好。

Apollo

Apollo(阿波罗)是携程框架部门研发的开源配置管理中心,可以集中化管理应用不一样环境、不一样集群的配置,配置修改后可以实时推送到应用端,而且具有规范的权限、流程治理等特性。

Apollo 支持4个维度管理 Key-Value 格式的配置:

  • application(应用):实际使用配置的应用,Apollo客户端在运行时须要知道当前应用是谁,从而能够去获取对应的配置;每一个应用都须要有惟一的身份标识 – appId,应用身份是跟着代码走的,因此须要在代码中配置。
  • environment(环境):配置对应的环境,Apollo客户端在运行时须要知道当前应用处于哪一个环境,从而能够去获取应用的配置。
  • cluster(集群):一个应用下不一样实例的分组,好比典型的能够按照数据中心分,把上海机房的应用实例分为一个集群,把北京机房的应用实例分为另外一个集群。对不一样的cluster,同一个配置能够有不同的值,如ZooKeeper地址。
  • namespace(命名空间):一个应用下不一样配置的分组,能够简单地把namespace类比为文件,不一样类型的配置存放在不一样的文件中,如数据库配置文件,RPC配置文件,应用自身的配置文件等;应用能够直接读取到公共组件的配置namespace,如DAL,RPC等;应用也能够经过继承公共组件的配置namespace来对公共组件的配置作调整,如DAL的初始数据库链接数。

Apollo配置中心包括:Config Service、Admin Service 和 Portal。

  • Config Service:提供配置获取接口、配置推送接口,服务于Apollo客户端;
  • Admin Service:提供配置管理接口、配置修改发布接口,服务于管理界面Portal;
  • Portal:配置管理界面,经过MetaServer获取AdminService的服务列表,并使用客户端软负载SLB方式调用AdminService。

上图简要描述了Apollo的整体设计,咱们能够从下往上看:

  • Config Service提供配置的读取、推送等功能,服务对象是Apollo客户端;
  • Admin Service提供配置的修改、发布等功能,服务对象是Apollo Portal(管理界面);
  • Config Service和Admin Service都是多实例、无状态部署,因此须要将本身注册到Eureka中并保持心跳;
  • 在Eureka之上咱们架了一层Meta Server用于封装Eureka的服务发现接口;
  • Client经过域名访问Meta Server获取Config Service服务列表(IP+Port),然后直接经过IP+Port访问服务,同时在Client侧会作load balance、错误重试;
  • Portal经过域名访问Meta Server获取Admin Service服务列表(IP+Port),然后直接经过IP+Port访问服务,同时在Portal侧会作load balance、错误重试;
  • 为了简化部署,咱们实际上会把Config Service、Eureka和Meta Server三个逻辑角色部署在同一个JVM进程中。

客户端设计:

上图简要描述了Apollo客户端的实现原理:

  1. 客户端和服务端保持了一个长链接,从而能第一时间得到配置更新的推送;
  2. 客户端还会定时从Apollo配置中心服务端拉取应用的最新配置
    • 这是一个fallback机制,为了防止推送机制失效致使配置不更新
    • 客户端定时拉取会上报本地版本,因此通常状况下,对于定时拉取的操做,服务端都会返回304 - Not Modified
    • 定时频率默认为每5分钟拉取一次,客户端也能够经过在运行时指定System Property: apollo.refreshInterval来覆盖,单位为分钟。
  3. 客户端从Apollo配置中心服务端获取到应用的最新配置后,会保存在内存中;
  4. 客户端会把从服务端获取到的配置在本地文件系统缓存一份;
    • 在遇到服务不可用,或网络不通的时候,依然能从本地恢复配置
  5. 应用程序从Apollo客户端获取最新的配置、订阅配置更新通知。

配置更新:

前面提到了Apollo客户端和服务端保持了一个长链接,从而能第一时间得到配置更新的推送。

长链接其实是经过Http Long Polling实现的,具体而言:

  • 客户端发起一个Http请求到服务端
  • 服务端会保持住这个链接60秒
    • 若是在60秒内有客户端关心的配置变化,被保持住的客户端请求会当即返回,并告知客户端有配置变化的namespace信息,客户端会据此拉取对应namespace的最新配置
    • 若是在60秒内没有客户端关心的配置变化,那么会返回Http状态码304给客户端
  • 客户端在收到服务端请求后会当即从新发起链接,回到第一步

考虑到会有数万客户端向服务端发起长连,在服务端使用了async servlet(Spring DeferredResult)来服务Http Long Polling请求。

调用链路分析

服务调用链路分析在微服务中是幕后相当重要的使者,试想几百个服务掺杂在一块儿,你想屡出谁先调用了谁,谁被谁调用,若是没有一个可监控的路径,光凭脑子跟踪那的多累。基于这种需求,各路大神们集中脑汁展开遐想弄出一套分布式链路追踪神器来。

在介绍调用链监控工具以前,咱们首先须要知道在微服务架构系统中常常会遇到两个问题:

  • 跨服务调用发生异常,要求快速定位当前此次调用出问题在哪一步;
  • 跨服务的调用发生性能瓶颈,要求迅速定位出系统瓶颈应该如何作。

打个比方说咱们有两个服务:订单中心,库存中心。用户下单,先去查询库存系统,那么调用链路分析系统对于一个下单查询服务应该记录什么呢?咱们造出以下一张调用链路请求记录表,表字段以下:

表字段说明:

  • id:自增id
  • span_id:惟一id
  • pspan_id:父级span_id
  • service_name:服务名称
  • api:api路径
  • stage:阶段/状态
  • timestamp:插入数据时的时间戳
id span_id p_span_id service_name api stage time_stamp
1 uid1 null order-center /shop/0001 cs t1
2 uid2 uid1 shop-center /getCount/0001 sr t2
3 uid2 uid1 shop-center /getCount/0001 ss t3
4 uid3 null order-center /shop/0001 cr t4

上表中的stage中的状态解释为:

  • CS(Client Sent 客户端发送):客户端发送一个请求,表示span的开始;
  • SR(Server Received 服务端接收):服务端接收请求并开始处理它。(SR - CS)等于网络的延迟;
  • SS(Server Sent 服务端发送):服务端处理请求完成,开始返回结束给服务端。(SR - SS)表示服务端处理请求的时间;
  • CR(Client Received 客户端接收):客户端完成接受返回结果,此时span结束。(CR - CS)表示客户端接收服务端数据的时间。

根据这个表咱们就能很快的分析上面提到的两个问题:

若是以上任何一步有问题,那么当前调用就不是完整的,咱们必然能追踪出来;

经过每一步的调用时间进行分析,咱们也必然知道阻塞在哪一步,从而对调用慢的地方进行优化。

现有的分布式Trace基本都是采用了google 的 Dapper 标准。

标准。

Dapper的思想很简单,就是在每一次调用栈中,使用同一个TraceId将不一样的server联系起来。

一次单独的调用链也能够称为一个span,dapper记录的是span的名称,以及每一个span的ID和父ID,以重建在一次追踪过程当中不一样span之间的关系。

对于一个特定的span,记录从Start到End,首先经历了客户端发送数据,而后server接收数据,而后server执行内部逻辑,这中间可能去访问另外一个应用。执行完了server将数据返回,而后客户端接收到数据。

在整个过程当中,TraceId和ParentId的生成相当重要。首先解释下TraceIdParentIdTraceId是标识这个调用链的Id,整个调用链,从浏览器开始放完,到A到B到C,一直到调用结束,全部应用在此次调用中拥有同一个TraceId,因此才能把此次调用链在一块儿。

既然知道了此次调用链的整个Id,那么每次查找问题的时候,只要知道某一个调用的TraceId,就能把全部这个Id的调用所有查找出来,可以清楚的知道本地调用链通过了哪些应用,产生了哪些调用。可是还缺一点,那就是链。

基于这种需求,目前各大厂商都作出了本身的分布式追踪系统,目前国内开源的有阿里的鹰眼,美团的CAT,京东的Hydra,还有广为人知的我的开源Apache顶级项目SkyWalking。国外的有Zipkin,Pinpoint。

Spring Cloud Sleuth + Zipkin

Spring Cloud Sleuth 实现了一种分布式的服务链路跟踪解决方案,经过使用Sleuth可让咱们快速定位某个服务的问题。简单来讲,Sleuth至关于调用链监控工具的客户端,集成在各个微服务上,负责产生调用链监控数据。

经过Sleuth产生的调用链监控信息,让咱们能够得知微服务之间的调用链路,可是监控信息只输出到控制台始终不太方便查看。因此咱们须要一个图形化的工具,这时候就轮到Zipkin出场了。Zipkin是Twitter开源的分布式跟踪系统,主要用来收集系统的时序数据,从而追踪系统的调用问题。

Spring Cloud Slueth 聚焦在链路追踪和分析,将信息发送到Zipkin,利用 Zipkin的存储来存储信息,固然,Zipkin也可使用ELK来记录日志和展现,再经过收集服务器性能的脚本把数据存储到ELK,则能够展现服务器情况信息。

PinPoint

pinpoint数据分析很是完备的。提供代码级别的可见性以便轻松定位失败点和瓶颈,对于执行的sql语句,都进行了记录。还能够配置报警规则等,设置每一个应用对应的负责人,根据配置的规则报警,支持的中间件和框架也比较完备。Pinpoint 是一个完整的性能监控解决方案:有从探针、收集器、存储到 Web 界面等全套体系。

Pinpoint 提供有 Java Agent 探针,经过字节码注入的方式实现调用拦截和数据收集,能够作到真正的代码无侵入,只须要在启动服务器的时候添加一些参数,就能够完成探针的部署。

对于这一点,Zipkin 使用修改过的类库和它本身的容器(Finagle)来提供分布式事务跟踪的功能。可是,它要求在须要时修改代码。pinpoint是基于字节码加强的方式,开发人员不须要修改代码,而且能够收集到更多精确的数据由于有字节码中的更多信息。

相对来讲,pinpoint界面显示的更加丰富,具体到调用的DB名,zipkin的拓扑局限于服务于服务之间。

SkyWalking

SkyWalking 和 pinpoint有一种既生瑜何生亮的感叹。SkyWalking 逻辑上分为四部分:

  1. 探针(SkyWalking-agent)
  2. 平台后端(oap-server)
  3. 存储(es)
  4. 用户界面(apm-webapp)

探针基于不一样的来源多是不同的(原生代理, SDK 以及 Zipkin, Jaeger 和 OpenCensus )、但做用都是收集数据、将数据格式化为 SkyWalking 适用的格式。

平台后端是一个支持集群模式运行的后台、用于数据聚合、数据分析以及驱动数据流从探针到用户界面的流程、平台后端还提供了各类可插拔的能力、如不一样来源数据(如来自 Zipkin)格式化、不一样存储系统以及集群管理、你甚至还可使用观测分析语言来进行自定义聚合分析。

存储是开放式的、你能够选择一个既有的存储系统、如 ElasticSearch, H2 或 MySQL 集群(Sharding-Sphere 管理)、也能够选择本身实现一个存储系统。

用户界面对于 SkyWalking 的最终用户来讲很是炫酷且强大、一样它也是可定制以匹配你已存在的后端的。

总结

以上是微服务过程全链路过程当中须要经历的阶段,固然还不包括发布系统的搭建,底层数据治理能力。因此提倡微服务能够,可是真的作起来不是全部公司都能作获得。小公司能作到服务拆分可是相应的配套设施不必定能跟上,大公司有人有钱有时间,才能提供这些基础设施。微服务的路任重道远,搭起来一套完整的设施并用于生产环境仍是挺有挑战,新的一年但愿我可以在践行微服务的路上走下去,只有走的完整才是微服务,走的不完整对于开发人员来讲,那就是过分开发,就是灾难。