Springcloud

官网
自学参考书:
SpringCloud Netflix 中文文档
SpringCloud 中文API文档
SpringCloud中国社区
SpringCloud中文网

面试知识

五大组件

  • 服务注册与发现——Netflix Eureka

  • 负载均衡
    客户端——Netflix Ribbon
    服务端——Feign(其也是依赖于Ribbon,只是将调用方式RestTemplete 更改成Service 接口)

  • 断路器——Netflix Hystrix

  • 服务网关——Netflix Zuul

  • 分布式配置——Spring Cloud Config

什么是微服务?

微服务:一种架构模式,或者说是一种架构风格,它体长将单一的应用程序划分成一组小的服务。微服务化的核心就是将传统的一站式应用,根据业务拆分成一个一个的服务,彻底地去耦合

微服务与微服务架构

微服务可以看成是项目的一个module,具体是使用SpringBoot开发的一个小模块
微服务架构:对微服务之间的通信协作,部署的服务管理机制

微服务的优缺点

优点
微服务是松耦合的,无论是在开发阶段或部署阶段都是独立的;
代码易理解,易维护与修改
开发效率高,一个服务可能就是专一的只干一件事
每个微服务都有自己的存储能力,可以有自己的数据库
易于和第三方集成,能使用不同的语言开发;

缺点
开发人员要处理分布式系统的复杂性;
多服务运维难度,随着服务的增加,运维的压力也在增大;
系统部署依赖问题;
服务间通信成本问题;
数据一致性问题;
系统集成测试问题;
性能和监控问题;

微服务技术栈有那些?

技术条目落地技术
开发SpringBoot、Spring、SpringMVC等
注册与发现Eureka、Consul、Zookeeper等
调用Rest、PRC、gRPC
熔断Hystrix、Envoy等
负载均衡Ribbon、Nginx等
服务接口调用(客户端调用服务的简化工具)Fegin等
消息队列Kafka、RabbitMQ、ActiveMQ等
服务配置中心管理SpringCloudConfig、Chef等
服务路由(API网关)Zuul等
服务部署Docker、OpenStack等

为什么选择SpringCloud作为微服务架构

整体解决方案和框架成熟度
社区热度
可维护性
学习曲线

SpringCloud和SpringBoot的关系

SpringBoot专注于方便的开发单个个体微服务;
SpringCloud是关注全局的微服务协调整理治理框架,为各个微服务之间提供: 服务注册与发现、服务的调用、服务监控、断路器、路由配置、分布式配置、负载均衡、消息总栈等等集成服务;

Dubbo 和 SpringCloud

最大区别:Spring Cloud 抛弃了Dubbo的RPC通信,采用的是基于HTTP的REST方式
二者解决的问题域不一样:Dubbo的定位是一款RPC框架,而SpringCloud的目标是微服务架构下的一站式解决方案

1.环境搭建

我们会使用一个Dept部门模块做一个微服务通用案例Consumer消费者(Client)通过REST调用Provider提供者(Server)提供的服务。

创建父工程

新建父工程项目springcloud,切记Packageing是pom模式

<properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
        <junit.version>4.12</junit.version>
        <log4j.version>1.2.17</log4j.version>
        <lombok.version>1.16.18</lombok.version>
    </properties>

    <packaging>pom</packaging>
    
    <dependencyManagement>
        <dependencies>

            <!--springCloud的依赖-->
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>Greenwich.SR1</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <!--SpringBoot-->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-dependencies</artifactId>
                <version>2.1.4.RELEASE</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <!--数据库-->
            <dependency>
                <groupId>mysql</groupId>
                <artifactId>mysql-connector-java</artifactId>
                <version>5.1.47</version>
            </dependency>
            <dependency>
                <groupId>com.alibaba</groupId>
                <artifactId>druid</artifactId>
                <version>1.1.22</version>
            </dependency>
            <!--SpringBoot 启动器-->
            <dependency>
                <groupId>org.mybatis.spring.boot</groupId>
                <artifactId>mybatis-spring-boot-starter</artifactId>
                <version>1.3.0</version>
            </dependency>
            <!--日志测试~-->
            <dependency>
                <groupId>ch.qos.logback</groupId>
                <artifactId>logback-core</artifactId>
                <version>1.2.3</version>
            </dependency>
            <dependency>
                <groupId>junit</groupId>
                <artifactId>junit</artifactId>
                <version>${junit.version}</version>
            </dependency>
            <dependency>
                <groupId>log4j</groupId>
                <artifactId>log4j</artifactId>
                <version>${log4j.version}</version>
            </dependency>
            <dependency>
                <groupId>org.projectlombok</groupId>
                <artifactId>lombok</artifactId>
                <version>${lombok.version}</version>
            </dependency>
        </dependencies>
    </dependencyManagement>

