springcloud学习笔记

80 阅读35分钟

SpringCloud

前提知识+相关的说明

1   学习微服务架构SpringCloud,默认已经熟悉SpringMVC+Spring/SpringBoot+Mybatis+Maven+git.......

2   本次Cloud的讲解的方式,由于Cloud大概21种技术之多。只能挑选最重要最常用的技能给大家分享,俗称Cloud技术的五大神兽。

image-20220812174513160.png

1、从面试题开始

image.png

2、微服务概述

2.1  是什么

  • Fred George在2012年最早提出微服务架构概念
  • 马丁-福勒(Martin Fowler)在2014年全面介绍微服务架构

image.png

微服务架构是一种架构模式,它提倡将单一应用程序划分成一组小的服务,服务之间互相协调、互相配合,为用户提供最终价值。每个服务运行在其独立的进程中,服务与服务间采用轻量级的通信机制互相协作(通常是基于HTTP协议的RESTful API)。每个服务都围绕着具体业务进行构建,并且能够被独立的部署到生产环境、类生产环境等。

 *All in One单机系统
 可以看作eclipse里面只有一个大的工程,商品/订单/交易/库存.....
 war
 ​
     
 -----分布式系统
 各个模块/服务,各自独立出来,分灶吃饭
 各自微小的一个进程,让专业的人专业的模块,来做专业的事情独立部署
 ​
 ​
 Dubbo是基于RPC远程过程调用
 ​
 微服务Cloud是基于HTTP协议的RESTful API调用

技术维度理解

微服务化的核心就是将传统的一站式应用,根据业务拆分成一个一个的服务,彻底 地去耦合,每一个微服务提供单个业务功能的服务,一个服务做一件事, 从技术角度看就是一种小而独立的处理过程,类似进程概念,能够自行单独启动 或销毁,拥有自己独立的数据库。

2.2  微服务与微服务架构

  • 微服务

强调的是服务的大小,它关注的是某一个点,是具体解决某一个问题/提供落地对应服务的一个服务应用,狭意的看,可以看作idea里面的一个个微服务工程/或者Module

 idea工具里面用maven开发的一个个独立的小moudle,它具体是使用springboot开发的一个小模块,专业的事情交给专业的模块来做,一个模块就做这一件事情
 强调的是一个个的个体,每个个体完成一个具体的任务或者功能
  • 微服务架构

微服务架构是一种架构模式,它提倡将单一应用程序划分成一组小的服务,服务之间互相协调、互相配合,为用户提供最终价值。每个服务运行在其独立的进程中,服务与服务间采用轻量级的通信机制互相协作(通常是基于HTTP协议的RESTful API)。每个服务都围绕着具体业务进行构建,并且能够被独立的部署到生产环境、类生产环境等。另外,应当尽量避免统一的、集中式的服务管理机制,对具体的一个服务而言,应根据业务上下文,选择合适的语言、工具对其进行构建。

2.3  微服务优缺点

  • 优点
 每个服务足够内聚,足够小,代码容易理解这样能聚焦一个指定的业务功能或业务需求
 开发简单、开发效率提高,一个服务可能就是专一的只干一件事。
 微服务能够被小团队单独开发,这个小团队是25人的开发人员组成。
 微服务是松耦合的,是有功能意义的服务,无论是在开发阶段或部署阶段都是独立的。
 微服务能使用不同的语言开发。
 易于和第三方集成,微服务允许容易且灵活的方式集成自动部署,通过持续集成工具,如Jenkins, Hudson, bamboo 。
 微服务易于被一个开发人员理解,修改和维护,这样小团队能够更关注自己的工作成果。无需通过合作才能体现价值。
 微服务允许你利用融合最新技术。
 微服务只是业务逻辑的代码,不会和HTML,CSS 或其他界面组件混合。
 每个微服务都有自己的存储能力,可以有自己的数据库。也可以有统一数据库。
  • 缺点
 开发人员要处理分布式系统的复杂性
 多服务运维难度,随着服务的增加,运维的压力也在增大
 系统部署依赖
 服务间通信成本
 数据一致性
 系统集成测试
 性能监控……

2.4  微服务技术栈

微服务条目落地技术备注
服务开发Springboot、Spring、SpringMVC
服务配置与管理Netflix公司的Archaius、阿里的Diamond等
服务注册与发现Eureka、Consul、Zookeeper等
服务调用Rest、RPC、gRPC
服务熔断器Hystrix、Envoy等
负载均衡Ribbon、Nginx等
服务接口调用(客户端调用服务的简化工具)Feign等
消息队列Kafka、RabbitMQ、ActiveMQ等
服务配置中心管理SpringCloudConfig、Chef等
服务路由(API网关)Zuul等
服务监控Zabbix、Nagios、Metrics、Spectator等
全链路追踪Zipkin,Brave、Dapper等
服务部署Docker、OpenStack、Kubernetes等
数据流操作开发包SpringCloud Stream(封装与Redis,Rabbit、Kafka等发送接收消息)
事件消息总线Spring Cloud Bus

3、springCloud入门概述

3.1  是什么

image-20220815145549612.png

SpringCloud,基于SpringBoot提供了一套微服务解决方案,包括服务注册与发现,配置中心,全链路监控,服务网关,负载均衡,熔断器等组件,除了基于NetFlix的开源组件做高度抽象封装之外,还有一些选型中立的开源组件。

SpringCloud利用SpringBoot的开发便利性巧妙地简化了分布式系统基础设施的开发,SpringCloud为开发人员提供了快速构建分布式系统的一些工具,包括配置管理、服务发现、断路器、路由、微代理、事件总线、全局锁、决策竞选、分布式会话等等,它们都可以用SpringBoot的开发风格做到一键启动和部署。

SpringBoot并没有重复制造轮子,它只是将目前各家公司开发的比较成熟、经得起实际考验的服务框架组合起来,通过SpringBoot风格进行再封装屏蔽掉了复杂的配置和实现原理,最终给开发者留出了一套简单易懂、易部署和易维护的分布式系统开发工具包

