1.SpringCloud详解

SpringCloud五大组件

注意:yml中微服务名使用(-)划线

​ 所有的操作都是在消费方服务提供方只负责暴露接口

​ SpringCloud体系都是短连接基于Http基于SpringBoot

1.Eureka注册中心

注解:

服务器:
@EnableEurekaServer // 声明这个应用是一个EurekaServer
客户端:
@EnableDiscoveryClient //声明Eureka客户端 (官方推荐使用它)支持zookeeper注册中心
@EnableEurekaClient //声明Eureka客户端 意义都是一样的

配置:

服务器:
server:
  port: 10086  #服务端口号
spring:
  application:
    name: eureka-server  #应用名称
eureka:
  client:
    service-url:
      defaultZone: http://localhost:10086/eureka //看源码请点defaultZone 55行
    fetch-registry: false       #因为是单台不抓取服务 默认是true
    register-with-eureka: false #因为是单台不需要互相注册 开发中是多台Eureka
客户端:每一个zuul或者微服务都要注册到Eureka上
server:
  port: 8080  #服务端口号
spring:
  application:
    name: order-server  #应用名称
eureka:
  client:
    service-url:
      defaultZone: http://localhost:10086/eureka   #指定注册中心的ip地址

1.2高可用的Eureka Server

Eureka 搭建集群 10086 10087

高可用注册中心:其实就是把EurekaServer自己也作为一个服务,注册到其它EurekaServer上,这样多个EurekaServer之间就能互相发现对方,从而形成集群

修改自己原来的Eureka配置

server:
  port: 10086 # 端口
spring:
  application:
    name: eureka-server # 应用名称,会在Eureka中显示
eureka:
  client:
    service-url: # 配置其他Eureka服务的地址,而不是自己,比如10087
      defaultZone: http://127.0.0.1:10087/eureka

客户端注册服务到集群:可以注册一个 可以注册几个上 因为Eureka 是互相抓取的

eureka:
  client:
    service-url: # EurekaServer地址,多个地址以','隔开
      defaultZone: http://127.0.0.1:10086/eureka,http://127.0.0.1:10087/eureka

其他配置参数说明:

默认注册时使用的是主机名,如果我们想用ip进行注册,可以在application.yml添加配置:

eureka:
  instance:
    ip-address: 127.0.0.1 # ip地址
    prefer-ip-address: true # 更倾向于使用ip,而不是host名
    instance-id: ${eureka.instance.ip-address}:${server.port} # 自定义实例的id

心跳续约:告诉EurekaServer:“我还活着” 30秒续约一次

获取服务列表:

eureka:
  client:
    registry-fetch-interval-seconds: 30 //每隔30秒拉取一次

剔除服务:我们可以通过下面的配置来关停自我保护:(在eureka注册中心的微服务中配置)心跳续约的比例是否低于了85%

eureka:
  server:
    enable-self-preservation: false # 关闭自我保护模式(缺省为打开)

总结:

  • 服务的注册和发现都是可控制的,可以关闭也可以开启。默认都是开启
  • 注册后需要心跳,心跳周期默认30秒一次,超过90秒没法认为宕机(失效)
  • 服务拉取默认30秒拉取一次
  • Eureka每个60秒会剔除标记为宕机的服务
  • Eureka会有自我保护,当心跳失败比例超过阈值(85%),那么开启自我保护,不再剔除服务。
  • Eureka高可用就是多台Eureka互相注册在对方上

2.Ribbon负载均衡

至少有两个微服务 实际开发部署在不同的服务器上

注解:谁发请求给谁加(加消费方) 去掉DiscoveryClient不需要服务发现

@LoadBalanced //打开Ribbon负载均衡功能 

SpringBoot也帮我们提供了修改负载均衡规则的配置入口:(消费方)

user-service:
  ribbon:
    NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule

格式是:{服务名称}.ribbon.NFLoadBalancerRuleClassName,值就是IRule的实现类。

附加:

Ribbon默认是采用懒加载,即第一次访问时才会去创建负载均衡客户端。往往会出现超时。如果需要采用饥饿加载,即项目启动即创建,可以这样配置:

