Spring Cloud Netflix 官方解读

目录

前言:

1、什么是微服务?

2、微服务架构和分布式架构的区别?

1、含义不同

2、概念层面不同

3、解决问题不同

4、部署方式不同

5、耦合度不同

3、什么是Spring Cloud?

4、SpringCloud的五大神兽?

Eureka

Ribbon

Feign

Hystrix

Zuul


前言:

准备学习SpringCloud系列的精英们,我想你们已经挺过了Java基础的艰苦斗争,也迎来了第一个春天(Spring)和第二个春天极速版(SpringBoot)

那么SpringCloud作为程序员的第三春,我们应该如何学习?

所以本文章就以解读官方文档为基础,阐述SpringCloud的理论知识,当然我也会列举这些理论的基本实现

1、什么是微服务?

在开始解读之前,我们首先要对微服务有个基本的认识:

微服务(或微服务架构)是一种云原生架构方法,其中单个应用程序由许多松散耦合且可独立部署的较小组件或服务组成。

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

2、微服务架构和分布式架构的区别?

为了避免将这两者概念弄混,这里单独拎出来作解释。

但需要注意的是分布式是属于微服务的,微服务的意思也就是将模块拆分成一个独立的服务单元通过接口来实现数据的交互。但是微服务不一定是分布式,因为微服务的应用不一定是分散在多个服务器上,他也可以是同一个服务器。这也是分布式

1、含义不同

微服务架构:微服务架构风格是一种将一个单一应用程序开发为一组小型服务的方法,每个服务运行在自己的进程中,服务间通信采用轻量级通信机制(通常用HTTP资源API)。这些服务围绕业务能力构建并且可通过全自动部署机制独立部署。这些服务共用一个最小型的集中式的管理,服务可用不同的语言开发,使用不同的数据存储技术。

分布式架构:分布式系统是若干独立计算机的集合,这些计算机对用户来说就像单个相关系统,即整个系统是由不同的计算机组成,而用户是无感知的,就像访问一台计算机一样。这里强调的是系统由不同物理上分离的计算机(服务器)组成。

2、概念层面不同

微服务架构:微服务是设计层面的东西,一般考虑如何将系统从逻辑上进行拆分,也就是垂直拆分。微服务可以是分布式的,即可以将不同服务部署在不同计算机上,当然如果量小也可以部署在单机上。

分布式架构:分布式是部署层面的东西,即强调物理层面的组成,即系统的各子系统部署在不同计算机上。

3、解决问题不同

微服务架构:微服务解决的是系统复杂度问题: 一般来说是业务问题,即在一个系统中承担职责太多了,需要打散,便于理解和维护,进而提升系统的开发效率和运行效率,微服务一般来说是针对应用层面的。微服务如果用在其它系统,如存储系统感觉怪怪的,就像说Mysql集群是微服务的,总觉得哪里不舒服。

分布式架构:分布式解决的是系统性能问题: 即解决系统部署上单点的问题,尽量让组成系统的子系统分散在不同的机器上进而提高系统的吞吐能力。

4、部署方式不同

微服务架构:微服务的应用可以部署在是同一个服务器,不一定是分散在多个服务器上。微服务架构是一项在云中部署应用和服务的新技术。微服务架构是一种架构模式,它将一个复杂的大型应用程序划分成多个微服务,这些小型服务都在各自独立的进程中运行。

分布式架构:分布式是将一个大的系统划分为多个业务模块,这些业务模块会分别部署到不同的机器上,通过接口进行数据交互。

5、耦合度不同

微服务相比分布式服务来说,它的粒度更小,服务之间耦合度更低,由于每个微服务都由独立的小团队负责,因此它敏捷性更高,分布式服务最后都会向微服务架构演化,这是一种趋势,不过服务微服务化后带来的挑战也是显而易见的,例如服务粒度小,数量大,后期运维将会很难。

3、什么是Spring Cloud?