springcloud-provider-dept-8001的dao接口调用springcloud-api模块下的pojo

<dependency>
    <groupId>com.haust</groupId>
    <artifactId>springcloud-api</artifactId>
    <version>1.0-SNAPSHOT</version>
</dependency>

在这里插入图片描述

2.provider和consumer

DeptConsumerController

@RestController
public class DeptConsumerController {

    //消费者,不应该有service层
    //RestTemplate供我们直接调用,注册到bean中
//    (地址:url, 实体:Map ,Class<T> responseType)
    @Autowired
    private RestTemplate restTemplate;

//    private static final String REST_URL_PREFIX="http://localhost:8001";
    private static final String REST_URL_PREFIX="http://SPRINGCLOUD-PROVIDER-DEPT";

    @RequestMapping ("/consumer/dept/add")
    public boolean addDept(Dept dept){
        return restTemplate.postForObject(REST_URL_PREFIX+"/dept/add",dept,Boolean.class);
    }

    @GetMapping("/dept/get/{id}")
    public Dept get(@PathVariable("id")Long id){
        return restTemplate.getForObject(REST_URL_PREFIX+"/dept/get"+id,Dept.class);

    }

    @GetMapping("/dept/list")
    public List<Dept> queryAll(){
        return restTemplate.getForObject(REST_URL_PREFIX+"/dept/list",List.class);

    }
}

DeptController

@RestController
public class DeptController {

    @Autowired
    private DeptService deptService;
    /**
     * DiscoveryClient 可以用来获取一些配置的信息,得到具体的微服务!
     */
    @Autowired
    private DiscoveryClient client;
    @GetMapping("/dept/discovery")
    public Object discovery() {
        // 获取微服务列表的清单
        List<String> services = client.getServices();
        System.out.println("discovery=>services:" + services);
        // 得到一个具体的微服务信息,通过具体的微服务id,applicaioinName;
        List<ServiceInstance> instances = client.getInstances("SPRINGCLOUD-PROVIDER-DEPT");
        for (ServiceInstance instance : instances) {
            System.out.println(
                    instance.getHost() + "\t" + // 主机名称
                            instance.getPort() + "\t" + // 端口号
                            instance.getUri() + "\t" + // uri
                            instance.getServiceId() // 服务id
            );
        }
        return this.client;
    }


    @PostMapping("/dept/add")
    public boolean addDept(Dept dept){
        return deptService.addDept(dept);
    }

    @GetMapping("/dept/get/{id}")
    public Dept get(@PathVariable("id")Long id){
        return deptService.queryById(id);
    }

    @GetMapping("/dept/list")
    public List<Dept> queryAll(){
        return deptService.queryAll();
    }
}
server:
  port: 8001
