SpringCloud使用手册

本文最后更新于:2021年1月25日 晚上

一、常见面试题

1.1 什么是微服务?

1.2 微服务之间是如何独立通讯的?

1.3 SpringCloud 和 Dubbo有那些区别?

1.4 SpringBoot 和 SpringCloud,请谈谈你对他们的理解

1.5 什么是服务熔断?什么是服务降级?

1.6 微服务的优缺点分别是什么?说下你在项目开发中遇到的坑

1.7 你所知道的微服务技术栈有哪些?列举一二

1.8 Eureka和Zookeeper都可以提供服务注册与发现的功能,请说说两者的区别

1.9 SpringCloud的五大组件

  • 服务注册与发现:Netflix Eureka
  • 负载均衡
    • 客户端负载均衡:Netflix Ribbon
    • 服务端负载均衡:Feign(其也是基于Ribbon,只是将调用方式Rest Templete更改成Service 接口)
  • 断路器:Netflix Hystrix
  • 服务网关:Netflix Zuul
  • 此外,分布式配置可以使用Spring Cloud Config实现

二、微服务概述

1)什么是微服务

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

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

2)优缺点

  • 优点:开发简单,开发效率高,一个服务可能就是专一的只干一件事;微服务是松耦合的,是有功能意义的服务,无论是在开发阶段或部署阶段都是独立的;每个微服务都有自己的存储能力,可以有自己的数据库,也可以有统一的数据库;微服务易于被一个开发人员理解,修改和维护,这样小团队能够更关注自己的工作成果,无需通过合作才能体现价值
  • 缺点:开发人员要处理分布式系统的复杂性,处理系统部署依赖、服务间通信成本、数据一致性、系统集成测试、性能和监控问题等等;多服务运维难度,随着服务的增加,运维的压力也在增大

3)微服务的技术栈

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

4)各微服务框架对比

功能点/服务框架 Netflix/SpringCloud Motan gRPC Thri t Dubbo/DubboX
功能定位 完整的微服务框架 RPC框架,但整合了ZK或Consul,实现集群环境的基本服务注册发现 RPC框架 RPC框架 服务框架
支持Rest 是,Ribbon支持多种可拔插的序列号选择
支持RPC 是(Hession2)
支持多语言 是(Rest形式)
负载均衡 是(服务端zuul+客户端Ribbon),zuul-服务,动态路由,云端负载均衡Eureka(针对中间层服务器) 是(客户端) 是(客户端)
配置服务 Netfix Archaius,Spring Cloud Config Server 集中配置 是(Zookeeper提供)
服务调用链监控 是(zuul),zuul提供边缘服务,API网关
高可用/容错 是(服务端Hystrix+客户端Ribbon) 是(客户端) 是(客户端)
典型应用案例 Netflix Sina Google Facebook
社区活跃程度 一般 一般 2017年后重新开始维护,之前中断了5年
学习难度 中等
文档丰富程度 一般 一般 一般
其他 Spring Cloud Bus为我们的应用程序带来了更多管理端点 支持降级 Netflix内部在开发集成gRPC IDL定义 实践的公司比较多

三、SpringCloud概述

1)SpringCloud 和 SpringBoot间的联系

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

2)SpringCloud 和 Dubbo间的区别

Dubbo SpringCloud
服务注册中心 Zookeeper Spring Cloud Netflix Eureka
服务调用方式 RPC REST API
服务监控 Dubbo-monitor Spring Boot Admin
断路器 不完善 Spring Cloud Netflix Hystrix
服务网关 Spring Cloud Netflix Zuul
分布式配置 Spring Cloud Config
服务跟踪 Spring Cloud Sleuth
消息总栈 Spring Cloud Bus
数据流 Spring Cloud Stream
批量任务 Spring Cloud Task