SpringCloud=分布式微服务架构下的一站式解决方案,是各个微服务架构落地技术的集合体,俗称微服务全家桶

springCloud和springBoot是什么关系?

 SpringBoot专注于快速方便的开发单个个体微服务。
  
 SpringCloud是关注全局的微服务协调整理治理框架,它将SpringBoot开发的一个个单体微服务整合并管理起来,
 为各个微服务之间提供,配置管理、服务发现、断路器、路由、微代理、事件总线、全局锁、决策竞选、分布式会话等等集成服务
  
 SpringBoot可以离开SpringCloud独立使用开发项目,但是SpringCloud离不开SpringBoot,属于依赖的关系.
  
 SpringBoot专注于快速、方便的开发单个微服务个体,SpringCloud关注全局的服务治理框架。

3.2  能干嘛

image.png

3.3  怎么玩

image.png

4、Eureka服务注册与发现

4.1   Eureka是什么

Eureka是Netflix的一个子模块,也是核心模块之一。Eureka是一个基于REST的服务,用于定位服务,以实现云端中间层服务发现和故障转移。服务注册与发现对于微服务架构来说是非常重要的,有了服务发现与注册,只需要使用服务的标识符,就可以访问到服务,而不需要修改服务调用的配置文件了。功能类似于dubbo的注册中心,比如Zookeeper。

4.2   基本架构

Spring Cloud 封装了 Netflix 公司开发的 Eureka 模块来实现服务注册和发现(请对比Zookeeper)。

Eureka 采用了 C-S 的设计架构。Eureka Server 作为服务注册功能的服务器,它是服务注册中心。

而系统中的其他微服务,使用 Eureka 的客户端连接到 Eureka Server并维持心跳连接。这样系统的维护人员就可以通过 Eureka Server 来监控系统中各个微服务是否正常运行。SpringCloud 的一些其他模块(比如Zuul)就可以通过 Eureka Server 来发现系统中的其他微服务,并执行相关的逻辑。

image.png

Eureka包含两个组件:Eureka Server 和 Eureka Client

Eureka Server提供服务注册服务,各个节点启动后,会在EurekaServer中进行注册,这样EurekaServer中的服务注册表中将会存储所有可用服务节点的信息,服务节点的信息可以在界面中直观的看到

EurekaClient是一个Java客户端,用于简化Eureka Server的交互,客户端同时也具备一个内置的、使用轮询(round-robin)负载算法的负载均衡器。在应用启动后,将会向Eureka Server发送心跳(默认周期为30秒)。如果Eureka Server在多个心跳周期内没有接收到某个节点的心跳,EurekaServer将会从服务注册表中把这个服务节点移除(默认90秒)。

4.3   引入Eureka

 服务端:
     pom文件:
         <!--eureka-server服务端 -->
         <dependency>
             <groupId>org.springframework.cloud</groupId>
             <artifactId>spring-cloud-starter-eureka-server</artifactId>
         </dependency>
     yml:
         server:
           port: 7001
         eureka:
           instance:
             hostname: eureka7001.com #eureka服务端的实例名称
           client:
             register-with-eureka: false     #false表示不向注册中心注册自己。
             fetch-registry: false     #false表示自己端就是注册中心,我的职责就是维护服务实例,并不需要去检索服务
             service-url:
               defaultZone: http://eureka7001.com:7001/eureka
     启动类:
         @EnableEurekaServer // EurekaServer服务器端启动类,接受其它微服务注册进来
 ​
 ========================================================================================================
 ​
 客户端:
     pom文件:
         <dependency>
             <groupId>org.springframework.cloud</groupId>
             <artifactId>spring-cloud-starter-eureka-server</artifactId>
         </dependency>
         <dependency>
             <groupId>org.springframework.cloud</groupId>
             <artifactId>spring-cloud-starter-config</artifactId>
         </dependency>
     yml:
         eureka:
           instance:
             instance-id: microservicecloud-dept8003
           client: #客户端注册进eureka服务列表内
             service-url:
               defaultZone: http://eureka7001.com:7001/eureka
     启动类:
         @EnableEurekaClient //本服务启动后会自动注册进eureka服务中

4.4  注册微服务信息完善

主机名称修改

image.png

访问信息ip提示

image.png

微服务info内容详细信息

1   修改microservicecloud-provider-dept-8001 pom文件

 添加:
 <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
 </dependency>

2   总的父工程microservicecloud修改pom.xml添加构建build信息

 添加
 <build>
    <finalName>microservicecloud</finalName>
    <resources>
      <resource>
        <directory>src/main/resources</directory>
        <filtering>true</filtering>
      </resource>
    </resources>
    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-resources-plugin</artifactId>
        <configuration>
          <delimiters>
           <delimit>$</delimit>
          </delimiters>
        </configuration>
      </plugin>
    </plugins>
 </build>

3   修改microservicecloud-provider-dept-8001 yml文件

info:
  app.name: springcloud学习课件
  company.name: 上海汉得信息技术股份有限公司
  build.artifactId: ${project.artifactId}
  build.version: ${project.version}

4.5   Eureka自我保护机制

image.png

—句话: 某时刻某一个微服务不可用了, eureka不会立刻清理,依旧会对该微服务的信息进行保存

什么是自我保护模式?

默认情况下,如果EurekaServer在一定时间内没有接收到某个微服务实例的心跳,EurekaServer将会注销该实例(默认90秒)。但是当网络分区故障发生时,微服务与EurekaServer之间无法正常通信,以上行为可能变得非常危险了——因为微服务本身其实是健康的,此时本不应该注销这个微服务。Eureka通过“自我保护模式”来解决这个问题——当EurekaServer节点在短时间内丢失过多客户端时(可能发生了网络分区故障),那么这个节点就会进入自我保护模式。一旦进入该模式,EurekaServer就会保护服务注册表中的信息,不再删除服务注册表中的数据(也就是不会注销任何微服务)。当网络故障恢复后,该Eureka Server节点会自动退出自我保护模式。

