hand_springcloud

概述

  • Spring Cloud是一个微服务框架的规范,而微服务是一种架构模式,将一个完整的项目根据不同的业务模块拆分成多个小的项目,即,服务模块,每个服务模块独立的运行在一个tomcat容器中,每个服务模块甚至可以有自己独立的数据库。

六大组件

服务注册与发现

eureka
  • eureka客户端心跳机制:
    在默认情况下,eureka的客户端默认是每30秒给eureka发送一次心跳,90秒没发送,eureka就认为该客户端宕机了。
  • eureka自我保护机制
    当Eureka Server节点在短时间内丢失过多客户端(微服务)时,那么这个节点就会进入自我保护模式。一旦进入该模式,Eureka Server就会保护服务注册表中的信息,不会注销任何微服务。当网络故障恢复后,该Eureka Server节点会自动退出自我保护模式。
# application.yml文件禁用自我保护模式
eureka:
  server:
    enable-self-preservation: false
eureka集群配置

每台eureka节点都注册到其他的eureka注册中心上,使得eureka节点之间可以互相拉取数据,保持数据同步。当一台eureka挂掉之后,客户端还可以继续使用其他的eureka,保证了eureka的高可用。
以三个eureka服务作集群为例:

  • 本机ip映射
C:\WINDOWS\system32\drivers\etc

该路径下的hosts文件配置如下:

# 文件尾部
# localhost name resolution is handled within DNS itself.
#	127.0.0.1       localhost
#	::1             localhost
127.0.0.1       activate.navicat.com
127.0.0.1       localhost1
127.0.0.1       localhost2
127.0.0.1       localhost3
  • Eureks Server yml配置:
spring:
  application:
    name: eureka
server:
  port: 7001
  servlet:
    context-path: /
eureka:
  instance:
    # 给服务起别名
    hostname: localhost1
  server:
    enable-self-preservation: false
  client:
    #    设置为 false,表示当前服务不要注册到注册中心。
    registerWithEureka: false
    #    设置为false,表示单节点的EurekaServer,不需要同步其他的EurekaServer节点的数据
    fetchRegistry: true
    serviceUrl:
      defaultZone: http://localhost2:6001/eureka/, http://localhost3:5001/eureka/
#      defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
spring:
  application:
    name: eureka2
server:
  port: 6001
  servlet:
    context-path: /
eureka:
  instance:
    hostname: localhost2
  server:
    enable-self-preservation: false
  client:
    #    设置为 false,表示当前服务不要注册到注册中心。
    registerWithEureka: false
    #    设置为false,表示单节点的EurekaServer,不需要同步其他的EurekaServer节点的数据
    fetchRegistry: true
    serviceUrl:
      defaultZone: http://localhost1:7001/eureka/, http://localhost3:5001/eureka/
#      defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
spring:
  application:
    name: eureka3
server:
  port: 5001
  servlet:
    context-path: /
eureka:
  instance:
    hostname: localhost3
  server:
    enable-self-preservation: false
  client:
    #    设置为 false,表示当前服务不要注册到注册中心。
    registerWithEureka: false
    #    设置为false,表示单节点的EurekaServer,不需要同步其他的EurekaServer节点的数据
    fetchRegistry: true
    serviceUrl:
      defaultZone: http://localhost2:6001/eureka/, http://localhost1:7001/eureka/
#      defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
  • Eureka Client yml配置
spring:
  application:
    name: mocro-8001
server:
  port: 8001
  servlet:
    context-path: /
eureka:
  client:
    serviceUrl:
      defaultZone: http://localhost2:6001/eureka/
#      , http://localhost1:7001/eureka/, http://localhost3:5001/eureka/
  • Eureka Server微服务启动类上加@EnableEurekaServer
  • Eureka Client微服务启动类上加@EnableEurekaClient
  • 效果:
    配置文件里Client实例只注册到了eureka2,但其他两个Server都同步了该实例。
    • eureka2
      在这里插入图片描述
    • eureka
      在这里插入图片描述
    • eureka3
      在这里插入图片描述
