微服务开发框架及核心功能
![](https://img2022.cnblogs.com/blog/793707/202211/793707-20221122154729579-535192530.png)
1.服务容器负责启动,加载,运行服务提供者;
2.服务提供者在启动时,向注册中心注册自己提供的服务;
3.服务消费者在启动时,向注册中心订阅自己所需的服务;
4.在注册中心返回服务提供者地址列表给消费者,如果有变更,注册中心将基于长连接推送变更数据给消费者;
5.服务消费者,从提供者地址列表中,基于软负载均衡算法,选一台提供者进行调用,如果调用失败,再选另一台调用;
6.服务消费者和提供者,在内存中累计调用次数和调用时间,定时每分钟发送一次统计数据到监控中心;
微服务框架核心功能
服务注册发现
微服务的注册发现是指应用的客户端与服务端的服务注册表进行交互,整个交互过程分为服务端的自注册和客户端的发现两个步骤。服务端的自注册是指服务实例向服务注册表注册,而客户端的发现是指客户端从服务注册表检索可用服务实例,并在它们之间进行负载均衡。同时服务注册表会定期调用服务API所提供的“运行状态检测”端点,来验证服务实例是否正常且处于可用状态。有时服务注册表还可能要求服务实例定期调用“心跳”API,以防止其注册过期。
Eureka是Netflix开源的一个高可用服务注册表,Eureka Java的客户端Ribbon是一个支持Eureka客户端的复杂HTTP客户端。
服务负载路由
在实施微服务的过程中,不免要面对服务的聚合与拆分。当后端服务的拆分相对比较频繁时,前端服务往往需要一个统一的入口,将不同的请求负载均衡路由到不同的后端服务,无论后端服务如何聚合与拆分,对于前端来讲都是透明的。有了API网关以后,简单的数据聚合可以在网关层完成,同时还可以进行统一的认证和鉴权。尽管服务之间的相互调用比较复杂,接口也比较多,但API网关往往只暴露必需的对外接口,并且对接口进行统一的认证和鉴权,使得内部的服务相互访问时不用再进行认证和鉴权,效率会比较高。有了统一的API网关,还可以在这一层设置一定的策略进行A/B测试、蓝绿发布、预发布环境导流等。API网关往往是无状态的,可以横向扩展,从而不会成为性能瓶颈。
Netflix Zuul就是一个典型的API网关
统一配置
一个配置中心来管理所有的配置,进行统一的配置下发。如果配置项发生变更,配置中心会通过通知服务告诉各个微服务实例关于配置项的变更情况,各个微服务实例收到配置项变更的通知后,使新的配置项生效,这样就实现了应用的动态更新。
微服务中的配置往往分为三类:
第一类是几乎不变的配置,这种配置可以被直接打包在容器镜像文件中;
第二类是启动时确定的配置,这种配置往往通过环境变量在容器启动时传进容器中;
第三类就是统一的配置,需要通过配置中心进行下发。如果将配置写到配置文件中,那么当遇到修改配置的情况时成本会很高,并且没有配置修改的记录,出问题很难追溯。
使用配置中心可以直接解决以上问题,可配置内容包括数据库连接、业务参数等。配置中心就是一个Web服务,配置人员通过后台页面修改配置,各个服务就会得到新的配置参数。
其实现方式主要有两种:Push和Pull。这两种方式各有优缺点:Push实时性较好,但是遇到网络抖动时会丢失消息;Pull不会丢失消息,但是其实时性差一些。
服务编排与弹性伸缩
将应用拆分后,微服务就会非常多,因此需要服务编排来管理微服务之间的依赖关系,以及将微服务的部署代码化,也就是Infrastructure as Code(基础设施即代码)。这样一来,服务的发布、更新、回滚、扩容、缩容等都可以通过修改编排文件来实现,从而增加了可追溯性、易管理性和自动化的能力。既然编排文件也可以用代码仓库进行管理,那么就可以实现部分升级。
编排一般分为资源编排和服务编排两类。资源编排定义所需的物理资源(如主机、CPU、内存、VPC、路由表、磁盘等),其对应Infrastructure as Code。服务编排以服务为中心,定义服务的弹性伸缩、灰度发布、滚动升级、资源配置等功能组合,其对应Application as Code。具体来说,编排包括批量部署、优雅启停、弹性伸缩。
流量管控
当微服务数量越来越多时,需要一种服务治理机制对所有微服务进行统一管控,保障微服务的正常运行。微服务治理覆盖整个生命周期,从微服务建模、开发、测试、审批、发布到运行时的管理及下线。而微服务中的服务治理主要是指运行时的治理,除了前面所讲的配置、健康检查等,还包括熔断、限流、降级等流量管控。
熔断:是指一个远程微服务调用在连续失败次数超过指定的阈值后的一段时间内会拒绝其他调用。例如,Spring Cloud的Hystrix就为保护服务依赖提供了熔断机制的开源库。
限流:通过全链路的压力测试,应该能够知道整个应用的支撑能力,因此制定了限流策略,保证应用处理请求处于其支撑能力范围内,超出其支撑能力范围的请求处理可被拒绝。例如,使用下单服务时弹出对话框,显示“系统忙,请重试”,这并不代表下单应用停止服务了,而是限流策略起到了作用。
降级:是指当发现整个应用服务负载过高时,可以选择降级某些功能来保证最重要的交易流程正常工作,以及最重要的资源全部用于保证最核心的流程。假设服务A依赖服务B和服务C,而服务B和服务C可能又依赖其他服务,继续下去会使得调用链路过长。如果在服务A后续的链路上某个或某几个被调用的微服务不可用或者延迟较高,则会导致调用服务A的请求被堵住。被堵住的请求会占用系统的线程、I/O等资源,当该类请求越来越多时,占用的资源就会越来越多,从而导致系统出现瓶颈,造成其他请求同样不可用,最终导致业务应用崩溃,所以应当及时将服务A降级。
可观察运维
1.健康检查
服务实例需要告诉微服务框架它是否可以处理请求,而微服务框架一般会调用服务提供的健康检查API,如GET/health来返回服务实例的状况。
2.统一日志聚合
对于故障排查,日志是必不可少的。由于微服务众多使其日志分散在不同的地方,因此需要通过日志聚合在支持搜索的集中式数据库中聚合所有微服务的日志。日志聚合将所有服务实例的日志发送给集中式日志服务器。在日志服务器中存储日志后,我们可以查看、搜索和分析日志,还可以配置在日志中出现某些消息时触发告警。在基于容器、Kubernetes 的微服务应用中,通常每个微服务实例的日志不是存储在服务实例的日志文件中的,而是应当把日志输出到stdout,由微服务框架决定如何处理。
3.监控告警
监控系统从技术栈的每个部分收集指标,这些指标提供有关应用程序健康状况的关键信息。这些指标涵盖的范围从基础设施的相关指标(如CPU、内存、磁盘等)到应用级别的指标(如服务请求延迟时间和执行请求数等)。监控服务收集各类指标,将指标数据发送给负责聚合、可视化和告警的中央监控服务。
目前主流监控系统采用Pull模型,监控服务调用各个微服务的监控API,从微服务实例检索指标信息。例如 Prometheus,该服务会定期轮询指定端口以检索指标。将指标数据保存在Prometheus中,可以通过可视化工具Grafana查看。
4.全链路追踪
全链路追踪把一个请求从进入微服务应用到返回过程中的相关数据,包括函数性能、错误日志、异常堆栈、访问缓存、数据库性能等数据联合起来,形成一个诊断闭环。其目的是当一个请求经过多个微服务时,可以通过一个固定值获取整条请求链路的行为日志,基于此可以进行分析等,衍生出一些性能诊断的功能。全链路追踪的首要目的就是问题定位,出了问题需要快速定位到发生异常的微服务,了解整个请求的链路是怎样的。
常用的轻量化解决方案是在日志中打印RequestId和TraceId来标识链路。请求(Request)在网关(Gateway)上会生成唯一的RequestId,并在后续调用其他微服务时一直透传该RequestId,保证这个请求在整个应用的处理过程中通过该RequestId可以把所有相关数据串联起来。同时还会使用到TraceId,TraceId相当于二级路径,在TraceId刚生成时,它与RequestId一样,但进入线程池或者消息队列后,TraceId会增加标记来标识唯一一条路径。