在自我保护模式中,Eureka Server会保护服务注册表中的信息,不再注销任何服务实例。当它收到的心跳数重新恢复到阈值以上时,该Eureka Server节点就会自动退出自我保护模式。它的设计哲学就是宁可保留错误的服务注册信息,也不盲目注销任何可能健康的服务实例。 一句话讲解:好死不如赖活着

综上,自我保护模式是一种应对网络异常的安全保护措施。它的架构哲学是宁可同时保留所有微服务(健康的微服务和不健康的微服务都会保留),也不盲目注销任何健康的微服务。使用自我保护模式,可以让Eureka集群更加的健壮、稳定。

在Spring Cloud中,可以使用eureka.server.enable-self-preservation = false 禁用自我保护模式。

4.6   Eureka服务发现

对于注册进eureka里面的微服务,可以通过服务发现来获得该服务的信息

1   修改microservicecloud-provider-dept-8001 DeptController

添加:
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;

  @Autowired
  private DiscoveryClient client;
  
  @RequestMapping(value = "/dept/discovery", method = RequestMethod.GET)
  public Object discovery()
  {
    List<String> list = client.getServices();
    System.out.println("**********" + list);
 
    List<ServiceInstance> srvList = client.getInstances("MICROSERVICECLOUD-DEPT");
    for (ServiceInstance element : srvList) {
     System.out.println(element.getServiceId() + "\t" + element.getHost() + "\t" + element.getPort() + "\t" + element.getUri());
    }
    return this.client;
  }

2   主启动类添加注解 @EnableDiscoveryClient

4.7   集群配置

image.png

4.8   作为服务注册中心,Eureka比Zookeeper好在哪里

作为服务注册中心,Eureka比Zookeeper好在哪里

著名的CAP理论指出,一个分布式系统不可能同时满足C(一致性)、A(可用性)和P(分区容错性)。由于分区容错性P在是分布式系统中必须要保证的,因此我们只能在A和C之间进行权衡。
因此
Zookeeper保证的是CP,
Eureka则是AP。
 
 
1 Zookeeper保证CP
    当向注册中心查询服务列表时,我们可以容忍注册中心返回的是几分钟以前的注册信息,但不能接受服务直接down掉不可用。也就是说,服务注册功能对可用性的要求要高于一致性。但是zk会出现这样一种情况,当master节点因为网络故障与其他节点失去联系时,剩余节点会重新进行leader选举。问题在于,选举leader的时间太长,30 ~ 120s, 且选举期间整个zk集群都是不可用的,这就导致在选举期间注册服务瘫痪。在云部署的环境下,因网络问题使得zk集群失去master节点是较大概率会发生的事,虽然服务能够最终恢复,但是漫长的选举时间导致的注册长期不可用是不能容忍的。
 
2 Eureka保证AP
    Eureka看明白了这一点,因此在设计时就优先保证可用性。Eureka各个节点都是平等的,几个节点挂掉不会影响正常节点的工作,剩余的节点依然可以提供注册和查询服务。而Eureka的客户端在向某个Eureka注册或时如果发现连接失败,则会自动切换至其它节点,只要有一台Eureka还在,就能保证注册服务可用(保证可用性),只不过查到的信息可能不是最新的(不保证强一致性)。除此之外,Eureka还有一种自我保护机制,如果在15分钟内超过85%的节点都没有正常的心跳,那么Eureka就认为客户端与注册中心出现了网络故障,此时会出现以下几种情况: 
    1. Eureka不再从注册列表中移除因为长时间没收到心跳而应该过期的服务 
    2. Eureka仍然能够接受新服务的注册和查询请求,但是不会被同步到其它节点上(即保证当前节点依然可用) 
    3. 当网络稳定时,当前实例新的注册信息会被同步到其它节点中


因此, Eureka可以很好的应对因网络故障导致部分节点失去联系的情况,而不会像zookeeper那样使整个注册服务瘫痪。

CAP理论:

C:强一致性;   A:可用性;   P:分区容错性。

最多只能同时较好的满足两个。 CAP理论的核心是:一个分布式系统不可能同时很好的满足一致性,可用性和分区容错性这三个需求因此,根据CAP原理将NoSQL数据库分成了满足CA原则、满足CP原则和满足AP原则三大类:

CA–单点集群,满足一致性,可用性的系统,通常在可扩展性上不太强大。 CP–满足一致性,分区容忍性的系统,通常性能不是特别高。 AP–满足可用性,分区容忍性的系统,通常可能对一致性要求低一些。image.png

CAP的3进2 CAP理论就是说在分布式存储系统中,最多只能实现上面的两点。而由于当前的网络硬件肯定会出现延迟丢包等问题,所以

分区容忍性是我们必须需要实现的

所以我们只能在一致性可用性之间进行权衡,没有NoSQL系统能同时保证这三点。 C:强一致性     A:高可用性       P:分布式容忍性

CA     传统Oracle数据库

AP     大多数网站架构的选择

CP     Redis、Mongodb

注意:分布式架构的时候必须做出取舍(CP或AP)。

5、Rabbon负载均衡

5.1   概述

是什么

Spring Cloud Ribbon是基于Netflix Ribbon实现的一套客户端 负载均衡的工具。
 
简单的说,Ribbon是Netflix发布的开源项目,主要功能是提供客户端的软件负载均衡算法,将Netflix的中间层服务连接在一起。Ribbon客户端组件提供一系列完善的配置项如连接超时,重试等。简单的说,就是在配置文件中列出Load Balancer(简称LB)后面所有的机器,Ribbon会自动的帮助你基于某种规则(如简单轮询,随机连接等)去连接这些机器。我们也很容易使用Ribbon实现自定义的负载均衡算法。

LB(负载均衡)

LB,即负载均衡(Load Balance),在微服务或分布式集群中经常用的一种应用。 负载均衡简单的说就是将用户的请求平摊的分配到多个服务上,从而达到系统的HA。 常见的负载均衡有软件Nginx,LVS,硬件 F5等。 相应的在中间件,例如:dubbo和SpringCloud中均给我们提供了负载均衡,SpringCloud的负载均衡算法可以自定义。