nacos
  • 导入依赖
<dependency>
   <groupId>com.alibaba.cloud</groupId>
   <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
  • application.yml配置
spring:
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848

服务调用

RestTemplate
  • 依赖导入
    引用spring-boot-starter-web即可
  • RestTemplate定义了多个与REST资源交互的方法,其中的大多数都对应于HTTP的方法。涉及到get 、post、put、delete 等请求类型,具体有:
delete() 在特定的URL上对资源执行HTTP DELETE操作
exchange() 在URL上执行特定的HTTP方法,返回包含对象的ResponseEntity,这个对象是从响应体中映射得到的
execute() 在URL上执行特定的HTTP方法,返回一个从响应体映射得到的对象
getForEntity() 发送一个HTTP GET请求,返回的ResponseEntity包含了响应体所映射成的对象
getForObject() 发送一个HTTP GET请求,返回的请求体将映射为一个对象
postForEntity() POST 数据到一个URL,返回包含一个对象的ResponseEntity,这个对象是从响应体中映射得到的
postForObject() POST 数据到一个URL,返回根据响应体匹配形成的对象
headForHeaders() 发送HTTP HEAD请求,返回包含特定资源URL的HTTP头
optionsForAllow() 发送HTTP OPTIONS请求,返回对特定URL的Allow头信息
postForLocation() POST 数据到一个URL,返回新创建资源的URL
put() PUT 资源到特定的URL

上述方法详细用法

Feign
  • Feign 采用的是基于接口的注解
  • Feign 整合了ribbon,具有负载均衡的能力
    整合了Hystrix,具有熔断的能力
  • 调用端和被调用端都要导依赖,设置注解
  • 依赖引入
<dependency>
	<groupId>org.springframework.cloud</groupId>
	<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<!--        若不加,idea的微服务可能不显示端口号-->
<dependency>
	<groupId>org.springframework.boot</groupId>
   	<artifactId>spring-boot-starter-web</artifactId>
</dependency>
  • 开启注解
@SpringCloudApplication
@EnableFeignClients
public class Provider1Application {
    public static void main(String[] args) {
        SpringApplication.run(Provider1Application.class, args);
    }
}
  • 在调用端创建接口
@FeignClient("provider1")	//指定被调用端的微服务名
public interface Provider1Feign {
	//直接把被调用端的方法名、返回值、参数、映射url粘过来就行,@ResponseBody可以不粘
    @RequestMapping("proInfo")
    public Map<String, Object> proInfo();
}
  • 如果客户端要传值,则一定要使用注解@RequestParam(“必须起名”)、@PathVariable等。
  • 直接注入使用
@Autowired
Provider1Feign provider1Feign;

@RequestMapping("recInfo1")
@ResponseBody
public Map<String, Object> recInfo1(){
    Map<String, Object> map = provider1Feign.proInfo();
    return map;
}
  • 开启内置的hystrix
    application.yml 配置:
# 老版本
# 开启Hystrix。其中Hystrix的默认time-out时间为1s。
feign:
  hystrix:
    enabled: true
#----------------------------------------------
# 新版本
feign:
  circuitbreaker:
    enabled: true
  • 超时时间配置
feign:
  hystrix:
    enabled: true
  client:
    config:
      default:
        #连接到目标的时间,此处会收到注册中心启动中的影响。设置为3秒钟,如果注册中心有明显的不在线,基本是毫秒级熔断拒绝
        connectTimeout: 3000
        #获取目标连接后执行的最长时间,设置为32秒,即服务最长时
        readTimeout: 32000
#超时时间配置,此处全局超时配置时间大于@HystrixProperty配置时间后,@HystrixProperty注解中的超时才生效
hystrix:
  command:
    default:
      execution:
        isolation:
          thread:
            timeoutInMilliseconds: 10000
  • 创建Feign接口实现类,重写远程调用的接口方法,实现方法即为hystrix的fallback方法。