Spring Cloud是一系列框架的有序集合。它利用Spring Boot的开发便利性巧妙地简化了分布式系统基础设施的开发,如服务发现注册、配置中心、消息总线、负载均衡、断路器、数据监控等,都可以用Spring Boot的开发风格做到一键启动和部署。Spring Cloud并没有重复制造轮子,它只是将各家公司开发的比较成熟、经得起实际考验的服务框架组合起来,通过Spring Boot风格进行再封装屏蔽掉了复杂的配置和实现原理,最终给开发者留出了一套简单易懂、易部署和易维护的分布式系统开发工具包

所以我们在上面的描述中得出一个结论,SpringCloud不是一门技术,而是一个工具,更像是一个生态!!!

开发分布式系统可能具有挑战性。复杂性从应用层转移到网络层,并要求服务之间有更多的交互。让你的代码“云原生”意味着要处理12个因素(也就是作为微服务开发的最终目的

十二个因素是哪些呢?

I. Codebase

从一个代码库部署到多个环境。

II. Dependencies

使用显式的声明隔离依赖,即模块单独运行,并可以显式管理依赖。

III. Config

在系统外部存储配置信息。

IV. Backing Services

把支持性服务看做是资源,支持性服务包括数据库、消息队列、缓冲服务器等。

V. Build, release, run

严格的划分编译、构建、运行阶段,每个阶段由工具进行管理。

VI. Processes

应用作为无状态执行。

VII. Port binding

经由端口绑定导出服务,优先选择 HTTP API 作为通用的集成框架。

VIII. Concurrency

并发性使用水平扩展实现,对于web就是水平扩展web应用实现。

IX. Disposability

服务可处置性,任何服务可以随意终止或启动。

X. Dev/prod parity

开发和生产环境保持高度一致,一键式部署。

XI. Logs

将日志看做是事件流来管理,所有参与的服务均使用该方式处理日志。

XII. Admin processes

管理任务作为一次性的过程运行(使用脚本管理服务启动和停止)。


Spring Cloud的子项目,大致可分成两类:

第一类是对现有成熟框架”Spring Boot化”的封装和抽象,也是数量最多的项目;

第二类是开发了一部分分布式系统的基础设施的实现,如Spring Cloud Stream扮演的就是kafka, ActiveMQ这样的角色。对于我们想快速实践微服务的开发者来说,第一类子项目就已经足够使用,所以为什么以Spring Cloud Netflix作为切入点,原因就在这里

Spring Cloud Netflix

是对Netflix开发的一套分布式服务框架的封装,包括服务的发现和注册,负载均衡、断路器、REST客户端、请求路由等。

Spring Cloud Config将配置信息中央化保存, 配置Spring Cloud Bus可以实现动态修改配置文件
Spring Cloud Stream分布式消息队列,是对Kafka, MQ的封装
Spring Cloud Security对Spring Security的封装,并能配合Netflix使用
Spring Cloud Zookeeper对Zookeeper的封装,使之能配置其它Spring Cloud的子项目使用
Spring Cloud Eureka是 Spring Cloud Netflix 微服务套件中的一部分,它基于Netflix Eureka 做了二次封装,主要负责完成微服务架构中的服务治理功能。

4、SpringCloud的五大神兽?

Eureka:

Eureka是由Netflix公司推出的服务注册和发现工具。现已被Spring Cloud集成,提供了开箱即用的支持。(直接在项目中直接集成,快捷使用)

(就是说Eureka就是一个注册中心,想要得到SpringCoud微服务支持就需要将项目注册到SpringCloud微服务架构中)

Eureka角色

    Eureka中分为两个角色:Eureka Server(Eureka服务)和Eureka Client(Eureka客户端)。

    无论是服务端还是客户端其本质都是一个Java项目,在Spring Cloud中主要通过启动类上添加@EnableEurekaServer和@EnableEurekaClient(可以省略)来区分当前应用程序是服务端还是客户端。

    Eureka Server可以理解成之前我们讲解的Zookeeper注册中心,只是现在使用的是Java项目实现的(Spring Cloud内嵌Eureka)。

    Eureka Client 可以理解成所有需要注册到Eureka Server中的项目。为什么需要向注册中心中注册呢?因为注册后别人才能通过注册中心获取到项目信息和项目所在服务器信息,通过这些信息调用这个项目。Spring Cloud中每个项目调用的信息都存储在了注册中心中(Eureka)。

注意:在这里,Spring Cloud中没有Provider和Consumer说法。如果A项目访问B项目,称A项目为Application Client,称B项目为Application Service。同时可能存在C访问A的情况,这是C项目是Application Client,A项目是Application Service。发现A项目又是Application Service又是Application Client,主要看针对哪个业务场景。无论是Applicatin Service还是Application Client都是Eureka Client。

 Eureka和Zookeeper对比(面试)
    在Spring Cloud Netfilx中可以使用Eureka作为注册中心,但是也可以通过配置的方式使用Zookeeper作为配置中心,既然都支持,就需要知道两者的区别。

CAP理论(分布式一致性定理)

    著名的CAP理论指出,一个分布式系统不可能同时满足C(一致性)、A(可用性)和P(分区容错性)。由于分区容错性在是分布式系统中必须要保证的,因此我们只能在A和C之间进行权衡。在此Zookeeper保证的是CP, 而Eureka则是AP

C(一致性Consistency):在分布式系统中,是否立即达到数据同步的效果(平时多说的强一致性)。在分布式系统一定最终会一致的。如果请求时,整个分布式系统同步后才返回结果,叫做强一致性(满足一致性)。如果先返回结果,在一定时间后才实现一致性就叫做弱一致性。

A(可用性Availability):在分布式系统中,其中一些节点出现问题,整个整体是否还可用。

P(分区容错性):在分布式系统中,是否可以在有限的时间内达到数据一致的效果,如果因为网络等问题最终没有达到一致性,这时称为出现分区错误。

Zookeeper 保证 CP

    在Zookeeper集群中,Zookeeper的数据保证的是一致性的。当Leader出现问题时,整个Zookeeper不可用,需要花费30~120s来进行重新选择Leader,当Leader选举成功以后才能进行访问整个Zookeeper集群。

    通过这点也可以看出Zookeeper是强一致性的,集群所有节点必须能通信,才能用集群。虽然这样集群数据安全了,但是可用性大大降低了。而作为注册中心来说可用性是很重要的。

Eureka 保证AP

    Eureka发现了Zookeeper的问题,所以它舍弃了Zookeeper中强一致性,而保证了可用性。

    在Eureka集群中所有的节点都是保存完整的信息的,当Eureka Client向Eureka中注册信息时,如果发现节点不可用,会自动切换到另一台Eureka Sever,也就是说整个集群中即使只有一个Eureka可用,那么整个集群也是可用的。

    同时Eureka的自我保护机制也是实现可用性非常重要的体现。

1、Eureka注册中心(Service端)

导入依赖:

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

<!-- 需要注意的是这里使用的SpringCloud版本为Greenwich-->
<dependency>
   <groupId>org.springframework.cloud</groupId>
   <artifactId>spring-cloud-dependencies</artifactId>
   <version>Greenwich.SR1</version>
   <type>pom</type>
   <scope>import</scope>
</dependency>

<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-dependencies</artifactId>
  <version>2.1.4.RELEASE</version>
  <type>pom</type>
  <scope>import</scope>
</dependency>

启动类:

@SpringBootApplication
@EnableEurekaServer // EnableEurekaServer表示 服务器启动类,可以接受别人注册进来
public class Application {
    public static void main(String[] args) {
        // EurekaService只是个启动类名称
        SpringApplication.run(EurekaService.class, args);
    }
}

请注意,前面的示例显示了普通的Spring Boot应用程序。通过在类路径上使用spring-cloud-starter-netflix-eureka-client,您的应用程序将自动在Eureka服务器中注册。如下例所示,需要进行配置才能找到Eureka服务器:

application.yml:

server:
    port: 8761

eureka:
  instance:
    hostname: localhost # Eureka服务端的实例名称
  client:
    register-with-eureka: false # 是否向eureka注册中心注册
    fetch-registry: false #  fetch-registry 如果为 false,则表示自己为注册中心
    service-url: #监控页面
      # 单机:只用配置自己的 注册中心 http://${eureka.instance.hostname}:${server.port}/eureka/
      # 集群(关联):http://IP地址:端口号/eureka/,http://IP地址:端口号/eureka/,···,http://IP地址:端口号/eureka/
      defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/

在前面的示例中,defaultZone是一个魔术字符串后备值,它为任何不表达首选项的客户端提供服务URL(换句话说,这是一个有用的默认值)。【defaultZone可以在 service-url源码中找到】

配置完成之后,我们只需启动项目就可以在浏览器上访问localhost:8761就可以看下以下页面:

这样注册中心也就准备完毕了

2、向Eureka注册中心注册(Client客户端)

导入依赖:

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

<dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-web</artifactId>
    <version>2.1.4.RELEASE</version>
</dependency>

启动类:

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

application.yml:

#spring配置
spring:
  application:
    name: springcloud-provider-dept

#eureka配置
#向euraka注册
eureka:
  client:
    service-url:
      defaultZone: http://localhost:8761/eureka/

 Controller:

@RestController
@RequestMapping("/dept")
public class DeptController {
    
    @GetMapper
    public String test(){
        return "Hello SpringCloud!";
    }
}

配置完成之后,我们只需启动项目就可以在浏览器上访问localhost:8761就可以看下以下页面:

我们可以在上图中看到提供者已经把项目注册到Eureka注册中心了 

当然这里的简单使用还没有去体现到Eureka注册中心的好处

但是我们可以试想一个场景,就是当消费者需要获取到提供者的数据,就需要去找到他们并且去访问数据,但是实际的开发中,不会只在一台服务器上进行操作吧,这就意味着多个服务器有多个IP和端口,消费者怎么知道呢?这就需要一个能够集成这些服务器的组件了,使用Eureka注册中心就可以很好的解决这个问题,我们将那些不同的服务器注册到Eureka中,消费者只需要到Eureka去发现服务并去使用即可,最重要的是只需要几步配置即可达到服务发现。


Ribbon:

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

负载均衡就是将用户请求(流量)通过一定的策略,分摊在多个服务实例上执行,它是系统处理高并发、缓解网络

压力和进行服务端扩容的重要手段之一。它分为服务端负载均衡客户端负载均衡

客户端负载均衡:
客户端会有一个服务器地址列表,在发送请求前通过负载均衡算法选择 一个服务器,然后进行访问,这是客户端负载均衡;即在客户端就进行负载均衡算法分配。

        

服务端负载均衡:
例如Nginx进行负载均衡,先发送请求,然后通过负载均衡算法,在多个服务器之间选择一个进行访问。即在服务器端再进行负载均衡算法分配。

Ribbon的简单使用(与Eureka整合,基于客户端)

导入依赖:

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

<!-- Ribbon -->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-ribbon</artifactId>
    <version>1.4.6.RELEASE</version>
</dependency>

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

启动类:

// Ribbon 和 Eureka 整合以后,客户端可以直接调用,不用关系IP地址和端口号
@SpringBootApplication
@EnableEurekaClient
// 在微服务启动的时候就能去加载我们定义的Ribbon类
// name:指定的是注册到Eureka的提供者Application的名称(可以在Eureka界面去查看)
// configuration:指定的是Ribbon的算法,可以自己定义Ribbon的算法规则
@RibbonClient(name = "SPRINGCLOUD-PROVIDER-DEPT", configuration = MyRule.class)
public class DeptConsumer_8080 {
    public static void main(String[] args) {
        SpringApplication.run(DeptConsumer_8080.class, args);
    }
}

 config:

@Configuration
public class ConfigBean {

    /**
     * @LoadBalanced 负载均衡
     * @return
     */
    @Bean
    @LoadBalanced // Ribbon
    public RestTemplate getRestTemplate(){
        return new RestTemplate();
    }
}

 MyRule:

@Configuration
public class MyRule {

    /*
     * IRule:算法策略
     * AvailabilityFilteringRule:会先过滤掉跳匝的服务,对剩下的进行轮询
     * RoundRobinRule:轮询
     * RandomRule:随机
     * RetryRule:会先按照轮询获取服务,如果服务获取失败,那么就会在指定时间重试
     *
     */
    @Bean
    public IRule myRules(){
        // 虽然可以自定义算法,但是对于初学者来说就用封装好的算法就可以了
        // 当然我们是可以选择需要的算法策略
        return new RoundRobinRule();
    }

}

application.yml:

server:
  port: 8080

# Eureka配置
eureka:
  client:
    register-with-eureka: false # 不向Eureka注册自己
    service-url:
      defaultZone: http://localhost:8761/eureka/

Controller:

@RestController
@RequestMapping("/consumer/dept")
public class DeptConsumerController {

    // 理解:消费者不应该有Service层
    // RestTemplate ==> 对应的请求 注册到SpringBoot中
    // 常用参数 url,实体:map,Class<T> responseType <=== 记住

    /**
     * 提供多种便捷访问远程http服务的方法,简单的restful服务模板~
     */
    @Resource
    private RestTemplate restTemplate;
//    通过Ribbon去实现的时候,地址应该是一个变量,也就是注册中心的Id;通过服务名来访问
    private static final String REST_URL_PREFIX = "http://SPRINGCLOUD-PROVIDER-DEPT";

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

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

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

 最后访问浏览器输入路径就可以访问了


Feign:

Feign是Spring Cloud Netflix组件中的一个轻量级RESTFULL的http服务客户端,实现了负载均衡和Rest调用的开源框架,封装了Ribbon和RestTemplate,实现了webservice的面向接口编程,进一步降低了项目的耦合度。Feign是声明式Web Service客户端,它让微服务之间的调用变得更简单,类似controller调用service。SpringCloud集成了Ribbon和Eureka,可以使用Feigin提供负载均衡的http客户端。Feign内置了Ribbon,用来做客户端负载均衡调用服务注册中心的服务。

Feign能干什么?
Feign旨在简化微服务消费方(调用者,客户端)代码的开发,前面在使用Ribbon+RestTemplate进行服务调用时,利用RestTemplate对http请求的封装处理,形成了一套模版化的调用方式,但是在实际开发中,由于服务提供者提供的接口非常多,一个接口也可能会被多处调用,Feign在Ribbon+RestTemplate的基础上做了进一步封装,在Feign封装之后,我们只需创建一个接口并使用注解的方式来配置,即可完成对服务提供方的接口绑定,简化了使用Ribbon + RestTemplate的调用,自动封装服务调用客户端,减少代码开发量;
 

Feign和Ribbon如何选择?

根据个人习惯而定,如果喜欢REST风格使用Ribbon;如果喜欢社区版的面向接口风格使用Feign.
 

Feign的简单使用(与Eureka整合,基于服务端)

导入依赖:

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

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

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

启动类:

@SpringBootApplication
@EnableEurekaClient
@EnableFeignClients(basePackages = {"com.wilson.springcloud"})
public class FeignDeptConsumer_8080 {
    public static void main(String[] args) {
        SpringApplication.run(FeignDeptConsumer_8080.class, args);
    }
}

config:

@Configuration
public class ConfigBean {

    @Bean
    public RestTemplate getRestTemplate(){
        return new RestTemplate();
    }
}

 application.yml:

server:
  port: 8080

# Eureka配置
eureka:
  client:
    register-with-eureka: false # 不向Eureka注册自己
    service-url:
      defaultZone: http://localhost:8761/eureka/

 Service:

@Service
@FeignClient(value = "SPRINGCLOUD-PROVIDER-DEPT")
public interface DeptClientService {

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

    @GetMapping("/dept")
    public List<Dept> queryAll();

    @PostMapping("/dept")
    public boolean addDept(Dept dept);
}

 Controller:

@RestController
@RequestMapping("/consumer/dept")
public class DeptConsumerController{

    /**
     * 从定义的接口和注解(feign)
     */
    @Resource
    private DeptClientService deptClientService;

    @PostMapping
    public boolean addDept(@RequestBody Dept dept){
        return this.deptClientService.addDept(dept);
    }

    @GetMapping("/{deptId}")
    public Dept getById(@PathVariable Long deptId){
        return deptClientService.queryById(deptId);
    }

    @GetMapping
    public List<Dept> getAll(){
        return deptClientService.queryAll();
    }
}

 最后访问浏览器输入路径就可以访问了


Hystrix:

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

Hystrix是干什么用的?

Hystrix的设计目的如下:
对通过第三方客户端库访问的依赖项(通常通过网络)的延迟和故障提供保护和控制。
在复杂的分布式系统中停止级联故障。
快速失败并迅速恢复。
如果可能的话,后退并优雅地降级。
支持近实时监控、警报和操作控制。

下面就是介绍使用Hystrix的原因和作用

 当许多后端系统中有一个潜在阻塞服务时,它可以阻止整个用户请求:

随着大容量通信量的增加,单个后端依赖项的潜在性会导致所有服务器上的所有资源在几秒钟内饱和。

应用程序中通过网络或客户端库可能导致网络请求的每个点都是潜在故障的来源。比失败更糟糕的是,这些应用程序还可能导致服务之间的延迟增加,从而备份队列、线程和其他系统资源,从而导致更多跨系统的级联故障。

 当使用Hystrix包装每个基础依赖项时,上面的图表中所示的体系结构会发生类似于以下关系图的变化。每个依赖项是相互隔离的,限制在延迟发生时它可以填充的资源中,并包含在回退逻辑中,该逻辑决定在依赖项中发生任何类型的故障时要做出什么样的响应:

 在这里插入图片描述

 Hystrix最主要的还是去实现服务降级和熔断机制,防止雪崩

服务降级:
降级是从系统功能优先级的角度考虑如何应对系统故障。

服务降级指的是当服务器压力剧增,整体负荷超出整体负载承受能力。根据当前业务情况及流量对一些服务和页面有策略的降级,保证重要或基本服务正常运行,非重要服务延迟使用或暂停使用,以此释放服务器资源以保证核心任务的正常运行。

自动降级分类
1)超时降级:主要配置好超时时间和超时重试次数和机制,并使用异步机制探测回复情况

2)失败次数降级:主要是一些不稳定的api,当失败调用次数达到一定阀值自动降级,同样要使用异步机制探测回复情况

