• 微服务架构(持续更新)


    微服务架构进化论

    单体应用阶段

    img

    单体应用的特点

    能够接纳的请求数量有限(服务器的内存,CPU配置有限)

    表现层,控制层,持久层都在一个应用里面,调用方便,快速。单个请求响应结果快

    开发简单,上手快,三五人团队建议使用

    垂直应用阶段

    img

    处理并发请求的能力和容量上增强,但是在单个请求的处理速度上下降。

    分布式系统阶段

    img

    服务治理阶段(SOA)

    img

    针对分布式系统存在的问题,可以通过服务治理基础服务来解决,随着服务数量的不断增加,服务中的资源浪费和调度问题加重,需要增加一个调度中心来治理服务。调用中心可以基于访问压力来实时管理集群的容量,从而提高集群的利用率。“在服务治理架构中,需要一个企业服务总线(ESB)将基于不同协议的服务节点连接起来,它的工作是转换,解释消息和路由”。

    微服务阶段

    img

    将系统的业务功能划分为极小的独立微服务,每个微服务只关注于完成某个小的任务。系统中的单个微服务可以被独立部署和扩展,且各个微服务之间是高内聚、低耦合的。微服务之间采用轻量化通信机制暴露来实现通信。

    组件解释

    • 服务网关:前台接待,Spring Cloud Gateway。
    • 熔断机制:什么时间提供什么,提供的量的大小。
    • 工作效率监督:工作流程的内容,时长监督,什么环节出了问题,Sleuth、日志监控ELK等。
    • 配置中心:菜单(各种菜系)
    • 服务集群:微服务集群,各个服务
    • 高可用注册中心:大堂经理,负责的人上班了,具体在哪里工作干了什么

    微服务拆分规范和原则

    压力模型拆分

    压力模型简单来说就是用户访问量,我们要识别出某些超高的并发量的业务,尽可能把这些业务拆分出来。

    压力模型拆分三个维度
    高并发场景

    如商品详情页,不仅是个高频场景也是高并发场景(QPS极高)

    低频突发场景

    如秒杀场景(偶尔发生)会突发大流量

    低频流量场景

    后台运营团队的服务接口,比如商品图文编辑,添加新的优惠计算规则,上架新商品。它发生的频率比较低,而且也不会造成很高的并发量

    业务模型拆分

    业务模型拆分的维度很多,实际中应用综合各个不同维度做考量,主要有三个维度(主链路、领域模型、用户群体)

    主链路拆分

    电商领域“主链路”是一个至关重要的业务链条,指的是用户完成下单场景所必须经过的场景。如商品搜索->商品详情页->购物车模块->订单结算->支付业务。

    核心业务拆分的目的

    异常容错:为主链路建立层次化的降级策略(多级降级),以及合理的熔断策略。

    调配资源:主链路通常是高频场景,体现在集群分配的虚拟机数最多

    服务隔离:把主链路和其它辅助的业务隔离开来,避免边缘服务的异常情况影响到主链路

    领域模型拆分
    用户群体拆分

    用户群体相当于一个二级域,我们建议先根据主链路和领域模型做一级域的拆分,再结合具体的业务分析,看是否需要在用户领域方向上做更细粒度的拆分。

    SpringCloud

    SpringCloud是一个基于SpringBoot实现的微服务架构开发工具。它为微服务架构中涉及的配置管理、服务治理、断路器、智能路由、控制总线、分布式会话和集群状态管理等等操作提供了一种简单的开发方式。

    img

    img

    服务注册选型

    1. Eureka:SpringCloud和Netflix的大儿子
    2. Nacos:后起之秀,曾经SpringCloud眼中别人家的孩子,已经纳入收养范围(SpringCloud Alibaba孵化项目)
    3. Apache Zookeeper:关系化,与Hadoop关系比较好
    4. etcd:关系户,与kubernetes关系比较好
    5. consul:关系户,曾经和docker关系比较好

    如果项目中已经使用到了Hadoop、kubernetes、Docker等的话,在SpringCloud实施过程中可以考虑其它组件,避免搭建两套注册中心,浪费资源

    分布式配置管理

    目前可选的分布式配置管理中心有,阿里的Nacos、携程的Apollo、SpringCloud Config

    服务网关

    推荐使用SpringCloud GateWay在各方面都比Zuul好

    熔断限流

    Hystrix

    2018年12月,Spring官方宣布Netflix的相关项目进入维护模式,不再开发新的功能,但是Hystrix整体上比较稳定。

    resilience4j

    在Hystrix停更之后,NetFlix官方推荐使用resilience4j,它是一个轻量级的、易用、可组装的高可用框架、支持熔断、高频控制、隔离、限流、重试等多种高可用机制。

    Sentinel

    Sentinel是阿里中间件团队开源的,面向分布式服务架构的轻量级高可用流量控制组件,主要以流量为切入点,从流浪控制、熔断降级、系统负载保护等多个维度来帮助用户保护服务的稳定性。

    特性总结

    img

    三大功能指的是微服务核心组件的功能维度,由浅入深层次递进;两大特性是构建在每个服务组件之上的高可用性和高扩展性。

    服务注册发现和治理

    img

    在没有进行服务治理之前,服务之间的通信是通过服务间直接相互调用来实现的。

    微服务系统中服务众多,这样会导致服务间的相互调用不方便,要记住提供服务的IP、名称、端口等。

    img

    服务治理的责任

    1. who:服务注册-服务提供方自报家门
    2. where:服务发现-服务消费者拉取注册数据
    3. how:心跳检测,服务续约和服务剔除一套由服务提供方和注册中心配合完成的去伪存真的过程
    4. leave:服务下线-服务提供方发起主动下线

    服务注册发现Eureka

    Eureka是Netflix开发的注册发现组价,是一个基于REST的服务,不仅提供注册发现,还提供了负载均衡,故障转移的能力。

    服务中心-服务提供者-服务消费者(三个角色)

    img

    Eureka Server:服务器端,提供服务的注册和发现功能,实现服务的治理

    Service Provider:服务提供者,它将自身服务注册到Eureka Server中,方便服务消费者通过服务器端提供的服务清单(注册服务列表)来调用

    Service Consumer:服务消费者。从Eureka获取已经注册的服务列表,实现服务消费

    Eureka和Zookeeper对比

    Eureka是AP架构,Zookeeper是CP架构。

    CAP原则又称CAP定理,指的是在一个分布式系统中,一致性(Consistency)、可用性(Availability)、分区容错性(Partition tolerance),但是CAP 原则指示3个要素最多只能同时实现两点,不可能三者兼顾,由于网络硬件肯定会出现延迟丢包等问题,但是在分布式系统中,我们必须保证部分网络通信问题不会导致整个服务器集群瘫痪,另外即使分成了多个区,当网络故障消除的时候,我们依然可以保证数据一致性,所以我们必须保证分区容错性;

    至于剩下的一致性和可用性,我们需要二选一,但是鱼和熊掌不可兼得,假设我们选择一致性,那我们就不能让用户访问无法进行数据同步的机器,毕竟该机器上的数据和其他正常机器上的不一致,但是这样我们就丢弃了可用性;假设我们选择可用性,那我们就可以让用户访问无法进行数据同步的服务器,虽然保证了可用性,但是我们无法保证数据一致性。

    AP结构选择了高可用和分区容错性,此时,那个失去联系的节点依然可以向系统提供服务,不过它的数据就不能保证是同步的了(失去了C属性)。Eureka就是一个AP架构的例子,当Eureka客户端心跳消失的时候,那Eureka服务端就会启动自我保护机制,不会剔除该EurekaClient客户端的服务,依然可以提供需求;

    CP结构选择的是一致性和分区容错性,如果选择一致性C(Consistency),为了保证数据库的一致性,我们必须等待失去联系的节点恢复过来,在这个过程中,那个节点是不允许对外提供服务的,这时候系统处于不可用状态(失去了A属性)。最好的例子就是zookeeper,如果客户端心跳消失的时候,zookeeper会很快剔除该服务,之后就无法提供需求;

    服务注册发现

    img

    参数

    Environment: 环境,默认为test,该参数在实际使用过程中,可以不用更改

    Data center**: 数据中心,使用的是默认的是** “MyOwn”

    Current time**:当前的系统时间**

    Uptime**:已经运行了多少时间**

    Lease expiration enabled:是否启用租约过期 ,自我保护机制关闭时,该值默认是true,自我保护机制开启之后为false。

    Renews threshold: 每分钟最少续约数,Eureka Server 期望每分钟收到客户端实例续约的总数。

    Renews (last min): 最后一分钟的续约数量(不含当前,1分钟更新一次),Eureka Server最后 1 分钟收到客户端实例续约的总数。

    img

    参数:

    这个下面的信息是这个Eureka Server相邻节点,互为一个集群。注册到这个服务上的实例信息

    img

    • Application:服务名称。配置的spring.application.name属性 。 AMIs:n/a,字符串n/a+实例的数量。
    • Availability Zones:实例的数量。
    • Status:实例的状态 + eureka.instance.instance‐id的值.实例的状态分为UP、DOWN、STARTING、
      OUT_OF_SERVICE、UNKNOWN.。
    • UP:服务正常运行,特殊情况当进入自我保护模式,所有的服务依然是UP状态,所以需要做好熔断重试等容错机制应对灾难性网络出错情况。
    • OUT_OF_SERVICE : 不再提供服务,其他的Eureka
    • Client将调用不到该服务,一般有人为的调用接口设置的,如:强制下线。 UNKNOWN: 未知状态。 STARTING:表示服务正在启动中。
    • DOWN: 表示服务已经宕机,无法继续提供服务。

    img

    total-avail-memory : 总共可用的内存

    environment : 环境名称,默认test

    num-of-cpus : CPU的个数

    current-memory-usage : 当前已经使用内存的百分比

    server-uptime : 服务启动时间

    registered-replicas : 相邻集群复制节点

    unavailable-replicas :不可用的集群复制节点,如何确定不可用? 主要是server1 向

    server2和server3发送接口查询自身的注册信息。

    available-replicas :可用的相邻集群复制节点

    img

    ipAddr:eureka服务端IP

    status:eureka服务端状态

    服务自我保护和剔除机制

    img

    服务自保和剔除,不能同时使用

    服务剔除

    img

    服务剔除把服务节点剔除,即使续约的请求发过来也没有用

    服务自保

    img

    服务自保把当前所有节点保留。在实际应用里面,并不是所有无心跳的服务都不可用,可能是因为短暂的网络抖动等原因,导致服务节点和注册中心续约不上,但是服务节点之间的调用还是可用状态,这时候强行剔除服务节点可能会造成大范围的业务停滞。

    服务自保模式是为了应对短暂的网络环境问题,在理想的服务节点的续约成功率为100%,如果突然发生网络问题,如一部分机房无法连接到注册中心,这时候续约的成功会降低。考虑到Eureka采用客户端的服务注册发现模式,客户端所有的节点的地址,如果服务节点只是因为网络原因无法续约,但其自身服务是可用的,那么客户端仍然可以成功发起调用请求,这样就避免了被服务剔除错杀。

    服务自保手动开关

    关闭服务保护机制,默认为true
    eureka.server.enable-self-preservation: false

    RestTemplate

    RestTemplate是从Spring3.0开始支持的一个HTTP请求工具,它提供了常见的REST请求方案的模板,例如GET、POST、PUT、DELETE请求以及一些通用的请求方法exchange和execute。

    @Configuration
    public class CloudConfig{
        @LoadBalanced
        @Bean
        public RestTemplate restTemplage(){
            return new RestTemplate();
        }
    }
    
    //测试Controller
    @RestController
    @RequestMapping("/test")
    public class TestRestController{
        
        //HTTP请求工具
        @Autowired
        private RestTemplate restTemplate;
        
        @GetMapping("/index")
        public String index(){
           //1.远程调用方法的主机
           //Stringhost="http://localhost:1000";
           //将远程微服务调用地址从"IP地址+端口号改成"微服务名称""
            String host = "http://xxx.xx.xx"; 123456789
            // 2. 远程调用方法具体URL地址
            String url = "/payment/index";
            // 3. 发起远程调用
            //getForObject:返回响应体中数据转化成的对象,可以理解为json
            //getForEntity:返回的是ResponseEntity的对象包含了一些重要的信息
            String forObject = restTemplate.getForObject(host + url,String.class);
            return forObject;
       }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34

    高可用注册中心Eureka

    img

    以SpringCloud为基础的微服务架构,所有的微服务都需要注册到注册中心,如果这个注册中心阻塞或者崩了,那么整个系统都无法继续正常提供服务,所以这里就要对注册中心搭建高可用(HA)集群。

    Eureka Server的设计从一开始就考虑到了高可用的问题,在Eureka的服务治理设计中,所有节点即是服务的提供方,也是服务消费方,服务注册中心也不例外。

    客户端负载均衡

    img

    负载均衡有,服务端负载均衡和客户端负载均衡

    服务端负载均衡

    在服务集群内设置一个中心负载均衡器,比如Nginx。发起服务间调用的时候,服务请求并不直接发向目标服务器而是发给全局负载均衡器,再根据配置的负载均衡策略将请求转发到目标服务。

    img

    优点:

    服务端负载均衡应用范围非常广泛,它不依赖服务发现技术,客户端并不需要拉取完整的服务列表,同时发起服务调用的客户端也不用操心使用什么负载均衡策略。

    缺点:

    网络消耗,复杂度和故障率提升

    客户端负载均衡

    Spring Cloud LoadBalaner

    Spring Cloud LoadBalaner 采用了客户端负载均衡技术,每个发起服务调用的客户端都存有完整的目标服务地址列表,根据配置的负载均衡策略,由客户端决定向哪台服务器发起调用。

    优点:网络开销小、配置简单

    缺点:需要满足一个前置条件,发起服务调用的客户端需要获取所有目标服务的地址,这样才能使用负载均衡规则选取调用的服务。客户端负载均衡技术需要依赖服务发现来获取服务列表

    Spring Cloud Ribbon

    Ribbon有助于Http和TCP的客户端,可以根据负载均衡算法(轮询、随机或者自动义)自动的帮助消费者的请求,默认就是轮询

    Ribbon已经停更,替代方案(Spring Cloud LoadBalancer)

    客户端负载均衡策略

    1. RandomRule - 随性而为
    2. RoundRobinRule - 按部就班(轮询)
    3. RetryRule - 卷土重来
    4. WeightedResponseTimeRule - 能者多劳
    5. BestAvailableRule - 让最闲的人来
    6. AvailabilityFilteringRule - 我是有底线的
    7. ZoneAvoidanceRule - 我的地盘我做主

    OpenFeign

    img

    Spring Cloud OpenFeign 用于Springboot应用程序的声明式REST客户端

    OpenFeign和Feign的区别

    Feign是一个声明式WebService客户端,使用Feign能让编写WebService 客户端更加简单(使用方法是定义一个服务接口然后在上面加注解)。支持可插拔式的编码器和解码器。Spring Cloud 对Feign进行了封装,支持SpringMVC标准注解和HttpMessageConverters

    img

    OpenFeign日志增强

    OpenFeign提供了日志增强功能,默认是显示任何日志的可以配置

    日志级别

    NONE:默认不显示任何级别

    BASIC:仅记录请求方法,URL、响应状态码

    HEADER:除了BASIC中定义的信息之外,还有请求呵呵响应的头信息

    FULL:除了HEADER中定义的信息之外,还有请求和响应的正文和元数据

    @Configuration
    public class OpenFeignConfig{
        
        /**
        * 日志级别定义
        */
        
        //Logger包位于Feign
        @Bean
        Logger.Level feignLoggerLevel(){
            return Logger.Level.FULL;
       }
    }
    
    /**
    配置文件配置接口日志级别
    logging:
       level:
         com.service: debug #openfeign接口所在包名
    */
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    OpenFeign超时机制

    服务消费者在调用服务提供者的时候发生了阻塞、等待的情形,这个时候,服务消费者会一 直等待下去。 在某个峰值时刻,大呈的请求都在同时请求服务消费者,会造成线程的大呈堆积,势必会造成雪崩。 利用超时机制来解决这个问题,设置一个超时时间,在这个时间段内,无法完成服务访问, 则自动断开连接。

    雪崩

    服务和服务之间的依赖性,故障会传播,造成连锁反应,会对整个微服务系统造成灾难性的严重后果

    原因:

    1. 服务提供者不可用(硬件故障、程序错误、缓存击穿、用户大量请求)。
    2. 用户重试,代码逻辑重试。
    3. 服务调用者不可用(同步等待造成的资源耗尽)。

    服务断路器

    解决雪崩的三个方案

    服务熔断器

    熔断就跟保险丝一样,当一个服务请求并发特别大,服务器已经招架不住了,调用错误率飙升,当错误率达到一定阈值后,就将这个服务熔断了。熔断之后,后续的请求就不会再请求服务器了,以减缓服务器的压力。

    当失败率(如因网络故障/超时造成的失败率高)达到阀值自动触发降级,熔断器触发的快速失败会进行快速恢复。

    服务降级

    出现原因:程序运行异常、超时、服务器熔断触发、线程池信号量打满

    当下游的服务因为某种原因响应过慢,下游服务主动停掉一些不太重要的业务,释放服务器资源,增加响应速度。当下游的服务因为某种原因不可用,上游主动调用本地的一些降级逻辑,避免卡顿,迅速返回。

    服务器繁忙,请稍后重试,不让客户端等待并且返回一个友好的提示。

    服务隔离

    避免服务之间的相互影响

    线程池隔离

    将用户请求线程和服务执行线程分开,同时约定每个服务最多可用线程数

    不同的http服务使用不同的线程池,当自己的资源用完,直接返回失败而不占用别人的资源
    优点:可提高并发性
    缺点:增加CPU调度开销
    使用场景:第三方应用或接口;并发量大

    信号量隔离

    原子计数器方式记录当前运行的线程数,超过则拒绝,不超过则+1,返回则-1使用场景:内部应用或中间件;并发需求不大

    区别:信号量可动态调整,但线程池不可以调整

    img

    服务限流

    服务熔断和服务隔离都是出错后的容错机制而服务限流是预防的机制

    限流模式主要是提前对各个类型的请求设置最高的QPS阈值,如果高于设置的阈值直接返回不再调用后续资源

    限流的目的是通过对并发访问/请求进行限速,或者对一个时间窗口内的请求进行限速来保护系统,一旦达到限速速率则可以拒绝服务、排队或者等待、降级等处理

    流量控制

    网关限流:防止大量请求进入系统,MQ实现消峰;用户交流限制:提交按钮限制点击频率限制等等。

    Resilience4j

    Resilience4j是一个轻量级的容错组件,主要是JAVA8和函数式编程设计(Lambda)轻量级体现在只用了VAVR(前身javaslang),没有依赖任何外部组件。提供了一系列增强微服务的可用性功能:

    1. resilience4j-circuitbreaker:熔断
    2. resilience4j-ratelimiter:限流
    3. resilience4j-bulkhead:隔离
    4. resilience4j-retry:自动重试
    5. resilience4j-cache:结果缓存
    6. resilience4j-timelimiter:超时处理

    Resilience4j断路器

    断路器(circuitBreaker)通常存在三种状态(CLOSE、OPEN、HALF_OPEN)并且通过一个时间或者数量窗口来记录当前的请求成功率或者慢速率,从作出正确的容错响应。

    三种重要的状态:

    1. closed -> open : 关闭状态到熔断状态, 当失败的调用率(比如超时、异常等)默认50%,达到一 定的阈值服务转为open状态,在open状态下,所有的请求都被拦截。
    2. open-> half_open: 当经过一定的时间后,CircubitBreaker中默认为60s服务调用者允许一定的请 求到达服务提供者。
    3. half_open -> open: 当half_open状态的调用失败率超过给定的阈值,转为open状态 half_open -> closed: 失败率低于给定的阈值则默认转换为closed状态

    共有六种状态

    1. CLOSED: 关闭状态,代表正常情况下的状态,允许所有请求通过,能通过状态转换为OPEN
    2. HALF_OPEN: 半开状态,即允许一部分请求通过,能通过状态转换为CLOSED和OPEN
    3. OPEN: 熔断状态,即不允许请求通过,能通过状态转为为HALF_OPEN
    4. DISABLED: 禁用状态,即允许所有请求通过,出现失败率达到给定的阈值也不会熔断,不会
    5. 发生状态转换。
    6. METRICS_ONLY: 和DISABLED状态一样,也允许所有请求通过不会发生熔断,但是会记录失
    7. 败率等信息,不会发生状态转换。
    8. FORCED_OPEN: 与DISABLED状态正好相反,启用CircuitBreaker,但是不允许任何请求通
    9. 过,不会发生状态转换。

    微服务网关

    网关统一向外部系统(访问者、服务)提供REST API。在Spring Cloud中,使用Zuul、Spring Cloud Gateway等作为API Gateway 来实现动态路由、监控、回退、安全等功能。

    img

    Spring Cloud Gateway

    Spring Cloud Gateway是Spring Cloud生态系统中的网关,基于Spring5.0、springboot2.0和project reactor等技术开发。用“Netty+WebFlux”实现。皆在为微服务架构提供一种简单有效的,统一的API路由管理方式

    特点

    1. 易于编写谓词( Predicates )和过滤器( Filters ) 。其Predicates和Filters可作用于特定路由。
    2. 支持路径重写。
    3. 支持动态路由。
    4. 集成了Spring Cloud DiscoveryClient。
    WebFlux

    Webflux模式替换了旧的Servlet线程模型。用少量的线程处理request和response io操作,这些线程称为Loop线程,而业务交给响应式编程框架处理,响应式编程是非常灵活的,用户可以将业务中阻塞的操作提交到响应式框架的work线程中执行,而不阻塞的操作依然可以在Loop线程中进行处理,大大提高了Loop线程的利用率。

    WebFlux可以兼容多个底层的通信框架,但是大多数情况下使用的是Netty,Netty是目前认可度最高的通信框架。WebFlux的loop线程,是著名的Reactor模式IO处理模型的Reactor线程。

    Netty

    1. 高并发:基于 NIO(Nonblocking IO,非阻塞IO)开发,对比于 BIO(Blocking I/O,阻塞IO),他的并发性能得到了很大提高;
    2. 传输快:传输依赖于零拷贝特性,尽量减少不必要的内存拷贝,实现了更高效率的传输;
    3. 封装好:封装了 NIO 操作的很多细节,提供了易于使用调用接口

    img

    三大核心

    首先任何请求进来,网关都会把它们拦住。根据请求的URL把它们分配到不同的路由上,路由上面会有断言,来判断请求能不能进来。进来之后会有一系列的过滤器对请求被转发前或转发后进行改动。 具体怎么个改动法,那就根据业务不同而自定义了。一般就是监控,限流,日志输出等等

    路由(Route)

    Gateway基本构建模块,它由一个ID,一个目标URL,一组断言和一组过滤器定义,如果断言为真,则路由匹配。

    断言(predicate)

    输入类型是ServerWebExchange,可以用来匹配来自HTTP请求的任何内容,如HEADER或者参数

    过滤(Filter)

    可以在请求被路由前或者之后对请求进行修改

  • 相关阅读:
    【力扣】304. 二维区域和检索 - 矩阵不可变 <二维前缀和>
    ECU安全访问系列_2(代码篇)
    JavaScript的变量和数据类型介绍、JavaScript的关系运算、JavaScript的逻辑运算
    操作系统 - 进程
    vue2的vue.config文件
    《联邦学习实战—杨强》之使用Python从零开始实现一个简单的横向联邦学习模型
    从源码看vue(v3.2.41)中的diff原理
    高端两轮电动车是否担得起“高端”头衔?
    企业级GitLab在Docker部署使用
    Git 的基础命令 码云 gitee
  • 原文地址:https://blog.csdn.net/qq_43545600/article/details/126481329