Spring Cloud Netflix 全套组件入门到实战

news2025/1/6 20:33:44

文章目录

  • 简介
  • 注册中心
    • 核心功能
    • 高可用配置
  • 服务调用
    • RestTemplate
    • RestTemplate+Ribbon
    • Fegin
    • 负载策略
    • 超时&重试
  • 服务熔断
    • 降级机制
    • 隔离机制
      • 线程池隔离
      • 信号量隔离
    • Hystrix仪表板
  • 服务路由
    • 启用Zuul
    • 路由配置
  • 参考文档
  • 代码仓库

通过本文可以给你带来什么?

  1. 熟悉掌握Spring Cloud,了解其生态及掌握多个组件的原理。
  2. 上手实践,基于Spring Cloud Netflix各组件搭建项目。

简介

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

Spring Cloud的诞生就是为了做分布式,它是一个生态,定义了一套标准,目前基于其落地实现的有:Spring Cloud NetflixSpring Cloud Alibaba,二者都可以提供一套分布式解决方案,例如:众多服务统一管理,服务之间的通信,服务熔断降级、链路追踪等。

Spring Cloud为我们提供的解决方案中包含很多组件,下面表格列出Spring Cloud生态常用组件以及其应用。

功能Spring Cloud官方Spring Cloud NetflixSpring Cloud Alibaba
服务发现/注册ConsulEurekaNacos
服务调用OpenFeign/RestTemplateFeignDubbo RPC
负载均衡LoadbalancerRibbonDubbo LB
服务路由Spring Cloud GatewayZuul-
配置中心Spring Cloud Config-Nacos
服务熔断-HystrixSentinel

注册中心

Eureka作为注册中心,分为服务端和客户端,服务端提供客户端注册,客户端可以在服务端拉取注册表到本地(所以客户端不会因为注册中心宕机而找不到其他服务,优先在本地找)。如下图
服务发现/注册

核心功能

:以下均为application.properties配置文件

  • Register

服务注册,向Eureka注册信息,以被发现。

#开启服务注册
eureka.client.register-with-eureka = true
#注册中心地址
eureka.client.service-url.defaultZone=http://eureka-server1.com:8001/eureka/
  • Renew

续租,心跳,30s发送一次心跳续租,通知Eureka实例时活动的,Eureka超过90s没发现更新,在注册表中移除。

#续租时间
eureka.instance.lease-renewal-interval-in-seconds=30
#该时间内未收到下次心跳移除实例
eureka.instance.lease-expiration-duration-in-seconds=90
  • Fetch Registry

Eureka客户端从服务器拉取注册表缓存本地,之后客户端使用这些信息查找其他服务,定期(30s)更新。

#在注册中心拉取服务注册列表
eureka.client.fetch-registry=true
#更新注册列表时间间隔
eureka.client.registry-fetch-interval-seconds=30
  • Cancel

Eureka客户端在关闭时向Eureka服务器发送取消请求,服务器将从注册表删除实例。

  • 自我保护机制

默认情况下,Eureka Server在一定时间内接收不到某个服务的续约会将其踢出服务列表。但是在网络故障时,上述行为就非常危险,因为服务正常,不应该被踢出。Eureka Server通过自我保护机制解决这个问题,当短时间内丢失过多服务时(小于85%),会保护注册列表中的服务不被注销,网络恢复后退出保护模式。

#开启自我保护机制
eureka.server.enable-self-preservation=true
#比较实际心跳和预计心跳时间频率
eureka.server.eviction-interval-timer-in-ms=60000
#短时间丢失服务比例,小于该值进入保护模式
eureka.server.renewal-percent-threshold = 0.85
  • 容错机制

在注册表内的服务一段时间内默认可用,每次调用不实时检查是否可用,提高可用,降低一致。

  • 健康检查

server和client通过心跳保持服务状态,心跳正常,服务一直UP。