负载均衡有两种:

集中式LB

即在服务的消费方和提供方之间使用独立的LB设施(可以是硬件,如F5, 也可以是软件,如nginx), 由该设施负责把访问请求通过某种策略转发至服务的提供方;

进程内LB

将LB逻辑集成到消费方,消费方从服务注册中心获知有哪些地址可用,然后自己再从这些地址中选择出一个合适的服务器。

Ribbon就属于进程内LB,它只是一个类库,集成于消费方进程,消费方通过它来获取到服务提供方的地址。

5.2   Ribbon初步配置

添加pom文件依赖

		<!-- Ribbon相关 -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-eureka</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-ribbon</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-config</artifactId>
        </dependency>

yml文件添加eureka的服务注册地址

eureka:
  client:
    register-with-eureka: false
    service-url:
      defaultZone: http://eureka7001.com:7001/eureka,http://eureka7002.com:7002/eureka,
      http://eureka7003.com:7003/eureka

对ConfigBean进行新注解@LoadBalanced    获得Rest时加入Ribbon的配置

package com.springcloud.cfgbeans;
 
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;
 
@Configuration
public class ConfigBean
{
  @Bean
  @LoadBalanced
  public RestTemplate getRestTemplate()
  {
   return new RestTemplate();
  }
}

主启动类DeptConsumer80_App添加注解 @EnableEurekaClient ** **

修改DeptController_Consumer客户端访问类image.png

5.3   Ribbon负载均衡

1   架构说明image.png

Ribbon在工作时分成两步 第一步先选择 EurekaServer ,它优先选择在同一个区域内负载较少的server. 第二步再根据用户指定的策略,在从server取到的服务注册列表中选择一个地址。 其中Ribbon提供了多种策略:比如轮询、随机和根据响应时间加权。

2    操作实现负载均衡image.png

5.4   Ribbon核心组件IRule

lRule:  根据特定算法中从服务列表中选取一个要访问的服务

image.png

5.6   Ribbon自定义rule

image.png

1   消费者主启动类添加注解

					//要使用自定义入了的微服务名称             //自定义的rule
@RibbonClient(name="MICROSERVICECLOUD-DEPT",configuration=MySelfRule.class)

2    这个自定义配置类不能放在 @ComponentScan所扫描的当前包下以及子包下,否则我们自定义的这个配置类就会被所有的Ribbon客户端所共享,也就是说我们达不到特殊化定制的目的了。

3     自定义rule类

@Configuration
public class MySelfRule {
    @Bean
    public IRule myRule() {
        return new RandomRule_Hand();// Ribbon默认是轮询,我自定义为随机
    }
}
public class RandomRule_Hand extends AbstractLoadBalancerRule {
    // total = 0 // 当total==5以后,我们指针才能往下走,
    // index = 0 // 当前对外提供服务的服务器地址,
    // total需要重新置为零,但是已经达到过一个5次,我们的index = 1
    // 分析:我们5次,但是微服务只有8001 8002 8003 三台
    // 

    private int total = 0;            // 总共被调用的次数,目前要求每台被调用5次
    private int currentIndex = 0;    // 当前提供服务的机器号

    public Server choose(ILoadBalancer lb, Object key) {
        if (lb == null) {
            return null;
        }
        Server server = null;

        while (server == null) {
            if (Thread.interrupted()) {
                return null;
            }
            List<Server> upList = lb.getReachableServers();
            List<Server> allList = lb.getAllServers();

            int serverCount = allList.size();
            if (serverCount == 0) {
                /*
                 * No servers. End regardless of pass, because subsequent passes only get more
                 * restrictive.
                 */
                return null;
            }

//			int index = rand.nextInt(serverCount);// java.util.Random().nextInt(3);
//			server = upList.get(index);

            if (total < 5) {
                server = upList.get(currentIndex);
                total++;
            } else {
                total = 0;
                currentIndex++;
                if (currentIndex >= upList.size()) {
                    currentIndex = 0;
                }
            }

            if (server == null) {
                /*
                 * The only time this should happen is if the server list were somehow trimmed.
                 * This is a transient condition. Retry after yielding.
                 */
                Thread.yield();
                continue;
            }

            if (server.isAlive()) {
                return (server);
            }

            // Shouldn't actually happen.. but must be transient or a bug.
            server = null;
            Thread.yield();
        }
        return server;
    }

    @Override
    public Server choose(Object key) {return choose(getLoadBalancer(), key);}
    
    @Override
    public void initWithNiwsConfig(IClientConfig clientConfig) { // TODO Auto-generated method stub
    }
}

6、Feign负载均衡

6.1   概述

Feign是一个声明式WebService客户端。使用Feign能让编写Web Service客户端更加简单, 它的使用方法是定义一个接口,然后在上面添加注解,同时也支持JAX-RS标准的注解。Feign也支持可拔插式的编码器和解码器。Spring Cloud对Feign进行了封装,使其支持了Spring MVC标准注解和HttpMessageConverters。Feign可以与Eureka和Ribbon组合使用以支持负载均衡。

image.png

Feign是一个声明式的Web服务客户端,使得编写Web服务客户端变得非常容易, 只需要创建一个接口,然后在上面添加注解即可。

Feign能干什么 Feign旨在使编写Java Http客户端变得更容易。 前面在使用Ribbon+RestTemplate时,利用RestTemplate对http请求的封装处理,形成了一套模版化的调用方法。但是在实际开发中,由于对服务依赖的调用可能不止一处,往往一个接口会被多处调用,所以通常都会针对每个微服务自行封装一些客户端类来包装这些依赖服务的调用。所以,Feign在此基础上做了进一步封装,由他来帮助我们定义和实现依赖服务接口的定义。在Feign的实现下,我们只需创建一个接口并使用注解的方式来配置它(以前是Dao接口上面标注Mapper注解,现在是一个微服务接口上面标注一个Feign注解即可) ,即可完成对服务提供方的接口绑定,简化了使用Spring cloud Ribbon时,自动封装服务调用客户端的开发量。