mybatis:
  type-aliases-package: com.thebs.springcloud.pojo
  config-location: classpath:mybatis/mybatis-config.xml
  mapper-locations: classpath:mybatis/mapper/*.xml
  
spring:
  application:
    name: springcloud-provider-dept
  datasource:
    type: com.alibaba.druid.pool.DruidDataSource
    driver-class-name: com.mysql.jdbc.Driver
    url: jdbc:mysql://localhost:3306/db01?useUnicode=true&characterEncoding=utf-8
    username: root
    password: root

3.Eureka注册中心

Springcloud 封装了Netflix公司开发的Eureka模块来实现服务注册与发现(对比Zookeeper).
在这里插入图片描述
Eureka 包含两个组件:Eureka Server 和 Eureka Client.

1. eureka-server

springcloud-eureka-7001 模块建立

<dependencies>
        <!--eureka-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-eureka-server</artifactId>
            <version>1.4.7.RELEASE</version>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>

        </dependency>
    </dependencies>

application.yml

server:
  port: 7001

# Eureka配置
eureka:
  instance:
    # Eureka服务端的实例名字
    hostname: 127.0.0.1
  client:
    # 表示是否向 Eureka 注册中心注册自己(这个模块本身是服务器,所以不需要)
    register-with-eureka: false
    # fetch-registry如果为false,则表示自己为注册中心,客户端的化为 ture
    fetch-registry: false
    # Eureka监控页面~
    service-url:
      defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/

主启动类添加

// @EnableEurekaServer 服务端的启动类,可以接受别人注册进来~
@EnableEurekaServer

启动成功后访问 http://localhost:7001/

2. eureka-client

provider导入依赖

<!--Eureka依赖-->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-eureka</artifactId>
    <version>1.4.6.RELEASE</version>
</dependency>

配置文件

#eureka配置
eureka:
  client:
    service-url:
      defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/
  instance:
    instance-id: provider-8001
#info配置
info:
  app.name: thebs-springcloud
  company.name: thebs

为主启动类添加@EnableEurekaClient注解

3. EureKa自我保护机制:好死不如赖活着

短时间内丢失大量的实例心跳,会触发该保护机制。总结:某时刻某一个微服务不可用,eureka不会立即清理,依旧会对该微服务的信息进行保存!
该保护机制的目的是避免网络连接故障,在发生网络故障时,微服务和注册中心之间无法正常通信,但服务本身是健康的,不应该注销该服务
自我保护模式关闭,只需在eureka server配置文件中加上如下配置即可:eureka.server.enable-self-preservation=false

4.Eureka:集群环境配置

在这里插入图片描述
新建springcloud-eureka-7002、springcloud-eureka-7003 模块
在这里插入图片描述
修改配置文件

server:
  port: 7001

eureka:
  instance:
    hostname: eureka7001.com
  client:
    register-with-eureka: false #是否向注册中心注册自己
    fetch-registry: false   #false表示自己是注册中心
    service-url:  #监控页面
      #defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
      defaultZone: http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/

修改provider配置:配置服务注册中心地址

#eureka配置
eureka:
  client:
    service-url:
      defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/
  instance:
    instance-id: provider-8001
#info配置
info:
  app.name: thebs-springcloud
  company.name: thebs

这样模拟集群就搭建号了,就可以把一个项目挂载到三个服务器上了

5.对比和Zookeeper区别

  1. 回顾CAP原则
    RDBMS (MySQL\Oracle\sqlServer) ===> ACID
    NoSQL (Redis\MongoDB) ===> CAP

  2. ACID是什么?
    A (Atomicity) 原子性
    C (Consistency) 一致性
    I (Isolation) 隔离性
    D (Durability) 持久性

  3. CAP是什么?
    C (Consistency) 强一致性
    A (Availability) 可用性
    P (Partition tolerance) 分区容错性
    CAP的三进二:CA、AP、CP

  4. CAP理论的核心
    一个分布式系统不可能同时很好的满足一致性,可用性和分区容错性这三个需求
    根据CAP原理,将NoSQL数据库分成了满足CA原则,满足CP原则和满足AP原则三大类
    CA:单点集群,满足一致性,可用性的系统,通常可扩展性较差
    CP:满足一致性,分区容错的系统,通常性能不是特别高
    AP:满足可用性,分区容错的系统,通常可能对一致性要求低一些

  5. 作为分布式服务注册中心,Eureka比Zookeeper好在哪里?
    著名的CAP理论指出,一个分布式系统不可能同时满足C (一致性) 、A (可用性) 、P (容错性),由于分区容错性P再分布式系统中是必须要保证的,因此我们只能再A和C之间进行权衡。

Zookeeper 保证的是 CP —> 满足一致性,分区容错的系统,通常性能不是特别高
Eureka 保证的是 AP —> 满足可用性,分区容错的系统,通常可能对一致性要求低一些
Zookeeper保证的是CP

​ 当向注册中心查询服务列表时,我们可以容忍注册中心返回的是几分钟以前的注册信息,但不能接收服务直接down掉不可用。也就是说,**服务注册功能对可用性的要求要高于一致性。但zookeeper会出现这样一种情况,当master节点因为网络故障与其他节点失去联系时,剩余节点会重新进行leader选举。**问题在于,选举leader的时间太长,30-120s,且选举期间整个zookeeper集群是不可用的,这就导致在选举期间注册服务瘫痪。在云部署的环境下,因为网络问题使得zookeeper集群失去master节点是较大概率发生的事件,虽然服务最终能够恢复,但是,漫长的选举时间导致注册长期不可用,是不可容忍的。

Eureka保证的是AP

Eureka看明白了这一点,因此在设计时就优先保证可用性。Eureka各个节点都是平等的,几个节点挂掉不会影响正常节点的工作,剩余的节点依然可以提供注册和查询服务。而Eureka的客户端在向某个Eureka注册时,如果发现连接失败,则会自动切换至其他节点,只要有一台Eureka还在,就能保住注册服务的可用性,只不过查到的信息可能不是最新的,除此之外,Eureka还有之中自我保护机制,如果在15分钟内超过85%的节点都没有正常的心跳,那么Eureka就认为客户端与注册中心出现了网络故障,此时会出现以下几种情况:

Eureka不在从注册列表中移除因为长时间没收到心跳而应该过期的服务
Eureka仍然能够接受新服务的注册和查询请求,但是不会被同步到其他节点上 (即保证当前节点依然可用)
当网络稳定时,当前实例新的注册信息会被同步到其他节点中
因此,Eureka可以很好的应对因网络故障导致部分节点失去联系的情况,而不会像zookeeper那样使整个注册服务瘫痪

4.Ribbon负载均衡(微服务名字)

Spring Cloud Ribbon 是基于Netflix Ribbon 实现的一套客户端负载均衡的工具。
在这里插入图片描述
负载均衡简单的说就是将用户的请求平摊的分配到多个服务上,从而达到系统的HA (高用)。
集中式LB:Nginx
进程式 LB:Ribbon

springcloud-consumer-dept-80向pom.xml中添加Ribbon和Eureka依赖

<!--Ribbon-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-ribbon</artifactId>
            <version>1.4.7.RELEASE</version>
        </dependency>
        <!--Eureka: Ribbon需要从Eureka服务中心获取要拿什么-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-eureka</artifactId>
            <version>1.4.7.RELEASE</version>

        </dependency>

在application.yml文件中配置Eureka

eureka:
  client:
    register-with-eureka: false # 不向 Eureka注册自己
    service-url: # 从三个注册中心中随机取一个去访问
      defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/

主启动类加上@EnableEurekaClient注解,开启Eureka
配置负载均衡实现RestTemplate

@LoadBalanced //配置负载均衡实现RestTemplate
    @Bean
    public RestTemplate getRestTemplate() {
        return new RestTemplate();
    }

修改conroller:DeptConsumerController.java

private static final String REST_URL_PREFIX = "http://SPRINGCLOUD-PROVIDER-DEPT";

在这里插入图片描述
新建两个服务提供者Moudle:springcloud-provider-dept-8003、springcloud-provider-dept-8002

启动所有provider服务测试

每次访问http://localhost/consumer/dept/list随机访问集群中某个服务提供者,这种情况叫做轮询,轮询算法在SpringCloud中可以自定义

在myRule包下自定义一个配置类MyRule.java,注意:该包不要和主启动类所在的包同级,要跟启动类所在包同级

①MyRule配置类

@Configuration
public class MyRule {

    @Bean
    public IRule myRule(){
        return new MyRandomRule();//默认是轮询RandomRule,现在自定义为自己的
    }
}

②自定义的规则:MyRandomRule.java

public class MyRandomRule extends AbstractLoadBalancerRule {
    /**
     * 每个服务访问5次则换下一个服务(总共3个服务)
     * <p>
     * total=0,默认=0,如果=5,指向下一个服务节点
     * index=0,默认=0,如果total=5,index+1
     */
    private int total = 0;//被调用的次数
    private int currentIndex = 0;//当前是谁在提供服务

    //@edu.umd.cs.findbugs.annotations.SuppressWarnings(value = "RCN_REDUNDANT_NULLCHECK_OF_NULL_VALUE")
    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 = chooseRandomInt(serverCount);//生成区间随机数
            //server = upList.get(index);//从或活着的服务中,随机获取一个

            //=====================自定义代码=========================

            if (total < 5) {
                server = upList.get(currentIndex);
                total++;
            } else {
                total = 0;
                currentIndex++;
                if (currentIndex > upList.size()-1) {
                    currentIndex = 0;
                }
                server = upList.get(currentIndex);//从活着的服务中,获取指定的服务来进行操作
            }

            //======================================================

            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;
    }

    protected int chooseRandomInt(int serverCount) {
        return ThreadLocalRandom.current().nextInt(serverCount);
    }

    @Override
    public void initWithNiwsConfig(IClientConfig iClientConfig) {

    }

    @Override
    public Server choose(Object o) {
        return null;
    }
}