如果此服务无法提供正常服务需要将服务下线(例如:DB连不上),此时需要启动eureka的健康检查,同时需要设置健康状态为DOWN,代码如下:

  1. 启动健康检查
eureka.client.healthcheck.enabled=true
  1. 根据实际情况通过调用setStatus设置服务健康状态。
public class HealthStatusEvent implements HealthIndicator {

    private Boolean status=true;

    @Override
    public Health health() {
        if(status)
            return new Health.Builder().up().build();
        return new Health.Builder().down().build();
    }

    public Boolean getStatus() {
        return status;
    }

    public void setStatus(Boolean status) {
        this.status = status;
    }
}

高可用配置

  1. eureka server作为客户端向其他eureka server注册。
    server1配置:
eureka.instance.hostname=eureka-server1.com
eureka.client.service-url.defaultZone=http://eureka-server2.com:8002/eureka/

server2配置:

eureka.instance.hostname=eureka-server2.com
eureka.client.service-url.defaultZone=http://eureka-server1.com:8001/eureka/
  1. 多个eureka server作为单节点注册到多个eureka server中

server1配置:

eureka.instance.hostname=eureka-server1.com
eureka.client.service-url.defaultZone=http://eureka-server1.com:8001/eureka/,http://eureka-server2.com:8002/eureka/,http://eureka-server3.com:8003/eureka/

server2配置:

eureka.instance.hostname=eureka-server2.com
eureka.client.service-url.defaultZone=http://eureka-server1.com:8001/eureka/,http://eureka-server2.com:8002/eureka/,http://eureka-server3.com:8003/eureka/

server3配置:

eureka.instance.hostname=eureka-server3.com
eureka.client.service-url.defaultZone=http://eureka-server1.com:8001/eureka/,http://eureka-server2.com:8002/eureka/,http://eureka-server3.com:8003/eureka/

注意:
由于是在一台服务器上搭建,所以需要指定eureka.instance.hostname,向系统的hosts文件添加ip映射

服务调用

SpringCloud服务之间的通信方式主要是以restful风格进行服务调用,常见调用方式为RestTemplate+Ribbon、Fegin。其中RestTemplate是Spring提供用于访问Rest服务的客户端,Ribbon主要功能是提供客户端在服务调用时的负载均衡,而Fegin是一个声明式的Http客户端,只需要在接口上添加一个注解,使得服务调用更简单。

service-provider工程提供的接口

package com.bg.serviecprovider.controller;

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class MainController {

    @RequestMapping("/hi")
    public String hi() {
        return "hi,im provider";
    }
}

service-consumer工程通过通过以下三种方式进行调用:

RestTemplate

@GetMapping("/hi")
    public String hi() {
        RestTemplate restTemplate = new RestTemplate();
        return restTemplate.getForObject("http://127.0.0.1:8081/hi", String.class);
    }

RestTemplate+Ribbon

注入RestTemplate时加上@LoadBalanced注解就会具有负载均衡的能力,代码如下:

    @Bean
    //开启负载均衡
    @LoadBalanced
    public RestTemplate restTemplate(){
        return new RestTemplate();
    }
    @GetMapping("/hi2")
    public String hi2() {
        return restTemplate.getForObject("http://service-provider/hi", String.class);
    }

Fegin

  1. pom文件中引入依赖
		<dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>
  1. 启动类加入@EnableFeignClients注解
@SpringBootApplication
@EnableEurekaClient
@EnableFeignClients
public class ServiceConsumerApplication {

    public static void main(String[] args) {

        new ClassPathXmlApplicationContext();
        SpringApplication.run(ServiceConsumerApplication.class, args);
    }
}
  1. 新建FeginService接口并加上@FeignClient注解,value为要调用的服务名称。hi接口url与service-provider提供的接口url一致。
package com.bg.serviceconsumer.service;

import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;

@FeignClient(value = "service-provider")
public interface FeginService {
    @GetMapping("/hi")
    public String hi();
}

  1. 在需要的地方直接注入FeginService进行调用