@Component
public class Provider1FeignImpl implements Provider1Feign {
    @Value("${server.port}")
    private int port;

    @Override
    public Map<String, Object> proInfo() {
        Map<String, Object> map = new HashMap<>();
        map.put("msg", "fallbackMethod 降级啦,provider端口:" + port);
        map.put("status", false);
        return map;
    }
}
  • Feign接口处也要在注解的fallback属性中指定该实现类
@FeignClient(value = "provider1", fallback = Provider1FeignImpl.class)
public interface Provider1Feign {
    @RequestMapping("proInfo")
    public Map<String, Object> proInfo();
}

负载均衡

  • 当调用的服务是一个集群时,选择哪一个实例来调用,使用什么策略来达到最优解,这就是负载均衡要做的事。
Ribbon
  • 依赖引入
    ribbon 基本上不需要单独引用,因为绝大多数的注册中心(eureka,consul等)都已集成了ribbon。

  • Ribbon作为一个负载均衡组件, 里面有一个个的负载均衡策略, 而这些策略的公共接口是IRule。
    在这里插入图片描述
    在这里插入图片描述

  • 通过往Spring容器中注入一个IRule接口的实现类, 可以改变Ribbon默认的负载均衡策略(默认是轮询)。

  • ribbon相关配置

  • application.yml中相关配置

ribbon:
  MaxAutoRetries: 2 #最大重试次数,当Eureka中可以找到服务,但是服务连不上时将会重试
  MaxAutoRetriesNextServer: 3 #切换实例的重试次数
  OkToRetryOnAllOperations: false  #对所有操作请求都进行重试,如果是get则可以,如果是post,put等操作没有实现幂等的情况下是很危险的,所以设置为false
  ConnectTimeout: 5000  #请求连接的超时时间
  ReadTimeout: 6000 #请求处理的超时时间
  • 设置ribbon策略
  1. application文件配置方式
# 被调用的微服务名
mocro-8001:
  ribbon:
    #指定使用的负载均衡策略
    NFLoadBalancerRuleClassName: com.hand.config.balance.IPFirstLB
  1. 注解方式
  • 注意:该配置类不能被启动类扫描到,否则会成为全局配置,@SpringBootApplication包含了@ComponentScan,所以配置类最好放在启动类的上一级,或者在启动类中排除配置类。

自定义一个配置类:

@Configuration
public class RibbonConfig {
    @Bean
    public IRule iRule(){
       	//可以自定义
        return new RandomRule();//随机策略
    }
}

添加@RibbonClient注解,指定配置类和要调用的微服务名

// name为微服务名称,必须和服务提供者的微服务名称一致,用来指定哪个服务使用该策略
// configuration为自定义的配置类,用于配置自定义的负载均衡规则
@RibbonClient(name = "mocro-8001",configuration = RibbonConfig.class)
@SpringBootApplication
@ComponentScan(excludeFilters = {@ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, classes = {RibbonConfig.class})})
public class Micro9001Application {

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

    @Bean	//配置在此,或在启动类扫描得到的地方,则全局生效
    @LoadBalanced
    public RestTemplate getRestTemplate() {
        return new RestTemplate();
    }

//    @Bean   //配置在此,或在启动类扫描得到的地方,则全局生效
//    public IRule iRule(){
//        return new RandomRule();//随机策略
//    }
}
  • 自定义负载均衡策略
// 优先把请求分发到ip相同的服务
public class IPFirstLB extends AbstractLoadBalancerRule {

    @Override
    public void initWithNiwsConfig(IClientConfig iClientConfig) {
        // 读取配置文件, 并且初始化, ribbon内部基本上用不上
    }