③主启动类开启负载均衡并指定自定义的MyRule配置类

//在微服务启动的时候就能加载自定义的Ribbon类(自定义的规则会覆盖原有默认的规则)
@RibbonClient(name = "SPRINGCLOUD-PROVIDER-DEPT",configuration = MyRule.class)//开启负载均衡,并指定自定义的规则

5.Feign负载均衡(接口和注解)

feign不是做负载均衡的,feign只是集成了ribbon,负载均衡还是feign内置的ribbon做。feign的作用的替代RestTemplate,性能比较低,但是可以使代码可读性很强。

根据个人习惯而定,如果喜欢REST风格使用Ribbon;如果喜欢社区版的面向接口风格使用Feign.
改造springcloud-api模块,添加依赖

<!--Feign的依赖-->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-feign</artifactId>
    <version>1.4.6.RELEASE</version>
</dependency>

新建service包,并新建DeptClientService.java接口

// @FeignClient:微服务客户端注解,value:指定微服务的名字,这样就可以使Feign客户端直接找到对应的微服务
@FeignClient(value = "SPRINGCLOUD-PROVIDER-DEPT")
public interface DeptClientService {

    @GetMapping("/dept/get/{id}")
    public Dept queryById(@PathVariable("id") Long id);

    @GetMapping("/dept/list")
    public Dept queryAll();