Feign集成了Ribbon 利用Ribbon维护了MicroServiceCloud-Dept的服务列表信息,并且通过轮询实现了客户端的负载均衡。而与Ribbon不同的是,通过feign只需要定义服务绑定接口且以声明式的方法,优雅而简单的实现了服务调用

6.2   使用步骤

image.png

1  新建Feign项目

2  修改feign工程pom.xml文件,主要添加对feign的支持

	<dependency>
       <groupId>org.springframework.cloud</groupId>
       <artifactId>spring-cloud-starter-feign</artifactId>
    </dependency>

3  修改microservicecloud-api工程

1. 修改pom.xml文件,主要添加对feign的支持
	<dependency>
       <groupId>org.springframework.cloud</groupId>
       <artifactId>spring-cloud-starter-feign</artifactId>
    </dependency>

2. 新建DeptClientService接口并新增注解@FeignClient
    
@FeignClient(value = "MICROSERVICECLOUD-DEPT")
public interface DeptClientService
{
  @RequestMapping(value = "/dept/get/{id}",method = RequestMethod.GET)
  public Dept get(@PathVariable("id") long id);
 
  @RequestMapping(value = "/dept/list",method = RequestMethod.GET)
  public List<Dept> list();
 
  @RequestMapping(value = "/dept/add",method = RequestMethod.POST)
  public boolean add(Dept dept);
}

4  feign工程修改Controller,添加上一步新建的DeptClientService接口

@RestController
public class DeptController_Feign
{
  @Autowired
  private DeptClientService service = null;
  
  @RequestMapping(value = "/consumer/dept/get/{id}")
  public Dept get(@PathVariable("id") Long id){return this.service.get(id);}
  
  @RequestMapping(value = "/consumer/dept/list")
  public List<Dept> list(){return this.service.list();}
  
  @RequestMapping(value = "/consumer/dept/add")
  public Object add(Dept dept){return this.service.add(dept);}
}

5  feign工程修改主启动类

//添加注解
@EnableFeignClients(basePackages= {"com.hand.springcloud"})
@ComponentScan("com.hand.springcloud")

总结