3)故障降级:比如要调用的远程服务挂掉了(网络故障、DNS故障、http服务返回错误的状态码、rpc服务抛出异常),则可以直接降级。降级后的处理方案有:默认值(比如库存服务挂了,返回默认现货)、兜底数据(比如广告挂了,返回提前准备好的一些静态页面)、缓存(之前暂存的一些缓存数据)

4)限流降级:秒杀或者抢购一些限购商品时,此时可能会因为访问量太大而导致系统崩溃,此时会使用限流来进行限制访问量,当达到限流阀值,后续请求会被降级;降级后的处理方案可以是:排队页面(将用户导流到排队页面等一会重试)、无货(直接告知用户没货了)、错误页(如活动太火爆了,稍后重试)。
 

熔断机制:
熔断是应对微服务雪崩效应的一种链路保护机制。相当于断路器

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

服务熔断和降级的区别
服务熔断—>服务端:某个服务超时或异常,引起熔断~,类似于保险丝(自我熔断)
服务降级—>客户端:从整体网站请求负载考虑,当某个服务熔断或者关闭之后,服务将不再被调用,此时在客户端,我们可以准备一个 FallBackFactory ,返回一个默认的值(缺省值)。会导致整体的服务下降,但是好歹能用,比直接挂掉强。


触发原因不太一样,服务熔断一般是某个服务(下游服务)故障引起,而服务降级一般是从整体负荷考虑;管理目标的层次不太一样,熔断其实是一个框架级的处理,每个微服务都需要(无层级之分),而降级一般需要对业务有层级之分(比如降级一般是从最外围服务开始)
实现方式不太一样,服务降级具有代码侵入性(由控制器完成/或自动降级),熔断一般称为自我熔断。