    @GetMapping("/dept/add")
    public Dept addDept(Dept dept);
}

拷贝springcloud-consumer-dept-80模块到springcloud-consumer-feign模块,并添加feign依赖。

<!--Feign的依赖-->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-feign</artifactId>
    <version>1.4.7.RELEASE</version>
</dependency>

主启动类

// feign客户端注解,并指定要扫描的包以及配置接口DeptClientService
@EnableFeignClients(basePackages = {"com.thebs.springcloud"})

改造后controller:DeptConsumerController.java

@Autowired
    private DeptClientService deptClientService;

6.Hystrix熔断

  • 服务降级
  • 服务熔断
  • 服务限流
  • 接近实时的监控

服务熔断

熔断机制是对应雪崩效应的一种微服务链路保护机制
①拷贝provider,新建springcloud-provider-dept-hystrix-8001模块,并导入hystrix依赖

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-hystrix</artifactId>
    <version>1.4.7.RELEASE</version>
</dependency>
#eureka配置
eureka:
  client:
    service-url:
      defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/
  instance:
    instance-id: provider-hystrix-8001
    prefer-ip-address: true #改为true后默认显示的是ip地址而不再是localhost

②修改Controller

  • 如果根据id查询出现异常,则走hystrixGet这段备选代码
    @HystrixCommand(fallbackMethod = "hystrixGet")
    @RequestMapping("/dept/get/{id}")//根据id查询
    public Dept get(@PathVariable("id") Long id){
        Dept dept = deptService.queryById(id);
        if (dept==null){
            throw new RuntimeException("这个id=>"+id+",不存在该用户,或信息无法找到~");
        }
        return dept;
    }
  • 根据id查询备选方案(熔断)
    public Dept hystrixGet(@PathVariable("id") Long id){
        return new Dept().setDeptno(id)
                .setDname("这个id=>"+id+",没有对应的信息,null---@Hystrix~")
                .setDb_source("在MySQL中没有这个数据库");
    }