最大区别是:SpringCloud抛弃了Dubbo的RPC通信,改为采用基于HTTP的REST方式调用服务,虽然在一定程度上来说,后者牺牲了服务调用的性能,但REST相比RPC更为灵活,服务提供方和调用方的依赖只依靠一纸契约,不存在代码级别的强依赖,这个优点在当下强调快速演化的微服务环境下,显得更加合适。

Dubbo断更了五年,重新维护后开始定位为一款专业的RPC框架,而SpringCloud的目标是微服务架构下的一站式解决方案

3)版本概述

官网:http://projects.spring.io/spring-cloud/

SpringCloud没有采用数字编号的方式命名版本号,而是采用了伦敦地铁站的名称,同时根据字母表的顺序来对应版本时间顺序,比如最早的Release版本:Angel,第二个Release版本:Brixton,然后是Camden、Dalston、Edgware,目前最新的是Hoxton.SR9

四、SpringCloud 基础环境构建

1)任务概述

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

2)创建父工程

新建父工程springcloud,导入相关依赖

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.kuang</groupId>
    <artifactId>springcloud</artifactId>
    <version>1.0-SNAPSHOT</version>
    
    <!-- 包含的各个子模块 -->
    <modules>
        <module>springcloud-api</module>
        <module>springcloud-provider-dept-8001</module>
        <module>springcloud-consumer-dept-80</module>
        <module>springcloud-eureka-7001</module>
        <module>springcloud-eureka-7002</module>
        <module>springcloud-eureka-7003</module>
        <module>springcloud-provider-dept-8002</module>
        <module>springcloud-provider-dept-8003</module>
        <module>springcloud-consumer-dept-feign</module>
        <module>springcloud-provider-dept-hystrix-8001</module>
        <module>springcloud-consumer-hystrix-dashboard</module>
        <module>springcloud-zuul-9527</module>
        <module>springcloud-config-server-3344</module>
        <module>springcloud-config-client-3355</module>
        <module>springcloud-config-eureka-7001</module>
        <module>springcloud-config-dept-8001</module>
    </modules>

    <!-- 打包方式为 pom-->
    <packaging>pom</packaging>

    <!-- 项目编码方式为UTF-8,java版本1.8 
          可以在此处指定一些包的版本,下面直接调用该值即可-->
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.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>

    
    <!-- 各个依赖项 -->
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-alibaba-dependencies</artifactId>
                <version>0.2.0.RELEASE</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <!--springCloud的依赖-->
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>Greenwich.SR1</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <!--SpringBoot依赖项(直接创建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>
            <!--数据库驱动、连接池、Mybatis-->
            <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.10</version>
            </dependency>
            <dependency>
                <groupId>org.mybatis.spring.boot</groupId>
                <artifactId>mybatis-spring-boot-starter</artifactId>
                <version>1.3.2</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>

</project>

3)创建实体类Dept

4)服务提供方

导入相关依赖,如实体类的api module、spring相关、数据库相关等等。由于子模块会集成父项目,因此,此处无需指定Spring这类包的版本号。

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

编写dao接口及其实现,编写service接口及其实现(调用dao接口),更新配置文件application.yml

server:
  port: 8001