熔断,降级,限流:

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

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

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

Hystrix的简单使用(基于Feign实现):


导入依赖:

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-hystrix</artifactId>
    <version>1.4.6.RELEASE</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-eureka</artifactId>
    <version>1.4.6.RELEASE</version>
</dependency>


<!-- 拿到实体类,分布式开发 -->
<dependency>
    <groupId>com.wilson</groupId>
    <artifactId>springcloud-api</artifactId>
    <version>1.0-SNAPSHOT</version>
</dependency>

<!-- junit -->
<dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <scope>test</scope>
</dependency>

<!-- 基于提供者实现Hystrix所以要用到数据库 -->
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
</dependency>

<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid</artifactId>
</dependency>

<!-- 日志 -->
<dependency>
    <groupId>ch.qos.logback</groupId>
    <artifactId>logback-core</artifactId>
</dependency>

<dependency>
    <groupId>org.mybatis.spring.boot</groupId>
    <artifactId>mybatis-spring-boot-starter</artifactId>
</dependency>

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-test</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-jetty</artifactId>
</dependency>

<!-- 热部署工具 -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-devtools</artifactId>
</dependency>

application.yml:

server:
 port: 8001

#spring配置
spring:
  application:
    name: springcloud-provider-dept
  datasource:
    type: com.alibaba.druid.pool.DruidDataSource
    username: root
    password: 123456
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql:///springcloud_db01?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai

