前言
微服务是一整套体系,并不是仅仅代码上业务开发,为了开发的完整性,我们究竟得配置多少治理的设施。在这一章节,我们先了解这些设施的作用是什么,为何会存在和需要这些设施,以便在我们后面章节对这些设施做详细讲解有个概要的认识。
一个国家人多了就需要有一个政府,由这个政府组织起来各个行政部门负责起来各种行政职能,对企业人民进行管理和服务,保证企业的正常生产,人民的安居乐业。
在微服务体系也是如此,一个公司的微服务系统庞大多了,也是需要有对应支撑组织对业务模块进行服务和治理。
下面我们就一起来看下,一个中大规模的公司,想要让微服务能够 “Drop in 业务开发”,需要多少的治理支撑。
1. 我们需要配齐多少设施
1.1 服务注册发现
当我们开始使用微服务架构时,我们会将一个大的单体应用拆分成多个独立的小服务,然后必须满足每个小的服务之间能够相互进行通信,假设我们没有服务发现的支撑,我们只能用硬编码的方式将需要通信的服务的网络信息写在调用方的服务中。
但是,这样会出现一系列的问题:
- 通信方式例如网络地址有变化时无法及时通知消费者;
- 在生产环境中,每个服务一般都会部署多个实例以实现负载均衡,当要对一组服务增加或减少实例,都得去相应改动消费者的编码。
要解决这个问题,就必须引入一个服务注册发现机制,服务生产者将自己的信息注册到服务注册中心,服务消费者再从注册中心进行拉取。这样,即使生产者的信息发生了变化,消费者也无需改动配置。
在微服务架构中,服务发现组件是一个非常重要的组件,目前常用的组件有以下几种:
- ZooKeeper;
- EureKa;
- Consule;
- Nacos。
1.2 配置中心
配置中心,顾名思义,就是用统一管理项目中所有的配置系统。
在项目中,我们可以简单理解程序 = 代码 + 配置。我们在程序中需要对一些参数进行自定义的配置,但我们并不想把这些配置直接写在代码中,为了方便修改,并让系统有更好的扩展性,我们会将这些配置写在工程的配置文件中。
在单体应用中,我们可以把所有的配置项集中在某个问题或某几个文件中,但是在微服务体系中,由于微服务众多,服务之间又是相互调用相互依赖,为每个服务进行配置文件就显得非常的难以管理。
如果没有配置中心,我们强行将配合文件写在各个工程中会有以下几个的问题:
- 配置文件过于分散,难以管理;
- 配置文件无法区分环境,可能我们的代码工程会运行在几套环境中,可能每个环境的参数各不相同,就得靠手动进行维护;
- 静态化配置,每次修改都必须通过修改文件并且重启工程来进行生效;
- 配置文件无法追溯,除了用代码本身的版本管理,否则无法进行追溯。
配置中心的思路就是把项目中各种配置,各种的参数都集中到一个地方进行统一的管理,并提供标准的接口。当服务需要获取配置,就通过接口进行拉取,当配置中心的配置和参数有了变化,也能实时同步到各个服务。
也就是说,配置中心需要解决和满足一下几个问题:
- 配置集中管理;
- 在系统运行期间可以动态配置,并实时刷新到服务;
- 高可用。
我们常用的配置中心的组件有:Apollo,Nacos,Disconf,SpringCloud Config 等等。
1.3 负载均衡
在微服务架构中,负载均衡是必须使用的技术,通过它来实现系统的高可用、集群扩容等功能。
一般来说,在微服务中有 2 种模式的负载均衡,一种是中间件负载均衡,一种是客户端负载均衡,这两种都微服务开发都有充分的使用。
先说中间件负载均衡器:客户先请求到负载均衡器,然后负载均衡器根据负载均衡算法将请求转发到微服务,在接入层的 LB 就是一个典型的负载均衡器。
还有一种就是客户端的负载均衡,客户端本身维护服务提供者的列表,和自身进行负载均衡的算法对服务提供者进行调用。
SpringCloud Ribbon 就是基于客服端的负载均衡工具,它可以将面向服务的 REST 模板请求自动转换成客户端负载均衡的服务调用:
负载均衡算法有:轮训、随机、加权轮训、加权随机、地址哈希等等,这些将在后面章节详细说到。
1.4 网络通讯
在微服务中,使用什么协议来构建服务体系?一般由两种选择:RPC 和 REST API:
- RPC:Remote Produce Call 远程过程调用,基于原生的 TCP 通讯,速度快,效率高。
- REST:是 Http 协议通讯,底层也是基于 TCP,规定了数据传输的格式,目前在 web 浏览器和服务器通讯大量使用,也可以用来进行远程服务调用。
优劣对比:
- 从使用的方面来看,REST 接口只需要关注提供方,客户端只要也用 Http 方式进行调用即可,可能不要考虑双方使用的语言,客户端只要通过接口发起调用即可,业务开发人员只需要关注业务方法,不需要关注网络传输细节。
- 从性能角度来看,REST 接口使用 Http 协议进行传输,导致在网络传输过程中,携带信息过多。而 RPC 服务一般只需要关注传输相关业务即可,传输数据更小,性能更高。
1.5 序列化
序列化是用来通信,服务端把数据序列化,发送到客户端,客户端把接受到的数据反序列化得到对应的数据,然后再讲数据序列化后发送到服务端,服务端再反序列化得到相应的数据。说白了,数据需要经过序列化后变成二进制流才能在服务端和客户端中传输。
常用的有下面几种序列化:
- Hessian2 序列化 : hessian 是一种跨语言的高效二进制序列化方式,它是 Dubbo RPC 协议默认的序列化方式;
- Dubbo 序列化 : 并不成熟,Dubbo 序列化其实不是 Dubbo RPC 默认的序列化;
- Java 序列化 :JDK 自带的 Java 序列化实现,效果并不理想。
1.6 安全认证
有些服务并不希望所有的人都能去调用到,涉及到一些敏感信息,比例跟钱相关的信息,那么我们需要安全和访问的控制策略,来限制对这些服务的访问。
我们这里说的安全访问指的是服务间的调用,而不是外部用户的调用,外部用户可以走 API 网关。
1.7 断路限流
断路,限流,降级,超时,隔离是一整套容错的组合拳。
在介绍断路之前,我们先了解微服务的雪崩效应。在微服务体系中由多个服务进行组成,服务之间的数据交互通过远程调用完成,这样带来一个问题,假设服务 A 调用服务 B 和服务 C,服务 B 又调用了服务 D 和服务 E,服务 C 又调用服务 F,这样就出现所谓的扇出,如果扇出的链路上某个服务调用出现不可用或者调用相应时间过长,那么服务 A 的调用资源会占用越来越多,因为服务 A 是入口资源,进而引起系统崩溃,这个就是所谓的雪崩效应。
当服务 E 出现问题,会导致服务 B 也出现问题,服务 B 出现问题会导致服务 A 出现问题,而的入口服务 A 的崩溃,就是整个系统的崩溃。
从可用性和可靠性触发,为了防止系统的整体崩溃,必须采用对应该的技术手段,采用的手段都是从系统可用性,可靠性角度出发,尽量防止系统整体缓慢甚至瘫痪。
- 服务熔断:是对雪崩效应的一种微服务链路保护机制;
- 服务降级:整体资源不够用,主动关闭部分服务,或在出现熔断情况下出现的兜底方案;
- 服务限流:当出现流量超越了整体系统可以承接的流量,系统主动做出管控,只允许部分流量进入,拒绝或延后其他流量;
断路降级限流,在微服务体系中是一个很大的保证性组件,在后续章节会作为一个大课题进行讲解。
1.8 链路跟踪
微服务将一个庞大的系统切分成各个小的服务,各个服务之间相互依赖,共同协同调用构建成整个系统。这个就是造成我们整个系统有复杂的调用链路,如果一个调用链路错误,如何快速定位错误资源,一个调用链路影响缓慢,如何快速定位其中延迟高的服务。
调用链漫长并且复杂,要了解每一个环节,我们需要全链路跟踪,应用的原理也很简单,就是在请求的开端,生成一个唯一的 ID,并将其传递到整个调用链,这样就可以根据整个 ID 来跟踪整个请求并获取各个调用环节的性能指标。
1.9 监控报警
监控是微服务治理的一个重要环节,监控系统的完善程度直接影响到我们微服务质量的好坏,我们的微服务在线上运行的时候有没有一套完善的监控体系能去了解到它的健康情况,对整个系统的可靠性和稳定性是非常重要。
微服务监控是一整套系统性的监控,一个比较完善得微服务监控体系需要涉及到哪些层次,以下划分为 5 个层次的监控
- 最底层基础设施监控;
- 系统层监控;
- 应用层监控;
- 业务监控;
- 端用户体验监控。
这个后续章节我们会对各个监控层面进行详细讲解。
1.10 统一日志
微服务将原来的单体应用拆分成 N 个服务分布在不同的机器,原来的单个日志也被分布在 N 台机器,日志对我们后期排查问题,定位问题非常关键,而分散的日志对监控和查看势必造成巨大的困扰。
解决这个问题,其实比较简单,只要解决 日志采集,日志存储,日志分析可视化日志数据,市面上 ELK 是一套比较成熟方案。
1.11 API 文档
在单体传统的 API 文档输出,是由一个组或一个团队统一的输出,这个时候比较容易进行规范。但在微服务中,每个文档都是由各个团队进行输出,这个时候容易出现:
- API 接口规则返回信息不明确;
- API 接口更新还关系到通知调用者,导致文档更新交流不断;
- 缺少在线接口测试,通常需要额外的 API 测试工具,例如 postman;
- 接口文档太多,不便于管理。
解决以上问题,可以引入比较成熟的统一生成 API 文档工具。例如 Swagger , 可以在较多层面解决上述问题,也便于统一管理。
1.12 统一异常
我们希望服务治理的环节能集成统一的服务异常处理的能力,这样的化异常能够达到更加标准化,出现问题能更好定位好属于什么类型的问题。如果说没有这样的一个环节,大家各自的玩法不一样,抛的异常各异,出现问题难以定位和无法标准化友好输出。
1.13 代码规范
现在在大规模开发的情况下,比较推从一个契约驱动开发的方法,开发人员先定立契约,代码自动生成的方式生成对应的代码脚手架,这个在大规模开发的时候更能确保代码的一致和规整。
1.14 集成 DB MQ Cache
微服务治理的核心思路就是把上面讲到的各个环节沉淀下来,变成平台和框架的一部分,开发人员可以更加专注业务逻辑的实现,在实现业务逻辑的时候不需要去关注外部环节的,从而提升开发的效率,治理环节沉淀在框架之中有专门的平台架构团队去进行管控。
2. 小结
在这一节,我们初步了解了能让我们业务代码 “安居乐业” 配套的各个部门,从一个大概知道每个部门存在的意义是什么,在下面的章节中,我们会逐个敲开这些部门的大门,进入一探究竟。