ribbon:
  eager-load:
    enabled: true
    clients: user-service

Ribbon默认策略是:轮询(!!!)(还有随机 Hash)

Dubbo重试次数是2次+初始的调用,一共三次 (必须两端都使用java开发)

3.Hystrix熔断器

Hystix(封装了线程池)多线程就是玩线程池

对每一个请求弄了一个线程池 spring整合了一个线程池

两个微服务解耦合 MQ中间件解耦合 MQ存消息做队列的堆积 加速持久化 开多线程(跟CPU性能有关)核心线程数 8核 能确定任务快速完成 使用16核

发起请求通过 Hystrix 的线程池来走的,不同服务走不同线程池,实现不同服务调用的隔离,避免服务雪崩问题 线程隔离:每个请求是独立的线程
熔断机制:生活中保险丝,对请求如果超时直接先返回

两大功能:服务降级(优先保证核心服务,而非核心服务不可用或弱可用),熔断(压力过大,不让访问)

Hystix解决雪崩问题的手段主要是服务降级(服务降级,友好的提示),包括:

  • 线程隔离
  • 服务熔断

触发Hystix服务降级的情况:

  • 线程池已满
  • 请求超时

使用流程:入口类上注解,消费方controller上注解指定降级方法,通用降级方法(不指定使用一个)

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>

注解:(加在消费方入口类上)

@EnableCircuitBreaker //开启熔断 

@SpringBootApplication
@EnableDiscoveryClient
@EnableCircuitBreaker
Spring就提供了一个组合注解:@SpringCloudApplication  一个顶三个

服务降级注解:消费方controller上 假提示

@HystrixCommand(fallbackMethod = "queryByIdFallBack") //写一个临时方法 直接返回
public String queryByIdFallBack(Long id){
    log.error("查询用户信息失败,id:{}", id);
    return "对不起,网络太拥挤了!";
}

服务降级方法:要求入参、出参必须和原方法一致!!!

方法多 不能每一个都写 :通用降级方法:默认的Fallback

消费方controller添加注解:@DefaultProperties(defaultFallback = “defaultFallBack”) 方法名自定义

   public String defaultFallBack(){
        return "默认提示:对不起,网络太拥挤了!";
    }
    //去掉@HystrixCommand 上的方法 不要指定降级方法 使用通用的

默认超时时间:

Hystrix的默认熔断时间是1秒

熔断有三个状态,默认关闭,当请求20次默认50%失败后打开熔断,5秒之后进入半开状态放行一次请求,如果请求正常熔断状态为关闭,如果继续异常那么状态继续保持熔断

消费方配置

hystrix:
  command:
    default:
      execution:
        isolation:
          thread:
            timeoutInMilliseconds: 2000
hystrix:
  command:
    default:
    	circuitBreaker:
 			requestVolumeThreshold: 10
 			sleepWindowInMilliseconds: 10000
 			errorThresholdPercentage: 50

解读:

  • requestVolumeThreshold:触发熔断的最小请求次数,默认10
  • sleepWindowInMilliseconds:休眠时长,默认是10000毫秒
  • errorThresholdPercentage:触发熔断的失败请求最小占比,默认50%

4.Feign(伪装)远程调用

基于 Feign 的动态代理机制,根据注解和选择的机器,拼接请求 URL 地址,发起请求。并且整合了Hystrix&Ribbon 。

消费方注解:

@EnableFeignClients // 开启Feign功能

Feign客户端

这是一个接口,Feign会通过动态代理,帮我们生成实现

@FeignClient,声明这是一个Feign客户端,同时通过value属性指定服务名称

@FeignClient("user-service")  //微服务的名称
public interface UserClient {
    /**
     *  http://user-service/user/{id}
     *  伪装的接口“入参”和“出参"和被调用方的服务要求一致
     */
    @GetMapping("/user/{id}")
    User findById(@PathVariable("id")Long id);
}

Fegin内置的ribbon默认设置了请求超时时长,默认是1000ms,我们可以通过手动配置来修改这个超时时长:

ribbon:
  ReadTimeout: 2000 # 读取超时时长
  ConnectTimeout: 1000 # 建立链接的超时时长