#Eureka配置
eureka:
  client:
    service-url:
      defaultZone: http://localhost:8761/eureka/

启动类:

@SpringBootApplication
@EnableEurekaClient // 在服务启动后自动注册到Eureka中
@EnableDiscoveryClient // 服务发现
@EnableCircuitBreaker  // 添加熔断支持
public class HystrixDeptProvider_8001 {
    public static void main(String[] args) {
        SpringApplication.run(HystrixDeptProvider_8001.class, args);
    }


    // 增加一个Servlet
    @Bean
    public ServletRegistrationBean servletRegistrationBean(){
        ServletRegistrationBean<HystrixMetricsStreamServlet> servletRegistrationBean = new ServletRegistrationBean<>(new HystrixMetricsStreamServlet());
        // Hystrix监控地址
        servletRegistrationBean.addUrlMappings("/actuator/hystrix.stream");
        return servletRegistrationBean;
    }
}

在消费者Feign模块中,application.yml增加一条配置:

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

Controller:

@Slf4j
@RestController
@RequestMapping("/dept")
public class DeptController {

    @Resource
    private DeptService deptService;

    @GetMapping("/{id}")
    /**
     * HystrixCommand:开启线程池隔离(开启后使用的是独立的线程池)
     * fallbackMethod:回调地址
     */
    @HystrixCommand(fallbackMethod = "getByIdFromHystrix")
    public Dept getById(@PathVariable Long id){
        Dept dept = deptService.queryById(id);
        if ( dept == null ){
            // 像这种抛出异常的,我们需要友好的提示给开发者
            throw new RuntimeException("id ======>" + id + ",不存在该用户,或者信息无法找到~");
        }
        return dept;
    }