@Autowired
private FeginService feginService;
@GetMapping("/hi3")
public String hi3() {
  return feginService.hi();
}

负载策略

Ribbon内置了几种负载策略,体现在源码BaseLoadBalancer类中IRule,可以配置其他负载规则或者自定义实现规则。

负载策略说明
RoundRobinRule轮询策略,默认采⽤的策略
RandomRule随机策略,从所有的提供者随机选一个
RetryRule重试策略,先按照RoundRobinRule策略获取,若获取失败,则在指定的时限内重试
BestAvailableRule最可⽤策略,选择并发量最⼩的提供者
WeightedResponseTimeRule权重策略,根据响应时间做权重,时间越快权重越大
@Bean
public IRule getRule(){
    return new RandomRule();
}

超时&重试

feign默认支持Ribbon,二者的重试机制有冲突,所以源码关闭了feign的重试机制,使用Ribbon的重试机制

  1. 添加Ribbon超时重试配置
# 连接超时时间
ribbon.ConnectTimeout=1000
# 响应超时时间
ribbon.ReadTimeout=3000
# 同一服务器上的最大重试次数(不包括首次尝试)
ribbon.MaxAutoRetries=1
# 要重试的下一个服务器的最大数量(不包括第一个服务器)
ribbon.MaxAutoRetriesNextServer=1
# 是否所有操作都重试,默认在get请求下会重试,其他情况不会重试
ribbon.OkToRetryOnAllOperations=false
  1. 提供者模拟超时
    AtomicInteger count = new AtomicInteger();

    @RequestMapping("/timeoutretry")
    public String timeoutretry() throws InterruptedException {
        System.out.println(count.getAndIncrement()+"次调用");
        Thread.sleep(5000L);
        return "hi,im provider,port" + port;
    }
  1. 消费者声明feign超时接口
@FeignClient(value = "service-provider")
public interface FeignService {
   
    @GetMapping("/timeoutretry")
    public String timeoutretry();
}
  1. 消费者调用feign
@Autowired
private FeginService feginService;
@GetMapping("/timeout")
public String timeout() {
  return feginService.timeoutretry();
}

服务熔断

Hystrix是Netflix提供的一个容错组件,用来提升系统的可用性和容错性。主要有以下几个功能:

  • 降级:当请求失败、超时、被拒绝或断路器被打开时执行回退逻辑,提供优雅的服务降级。
  • 隔离:Hystrix为每个请求的依赖都维护了一个小型线程池或信号量,当请求达到阈值时快速失败并降级,避免因该请求影响整个系统造成级联失败。
  • 熔断:当某服务失败率达到阈值时,Hystrix可以自动跳闸,一段时间内停止请求某服务。

降级机制

hystrix超时时间配置,要大于ribbon的超时时间,否则重试机制就没有任何意义

# 开启fegin熔断
feign.hystrix.enabled=true
# hystrix的超时时间
hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds=7000

降级回退的两种方式:

  1. 当断路器被打开或出现错误时执行的默认代码路径。
@FeignClient(value = "service-provider",fallback = FeignCallback.class )
public interface FeignService {
    @GetMapping("/timeoutretry")
    public String timeoutretry();

}

@Component
class FeignCallback implements FeignService {
    @Override
    public String timeoutretry() {
        return "降级了";
    }
}
  1. 如果需要访问导致回退触发的原因,可以使用@FeignClient内的fallbackFactory属性,然后根据回退原因执行相关操作。
@FeignClient(value = "service-provider", fallbackFactory = FeignCallbackFactory.class)
public interface FeignService {
    @GetMapping("/timeoutretry")
    public String timeoutretry();

}
 
@Component
class FeignCallbackFactory implements FallbackFactory<FeignService> {

    @Override
    public FeignService create(Throwable throwable) {
        return new FeignService() {
            @Override
            public String timeoutretry() {
                return "降级了:" + throwable.getMessage();
            }
        };
    }
}

隔离机制