③为主启动类添加对熔断的支持注解@EnableCircuitBreaker
测试访问一个不存在的id时,前台页展示数据如下:
在这里插入图片描述
不使用熔断的provider模块访问相同地址会出现下面状况:
在这里插入图片描述

服务降级

就是尽可能的把系统资源让给优先级高的服务。
在springcloud-api模块下的service包中新建降级配置类

@Component
public class DeptClientServiceFallBackFactory implements FallbackFactory {
    @Override
    public DeptClientService create(Throwable throwable) {
        return new DeptClientService() {
            @Override
            public Dept queryById(Long id) {
                return new Dept()
                        .setDeptno(id)
                        .setDname("id=>" + id + "没有对应的信息,客户端提供了降级的信息,这个服务现在已经被关闭")
                        .setDb_source("没有数据~");
            }
            @Override
            public List<Dept> queryAll() {
                return null;
            }

            @Override
            public boolean addDept(Dept dept) {
                return false;
            }
        };
    }
}

在DeptClientService中指定降级配置类

@FeignClient(value = "SPRINGCLOUD-PROVIDER-DEPT",fallbackFactory = DeptClientServiceFallBackFactory.class)

在springcloud-consumer-dept-feign模块中开启降级:

# 开启降级feign.hystrix
feign:
  hystrix:
    enabled: true

关闭provider模块,访问相同地址会出现下面状况:
在这里插入图片描述

服务熔断和降级的区别

服务熔断—>服务端:某个服务超时或异常
服务降级—>客户端:从整体网站请求负载考虑,当某个服务熔断或者关闭之后,服务将不再被调用,此时在客户端,我们可以准备一个 FallBackFactory ,返回一个默认的值(缺省值)。

  • 限流:限制并发的请求访问量,超过阈值则拒绝;

  • 降级:服务分优先级,牺牲非核心服务(不可用),保证核心服务稳定;从整体负荷考虑

  • 熔断:依赖的下游服务故障触发熔断,避免引发本系统崩溃;系统自动执行和恢复

实时的监控:Dashboard流

①新建springcloud-consumer-hystrix-dashboard模块

<dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-hystrix</artifactId>
            <version>1.4.7.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-hystrix-dashboard</artifactId>
            <version>1.4.7.RELEASE</version>
        </dependency>

②主启动类,@EnableHystrixDashboard开启Dashboard

③给springcloud-provider-dept-hystrix-8001模块下的主启动类添加如下代码,添加监控

//增加一个 Servlet
    @Bean
    public ServletRegistrationBean hystrixMetricsStreamServlet(){
        ServletRegistrationBean registrationBean = new ServletRegistrationBean(new HystrixMetricsStreamServlet());
        //访问该页面就是监控页面
        registrationBean.addUrlMappings("/actuator/hystrix.stream");
       
        return registrationBean;
    }

访问:http://localhost:9001/hystrix,进入监控页面:
在这里插入图片描述
在这里插入图片描述

7.Zuul网关

​ Zull包含了对请求的路由过滤两个最主要功能
其中路由功能负责将外部请求转发到具体的微服务实例上,是实现外部访问统一入口的基础,而过滤器功能则负责对请求的处理过程进行干预,是实现请求校验,服务聚合等功能的基础
在这里插入图片描述
注意:Zuul 服务最终还是会注册进 Eureka