Feign通过接口的方法调用Rest服务(之前是Ribbon+RestTemplate),
该请求发送给Eureka服务器(http://MICROSERVICECLOUD-DEPT/dept/list),
通过Feign直接找到服务接口,由于在进行服务调用的时候融合了Ribbon技术,所以也支持负载均衡作用。

7、Hystrix断路器

7.1   概述

  • 分布式系统面临的问题

复杂分布式体系结构中的应用程序有数十个依赖关系,每个依赖关系在某些时候将不可避免地失败。image.png

服务雪崩 多个微服务之间调用的时候,假设微服务A调用微服务B和微服务C,微服务B和微服务C又调用其它的微服务,这就是所谓的“扇出”。如果扇出的链路上某个微服务的调用响应时间过长或者不可用,对微服务A的调用就会占用越来越多的系统资源,进而引起系统崩溃,所谓的“雪崩效应”.

	对于高流量的应用来说,单一的后端依赖可能会导致所有服务器上的所有资源都在几秒钟内饱和。比失败更糟糕的是,这些应用程序还可能导致服务之间的延迟增加,备份队列,线程和其他系统资源紧张,导致整个系统发生更多的级联故障。这些都表示需要对故障和延迟进行隔离和管理,以便单个依赖关系的失败,不能取消整个应用程序或系统。
备注:一般情况对于服务依赖的保护主要有3中解决方案:

(1)熔断模式:这种模式主要是参考电路熔断,如果一条线路电压过高,保险丝会熔断,防止火灾。放到我们的系统中,如果某个目标服务调用慢或者有大量超时,此时,熔断该服务的调用,对于后续调用请求,不在继续调用目标服务,直接返回,快速释放资源。如果目标服务情况好转则恢复调用。

(2)隔离模式:这种模式就像对系统请求按类型划分成一个个小岛的一样,当某个小岛被火少光了,不会影响到其他的小岛。例如可以对不同类型的请求使用线程池来资源隔离,每种类型的请求互不影响,如果一种类型的请求线程资源耗尽,则对后续的该类型请求直接返回,不再调用后续资源。这种模式使用场景非常多,例如将一个服务拆开,对于重要的服务使用单独服务器来部署,再或者公司最近推广的多中心。

(3)限流模式:上述的熔断模式和隔离模式都属于出错后的容错处理机制,而限流模式则可以称为预防模式。限流模式主要是提前对各个类型的请求设置最高的QPS阈值,若高于设置的阈值则对该请求直接返回,不再调用后续资源。这种模式不能解决服务依赖的问题,只能解决系统整体资源分配问题,因为没有被限流的请求依然有可能造成雪崩效应。
  • 是什么

Hystrix是一个用于处理分布式系统的延迟容错的开源库,在分布式系统里,许多依赖不可避免的会调用失败,比如超时、异常等,Hystrix能够保证在一个依赖出问题的情况下,不会导致整体服务失败,避免级联故障,以提高分布式系统的弹性

“断路器”本身是一种开关装置,当某个服务单元发生故障之后,通过断路器的故障监控(类似熔断保险丝),向调用方返回一个符合预期的、可处理的备选响应(FallBack),而不是长时间的等待或者抛出调用方无法处理的异常,这样就保证了服务调用方的线程不会被长时间、不必要地占用,从而避免了故障在分布式系统中的蔓延,乃至雪崩。

  • 能干嘛

image.png

Hystrix服务降级,其实就是线程池中单个线程障处理,防止单个线程请求时间太长,导致资源长期被占有而得不到释放,从而导致线程池被快速占用完,导致服务崩溃。
Hystrix能解决如下问题:
1.请求超时降级,线程资源不足降级,降级之后可以返回自定义数据
2.线程池隔离降级,分布式服务可以针对不同的服务使用不同的线程池,从而互不影响
3.自动触发降级与恢复
4.实现请求缓存和请求合并
熔断模式:这种模式主要是参考电路熔断,如果一条线路电压过高,保险丝会熔断,防止火灾。放到我们的系统中,如果某个目标服务调用慢或者有大量超时,此时,熔断该服务的调用,对于后续调用请求,不在继续调用目标服务,直接返回,快速释放资源。如果目标服务情况好转则恢复调用。
限流模式主要是提前对各个类型的请求设置最高的QPS阈值,若高于设置的阈值则对该请求直接返回,不再调用后续资源。这种模式不能解决服务依赖的问题,只能解决系统整体资源分配问题,因为没有被限流的请求依然有可能造成雪崩效应。

7.2   服务熔断

image.png

熔断机制是应对雪崩效应的一种微服务链路保护机制。 当扇出链路的某个微服务不可用或者响应时间太长时,会进行服务的降级,进而熔断该节点微服务的调用,快速返回"错误"的响应信息。当检测到该节点微服务调用响应正常后恢复调用链路。在SpringCloud框架里熔断机制通过Hystrix实现。Hystrix会监控微服务间调用的状况,当失败的调用到一定阈值,缺省是5秒内20次调用失败就会启动熔断机制。熔断机制的注解是@HystrixCommand。

使用步骤:

1  参考microservicecloud-provider-dept-8001,新建microservicecloud-provider-dept-hystrix-8001

2  pom文件添加hystrix依赖

   <!--  hystrix -->
   <dependency>
     <groupId>org.springframework.cloud</groupId>
     <artifactId>spring-cloud-starter-hystrix</artifactId>
   </dependency>

3  yml指定服务instance_id

eureka:
 instance:
    instance-id: microservicecloud-dept8001-hystrix   #自定义服务名称信息

4  修改DeptController

@HystrixCommand报异常后如何处理image.png

一旦调用服务方法失败并抛出了错误信息后,会自动调用@HystrixCommand标注好的fallbackMethod调用类中的指定方法

@RestController
public class DeptController{
  @Autowired
  private DeptService service = null;
  
  @RequestMapping(value="/dept/get/{id}",method=RequestMethod.GET)
    @HystrixCommand(fallbackMethod = "processHystrix_Get")
  public Dept get(@PathVariable("id") Long id){
   Dept dept =  this.service.get(id);
   if(null == dept){
     throw new RuntimeException("该ID:"+id+"没有没有对应的信息");
   }
   return dept;
  }
  
  public Dept processHystrix_Get(@PathVariable("id") Long id){
   return new Dept().setDeptno(id)
           .setDname("该ID:"+id+"没有没有对应的信息,null--@HystrixCommand")
           .setDb_source("no this database in MySQL");
  }
}

5  修改主启动类并添加新注解 @EnableCircuitBreaker ** **

@SpringBootApplication
@EnableEurekaClient //本服务启动后会自动注册进eureka服务中
@EnableDiscoveryClient //服务发现
@EnableCircuitBreaker//对hystrixR熔断机制的支持

6  测试

7.3  服务降级

image.png

整体资源快不够了,忍痛将某些服务先关掉,待渡过难关,再开启回来。

服务降级处理是在客户端实现完成的,与服务端没有关系

image.png

参考步骤:

1   修改microservicecloud-api工程,根据已经有的DeptClientService接口新建一个实现了FallbackFactory接口的类DeptClientServiceFallbackFactory

@Component//不要忘记添加,不要忘记添加
public class DeptClientServiceFallbackFactory implements FallbackFactory<DeptClientService>{
  @Override
  public DeptClientService create(Throwable throwable){
   return new DeptClientService() {
     @Override
     public Dept get(long id){
       return new Dept().setDeptno(id)
               .setDname("该ID:"+id+"没有没有对应的信息,Consumer客户端提供的降级信息,此刻服务Provider已经关闭")
               .setDb_source("no this database in MySQL");
     }
     @Override
     public List<Dept> list(){ return null; }
     @Override
     public boolean add(Dept dept){ return false; }
   };
  }
}

2   修改microservicecloud-api工程,DeptClientService接口在注解@FeignClient中添加fallbackFactory属性值image.png

3   microservicecloud-consumer-dept-feign工程修改YML, 添加熔断降级机制

feign: 
  hystrix: 
    enabled: true

4   测试

7.4  服务监控hystrixDashboard

image.png

除了隔离依赖服务的调用以外,Hystrix还提供了准实时的调用监控(Hystrix Dashboard),Hystrix会持续地记录所有通过Hystrix发起的请求的执行信息,并以统计报表和图形的形式展示给用户,包括每秒执行多少请求多少成功,多少失败等。Netflix通过hystrix-metrics-event-stream项目实现了对以上指标的监控。Spring Cloud也提供了Hystrix Dashboard的整合,对监控内容转化成可视化界面。

使用参考步骤:

1  新建工程microservicecloud-consumer-hystrix-dashboard

2  修改pom文件,添加hystrix-dashboard依赖

   <!-- hystrix和 hystrix-dashboard相关-->
   <dependency>
       <groupId>org.springframework.cloud</groupId>
       <artifactId>spring-cloud-starter-hystrix</artifactId>
   </dependency>
   <dependency>
       <groupId>org.springframework.cloud</groupId>
       <artifactId>spring-cloud-starter-hystrix-dashboard</artifactId>
   </dependency>

3  添加yml文件,指定9001端口

server:
  port: 9001

4  主启动类改名+新注解@EnableHystrixDashboard

5  所有Provider微服务提供类(8001/8002/8003)都需要添加监控依赖配置(actuator)

   <!-- actuator监控信息完善 -->
   <dependency>
     <groupId>org.springframework.boot</groupId>
     <artifactId>spring-boot-starter-actuator</artifactId>
   </dependency>

6   启动microservicecloud-consumer-hystrix-dashboard该微服务监控消费端

http://localhost:9001/hystriximage.png

7  启动3个eureka集群,  启动microservicecloud-provider-dept-hystrix-8001

http://localhost:8001/dept/get/1

http://localhost:8001/hystrix.streamimage.png

8  多次刷新http://localhost:8001/dept/get/1

填写监控地址image.png

Delay:该参数用来控制服务器上轮询监控信息的延迟时间,默认为2000毫秒,可以通过配置该属性来降低客户端的网络和CPU消耗。

Title:该参数对应了头部标题Hystrix Stream之后的内容,默认会使用具体监控实例的URL,可以通过配置该信息来展示更合适的标题。

监控结果:image.png

图解:image.png

实心圆:共有两种含义。它通过颜色的变化代表了实例的健康程度,它的健康度从绿色<黄色<橙色<红色递减。 该实心圆除了颜色的变化之外,它的大小也会根据实例的请求流量发生变化,流量越大该实心圆就越大。所以通过该实心圆的展示,就可以在大量的实例中快速的发现故障实例和高压力实例。

曲线:用来记录2分钟内流量的相对变化,可以通过它来观察到流量的上升和下降趋势。

8、zuul路由网关

8.1  概述

Zuul包含了对请求的路由和过滤两个最主要的功能: 其中路由功能负责将外部请求转发到具体的微服务实例上,是实现外部访问统一入口的基础,而过滤器功能则负责对请求的处理过程进行干预,是实现请求校验、服务聚合等功能的基础. Zuul和Eureka进行整合,将Zuul自身注册为Eureka服务治理下的应用,同时从Eureka中获得其他微服务的消息,也即以后的访问微服务都是通过Zuul跳转后获得。

注意:Zuul服务最终还是会注册进Eureka

提供=代理+路由+过滤三大功能

8.2  路由基本配置

image.png

1   新建Module模块microservicecloud-zuul-gateway-9527

2   修改pom文件,主要是添加zuul路由网关依赖

   <!-- zuul路由网关 -->
   <dependency>
     <groupId>org.springframework.cloud</groupId>
     <artifactId>spring-cloud-starter-zuul</artifactId>
   </dependency> 
   <dependency>
     <groupId>org.springframework.cloud</groupId>
     <artifactId>spring-cloud-starter-eureka</artifactId>
   </dependency>]