Ribbon负载均衡:消费方

ribbon:
  ReadTimeout: 2000 # 数据通信超时时长
  ConnectTimeout: 500 # 连接超时时长  
  MaxAutoRetries: 0 # 当前服务器的重试次数
  MaxAutoRetriesNextServer: 1 # 重试多少次服务
  OkToRetryOnAllOperations: false # 是否对所有的请求方式都重试 如果是false代表只对get请求重试

Feign默认整合了Ribbon和Hystrix,但是Hystrix需要手动打开

消费方

feign:
  hystrix:
    enabled: true # 开启Feign的熔断功能

请求压缩:

Feign 支持对请求和响应进行GZIP压缩,以减少通信过程中的性能损耗

feign:
  compression:
    request:
      enabled: true # 开启请求压缩
    response:
      enabled: true # 开启响应压缩
feign:
  compression:
    request:
      enabled: true # 开启请求压缩
      mime-types: text/html,application/xml,application/json # 设置压缩的数据类型
      min-request-size: 2048 # 设置触发压缩的大小下限

日志级别:消费方

logging:
  level:
    cn.itcast: debug

5.Zuul网关(入口)

场景非常多:

  • 请求鉴权:一般放在pre类型,如果发现没有访问权限,直接就拦截了
  • 异常处理:一般会在error类型和post类型过滤器中结合来处理。
  • 服务调用时长统计:pre和post结合使用。

基于过滤器:4种

preFilter 前置(自定义过滤器)、routingFilter 路由、 postFilter 后置 、 errorFilter 异常

注解:

@EnableZuulProxy // 开启Zuul的网关功能

实际开发自己写路由规则

Zuul就指定了默认的路由规则:默认情况下,一切服务的映射路径就是服务名本身。

zuul的默认路由规则是  zuul服务器地址 + eureka上微服务名称 + 请求路径及参数
#默认的简化路由规则 
zuul:
  routes:
    user-service: /user-service/**  #这里是映射路径 **所有请求
    
#如果没有eureka,直接调用的话,注意下面是说明,不要复制
zuul:
  routes:
    user-service:				  #自定义的路由id
      path: /user-service/**      #映射的访问名称
      url: http://127.0.0.1:8081  #通过ip地址端口号可以不用注册eureka
      #将符合`path` 规则的一切请求,都代理到 `url`参数指定的地址
      
#如果有eureka,则可以直接通过微服务名称调用,不用ip地址端口号
zuul:
  routes:
    user-service:				  #自定义的路由id
      path: /user-service/**      #映射的访问名称
      serviceId: user-service     #指定服务名称(eureka上的名称)

忽略规则(禁用某个路由规则):放开互相抓取

zuul:
  ignored-services: #忽略规则
    - eureka-server

自定义过滤器:如果用户请求的参数中没有token,直接返回403异常)

编写自定义过滤器类继承ZuulFilter 重写4个方法

(1).类型是前置过滤器

(2).设置order为0

(3).是否有用到过滤器

(4).过滤器逻辑,判断参数中是否有token

@Component //将自定义过滤器放入spring容器
public class MyFilter extends ZuulFilter {

    /**
     * 过滤器类型:四种类型pre   route  post  error
     * @return
     */
    @Override
    public String filterType() {
        //前置过滤器
        return FilterConstants.PRE_TYPE;
    }

    /**
     * 过滤器顺序
     * @return
     */
    @Override
    public int filterOrder() {
        //过滤器的顺序是从小到大  -1最小
        return 0;
    }

    //过滤器是否开启过滤功能
    @Override
    public boolean shouldFilter() {
        //如果为false代表过滤器没有用到
        return true;
    }

    //过滤器的主逻辑
    @Override
    public Object run() throws ZuulException {
        /**
         * 过滤器逻辑
         * 如果用户请求参数没有token,则403
         */
        RequestContext ctx = RequestContext.getCurrentContext();
        HttpServletRequest request = ctx.getRequest();
        //从request的请求的参数中获取内容
        String token = (String) request.getParameter("token");

        //通过工具类进行非空判断
       if (StringUtils.isEmpty(token)) {
            ctx.setResponseStatusCode(403);
            ctx.setSendZuulResponse(false);//禁止转发
        }
        return null;
    }
}