    // 备选方案(熔断)
    public Dept getByIdFromHystrix(@PathVariable Long id){
        // 因为不存在用户,回抛出异常数据,我们就可以new一个对象,将错误的信息放在里面进行一个数据封装
        return new Dept().setDeptId(id)
                .setDeptName("id=>" + id + ",There is no corresponding information, null--@Hystrix")
                .setDbSource("no this datasource in mysql");
    }
}

如果测试一个正常的数据,就不会发生问题,如果传入的参数有问题,就会查不到值并抛出异常,Hystrix此事开始介入,将封装好的预备方案启用,返回提示给开发人员

如果想要开启Hystrix监控页面,写一个dashborad的Maven模块

启动类:

@SpringBootApplication
@EnableHystrixDashboard // 开启监控页面
public class DeptConsumerDashBoard_9001 {
    public static void main(String[] args) {
        SpringApplication.run(DeptConsumerDashBoard_9001.class,args);
    }
}

application.yml:

server:
  port: 9001

启动项目之后,就可以访问localhost:9001/hystrix看到一个刺猬的界面了

 在这里插入图片描述

在这里插入图片描述

在这里插入图片描述


Zuul:

Zuul是从设备和网站到Netflix流媒体应用程序后端的所有请求的前门。作为一个Zuul是为实现动态路由、监控、弹性和安全性而构建的。它还可以根据需要将请求路由到多个Amazon Auto Scaling Groups。