3   修改yml文件

server: 
  port: 9527
 
spring: 
  application:
    name: microservicecloud-zuul-gateway
 
eureka: 
  client: 
    service-url: 
      defaultZone: http://eureka7001.com:7001/eureka,http://eureka7002.com:7002/eureka,http://eureka7003.com:7003/eureka  
  instance:
    instance-id: gateway-9527.com
    prefer-ip-address: true

4   主启动类添加注解@EnableZuulProxy

@SpringBootApplication
@EnableZuulProxy

8.3   路由访问映射规则

image.png

mydept.serviceId :   原服务名

mydept.path :  代理名称

ignored-services :   原真实服务名忽略(单个写具体服务名,多个可以用"*")

prefix :   设置统一公共前缀

9、SpringCloud Config分布式配置中心

9.1   概述

  • 分布式系统面临的---配置问题

微服务意味着要将单体应用中的业务拆分成一个个子服务,每个服务的粒度相对较小,因此系统中会出现大量的服务。由于每个服务都需要必要的配置信息才能运行,所以一套集中式的、动态的配置管理设施是必不可少的。SpringCloud提供了ConfigServer来解决这个问题,我们每一个微服务自己带着一个application.yml,上百个配置文件的管理....../(ㄒoㄒ)/~~

  • 是什么image.png

SpringCloud Config为微服务架构中的微服务提供集中化的外部配置支持,配置服务器为各个不同微服务应用的所有环境提供了一个中心化的外部配置。

SpringCloud Config分为服务端和客户端两部分。

服务端也称为分布式配置中心,它是一个独立的微服务应用,用来连接配置服务器并为客户端提供获取配置信息,加密/解密信息等访问接口

客户端则是通过指定的配置中心来管理应用资源,以及与业务相关的配置内容,并在启动的时候从配置中心获取和加载配置信息配置服务器默认采用git来存储配置信息,这样就有助于对环境配置进行版本管理,并且可以通过git客户端工具来方便的管理和访问配置内容。

  • 能干嘛
  • image.png
  • dev:    开发环境
  • test:    测试环境
  • prod:    产品环境
  • beta:    预发布环境
  • release:    灰度发布

9.2  SpringCloud Config服务端配置

image.png 1  用自己的GitHub账号在GitHub上新建一个名为microservicecloud-config的新Repository

2  由上一步获得协议的git地址

3  本地硬盘目录上新建git仓库并clone  microservicecloud-config仓库到本地