#mybatis配置
mybatis:
  type-aliases-package: com.kuang.springcloud.pojo
  config-location: classpath:mybatis/mybatis-config.xml
  mapper-locations: classpath:mybatis/mapper/*.xml


#spring的配置
spring:
  application:
    name: springcloud-provider-dept   # 该名字对应Eureka监控界面中的application name
  datasource:
    type: com.alibaba.druid.pool.DruidDataSource
    driver-class-name: org.gjt.mm.mysql.Driver
    url: jdbc:mysql://localhost:3306/db01?serverTimezone=UTC&useUnicode=true&useSSL=false&characterEncoding=utf-8
    username: root
    password: root

5)服务消费方

DeptConsumerController.java

package com.kuang.springcloud.controller;

import com.kuang.springcloud.pojo.Dept;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

import java.util.List;

@RestController
public class DeptConsumerController {

    // 消费者,其调用生成者的服务,因此其本身无需创建service层
    
    // RestTemplate 提供多种便捷访问远程http服务的方法,简单的Restful服务模板!
    @Autowired
    private RestTemplate restTemplate;

    // 服务提供方的地址
    //private static final String REST_URL_PREFIX = "http://SPRINGCLOUD-PROVIDER-DEPT";
    private static final String REST_URL_PREFIX = "http://localhost:8001";


    // 通过url+实体 +响应类型 调用服务提供者的对应方法
    // 提交用postForObject,获取用getForObject
    @RequestMapping("/consumer/dept/add")
    public boolean add(Dept dept){
        return restTemplate.postForObject(REST_URL_PREFIX+"/dept/add",dept,Boolean.class);
    }

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


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

}

采用RestTemplete前,需将其添加到Spring容器中。创建config/ConfigBean.java文件

package com.kuang.springcloud.config;

import com.netflix.loadbalancer.IRule;
import com.netflix.loadbalancer.RandomRule;
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 { 

    // 配置负载均衡实现RestTemplate
    // 可以通过重写IRule类,自定义负载均衡的规则,默认为轮询
    // RoundRobinRule 轮询;RandomRule 随机;AvailabilityFilteringRule 先过滤掉跳闸、访问故障的服务,再对剩下的进行轮询;RetryRule 先按照轮询获取服务,如果服务获取失败,则会在指定的时间内进行,重试
    
    @Bean   // 将Restful服务模板注册到Spring容器中
    @LoadBalanced // 开启Ribbon的负载均衡
    public RestTemplate getRestTemplate(){
        return new RestTemplate();
    }
}

此时,按理说此时就可以启动springcloud-provider-dept-8001和springcloud-consumer-dept-80的启动类,然后通过

http://localhost:8001/consumer/dept/list调用相关方法了。

五、Eureka:服务注册中心

1)概述

Eureka是Netflix开发的一款服务发现框架,本身是一个基于REST的服务,主要用于定位运行在AWS域中的中间层服务,以达到负载均衡和中间层服务故障转移的目的。SpringCloud将它集成在其子项目spring-cloud-netflix中,以实现SpringCloud的服务发现功能。

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

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

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

  • Eureka Server:提供服务的注册与发行
  • Service Provider:服务提供方,将自身服务注册到Eureka中,从而使服务消费方可以找到并调用
  • Service Consumer:服务消费方,从Eureka中获取注册服务列表,从而找到所需要的服务

基础环境中搭配完毕,只要再构建好服务注册中心,就可以…(Eureka的好处体现在哪呢。。)

2)构建步骤

基本可以分为三步:导入依赖、配置yaml文件、开启注解

🌏 服务器端:创建子maven模块springcloud-eureka-7001,导入eureka依赖,编写配置文件修改服务器端实例名称、监控界面地址等等,最后在主启动类中开启注解

<dependencies>
    <!-- 注册中心Eureka -->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-eureka-server</artifactId>
        <version>1.4.6.RELEASE</version>
    </dependency>
    <!-- 热部署工具 -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-devtools</artifactId>
    </dependency>
</dependencies>
server:
  port: 7001

#Eureka配置
eureka:
  instance:
    hostname: eureka7001.com   # Eureka服务端的实例名称,一般为127.0.0.1或者localhost(此处修改了host文件)
  client:
    register-with-eureka: false # 是否在eureka注册中心中进行注册,此处为服务器端,无需注册
    fetch-registry: false   # 注册中心端为false,客户端为true
    service-url:   # 监控界面
     # 单机:
     #defaultZone: http://${eureka.instance.hostname}:${server.port}/
     # 集群(关联):
     defaultZone: http://eureka7002.com:7002/,http://eureka7003.com:7003/
package com.kuang.springcloud;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;


@SpringBootApplication
@EnableEurekaServer // 开启注解,使客户端可以注册进来
public class EurekaServer_7001 {
    public static void main(String[] args) {
        SpringApplication.run(EurekaServer_7001.class,args);
    }
}

若要构建注册中心集群,可以按照子maven模块springcloud-eureka-7001中的文件,新建7002和7003子模块,然后仅修改两个新的子模块中的yaml配置文件即可

server:
  port: 7002

#Eureka配置
eureka:
  instance:
    hostname: eureka7002.com #Eureka服务端的实例名称
  client:
    register-with-eureka: false # 是否在eureka注册中心中进行注册,此处为服务器端,无需注册
    fetch-registry: false   # 注册中心端为false,客户端为true
    service-url:   # 监控界面,端口号后面没有Eureka!!
      defaultZone: http://eureka7001.com:7001/,http://eureka7003.com:7003/
server:
  port: 7003

#Eureka配置
eureka:
  instance:
    hostname: eureka7003.com #Eureka服务端的实例名称
  client:
    register-with-eureka: false # 表示是否向eureka注册中心注册自己
    fetch-registry: false #fetch-registry如果为false,则表示自己为注册中心
    service-url:  # 监控页面
      defaultZone: http://eureka7001.com:7001/,http://eureka7002.com:7002/

🌏 客户端1:修改之前的 服务提供端子模块springcloud-provider-dept-8001,将其在注册中心中注册服务。依旧是导入eureka依赖、更新yaml文件、开启注解三步

# Eureka的配置,服务注册到哪里
eureka:
  client:
    service-url:
      defaultZone: http://eureka7001.com:7001/eureka/
  instance:
    instance-id: springcloud-provider-dept8001   # 修改eureka上的默认描述信息!
    prefer-ip-address: true  # 是否在eurake监控界面显示服务的IP地址
package com.kuang.springcloud;

import com.netflix.hystrix.contrib.metrics.eventstream.HystrixMetricsStreamServlet;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.context.annotation.Bean;

//启动类
@SpringBootApplication
@EnableEurekaClient   //在服务启动后自动注册到Eureka中!
public class DeptProvider_8001 {
    public static void main(String[] args) {
        SpringApplication.run(DeptProvider_8001.class,args);
    }
}

此时,启动这两个子模块,访问http://eureka7001.com:7001/ 或者 http://localhost:7001/即可进入Spring Eureka的监控界面。

🌏 客户端2:修改之前的 服务消费端子模块springcloud-consumer-dept-80,导入eureka依赖,并在yaml文件中配置注册中心的地址,主启动类开启注解

server:
  port: 80

#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/
package com.kuang.springcloud;

import com.kuang.myrule.KuangRule;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.cloud.netflix.ribbon.RibbonClient;

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

此时启动该子模块,即可通过http://localhost:80/consumer/dept/list执行相应的服务

3)Eureka 和 ZooKeeper

  • ACID原则:Atomicity 原子性、Consistency 一致性、Isolation 隔离性、Durability 持久性
  • CAP原则:Consistency 一致性、Availability 可用性、Partition tolerance 分区容错性
    • 一个分布式系统不可能同时很好的满足CAP原则,只能三选二;但分区容错性对分布式系统是非常重要的,因此,只能最终只能在一致性和可用性间抉择。
  • 两者的区别在于:
    • Zookeeper保证的是一致性和分区容错性,CP:当向注册中心查询服务列表时,我们可以容忍注册中心返回的是几分钟以前的注册信息,但不能接受服务直接down掉不可用。也就是说,服务注册功能对可用性的要求要高于一致性。但zookeeper会出现这样一种情况,当主节点因为网络故障与其他节点失去联系时,剩余节点会重新进行leader选举。而leader选举的时间一般可能会持续30-120s,且选举期间整个zookeeper集群是不可用的,这就会导致选举期间的整个注册服务瘫痪。在云部署的环境下,因为网络问题使得zookeeper集群失去master节点是较大概率发生的事件,虽然服务最终能够恢复,但是,漫长的选举时间导致注册长期不可用,是不可容忍的。
    • Eureka保证的是可用性和分区容错性,AP:各个节点是平等的,几个节点挂掉不会影响正常节点的工作,剩余的节点依然可以提供注册和查询服务。而Eureka的客户端在向某个Eureka注册时,如果发现连接失败,则会自动切换至其他节点,只要有一台Eureka还在,就能保住注册服务的可用性,只不过查到的信息可能不是最新的,除此之外,Eureka还有之中自我保护机制,如果在15分钟内超过85%的节点都没有正常的心跳,那么Eureka就认为客户端与注册中心出现了网络故障,此时会出现以下几种情况:
      • Eureka不在从注册列表中,移除因为长时间没收到心跳而应该过期的服务
      • Eureka仍然能够接受新服务的注册和查询请求,但是不会被同步到其他节点上 (即保证当前节点依然可用)
      • 当网络稳定时,当前实例新的注册信息会被同步到其他节点中
    • Eureka可以很好的应对因网络故障导致部分节点失去联系的情况,而不会像zookeeper那样使整个注册服务瘫痪

六、Ribbon:基于客户端的负载均衡

1)概述

Spring Cloud Ribbon 是基于Netflix Ribbon 实现的一套客户端负载均衡的工具

  • 负载均衡(LoadBalancer,LB)就是将用户的请求分配到多个服务器上,从而达到系统的HA (高用)。

  • 常见的负载均衡软件有 Nginx、Lvs等等。Dubbo、SpringCloud等也支持负载均衡,

  • 分类:

    • 集中式LB:在服务的提供方和消费方之间使用独立的负载均衡设施,如反向代理服务器Nginx,由该设施负责将访问请求通过某种策略转发至服务提供方
    • 进程式LB:将负载均衡集成到消费方,消费方从服务注册中心获取可用的服务地址,然后自己再从这些地址选取一个使用,如Ribbon
    • 没太懂啊…

2)集成Ribbon

黄金三步,导入依赖,配置yaml文件,开启注释

由于Ribbon是集成于消费方的负载均衡应用,因此我们对之前的子模块springcloud-consumer-dept-80进行升级改造

  • 导入Eureka和Ribbon依赖

    <?xml version="1.0" encoding="UTF-8"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
        <parent>
            <artifactId>springcloud</artifactId>
            <groupId>com.kuang</groupId>
            <version>1.0-SNAPSHOT</version>
        </parent>
        <modelVersion>4.0.0</modelVersion>
    
        <artifactId>springcloud-consumer-dept-80</artifactId>
    
        <dependencies>
            <!-- 实体类、web、热部署 -->
            <dependency>
                <groupId>com.kuang</groupId>
                <artifactId>springcloud-api</artifactId>
                <version>1.0-SNAPSHOT</version>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-devtools</artifactId>
            </dependency>
            
            <!-- 注册中心erueka -->
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-eureka</artifactId>
                <version>1.4.6.RELEASE</version>
            </dependency>
            <!-- 负载均衡Ribbon -->
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-ribbon</artifactId>
                <version>1.4.6.RELEASE</version>
            </dependency>
        </dependencies>
    
    
    </project>
  • 配置yaml

    server:
      port: 80
    
    
    #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/
  • 开启注释

    在配置类src/main/java/com/kuang/springcloud/config/ConfigBean.java加入注释@LoadBalanced开启负载均衡

    package com.kuang.springcloud.config;
    
    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();
        }
    
    }
  • 修改Controller这的远程路径:之前只有一个服务提供者,我们可以采用某个端口号来访问,但目前多个服务提供者时采用固定的地址和端口就不现实了。此时,我们可以将控制器类DeptConsumerController.java的restful地址修改为应用程序名。

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

    此时,多次访问http://localhost/consumer/dept/list,便会发现数据来源从db01-db03直接切换。这是因为Ribbon负载均衡已成功启用,每次访问时按照轮询算法访问服务器

如何改变或者自定义Ribbon的负载均衡规则呢?

创建文件src/mian/java/com/kuang/myrule/KuangRule.java重写Irule方法即可。

  • myrule文件夹不可与主启动类同一级目录
package com.kuang.myrule;

import com.netflix.loadbalancer.IRule;
import com.netflix.loadbalancer.RoundRobinRule;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class KuangRule {

    @Bean
    public IRule myRule(){
        return new RoundRobinRule();    // 默认是轮询
        //return new RandomRule();  // 随机
        //return new AvailabilityFilteringRule();  // 会先过滤掉,跳闸,访问故障的服务,对剩下的进行轮询
        //return new RetryRule();    // 会先按照轮询获取服务,如果服务获取失败,则会在指定的时间内进行,重试
        //return new MyCustomRule()  // 我们自定义的规则
    }

}

之后,还需将该配置文件绑定到主启动类上

package com.kuang.springcloud;

import com.kuang.myrule.KuangRule;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.cloud.netflix.ribbon.RibbonClient;

//Ribbon 和 Eureka 整合以后,客户端可以直接调用,不用关心IP地址和端口号~
@SpringBootApplication
@EnableEurekaClient
//在微服务启动的时候就能去加载我们自定义Ribbon类;该类不要和主启动类放在同一目录下
@RibbonClient(name = "SPRINGCLOUD-PROVIDER-DEPT",configuration = KuangRule.class)
public class DeptConsumer_80 {
    public static void main(String[] args) {
        SpringApplication.run(DeptConsumer_80.class,args);
    }
}

七、Feign:基于服务端的负载均衡

1)Feign概述

2)使用步骤

3)Feign与Ribbon区别

八、Hystrix:服务熔断

1)概述

服务雪崩

Hystrix

2)采用服务熔断

3)服务降级

九、Zuul:路由网关

1)Zuul概述

Zull包含了对请求的路由(用来跳转的)和过滤两个最主要功能:

  • 路由功能:负责将外部请求转发到具体的微服务实例上,是实现外部访问统一入口的基础,
  • 过滤器功能:负责对请求的处理过程进行干预,是实现请求校验,服务聚合等功能的基础。

Zuul和Eureka进行整合,将Zuul自身注册为Eureka服务治理下的应用,同时从Eureka中获得其他服务的消息,也即以后的访问微服务都是通过Zuul跳转后获得。

2)入门案例

  • 新建springcloud-zuul-9527,导入依赖

    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-zuul</artifactId>
        <version>1.4.6.RELEASE</version>
    </dependency>
  • 编写配置文件

    server:
      port: 9527
    
    spring:
      application:
        name: springcloud-zuul #微服务名称
    
    # eureka 注册中心配置
    eureka:
      client:
        service-url:
          defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/
      instance: #实例的id
        instance-id: zuul9527.com
        prefer-ip-address: true # 显示ip
    
    info:
      app.name: haust.springcloud # 项目名称
      company.name: 河南科技大学西苑校区 # 公司名称
    
    # zull 路由网关配置
    zuul:
      # 路由相关配置
      # 原来访问路由 eg:http://www.cspStudy.com:9527/springcloud-provider-dept/dept/get/1
      # zull路由配置后访问路由 eg:http://www.cspstudy.com:9527/haust/mydept/dept/get/1
      routes:
        mydept.serviceId: springcloud-provider-dept # eureka注册中心的服务提供方路由名称
        mydept.path: /mydept/** # 将eureka注册中心的服务提供方路由名称 改为自定义路由名称
      # 不能再使用这个路径访问了,*: 忽略,隐藏全部的服务名称~
      ignored-services: "*"
      # 设置公共的前缀
      prefix: /haust

十、SpringCloud Config分布式配置


本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!