Hystrix隔离机制分为两种:

  • 线程池隔离:Hystrix用自己的线程执行调用;
  • 信号量隔离:直接用tomcat线程执行调用;

Hystrix默认使用线程池控制请求隔离,二者具体区别如下:

线程池隔离信号量隔离
开销有线程调度、排队、上下文切换开销无线程切换,开销小
异步支持异步不支持异步
是否支持熔断当请求达到线程池阈值时会触发fallback接口进行熔断当请求量达到信号量阈值时会触发fallback接口进行熔断
隔离原理各个服务单独用线程池各个服务通过信号量的计数器
使用场景适合网络开销比较大或比较耗时的场景。避免容器(tomcat)中线程因阻塞或等待影响整个系统适合请求不耗时、高并发场景

线程池隔离

线程池隔离配置

# 调用每个服务时的核心线程数(全局)
#hystrix.threadpool.default.coreSize=2
# 调用每个服务时的最大线程数(全局)
#hystrix.threadpool.default.maximumSize=2
# 调用service-provider服务时的核心线程数
#hystrix.threadpool.service-provider.coreSize=1
# 调用service-provider服务时的最大线程数
#hystrix.threadpool.service-provider.maximumSize=1

当service-provider服务的请求量达到阈值时抛出以下异常

Task java.util.concurrent.FutureTask@6eefc19c rejected from java.util.concurrent.ThreadPoolExecutor@4f3a844f[Running, pool size = 1, active threads = 1, queued tasks = 0, completed tasks = 3]

信号量隔离

Hystrix默认使用线程池控制请求隔离,当使用信号量隔离时需要开启,配置如下

# 信号量
hystrix.command.default.execution.isolation.strategy=SEMAPHORE
# 并发请求量
hystrix.command.default.execution.isolation.semaphore.maxConcurrentRequests=1

当service-provider服务的请求量达到阈值时抛出以下异常

could not acquire a semaphore for execution

Hystrix仪表板

Hystrix仪表板以有效的方式显示每个断路器的运行状况。仪表板显示步骤:

  1. pom.xml文件中引入仪表板依赖
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-hystrix-dashboard</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
  1. 启动类添加相关注解
@EnableCircuitBreaker
@EnableHystrixDashboard
  1. 启动成功后访问http://127.0.0.1:8082/actuator/hystrix.stream端点,如下:在这里插入图片描述
  2. http://127.0.0.1:8082/hystrix/ 访问仪表板
    在这里插入图片描述
  3. 将仪表板指向实例的/hystrix.stream端点,通过feign访问失败后显示监控数据
    在这里插入图片描述
    如果出现以下现象,在配置文件中加入hystrix.dashboard.proxyStreamAllowList=127.0.0.1即可
    在这里插入图片描述

服务路由

通常在应用启动后,我们通过链接直接访问即可,但是如果一个系统有多个微服务组成,那么客户端访问众多的服务是一件头疼的事。
服务路由可以帮忙客户端统一接入请求并路由相应的服务。如下图:
在这里插入图片描述
Zuul是Netflix开源的微服务网关,其核心是一系列过滤器,这些过滤器可以完成路由、限流、统一认证的功能。

启用Zuul

  1. pom.xml文件引入Zuul依赖
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-zuul</artifactId>
        </dependency>
  1. 启动类添加@EnableZuulProxy注解

应用启动后即可通过Zuul+服务名进行访问,配置文件中端口为80,访问地址为http://127.0.0.1/service-consumer/hi1

路由配置