    @Override
    public Server choose(Object key) {
        ILoadBalancer loadBalancer = this.getLoadBalancer();
        //获取当前请求的服务的实例
        List<Server> reachableServers = loadBalancer.getReachableServers();
        List<Server> ipEqualServers = new ArrayList<>();
        for(Server s : reachableServers){
            if(s instanceof DiscoveryEnabledServer){
                String serverIP = ((DiscoveryEnabledServer) s).getInstanceInfo().getIPAddr();
                try {
                    String clientIP = InetAddress.getLocalHost().getHostAddress();
                    if(serverIP.equals(clientIP)){
                        ipEqualServers.add(s);
                    }
                } catch (UnknownHostException e) {
                    e.printStackTrace();
                }
            }
        }
        //没有ip相同的,则对全部用随机策略
        if(ipEqualServers.isEmpty()){
            int index = ThreadLocalRandom.current().nextInt(reachableServers.size());
            return reachableServers.get(index);
        }else {     //有ip相同的,则对相同的这些用随机策略
            int index = ThreadLocalRandom.current().nextInt(ipEqualServers.size());
            return ipEqualServers.get(index);
        }
    }
}
  • RestTemplate中ribbon实现原理
    LoadBalancerInterceptor会去拦截RestTemplate的请求,然后从Eureka中获取服务id与端口号,随后利用负载均衡算法得到真实的服务地址信息,替换服务id
  • ribbon 饥饿加载
    • 问题:服务消费方调用服务提供方接口的时候,第一次请求经常会超时,而之后的调用就没有问题了。
    • 问题原因:Ribbon进行客户端负载均衡的Client并不是在服务启动的时候就初始化好的,而是在调用的时候才会去创建相应的Client,所以第一次调用的耗时不仅仅包含发送HTTP请求的时间,还包含了创建RibbonClient的时间,这样一来如果创建时间速度较慢,同时设置的超时时间又比较短的话,可能就熔断了。
    • 解决方法:开启饥饿加载模式提前加载好客户端
    • 实现方法:
      application 文件配置
ribbon.eager-load.enabled=true # 开启Ribbon的饥饿加载模式
ribbon.eager-load.clients=hello-service, user-service # 指定需要饥饿加载的微服务名
  • CAP定理

    • CAP 定理是分布式系统的基础,也是分布式系统的 3 个指标:
    1. Consistency(一致性)
    2. Availability(可用性)
    3. Partition tolerance(分区容错性)
  • 负载均衡与高可用

    • 负载均衡(LB,Load Balance),是一种技术解决方案。用来在多个资源(一般是服务器)中分配负载,达到最优化资源使用,避免过载。
    • 高可用(High Availability),简称 HA,是系统一种特征或者指标,通常是指,提供一定性能上的服务运行时间高于平均正常时间段。
    • 一般通过负载均衡,冗余同一个服务实例的方式,解决分布式系统的大流量、高并发和高可用的问题。
    • 只要存在调用,就需要考虑负载均衡这个因素。
    • 负载均衡核心关键:在于是否分配均匀。

服务熔断降级

  1. 服务熔断
  • 当扇出链路的某个微服务不可用或者响应时间太长时,会进行服务的降级,进而熔断该节点微服务的调用,快速返回“错误”的响应信息。当检测到该节点微服务调用响应正常后恢复调用链路。
  • Hystrix会监控微服务间调用的状况,当失败的调用到一定阈值,缺省是5秒内20次调用失败就会启动熔断机制。熔断机制的注解是@HystrixCommand。
  1. 服务降级
  • 服务降级的处理是在客户端完成的,与服务端没有关系。
  • 所谓降级,就是一般是从整体符合考虑,就是当某个服务熔断之后,服务器将不再被调用,此刻客户端可以自己准备一个本地的fallback回调,返回一个缺省值,这样做,虽然服务水平下降,但好过直接挂掉。
  • 熔断与降级的区别
    • 触发原因不一样,服务熔断由链路上某个服务引起的,服务降级是从整体的负载考虑
    • 管理目标层次不一样,服务熔断是一个框架层次的处理,服务降级是业务层次的处理
      实现方式不一样,服务熔断一般是自我熔断恢复,服务降级相当于人工控制
    • 触发原因不同 服务熔断一般是某个服务(下游服务)故障引起,而服务降级一般是从整体负荷考虑
    • 服务熔断是服务降级的一种特殊情况