Zuul高可用:

启动多个Zuul服务,自动注册到Eureka,形成集群。如果是服务内部访问,你访问Zuul,自动负载均衡。来对Zuul进行代理。比如:Nginx

Zuul中默认就已经集成了Ribbon负载均衡和Hystix熔断机制。但是都是默认值

hystrix:
  command:
    default:
      execution:
        isolation:
          thread:
            timeoutInMilliseconds: 6000  #熔断时间要能覆盖ribbon的重试时间
ribbon:
  ConnectTimeout: 1000
  ReadTimeout: 2000
  MaxAutoRetries: 0 #每台服务器最多重试次数,但是首次调用不包括在内
  MaxAutoRetriesNextServer: 1 #最多重试多少台服务器
  OkToRetryOnAllOperations: false # 是否对所有的请求方式都重试

计算重试次数公式:MaxAutoRetries+MaxAutoRetriesNextServer+(MaxAutoRetries *MaxAutoRetriesNextServer) 从而得知最终会重试1次+起始调用1次=2次的时间

Hystix的超时时间,应该比重试的时间加原本时间的总时间要大,应该配 大于(2000+1000)*2 = 6000

(ribbon.ReadTimeout + ribbon.ConnectTimeout) * (MaxAutoRetries+MaxAutoRetriesNextServer+(MaxAutoRetries *MaxAutoRetriesNextServer) +1)

6.SpringCloudConfig + SpringCloudBus

SpringCloudConfig集中配置组件

SpringCloudConfig目的:将yml文件集中管理 分两个角色,一是config server,二是config client。

Config Server是一个可横向扩展、集中式的配置服务器,它用于集中管理应用程序各个环境下的配置,默认使用Git存储配置文件内容,也可以使用SVN存储,或者是本地文件存储。

Config Client是Config Server的客户端,用于操作存储在Config Server中的配置内容。微服务在启动时会请求Config Server获取配置文件的内容,请求到后再启动容器。

配置服务端

将yml文件放入码云中,创库,公开,勾选第一个(可以直接上传文件),上传到配置yml配置的命名规则 :微服务名称-dev(开发模式).yml

配置中心:config_server 服务端

pom
<!--config配置中心的坐标-->
    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-config-server</artifactId>
        </dependency>
    </dependencies>
yml  
    spring:
  application:
    name: config-server
  cloud:
    config:
      server:
        git:
          uri: https://gitee.com/blueboyhi/itcast03.git  #将yml文件的所在git路径复制
server:
  port: 12000
  
入口类
@SpringBootApplication
@EnableConfigServer  //打开配置中心功能
public class ConfigApplication {
    public static void main(String[] args) {
        SpringApplication.run(ConfigApplication.class);
    }
}

注解:

@EnableConfigServer  //打开配置中心功能

客户端:通过gitter中心获取过来的 随便修改一个user_server的yml文件 修改yml文件名为bootstrap.yml

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-config-client</artifactId>
</dependency>

spring:
  cloud:
    config:
      name: user		#配置文件名  user-dev.yml
      profile: dev
      label: master     #git上分支名称
      uri: http://127.0.0.1:12000   #config配置服务器地址

SpringCloudBus 消息总线组件

要是修改了git上的yml配置 1.重启微服务可以重新拉取2.使用SpringCloudBus 消息总件 可以不重启刷新配置文件

config_server加入SpringCloudBus 坐标 前提是:Rabbit开启状态

<!--springcloudbus的坐标-->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-bus-amqp</artifactId>
</dependency>

yml

spring:
	rabbitmq:
  		host: 127.0.0.1
management: #暴露触发消息总线的地址,访问地址后可以刷新yml配置
  endpoints:
    web:
      exposure:
        include: bus-refresh   #http://127.0.0.1:12000/actuator/bus-refresh  

user_server的yml文件 修改yml文件名为bootstrap.yml 只做了拉取相关配置要到git上的yml文件中进行配置

yml

spring:
	rabbitmq:
  		host: 127.0.0.1

pom