Netflix API流量的数量和多样性有时会导致生产问题迅速出现,而且没有任何警告。我们需要一个系统,使我们能够迅速改变行为,以便对这些情况作出反应。Zuul使用了一系列不同类型的过滤器,使我们能够快速、灵活地将功能应用到我们的边缘服务。

这些过滤器帮助我们执行以下功能:

身份验证和安全性——识别每个资源的身份验证需求,并拒绝不满足这些需求的请求。洞察和监控-在边缘跟踪有意义的数据和统计数据,以便为我们提供准确的生产视图。

动态路由——根据需要将请求动态路由到不同的后端集群。

压力测试——逐渐增加到集群的流量,以衡量性能。负载减少-为每种类型的请求分配容量,并删除超过限制的请求。

静态响应处理——直接在边缘构建一些响应,而不是将它们转发到内部集群多区域弹性-跨AWS区域路由请求,以使我们的ELB使用多样化,并使我们的优势更接近我们的成员

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

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

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

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

Zuul的简单使用:

导入依赖:

<dependencies>
    <!--导入zuul依赖-->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-zuul</artifactId>
        <version>1.4.6.RELEASE</version>
    </dependency>
    <!--Hystrix依赖-->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-hystrix</artifactId>
        <version>1.4.6.RELEASE</version>
    </dependency>
    <!--dashboard依赖-->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-hystrix-dashboar</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>
    <!--Eureka-->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-eureka</artifactId>
        <version>1.4.6.RELEASE</version>
    </dependency>
    <!--实体类+web-->
    <dependency>
        <groupId>com.haust</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>