Hystrix

Hystrix是一个用于处理分布式系统的延迟和容错的开源库。

  • 断路器
    “断路器”本身是一种开关装置,当某个服务单元发生故障之后,通过断路器的故障监控(类似熔断保险丝),向调用方返回一个符合预期的、可处理的备选响应(FallBack)。
  • Hystrix功能包括:服务降级,服务熔断,服务限流,几近实时监控。
  • 依赖导入
<dependency>
   <groupId>org.springframework.cloud</groupId>
   <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
  • 添加启动熔断器注解
@SpringBootApplication
@EnableCircuitBreaker   // 开启熔断器
public class Micro9001Application {

    public static void main(String[] args) {
        SpringApplication.run(Micro9001Application.class, args);
    }
}
  • 接口方法
@RequestMapping("hytest")
@HystrixCommand(
       // 每一个属性都是一个HystrixProperties
       commandProperties = {
               // 调用超时2秒则熔断
               @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "2000")
       }
       // 服务降级
       ,fallbackMethod = "fallbackMethod"
)
@ResponseBody
public Map<String, Object> hystrixTest(){
   Map<String, Object> map = new HashMap<>();
   map.put("msg", "service端口:" + port);
   map.put("status", true);
   try {
       Thread.currentThread().sleep(5000);
   } catch (InterruptedException e) {
       e.printStackTrace();
   }
   return map;
}

//指定一个降级的方法
//该方法返回值、参数要和接口方法相似
public Map<String, Object> fallbackMethod(){
   Map<String, Object> map = new HashMap<>();
   map.put("msg", "fallbackMethod 降级啦,service端口:" + port);
   map.put("status", false);
   return map;
}
  • 熔断异常
java.util.concurrent.TimeoutException: null
	at com.netflix.hystrix.AbstractCommand.handleTimeoutViaFallback(AbstractCommand.java:997) ~[hystrix-core-1.5.18.jar:1.5.18]
  • 降级 fallback 方法执行结果
    在这里插入图片描述
    • 有了fallback函数,就不会报异常了。
Sentinel
  • Sentinel 与 Hystrix对比:
    在这里插入图片描述
  • 依赖导入
<dependency>
   <groupId>com.alibaba.cloud</groupId>
   <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
  • application文件配置
spring:
  application:
    name: receiver1
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848
    sentinel:
      transport:
        dashboard: localhost:8858
management:
  endpoints:
    web:
      exposure:
        include: "*"
  • @SentinelResource注解的使用
@Service
@Slf4j
public class SentinelTestServiceImpl implements SentinelTestService {

    @Value("${server.port}")
    private int port;

    @Override
    //value:资源名称,必需项(不能为空)
    //blockHandler 对应处理 BlockException 的函数名称
    //fallback  用于在抛出异常的时候提供 fallback 处理逻辑
    @SentinelResource(value = "hello", blockHandler = "exceptionHandler", fallback = "helloFallback")
    public Map<String, Object> sentinelTest() {
        Map<String, Object> map = new HashMap<>();
        map.put("msg", "provider端口:" + port);
        map.put("status", true);
        return map;
    }

    // Fallback 函数,函数签名与原函数一致或加一个 Throwable 类型的参数.
    public String helloFallback() {
        log.error("helloFallback:{}",port);
        return String.format("Halooooo %d", port);
    }