# zuul相关配置 ZuulProperties.class
# 关闭默认路由
zuul.ignoredServices=*
# 为所有映射添加前缀
zuul.prefix=/zuul
# 请求被转发之前,代理前缀被删除,设置false切换此行为
zuul.stripPrefix=false
# 对具体服务进行路由
zuul.routes.service-consumer=/server1/**
zuul.routes.service-provider=/server2/**

参考文档

spring-cloud-netflix中文文档
Netflix github

代码仓库

仓库地址

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/144091.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

关于OPCUA的配套规范

OPC UA中的信息建模能力足够强大&#xff0c;使OPC UA成为定义从简单的数据&#xff08;如工程单位和传感器或设备生成的最大/最小范围&#xff09;到大型复杂关系的理想选择&#xff0c;其中包括涉及数据结构&#xff0c;方法和状态机的复杂对象类型的实例化。也就是说&#x…

mysql数据库的基础操作(一)

一、导入/导出sql脚本 1.1 导入sql脚本 1.1.1 终端导入sql脚本 在mysql中&#xff0c;执行source命令 mysql> source /chenshuai/cs.sql 1.1.2 可视化工具导入sql脚本 在Navicat Premium中&#xff0c;右键这个数据库&#xff0c;然后Execute SQL File 1.2 导出sql脚本…

Redis主从、哨兵、集群模式

众所周知,redis是目前非常流行的缓存中间件之一。在redis官网有这么一段话: redis有着丰富的数据结构&#xff0c;如 字符串&#xff08;strings&#xff09;&#xff0c; 散列&#xff08;hashes&#xff09;&#xff0c; 列表&#xff08;lists&#xff09;&#xff0c; 集合…

Please restart this script from an administrative PowerShell!

执行 npm install --global --vs2019 --production windows-build-tools报一下错误信息 Downloading python-2.7.15.amd64.msi Downloading Python failed. Error: Error: getaddrinfo ENOTFOUND cdn.npmmirror.com at GetAddrInfoReqWrap.onlookup [as oncomplete] (dns.js:…

养老院管理系统|基于JavaWeb开发实现养老院管理系统

作者主页&#xff1a;编程指南针 作者简介&#xff1a;Java领域优质创作者、CSDN博客专家 、掘金特邀作者、多年架构师设计经验、腾讯课堂常驻讲师 主要内容&#xff1a;Java项目、毕业设计、简历模板、学习资料、面试题库、技术互助 收藏点赞不迷路 关注作者有好处 文末获取源…

ROS用pyqt实现GUI界面控制乌龟运动

#!/usr/bin/env python3 #codingutf-8 from PyQt5.QtWidgets import * import sys from window import MainWindow,TurtleWindow import rospy if __name__ __main__: rospy.init_node(turtle_ctrl_node) appQApplication(sys.argv) #窗口展示 windowTurtleWindow() …

问题排查 - DotNet 6 后台服务Docker部署后部分接口返回值乱码

问题描述 最近有一个DotNetWebApi服务需要使用Docker在服务器部署&#xff0c;部署后部分接口返回内容会出现部分乱码的情况。 一些关键点&#xff1a; 服务本机直接启动&#xff0c;此接口无异常&#xff1b;服务器直接启动&#xff0c;此接口无异常 服务器为Ubuntu20.04安…

rabbitmq加入linux开机自启动脚本

cd /etc/init.d编辑脚本 vi rabbitmq#! /bin/sh # chkconfig: 2345 20 60 # description: rabbitmq server export HOME/root export PATH/usr/local/rabbitmq/erlang/bin:$PATH case "$1" instart)/usr/local/rabbitmq/sbin/rabbitmq-server start;;stop)/usr/loc…

命令模式Command

1.意图&#xff1a;将一个请求封装为一个对象&#xff0c;从而使得可以用不同的请求对客户进行参数化&#xff1b;对请求排队或记录请求日志&#xff0c;以及支持可撤销的操作。 2.结构 Command声明执行操作的接口。 ConcreteCommand将一个接收者对象绑定于一个动作&#xff1…

利用nginx 反向代理解决跨域问题

说到nginx&#xff0c;不得不说真的很强大&#xff0c;也带来很多便利用于解决一些头疼的难题。 一般来说可以用来做&#xff1a;静态页面的服务器、静态文件缓存服务器、网站反向代理、负载均衡服务器等等&#xff0c;而且实现这一切&#xff0c;基本只需要改改那万能的配置…

前端插件的应用

像这种页面四个页面下面的展示格式都一样&#xff0c;这个时候就把公共部分代码抽取出来作为组件使用 直接把中间部分代码赋值过来 <template> <div> <div v-for"(items, index) in ford" :key"index"> <div v-if"items.shopC…

P3- 傅里叶变换1-通讯原理

前言&#xff1a;傅里叶变换是Modulation, OFDM 技术的理论基础这里主要介绍连续性随机变量的傅里叶变换,以及对应的性质。https://zhuanlan.zhihu.com/p/339281545https://wenku.baidu.com/view/ab338e55a16925c52cc58bd63186bceb19e8ede4.html?_wkts_1672887094135https://w…

pdf如何防止被他人编辑

好多人一直在寻找研究如何编辑或者修改PDF文件&#xff0c;有需求就会有市场&#xff0c;现在市场上或者网络上有非常多的PDF编辑软件&#xff0c;可以编辑修改PDF文件中的内容。即使PDF文件加了密码保护&#xff0c;我们大部分人依然可以轻易的通过在浏览器中虚拟打印的方式&a…

2023.1.6 学习总结

1.set容器的相关函数 set&#xff0c;顾名思义是“集合”的意思&#xff0c;在set中元素都是唯一的&#xff0c;而且默认情况下会对元素自动进行升序排列。 set容器 包含头文件&#xff1a; #include<set> set中只能用insert函数实现数据的输入。 set<int> s…

32.深度学习模型优化加速方法-1

32.1 模型优化加速方法 模型优化加速能够提升网络的计算效率,具体包括: Op-level的快速算法:FFT Conv2d (7x7, 9x9), Winograd Conv2d (3x3, 5x5) 等;Layer-level的快速算法:Sparse-block net [1] 等;优化工具与库:TensorRT (Nvidia), Tensor Comprehension (Facebook) …

【代码题】栈的应用

目录 1.有效的括号 2.逆波兰表达式求值 1.有效的括号 点击进入该题 https://leetcode.cn/problems/valid-parentheses/description/ 给定一个只包括 (&#xff0c;)&#xff0c;{&#xff0c;}&#xff0c;[&#xff0c;] 的字符串 s &#xff0c;判断字符串是否有效。 有…

【黑马】瑞吉外卖-Day01、02笔记

瑞吉外卖 数据库搭建 表结构 Maven项目 创建Maven项目 编写pom文件 编写配置文件application.yml 创建启动类ReggieApplication.java 前端静态资源的配置 将两个前端静态资源包导入到resource目录下方&#xff0c;由于Spring-MVC默认只能访问static和templete下面的文件…

04-GC的常见收集方法:标记清除、标记复制、标记整理算法、分代收集的原理与特点?

1.标记清除算法(Mark-Sweep) 最基础的垃圾回收算法&#xff0c;分为两个阶段&#xff0c;标记和清除。 1.标记阶段标记出所有需要回收的对象 2.清除阶段回收被标记的对象所占用的空间 缺点: 1.容易产生大量的内存碎片,后续可能发生大对象不能找到可利用空间的问题 2.标记和清…

【JavaGuide面试总结】Java基础篇·上

【JavaGuide面试总结】Java基础篇上1.JVM vs JDK vs JRE2.Java 和 C 的区别?3.Java 程序从源代码到运行的过程4.为什么说 Java 语言“编译与解释并存”&#xff1f;5.说说default关键字的几个用法6.静态变量有什么作用&#xff1f;7.字符型常量和字符串常量的区别?8.成员变量…

Verilog语法笔记(夏宇闻第三版)-运算符及表达式

目录 运算符按其功能可分为以下几类: 按其所带操作数的个数运算符可分为三种&#xff1a; 基本的算术运算符&#xff1a; 位运算符&#xff1a; 逻辑运算符&#xff1a; 关系运算符&#xff1a; 等式运算符&#xff1a; 移位运算符&#xff1a; 位拼接运算符(Concatati…