① 新建springcloud-zuul模块,并导入依赖

 <dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-zuul</artifactId>
    <version>1.4.7.RELEASE</version>
</dependency>
# zuul 路由网关配置
zuul:
  # 路由相关配置
  # 原来访问路由 eg:http://www.thebs.com:9527/springcloud-provider-dept/dept/get/1
  # zull路由配置后访问路由 eg:http://www.thebs.com:9527/thebs/mydept/dept/get/1
  routes:
    mydept.serviceId: springcloud-provider-dept # eureka注册中心的服务提供方路由名称
    mydept.path: /mydept/** # 将eureka注册中心的服务提供方路由名称 改为自定义路由名称
  # 不能再使用这个路径访问了,*: 忽略,隐藏全部的服务名称~
  ignored-services: "*"
  # 设置公共的前缀
  prefix: /thebs

主启动类

@SpringBootApplication
@EnableZuulProxy // 开启Zuul
public class ZuulApplication_9527 {

    public static void main(String[] args) {
        SpringApplication.run(ZuulApplication_9527.class,args);
    }
}

在这里插入图片描述
服务接口访问的路由,可以看出直接用微服务(服务提供方)名称去访问,这样不安全
所以经过Zull路由网关配置后,访问的路由为:
在这里插入图片描述

8.Spring Cloud Config 分布式配置

分布式系统面临的–配置文件问题
微服务意味着要将单体应用中的业务拆分成一个个子服务,每个服务的粒度相对较小,因此系统中会出现大量的服务,由于每个服务都需要必要的配置信息才能运行,所以一套集中式的,动态的配置管理设施是必不可少的。
在这里插入图片描述

​ spring cloud config 分为服务端和客户端两部分。
git基本命令:

git clone
git add .
git status
git commit -m ""
git push origin master

spring cloud config 分布式配置中心与Git整合

服务端

新建springcloud-config-server-3344模块导入pom.xml依赖

<dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-config-server</artifactId>
            <version>2.1.1.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-eureka</artifactId>
            <version>1.4.7.RELEASE</version>
        </dependency>
    </dependencies>
server:
  port: 3344

spring:
  application:
    name: springcloud-config-server
    # 远程连接仓库
  cloud:
    config:
      server:
        git:
          uri: https://gitee.com/YioiL/springcloud-config.git #http,不是git
# 通过 config-server可以连接到git,访问其中的资源以及配置~

主启动类

@SpringBootApplication
@EnableConfigServer
public class Config_Server_3344 {
    public static void main(String[] args) {
        SpringApplication.run(Config_Server_3344.class,args);
    }
}

HTTP服务具有以下格式的资源:

/{application}/{profile}[/{label}]
/{application}-{profile}.yml
/{label}/{application}-{profile}.yml
/{application}-{profile}.properties
/{label}/{application}-{profile}.properties

测试访问http://localhost:3344/application-dev.yml

客户端

远程配置文件

spring:
  profiles:
    active: dev
---
server:
  port: 8201

spring:
  profiles: dev
  application:
    name: springcloud-provider
eureka:
  client:
    service-url: 
      defaultZone:  http://eureka7001.com:7001/eureka/
---
server:
  port: 8202

spring:
  profiles: test
  application:
    name: springcloud-provider
eureka:
  client:
    service-url:
      defaultZone:  http://eureka7001.com:7001/eureka/
<dependencies>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-config</artifactId>
    </dependency>

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-actuator</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
</dependencies>

创建配置文件

bootstrap.yml 是系统级别的配置

# 系统级别的配置
spring:
  cloud:
    config:
      name: config-client # 需要从git上读取的资源名称,不要后缀
      profile: dev
      label: master
      uri: http://localhost:3344

application.yml 是用户级别的配置

# 用户级别的配置
spring:
  application:
    name: springcloud-config-client

创建controller包下的ConfigClientController.java 用于测试

@RestController
public class ConfigClientController {

    @Value("${spring.application.name}")
    private String applicationName; //获取微服务名称

    @Value("${eureka.client.service-url.defaultZone}")
    private String eurekaServer; //获取Eureka服务

    @Value("${server.port}")
    private String port; //获取服务端的端口号


    @RequestMapping("/config")
    public String getConfig(){
        return "applicationName:"+applicationName +
         "eurekaServer:"+eurekaServer +
         "port:"+port;
    }
}

主启动类

@SpringBootApplication
public class ConfigClient {
    public static void main(String[] args) {
        SpringApplication.run(ConfigClient.class,args);
    }
}

访问http://localhost:8201/config/
在这里插入图片描述

小案例

本地新建config-dept.yml和config-eureka.yml并提交到码云仓库

spring:
  profiles:
    active: dev
---
server:
  port: 7001

  spring:
    profiles: dev
    application:
      name: springcloud-config-eureka

eureka:
  instance:
    hostname: eureka7001.com
  client:
    register-with-eureka: false #是否向注册中心注册自己
    fetch-registry: false   #false表示自己是注册中心
    service-url:  #监控页面
      #defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
      defaultZone: http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/
---
server:
  port: 7002

  spring:
    profiles: test
    application:
      name: springcloud-config-eureka

eureka:
  instance:
    hostname: eureka7002.com
  client:
    register-with-eureka: false #是否向注册中心注册自己
    fetch-registry: false   #false表示自己是注册中心
    service-url:  #监控页面
      #defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
      defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7003.com:7003/eureka/
spring:
  profiles:
    active: dev
---
server:
  port: 8001
mybatis:
  type-aliases-package: com.thebs.springcloud.pojo
  config-location: classpath:mybatis/mybatis-config.xml
  mapper-locations: classpath:mybatis/mapper/*.xml


spring:
  profiles: dev
  application:
    name: springcloud-provider-dept
  datasource:
    type: com.alibaba.druid.pool.DruidDataSource
    driver-class-name: com.mysql.jdbc.Driver
    url: jdbc:mysql://localhost:3306/db01?useUnicode=true&characterEncoding=utf-8
    username: root
    password: root


#eureka配置
eureka:
  client:
    service-url:
      defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/
  instance:
    instance-id: provider-8001
#info配置
info:
  app.name: thebs-springcloud
  company.name: thebs
---
server:
  port: 8002
mybatis:
  type-aliases-package: com.thebs.springcloud.pojo
  config-location: classpath:mybatis/mybatis-config.xml
  mapper-locations: classpath:mybatis/mapper/*.xml


spring:
  profiles: test
  application:
    name: springcloud-provider-dept
  datasource:
    type: com.alibaba.druid.pool.DruidDataSource
    driver-class-name: com.mysql.jdbc.Driver
    url: jdbc:mysql://localhost:3306/db02?useUnicode=true&characterEncoding=utf-8
    username: root
    password: root


#eureka配置
eureka:
  client:
    service-url:
      defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/
  instance:
    instance-id: provider-8002
#info配置
info:
  app.name: thebs-springcloud
  company.name: thebs

拷贝原有的,新建springcloud-config-eureka-7001模块
并新建bootstrap.yml连接远程配置

spring:
  cloud:
    config:
      name: config-eureka # 仓库中的配置文件名称
      label: master
      profile: dev
      uri: http://localhost:3344

加入依赖

<!--config-->
<!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-config -->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-config</artifactId>
    <version>2.1.1.RELEASE</version>
</dependency>

主启动类

@SpringBootApplication
@EnableEurekaServer //EnableEurekaServer 服务端的启动类,可以接受别人注册进来~
public class ConfigEurekaServer_7001 {
    public static void main(String[] args) {
        SpringApplication.run(ConfigEurekaServer_7001.class,args);
    }
}

访问 http://localhost:7001/ 测试
在这里插入图片描述

同理privider配置如下:

spring:
  cloud:
    config:
      name: config-dept
      label: master
      profile: dev
      uri: http://localhost:3344

总结

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值