    // Block 异常处理函数,参数最后多一个 BlockException,其余与原函数一致.
    public String exceptionHandler(BlockException ex) {
        // Do some log here.
        log.error("exceptionHandler:{}",port);
        ex.printStackTrace();
        return "Oops, error occurred at " + port;
    }
}

服务网关

zuul
  • 依赖导入
<dependency>
  <groupId>org.springframework.cloud</groupId>
  <artifactId>spring-cloud-starter-netflix-zuul</artifactId>
</dependency>
  • application.yml配置
spring:
  application:
    name: zuul-gateway

server:
  port: 10001
  servlet:
    context-path: /

eureka:
  client:
    serviceUrl:
      defaultZone: http://localhost2:2001/eureka/
#      , http://localhost1:1001/eureka/, http://localhost3:3001/eureka/

zuul:
  # 要求所有来网关的请求都加上该前缀,否则404
  prefix: /zuul_head
  # 忽略一些微服务,让他们不能通过微服务名直接路由
  ignored-services: provider-6
#  ignored-services: "*"
#  ignored-services: provider-5, provider-6
  routes:
    # 路由名,随便起
    p5Route:
      # 微服务名,只要没被忽略,就可以通过微服务名直接路由
      serviceId: provider-5
      # 匹配路径,**匹配到的路径会拼接到对应微服务的端口号后面
      path: /p5/**
    p6Route:
      serviceId: provider-6
      path: /p6/**
  host:
    # 超时时间设置
    connect-timeout-millis: 10000
    socket-timeout-millis: 60000
# 被调用的微服务名
provider-5:
  ribbon:
    #指定使用的负载均衡策略
    NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule
  • springcloud gateway

服务追踪

  • Sleuth

配置中心

Spring Cloud Config

  • Spring Cloud Config分为服务端和客户端两部分
  • 服务端也称为分布式配置中心,它是一个独立的微服务,用来连接配置服务器并为客户端提供获取配置信息。
  • 客户端则是通过指定的配置中心来管理相关的配置内容,并在启动的时候从配置中心获取和加载配置信息,不再需要再在每个微服务上编写配置文件。
  • 配置服务器默认采用git来存储配置信息,这样就有助于对环境配置进行版本管理。
  • 当配置发生变动时,服务不需要重启即可感知到配置的变化并应用新的配置。
  • 配置信息以REST接口的形式暴露。
Config Server
  • 导入依赖
<dependency>
	<groupId>org.springframework.cloud</groupId>
   	<artifactId>spring-cloud-config-server</artifactId>
</dependency>
  • application.yml 配置
spring:
  application:
    name: config-server
  cloud:
    config:
      server:
        git:
          uri: https://gitee.com/my_username/config-server.git	# git clone 的url地址
          search-paths:
            - /
          username: my_username
          password: my_passwory
          label: master
  • 启动类注解
@SpringBootApplication
@EnableEurekaClient
@EnableConfigServer
public class ConfigServerApplication {
    public static void main(String[] args) {
        SpringApplication.run(ConfigServerApplication.class, args);
    }

}
  • 配置读取规则(url路径)
  1. /{label}/{application}-{profiles}.yml (label 即 branch)
  2. /{application}-{profiles}.yml (默认根据yml中的label)
  3. /{application}/{profiles}/{label}
Config Client
  • 配置文件
    • applicaiton.yml 是用户级的资源配置项
    • bootstrap.yml 是系统级的
    • bootstrap.yml比application.yml先加载
    • bootstrap.yml优先级高于application.yml
  • 依赖导入
    客户端
<dependency>
	<groupId>org.springframework.cloud</groupId>
	<artifactId>spring-cloud-config-client</artifactId>
</dependency>

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

Nacos

  • 依赖导入
<dependency>
   <groupId>com.alibaba.cloud</groupId>
   <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
  • bootstrap.yml配置
spring:
  profiles:
    active: dev
  application:
    name: receiver1
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848
      config:
        server-addr: localhost:8848
        file-extension: yml
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值