4  在本地microservicecloud-config仓库里面新建一个application.yml(保存格式必须为UTF-8

spring:
  profiles:
    active:
    - dev
---
spring:
  profiles: dev     #开发环境
  application: 
    name: microservicecloud-config-atguigu-dev
---
spring:
  profiles: test   #测试环境
  application: 
    name: microservicecloud-config-atguigu-test
#  请保存为UTF-8格式

5  将上一步的YML文件推送到github仓库上

6  新建Module模块microservicecloud-config-3344它即为Cloud的配置中心模块

7  修改pom和yml文件

<dependencies>
   <!-- springCloud Config -->
   <dependency>
     <groupId>org.springframework.cloud</groupId>
     <artifactId>spring-cloud-config-server</artifactId>
   </dependency>
   <!-- 避免Config的Git插件报错:org/eclipse/jgit/api/TransportConfigCallback  -->
   <dependency>
       <groupId>org.eclipse.jgit</groupId>
       <artifactId>org.eclipse.jgit</artifactId>
       <version>4.10.0.201712302008-r</version>
   </dependency>
   <!-- 图形化监控 -->
   <dependency>
     <groupId>org.springframework.boot</groupId>
     <artifactId>spring-boot-starter-actuator</artifactId>
   </dependency>
   <!-- 熔断 -->
   <dependency>
     <groupId>org.springframework.cloud</groupId>
     <artifactId>spring-cloud-starter-hystrix</artifactId>
   </dependency>
   <dependency>
     <groupId>org.springframework.cloud</groupId>
     <artifactId>spring-cloud-starter-eureka</artifactId>
   </dependency>
   <dependency>
     <groupId>org.springframework.cloud</groupId>
     <artifactId>spring-cloud-starter-config</artifactId>
   </dependency>
   <dependency>
     <groupId>org.springframework.boot</groupId>
     <artifactId>spring-boot-starter-jetty</artifactId>
   </dependency>
   <dependency>
     <groupId>org.springframework.boot</groupId>
     <artifactId>spring-boot-starter-web</artifactId>
   </dependency>
   <dependency>
     <groupId>org.springframework.boot</groupId>
     <artifactId>spring-boot-starter-test</artifactId>
   </dependency>
   <!-- 热部署插件 -->
   <dependency>
     <groupId>org.springframework</groupId>
     <artifactId>springloaded</artifactId>
   </dependency>
   <dependency>
     <groupId>org.springframework.boot</groupId>
     <artifactId>spring-boot-devtools</artifactId>
   </dependency>
  </dependencies> 




server:
  port: 3344

spring:
  application:
    name:  cloud-config-center #注册进Eureka服务器的微服务名
  cloud:
    config:
      # 配置中心服务器端配置
      server:
        # git地址,建议填写uri为http,而不是git,不然认证失败
        #当然使用git,也可以不过必须要加username,password
        git:
          uri: https://gitee.com/iamyaojian/springcloud-config.git #GitHub上面的git仓库名字
          username: iamyaojian
          password: asdfghyj2580
          # 搜索路径
          search-paths:
            - springcloud-config
      # 读取分支
      label: springcloud2

#服务注册到eureka地址
eureka:
  client:
    service-url:
      defaultZone: http://localhost:7001/eureka

8  主启动类Config_3344_StartSpringCloudApp添加注解 @EnableConfigServer ** **

@SpringBootApplication
@EnableConfigServer

9  测试通过Config微服务是否可以从GitHub上获取配置内容

启动微服务3344
http://config-3344.com:3344/application-dev.yml
http://config-3344.com:3344/application-test.yml
http://config-3344.com:3344/application-xxx.yml(不存在的配置)

配置读取规则

image.png

image.png

9.3  SpringCloud Config客户端配置与测试

image.png

客户端3355调用SpringCloud  Config服务端3344获取仓库中的配置文件

9.4  SpringCloud Config配置实战

image.png 目前情况:

1  Config服务端配置配置OK且测试通过,我们可以和config+GitHub进行配置修改并获得内容

2 此时我们做一个eureka服务+一个Dept访问的微服务,将两个微服务的配置统一由于github获得实现统一配置分布式管理,完成多环境的变更

Config版的eureka服务端

1  新建工程microservicecloud-config-eureka-client-7001

2  修改pom文件,添加config依赖

<!-- SpringCloudConfig配置 -->
    <dependency>
     <groupId>org.springframework.cloud</groupId>
     <artifactId>spring-cloud-starter-config</artifactId>
    </dependency> 
    <dependency>
     <groupId>org.springframework.cloud</groupId>
     <artifactId>spring-cloud-starter-eureka-server</artifactId>
    </dependency>

3  添加bootstrap.yml和application.yml文件

bootstrap.yml:
spring: 
  cloud: 
    config: 
      name: microservicecloud-config-eureka-client     #需要从github上读取的资源名称,注意没有yml后缀名
      profile: dev 
      label: master 
      uri: http://config-3344.com:3344      #SpringCloudConfig获取的服务地址
      

application.yml:
spring:
  application:
    name: microservicecloud-config-eureka-client

4  主启动类Config_Git_EurekaServerApplication添加注解

5  测试 image.png

Config版的dept微服务

1  参考之前的8001拷贝后新建工程microservicecloud-config-dept-client-8001

2  修改pom文件,添加config依赖

3  添加bootstrap.yml和application.yml文件

bootstrap.yml:
spring:
  cloud:
    config:
      name: microservicecloud-config-dept-client #需要从github上读取的资源名称,注意没有yml后缀名
      #profile配置是什么就取什么配置dev or test
      #profile: dev
      profile: test
      label: master
      uri: http://config-3344.com:3344  #SpringCloudConfig获取的服务地址
      

application.yml:
spring:
  application:
    name: microservicecloud-config-dept-client

4  主启动类及其它一套业务逻辑代码

5  测试

10、第一季内容技术梳理与架构

image-20220819112745890.png

1  整套开发技术栈以SpringCloud为主,单个微服务模块以SpringMVC+SpringBoot/Spring+MyBatis组合进行开发

2  前端层,页面H5+thymeleaf/样式CSS3+Bootstrap/前端框架JQuery+Node|Vue等

3  负载层,前端访问通过Http或Https协议到达服务端的LB,可以是F5等硬件做负载均衡,还可以自行部署LVS+Keepalived等(前期量小可以直接使用Nginx)

4  网关层,请求通过LB后,会到达整个微服务体系的网关层Zuul(Gateway),内嵌Ribbon做客户端负载均衡,Hystrix做熔断降级等

5  服务注册,采用Eureka来做服务治理,Zuul会从Eureka集群获取已发布的微服务访问地址,然后根据配置把请求代理到相应的微服务去

6  docker容器,所有的微服务模块都部署在Docker容器里面,而且前后端的服务完全分开,各自独立部署后前端微服务调用后端微服务,后端微服务之间会有相互调用

7  服务调用,微服务模块间调用都采用标准的Http/Https+REST+JSON的方式,调用技术采用Feign+HttpClient+Ribbon+Hystrix

8  统一配置,每个微服务模块会跟Eureka集群、配置中心(SpringCloudConfig)等进行交互

9  第3方框架,每个微服务模块根据实现的需要,通常还需要使用一些第三发框架,比如常见的有:缓存服务(Redis)、图片服务(FastDFS)、搜索服务(ElasticSearch)、安全管理(Shiro)等等

10  Mysql数据库,可以按照微服务模块进行拆分,统一访问公共库或者单独自己库,可以单独构建MySQL集群或者分库分表MyCat等

附件: SpringCloud.mmap