<!--springcloudbus的坐标-->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-bus-amqp</artifactId>
</dependency>

最后重启后 通过postman发送post请求到 http://127.0.0.1:12000/actuator/bus-refresh 地址更新配置 给配置中心发消息 配置中心给Rabbit发消息

bootstrap.yml 和 application.yml区别

bootstrap.yml(bootstrap.properties)用来程序引导时执行,应用于更加早期配置信息读取,如可以使用来配置application.yml中使用到参数等

application.yml(application.properties) 应用程序特有配置信息,可以用来配置后续各个模块中需使用的公共参数等。

bootstrap.yml 先于 application.yml 加载

技术上,bootstrap.yml 是被一个父级的 Spring ApplicationContext 加载的。

这个父级的 Spring ApplicationContext是先加载的,在加载application.yml 的 ApplicationContext之前。

可以通过设置spring.cloud.bootstrap.enabled=false来禁用bootstrap

Spring Boot多环境配置切换

一般在一个项目中,总是会有好多个环境。

比如:开发环境 -> 测试环境 -> 预发布环境 -> 生产环境。

每个环境上的配置文件总是不一样的,甚至开发环境中每个开发者的环境可能也会有一点不同,配置读取可是一个让人有点伤脑筋的问题。

Spring Boot提供了一种优先级配置读取的机制来帮助我们从这种困境中走出来。

常规情况下,我们都知道Spring Boot的配置会从application.yml或.properties中读取

根据Spring Boot的文档,配置使用的优先级从高到低的顺序,具体如下所示:

1. 命令行参数。
2. 通过 System.getProperties() 获取的 Java 系统参数。
3. 操作系统环境变量。
4. 从 java:comp/env 得到的 JNDI 属性。
5. 通过 RandomValuePropertySource 生成的“random.*”属性。
6. 应用 Jar 文件之外的属性文件(application.properties/yml)。
7. 应用 Jar 文件内部的属性文件(application.properties/yml)。
8. 在应用配置 Java 类(包含“@Configuration”注解的 Java 类)中通过“@PropertySource”注解声明的属性文件。
9. 通过“SpringApplication.setDefaultProperties”声明的默认属性。

这意味着,如果Spring Boot在优先级更高的位置找到了配置,那么它就会无视低级的配置。

方法一、不在配置文件写上配置节定义,而是通过执行时定位不同配置文件来区分。如:

java -jar demo.jar --spring.config.location=/path/test_evn.properties

方法二、在配置文件写上配置节定义,在执行时传递配置节需激活定义名称来区分。

一般情况下我们这样定义环境:dev :开发,test:测试环境,prod:生产环境

在yml 文件中配置的话,写法如下:

spring:
  profiles:
    active: prod #生产环境
  datasource:
    driver-class-name: com.mysql.jdbc.Driver
    url: jdbc:mysql://127.0.0.1:3306/test
    username: root
    password: root

yml)。
7. 应用 Jar 文件内部的属性文件(application.properties/yml)。
8. 在应用配置 Java 类(包含“@Configuration”注解的 Java 类)中通过“@PropertySource”注解声明的属性文件。
9. 通过“SpringApplication.setDefaultProperties”声明的默认属性。


这意味着,如果Spring Boot在优先级更高的位置找到了配置,那么它就会无视低级的配置。

方法一、不在配置文件写上配置节定义,而是通过执行时定位不同配置文件来区分。如:

```shell
java -jar demo.jar --spring.config.location=/path/test_evn.properties

方法二、在配置文件写上配置节定义,在执行时传递配置节需激活定义名称来区分。

一般情况下我们这样定义环境:dev :开发,test:测试环境,prod:生产环境

在yml 文件中配置的话,写法如下:

spring:
  profiles:
    active: prod #生产环境
  datasource:
    driver-class-name: com.mysql.jdbc.Driver
    url: jdbc:mysql://127.0.0.1:3306/test
    username: root
    password: root

启动Jar包的时候:Java -jar xxxxxx.jar spring.profiles.active=prod 也可以这样启动设置配置文件,但是这只是用于开发和测试

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

竹子君@

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

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

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

打赏作者

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

抵扣说明:

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

余额充值