</dependencies>

application.yml:

server:
  port: 9527

spring:
  application:
    name: springcloud-zuul-geteway

eureka:
  client:
    service-url:
      defaultZone: http://localhost:8761/eureka/
# zuul配置
zuul:
# 路由相关配置
  # 原来访问路由 eg:http://localhost:9527/springcloud-provider-dept/dept/get/1
  # zull路由配置后访问路由 eg:http://localhost:9527/wilson/mydept/dept/get/1
  routes:
    mydept.serviceId: springcloud-provider-dept # eureka注册中心的服务提供方路由名称
    mydept.path: /mydept/** # 将eureka注册中心的服务提供方路由名称 改为自定义路由名称
  ignored-services: "*" # 忽略,不能以此路径访问数据 ‘*’代表隐藏全部
  # 指定访问的路径的前缀  
  prefix: /wilson

Controller:

@SpringBootApplication
// 开启Zuul代理
@EnableZuulProxy
public class ZuulApplication_9527 {
    public static void main(String[] args) {
        SpringApplication.run(ZuulApplication_9527.class, args);
    }
}

OK,以上就是Spring Cloud Netflix 官方解读部分内容了,还有许多技术栈没有讲到,下面就列出SpringCloud的技术栈,有需要的可以保存下来

 更多解答请访问Spring | HomeLevel up your Java code and explore what Spring can do for you.https://spring.io/

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

不爱编程的艾编程

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值