SpringCloud-Netfilx

注册中心eureka

eureka-server

  • spring boot和spring cloud的依赖

    <parent>
       <groupId>org.springframework.boot</groupId>
       <artifactId>spring-boot-starter-parent</artifactId>
       <version>2.2.6.RELEASE</version>
       <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <properties>
       <java.version>1.8</java.version>
       <spring-cloud.version>Hoxton.SR3</spring-cloud.version>
    </properties>
    
  • 启动类开启eureka服务

    @EnableEurekaServer
    
  • eureka单点配置

    server.port=7001
    #是否将自己注册到Eureka Server,默认为true,由于当前就是server,故而设置成false,表明该服务不会向eureka注册自己的信息
    eureka.client.register-with-eureka=false
    #是否从eureka server获取注册信息,由于单节点,不需要同步其他节点数据,用false
    eureka.client.fetch-registry=false
    #设置服务注册中心的URL,用于client和server端交流
    eureka.client.service-url.defaultZone=http://localhost:7002/eureka/
    

eureka高可用配置服务相互注册

  • 第1台eureka服务器配置
server.port=7001
#设置服务注册中心的URL,用于client和server端交流
eureka.client.service-url.defaultZone=http://euk2.top:7002/eureka/
#设置服务名
spring.application.name=eureka-server
  • 第2台eureka服务器配置
server.port=7002
#设置服务注册中心的URL,用于client和server端交流
eureka.client.service-url.defaultZone=http://euk1.top:7001/eureka/
#设置服务名
spring.application.name=eureka-server

在这里插入图片描述

  • 自我保护机制
    • 客户端每分钟续约数量小于客户端总数的85%时会触发保护机制
      关闭:eureka.server.enable-self-preservation=false

    • 关闭后会提示
      在这里插入图片描述

    • 清理时间(默认60秒)

      eureka.server.eviction-interval-timer-in-ms=3000
      

eureka-client

  • EurekaClient 可以在客户端获取eureka服务器上的注册者信息
    • org.springframework.cloud.client.discovery与com.netflix.discovery.DiscoveryClient
    • org.springframework.cloud.client.discovery是SpringCloud对注册中心client的抽象封装,提供公用功能
    • org.springframework.cloud.client.discovery定义用来服务发现的客户端接口,是客户端进行服务发现的核心接口,是spring cloud用来进行服务发现的顶级接口,在common中可以看到其地位。在Netflix Eureka和Consul中都有具体的实现类。
    • 代表通用于服务发现的读操作,例如在 eureka或consul中。
    @Autowired
    DiscoveryClient client; // 抽象
    @Autowired
    EurekaClient client2; // Eureka
    
    List<String> services = client.getServices();//获取所有服务实例id。
    List<ServiceInstance> instances = client.getInstances("provider");//通过服务id查询服务实例信息列表。
    
    • com.netflix.discovery.DiscoveryClient为Eureka注册中心客户端的接口,功能更丰富

远程调用RestTemplate

  • 注入RestTemplate对象到spring
    @Bean
    	// 开启负载均衡
    	@LoadBalanced
    	RestTemplate restTemplate() {
    		return new RestTemplate();
    	}
    
  • 接下来便可以使用资源地址调用服务
    • get 请求处理

      @RestController
      @RequestMapping("/demo")
      public class DemoController {
          @Autowired
          RestTemplate restTemplate;
          @GetMapping("getHi")
          public String getHi(){
              String url = "http://PROVIDER/demo/getHi";
              String resp = restTemplate.getForObject(url, String.class);
              return resp;
          }
      }
      
    • post 请求处理

    • exchange可以自定义http请求的头信息,同时保护get和post方法

    • 拦截器

    1. 需要实现ClientHttpRequestInterceptor接口

      	public class LoggingClientHttpRequestInterceptor implements ClientHttpRequestInterceptor {
      	
      		@Override
      		public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution)
      				throws IOException {
      	
      			System.out.println("拦截啦!!!");
      			System.out.println(request.getURI());
      	
      			ClientHttpResponse response = execution.execute(request, body);
      	
      			System.out.println(response.getHeaders());
      			return response;
      		}
      
    2. 添加到resttemplate中

      @Bean
      @LoadBalanced
      RestTemplate restTemplate() {
      	RestTemplate restTemplate = new RestTemplate();
      	restTemplate.getInterceptors().add(new LoggingClientHttpRequestInterceptor());
      	return restTemplate;
      }
      

负载均衡Ribbon

  • pom

    <dependency>
          <groupId>org.springframework.cloud</groupId>
          <artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
    </dependency>
    
  • 切换负载均衡策略

    • 注解方式

      @Bean
      public IRule myRule(){
      	//return new RoundRobinRule();
      	//return new RandomRule();
      	return new RetryRule(); 
      
    • 配置文件
      针对服务定ribbon策略:

      provider.ribbon.NFLoadBalancerRuleClassName=com.netflix.loadbalancer.RandomRule
      

      给所有服务定ribbon策略:

      ribbon.NFLoadBalancerRuleClassName=com.netflix.loadbalancer.RandomRule
      
    • 属性配置方式优先级高于Java代码。

  • Ribbon脱离Eureka
    设置 请求的网络地址列表。
    Ribbon可以和服务注册中心Eureka一起工作,从服务注册中心获取服务端的地址信息,也可以在配置文件中使用listOfServers字段来设置服务端地址。

    ribbon.eureka.enabled=false
    ribbon.listOfServers=localhost:80,localhost:81
    
  • 用法:

    @RestController
    @RequestMapping("/demo")
    public class DemoController {
        @Autowired
        LoadBalancerClient lb;
        @Autowired
        RestTemplate restTemplate;
        @GetMapping("getHi")
        public String getHi(){
        	// ribbon 完成客户端的负载均衡,过滤掉down了的节点
            ServiceInstance provider = lb.choose("PROVIDER");
            String url ="http://" + provider.getHost() +":"+ provider.getPort() + "/demo/getHi";
            return restTemplate.getForObject(url, String.class);
        }
    }
    
  • 手动实现,其实也是它的原理,做事的方法

    手写客户端负载均衡
    1、知道自己的请求目的地(虚拟主机名,默认是spring.application.name)
    2、获取所有服务端地址列表(也就是注册表)。
    3、选出一个地址,找到虚拟主机名对应的ip、port(将虚拟主机名 对应到 ip和port上)。
    4、发起实际请求(最朴素的请求)
  • 负载均衡算法

    • 默认实现:
      ZoneAvoidanceRule(区域权衡策略):复合判断Server所在区域的性能和Server的可用性,轮询选择服务器。

    • 其他规则:
      BestAvailableRule(最低并发策略):会先过滤掉由于多次访问故障而处于断路器跳闸状态的服务,然后选择一个并发量最小的服务。逐个找服务,如果断路器打开,则忽略。

      RoundRobinRule(轮询策略):以简单轮询选择一个服务器。按顺序循环选择一个server。

      RandomRule(随机策略):随机选择一个服务器。

      AvailabilityFilteringRule(可用过滤策略):会先过滤掉多次访问故障而处于断路器跳闸状态的服务和过滤并发的连接数量超过阀值得服务,然后对剩余的服务列表安装轮询策略进行访问。

      WeightedResponseTimeRule(响应时间加权策略):据平均响应时间计算所有的服务的权重,响应时间越快服务权重越大,容易被选中的概率就越高。刚启动时,如果统计信息不中,则使用RoundRobinRule(轮询)策略,等统计的信息足够了会自动的切换到WeightedResponseTimeRule。响应时间长,权重低,被选择的概率低。反之,同样道理。此策略综合了各种因素(网络,磁盘,IO等),这些因素直接影响响应时间。

      RetryRule(重试策略):先按照RoundRobinRule(轮询)的策略获取服务,如果获取的服务失败则在指定的时间会进行重试,进行获取可用的服务。如多次获取某个服务失败,就不会再次获取该服务。主要是在一个时间段内,如果选择一个服务不成功,就继续找可用的服务,直到超时。

声明式调用Open Feign

  • pom

    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-openfeign</artifactId>
    </dependency>
    
  • 启动类

    @EnableFeignClients
    
  • FeignClieng

    @FeignClient(name="provider",configuration = FeignConfig.class)
    public interface ProviderClient extends ApiDemo {
    }
    
  • 服务提供方接口Controller,继承到FeignClient就省的自己写。

    @RequestMapping("/demo")
    public interface ApiDemo {
        @GetMapping("/getHi")
        String getHi();
    }
    
  • 远程调用

    @Autowired
    ProviderClient providerClient;
    
    @GetMapping("getHiFeign")
    public String getHiFeign(){
        return providerClient.getHi();
    }
    
  • feign的配置类( 1.自定义配置类、2.增加拦截器)

    • Feign拦截器RequestInterceptor ,用于header中增加设置参数
      • 通用配置

        @Configuration
        public class FeignConfig  implements RequestInterceptor {
            private String iamKey="123456";
            @Override
            public void apply(RequestTemplate requestTemplate) {
                requestTemplate.header("Content-Type","application/json");
                requestTemplate.header("X-Gaia-Api-Key",iamKey);
            }
        }
        
      • 配置类不加@Configuration,在配置文件里配置哪个服务用哪个配置类provider是服务名,不指定就写defult

        @FeignClient(name = "provider")
        
        feign:
          client: 
            config:  
              provider: 
                request-interceptors:
                - com.msb.config.FeignConfig
        
    • 默认配置类:org.springframework.cloud.openfeign.FeignClientsConfiguration默认定义了feign使用的编码器,解码器等
    • 使用@FeignClient的configuration的属性自定义Feign配置。自定义的配置优先级高于上面的FeignClientsConfiguration
    • 扩展
      • 通用配置:
         feign:
             client: 
               config:  
                 default: 
                   connect-timeout: 5000
                   read-timeout: 5000
                   logger-level: full
        
      • 指定服务名称配置:
         feign:
             client: 
               config:  
                 provider: 
                   connect-timeout: 5000
                   read-timeout: 5000
                   logger-level: full
        
      • 属性配置比Java代码优先级高。也可通过配置设置java代码优先级高。
        feign:
        	client: 
        		default-to-properties: false
        
  • 原理

    • 主程序入口添加@EnableFeignClients注解开启对Feign Client扫描加载处理。根据Feign Client的开发规范,定义接口并加@FeignClient注解。
    • 当程序启动时,会进行包扫描,扫描所有@FeignClient注解的类,并将这些信息注入Spring IoC容器中。当定义的Feign接口中的方法被调用时,通过JDK的代理方式,来生成具体的RequestTemplate。当生成代理时,Feign会为每个接口方法创建一个RequestTemplate对象,该对象封装了HTTP请求需要的全部信息,如请求参数名、请求方法等信息都在这个过程中确定。
    • 然后由RequestTemplate生成Request,然后把这个Request交给client处理,这里指的Client可以是JDK原生的URLConnection、Apache的Http Client,也可以是Okhttp。最后Client被封装到LoadBalanceClient类,这个类结合Ribbon负载均衡发起服务之间的调用。
  • 压缩

    • 服务端provider配置
      #服务端开启压缩
      server.compression.enabled=true
      
    • 调用方consumer配置
      #配置请求GZIP压缩
      feign.compression.request.enabled=true
      #配置响应GZIP压缩
      feign.compression.response.enabled=true
      #单位是B
      feign.compression.request.min-request-size=100
      
  • 开启日志

    • 配置文件
      logging.level.com.mashibing.UserConsumer:debug
      
    • 重写日志等级
      @Configuration
      public class FeiginConfig {
      	@Bean
      	Logger.Level logLevel(){
      		return Logger.Level.BASIC;
      	}
      }
      
  • 超时

    • Feign默认支持Ribbon;Ribbon的重试机制和Feign的重试机制有冲突,所以源码中默认关闭Feign的重试机制,使用Ribbon的重试机制
    #连接超时时间(ms)
    ribbon.ConnectTimeout=1000
    #业务逻辑超时时间(ms)
    ribbon.ReadTimeout=6000
    
  • 重试
    使用ribbon重试机制,请求失败后,每个6秒会重新尝试

    #同一台实例最大重试次数,不包括首次调用
    ribbon.MaxAutoRetries=1
    #重试负载均衡其他的实例最大重试次数,不包括首次调用
    ribbon.MaxAutoRetriesNextServer=1
    #是否所有操作都重试
    ribbon.OkToRetryOnAllOperations=false
    

服务监控Actuator

  • Eureka 健康检查

    • 由于server和client通过心跳保持 服务状态,而只有状态为UP的服务才能被访问。看eureka界面中的status。

    • 比如心跳一直正常,服务一直UP,但是此服务DB连不上了,无法正常提供服务。

    • 开启手动控制

      • 在client端配置:将自己真正的健康状态传播到server。

        eureka:
          client:
            healthcheck:
              enabled: true
        
      • Client端配置Actuator

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

    改变健康状态的Service

    @Service
    public class HealthStatusService implements HealthIndicator{
    
    	private Boolean status = true;
    
    	public void setStatus(Boolean status) {
    		this.status  = status;
    	}
    
    	@Override
    	public Health health() {
    		// TODO Auto-generated method stub
    		if(status)
    		return new Health.Builder().up().build();
    		return new Health.Builder().down().build();
    	}
    
    	public String getStatus() {
    		// TODO Auto-generated method stub
    		return this.status.toString();
    	}
    
  • 测试用的Controller

    @GetMapping("/health")
    public String health(@RequestParam("status") Boolean status) {
    	
    	healthStatusSrv.setStatus(status);
    	return healthStatusSrv.getStatus();
    }
    
  • 开启所有端点

    • Spring Boot 2.0 的Actuator只暴露了health和info端点,提供的监控信息无法满足我们的需求
    • 在1.x中有n多可供我们监控的节点,官方的回答是为了安全….
    #开启所有端点
    management.endpoints.web.exposure.include=*
    
  • api端点功能

    • Health
      会显示系统状态
      {“status”:“UP”}
    • shutdown
      用来关闭节点
      开启远程关闭功能management.endpoint.shutdown.enabled=true
    • autoconfig
      获取应用的自动化配置报告 beans
      获取应用上下文中创建的所有Bean
    • configprops
      获取应用中配置的属性信息报告
    • env
      获取应用所有可用的环境属性报告
    • Mappings
      获取应用所有Spring Web的控制器映射关系报告
    • info
      获取应用自定义的信息
    • metrics
      返回应用的各类重要度量指标信息
      Metrics节点并没有返回全量信息,我们可以通过不同的key去加载我们想要的值metrics/jvm.memory.max
    • Threaddump
      1.x中为dump
      返回程序运行中的线程信息
      东宝商城(仿淘宝)项目技术架构图 高并发电商系统瓶颈分析 秒杀系统多级“读、写”分离 神一样的CAP定理以及BASE理论

熔断器Hystrix

  • pom

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

    单独使用

    public class HystrixTest extends HystrixCommand {
        public static void main(String[] args) {
        String result="";
            Future<String> spring = new HystrixTest(HystrixCommandGroupKey.Factory.asKey("spring")).queue();
        try {
           result = spring.get();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
        System.out.println("程序结果:"+result);
        }
        
        protected HystrixTest(HystrixCommandGroupKey key) {
            super(key);
            // TODO Auto-generated constructor stub
        }
        @Override
        protected Object run() throws Exception {
            System.out.println("执行逻辑");
            int i = 1/0;
            return "ok";
        }
        @Override
        protected Object getFallback() {
            // TODO Auto-generated method stub
            return "getFallbackgetFallback";
        }
    }
    

    配合RestTemplate使用

    启动类

    @EnableCircuitBreaker
    
    @HystrixCommand(fallbackMethod = "back")
    public String alive() {
        // 自动处理URL
    
        RestTemplate restTemplate = new RestTemplate();
    
        String url ="http://user-provider/User/alive";
        String object = restTemplate.getForObject(url, String.class);
    
        return object;
    
    }
    
    
    public String back() {
    
        return "请求失败~bbb...";
    }
    

    配合OpenFeign使用

    启动类

    @EnableHystrix
    

    配置文件开启

    feign.hystrix.enabled=true
    

    FeignClient添加fallback执行类
    在这里插入图片描述
    fallback类
    在这里插入图片描述
    FallbackFactory类
    在这里插入图片描述

    @Component
    public class ProError implements FallbackFactory<ProviderClient> {
        @Override
        public ProviderClient create(Throwable throwable) {
            return new ProviderClient() {
                @Override
                public String getHi() {
                    throwable.printStackTrace();
                    if(throwable instanceof FeignException.InternalServerError) {
                        System.out.println("InternalServerError");
                        return "远程服务报错";
                    }else if(throwable instanceof RuntimeException) {
                        System.out.println("RuntimeException");
                        return "远程服务链接超时";
                    }else {
                        return "都算不上";
                    }
                }
            };
        }
    }
    

    信号量隔离与线程隔离

    • 默认情况下hystrix使用线程池控制请求隔离

    • 线程池隔离技术,是用 Hystrix 自己的线程去执行调用;而信号量隔离技术,是直接让 tomcat 线程去调用依赖服务。信号量隔离,只是一道关卡,信号量有多少,就允许多少个 tomcat 线程通过它,然后去执行。

    • 信号量隔离主要维护的是Tomcat的线程,不需要内部线程池,更加轻量级。

    • 配置

      hystrix.command.default.execution.isolation.strategy 隔离策略,默认是Thread, 可选Thread|Semaphore
      thread 通过线程数量来限制并发请求数,可以提供额外的保护,但有一定的延迟。一般用于网络调用
      semaphore 通过semaphore count来限制并发请求数,适用于无网络的高并发请求
      hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds 命令执行超时时间,默认1000ms
      hystrix.command.default.execution.timeout.enabled 执行是否启用超时,默认启用true
      hystrix.command.default.execution.isolation.thread.interruptOnTimeout 发生超时是是否中断,默认true
      hystrix.command.default.execution.isolation.semaphore.maxConcurrentRequests 最大并发请求数,默认10,该参数当使用ExecutionIsolationStrategy.SEMAPHORE策略时才有效。如果达到最大并发请求数,请求会被拒绝。理论上选择semaphore size的原则和选择thread size一致,但选用semaphore时每次执行的单元要比较小且执行速度快(ms级别),否则的话应该用thread。
      semaphore应该占整个容器(tomcat)的线程池的一小部分。
      
    • Feign下配置

      hystrix.command.default.execution.isolation.strategy=SEMAPHORE
      

    dashboard

    • pom

      <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>
      
    • 启动类

      @EnableHystrixDashboard
      
    • 图形化

      http://localhost:90/hystrix
      
    • 健康上报

      http://localhost:90/actuator/hystrix.stream
      

服务网关Zuul

  • pom

    <dependency>
    	<groupId>org.springframework.cloud</groupId>
    	<artifactId>spring-cloud-starter-netflix-zuul</artifactId>
    </dependency>
    
  • 启动类

    @EnableZuulProxy
    
  • 访问(网关会将服务名转换成具体服务的ip和端口,实际进行访问)

    http://euk1.top:1000/consumer/demo1/getHiFeign
    
  • 负载均衡(默认是轮询)

    consumer.ribbon.NFLoadBalancerRuleClassName=com.netflix.loadbalancer.RandomRule
    
  • 路由端点
    调试的时候,看网关请求的地址,以及 映射是否正确。网关请求有误时,可以通过此处排查错误。

    management.endpoints.web.exposure.include=*
    management.endpoint.health.show-details=always
    management.endpoint.health.enabled=true
    management.endpoint.routes.enabled=true
    
  • 配置指定微服务的访问路径

    1. 通过服务名配置(虚拟主机名)
      http://euk1.top:1000/consumer/demo1/getHiFeign
      http://euk1.top:1000/consumer_v1/demo1/getHiFeign

      zuul.routes.consumer=/consumer_v1/**
      
    2. 自定义映射

      zuul.routes.baidu.path=/baidu/**
      zuul.routes.baidu.url=http://baidu.com
      

      自定义下的负载均衡

      zuul.routes.user-provider.path=/user-provider/**
      zuul.routes.user-provider.service-id=cuid
      cuid.ribbon.listOfServers=euk1.top:8001,euk1.top:8002
      ribbon.eureka.enabled=false
      
  • 忽略微服务

    zuul.ignored-services=consumer
    
  • 前缀

    zuul.prefix=/api/v1
    
    • 带上前缀请求
      zuul.strip-prefix=false
      

链路追踪Sleuth

Sleuth是Spring cloud的分布式跟踪解决方案。

  • pom

    <!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-sleuth -->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-sleuth</artifactId>
        <version>2.2.6.RELEASE</version>
    </dependency>
    

Sleuth单独使用

  • 启动服务访问一次。看日志结果。

    在这里插入图片描述
    在这里插入图片描述

zipkin
上面拍错看日志,很原始。刀耕火种,加入利器 zipkin。

zipkin是twitter开源的分布式跟踪系统。

原理收集系统的时序数据,从而追踪微服务架构中系统延时等问题。还有一个友好的界面。
  • 由4个部分组成:
    • Collector、Storage、Restful API、Web UI组成
    • 采集器,存储器,接口,UI。
  • 原理:
    • sleuth收集跟踪信息通过http请求发送给zipkin server,zipkin将跟踪信息存储,以及提供RESTful API接口,zipkin ui通过调用api进行数据展示。
    • 默认内存存储,可以用mysql,ES等存储。
    操作步骤:
    • pom
      <!-- zipkin -->
      <dependency>
          <groupId>org.springframework.cloud</groupId>
          <artifactId>spring-cloud-starter-zipkin</artifactId>
      </dependency>
      
    • 每个需要监听的服务yml中
      spring:
        #zipkin
        zipkin:
          base-url: http://localhost:9411/
          #采样比例1
        sleuth:
          sampler:
            rate: 1  
      
    • 启动zipkin
    1. jar包下载:wget ‘https://search.maven.org/remote_content?g=io.zipkin.java&a=zipkin-server&v=LATEST&c=exec’

    2. curl -sSL https://zipkin.io/quickstart.sh | bash -s
      我放到了 目录:C:\github\online-taxi-demo 下面。

       java -jar zipkin.jar
      
    3. 或者docker:
      docker run -d -p 9411:9411 openzipkin/zipkin

    • 访问http://localhost:9411/
      在这里插入图片描述

健康检查Spring Cloud Admin

server

  • pom

    <properties>
    	<spring-boot-admin.version>2.2.1</spring-boot-admin.version>
    </properties>
    <!-- Admin 界面 -->
    <dependency>
    	<groupId>de.codecentric</groupId>
    	<artifactId>spring-boot-admin-starter-server</artifactId>
    	<version>${spring-boot-admin.version}</version>
    </dependency>
    <dependency>
    	<groupId>de.codecentric</groupId>
    	<artifactId>spring-boot-admin-server-ui</artifactId>
    	<version>${spring-boot-admin.version}</version>
    </dependency>
    
  • 配置

    server.port=1100
    #设置服务注册中心的URL,用于client和server端交流
    eureka.client.service-url.defaultZone=http://euk2.top:7002/eureka/,http://euk1.top:7001/eureka/
    spring.application.name=admin
    
    management.endpoints.web.exposure.include=*
    management.endpoint.health.show-details=always
    management.endpoint.health.enabled=true
    management.endpoint.routes.enabled=true
    
  • 启动类

    @EnableAdminServer
    

client

  • pom

    <!-- Admin 服务 -->
    <dependency>
        <groupId>de.codecentric</groupId>
        <artifactId>spring-boot-admin-starter-client</artifactId>
        <version>2.2.1</version>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-actuator</artifactId>
    </dependency>
    
  • 配置

    management.endpoints.web.exposure.include=*
    management.endpoint.health.show-details=always
    spring.boot.admin.client.url=http://localhost:1100
    

邮件通知

  • pom

    <dependency>
    	<groupId>org.springframework.boot</groupId>
    	<artifactId>spring-boot-starter-mail</artifactId>
    </dependency>
    
  • 配置

    # 邮件设置
    spring.mail.host=smtp.qq.com
    spring.mail.username=QQ号码
    spring.mail.password=pbwyfawjefspbdhd1
    spring.mail.properties.mail.smpt.auth=true
    spring.mail.properties.mail.smpt.starttls.enable=true
    spring.mail.properties.mail.smpt.starttls.required=true
    #收件邮箱
    spring.boot.admin.notify.mail.to=QQ号码@qq.com
    # 发件邮箱
    spring.boot.admin.notify.mail.from=QQ号码@qq.com
    

钉钉群通知

  • pom

    <dependency>
    	<groupId>com.alibaba</groupId>
    	<artifactId>fastjson</artifactId>
    	<version>1.2.68</version>
    </dependency>
    
  • 配置

    # spring cloud access&secret config
    # 可以访问如下地址查看: https://usercenter.console.aliyun.com/#/manage/ak
    spring.cloud.alicloud.access-key=LTAIEW7ORp2hYTBB1
    spring.cloud.alicloud.secret-key=TSqXlzrivoVYdD7CH9HVmjKwbtC9Xa1
    
  • 启动类

    @Bean
    public DingDingNotifier dingDingNotifier(InstanceRepository repository) {
    	return new DingDingNotifier(repository);
    }
    
  • DingDingNotifier

    public class DingDingNotifier extends AbstractStatusChangeNotifier  {
    	public DingDingNotifier(InstanceRepository repository) {
            super(repository);
        }
        @Override
        protected Mono<Void> doNotify(InstanceEvent event, Instance instance) {
            String serviceName = instance.getRegistration().getName();
            String serviceUrl = instance.getRegistration().getServiceUrl();
            String status = instance.getStatusInfo().getStatus();
            Map<String, Object> details = instance.getStatusInfo().getDetails();
            StringBuilder str = new StringBuilder();
            str.append("系统警告 : 【" + serviceName + "】");
            str.append("【服务地址】" + serviceUrl);
            str.append("【状态】" + status);
            str.append("【详情】" + JSONObject.toJSONString(details));
            return Mono.fromRunnable(() -> {
                DingDingMessageUtil.sendTextMessage(str.toString());
            });
        }
    }
    
  • DingDingMessageUtil

    public class DingDingMessageUtil {
    	// 从钉钉群获取的
    	public static String access_token = "55420aefab13c4cf75b3ad144a0efa71ba406ba0037e2619fb99ad2ca5e2c452";
    
    	public static void sendTextMessage(String msg) {
    		
    		
    		//https://oapi.dingtalk.com/robot/send?access_token=55420aefab13c4cf75b3ad144a0efa71ba406ba0037e2619fb99ad2ca5e2c452
    		try {
    			Message message = new Message();
    			message.setMsgtype("text");
    			message.setText(new MessageInfo(msg));
    			URL url = new URL("https://oapi.dingtalk.com/robot/send?access_token=" + access_token);
    			// 建立 http 连接
    			HttpURLConnection conn = (HttpURLConnection) url.openConnection();
    			conn.setDoOutput(true);
    			conn.setDoInput(true);
    			conn.setUseCaches(false);
    			conn.setRequestMethod("POST");
    			conn.setRequestProperty("Charset", "UTF-8");
    			conn.setRequestProperty("Content-Type", "application/Json; charset=UTF-8");
    			conn.connect();
    			OutputStream out = conn.getOutputStream();
    			String textMessage = JSONObject.toJSONString(message);
    			byte[] data = textMessage.getBytes();
    			out.write(data);
    			out.flush();
    			out.close();
    			InputStream in = conn.getInputStream();
    			byte[] data1 = new byte[in.available()];
    			in.read(data1);
    			System.out.println(new String(data1));
    		} catch (Exception e) {
    			e.printStackTrace();
    		}
    	}
    }
    
  • Message

    public class Message {
    	private String msgtype;
        private MessageInfo text;
        public String getMsgtype() {
            return msgtype;
        }
        public void setMsgtype(String msgtype) {
            this.msgtype = msgtype;
        }
        public MessageInfo getText() {
            return text;
        }
        public void setText(MessageInfo text) {
            this.text = text;
        }
    }
    
  • MessageInfo

    public class MessageInfo {
        private String content;
        public MessageInfo(String content) {
            this.content = content;
        }
        public String getContent() {
            return content;
        }
        public void setContent(String content) {
            this.content = content;
        }
    }
    

配置中心Spring Cloud Config

1、创建配置文件git仓库

在这里插入图片描述

2、config-server端

  • pom

    <dependency>
    	<groupId>org.springframework.cloud</groupId>
    	<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
    </dependency>
    <dependency>
    	<groupId>org.springframework.cloud</groupId>
    	<artifactId>spring-cloud-config-server</artifactId>
    </dependency>
    
  • 配置文件

    server.port=1141
    # git地址
    spring.cloud.config.server.git.uri=https://gitee.com/a84/config-server.git
    # git分支
    spring.cloud.config.label=master
    #设置服务注册中心的URL,用于client和server端交流
    eureka.client.service-url.defaultZone=http://euk2.top:7002/eureka/,http://euk1.top:7001/eureka/
    spring.application.name=config-server
    

    下面简单说一下,因为我们读取的配置文件名字叫做【provider-dev.properties】,所以spring.application.name对应【provider】;属性【profile】对应【dev】;然后就是spring.cloud.config.discovery.service-id对应的是注册在Eureka上的config Server的名字

  • 启动类

    @EnableEurekaClient
    @EnableConfigServer
    
  • 启动测试拉取
    不写默认master http://host:port/lable/fileName
    http://localhost:1141/master/config-client-dev.properties

  • 匹配规则
    正确配置后能读到来自git的配置文件

    获取配置规则:根据前缀匹配
    /{name}-{profiles}.properties
    /{name}-{profiles}.yml
    /{name}-{profiles}.json
    /{label}/{name}-{profiles}.yml
    
    name 服务名称
    profile 环境名称,开发、测试、生产:dev qa prd
    lable 仓库分支、默认master分支
    
    匹配原则:从前缀开始。
    

3、config-client端

  • pom

    <dependency>
    	<groupId>org.springframework.cloud</groupId>
    	<artifactId>spring-cloud-config-client</artifactId>
    </dependency>
    
  • 配置文件

    • bootstrap.properties(eureka和config-server)
      #设置服务注册中心的URL,用于client和server端交流
      eureka.client.service-url.defaultZone=http://euk2.top:7002/eureka/,http://euk1.top:7001/eureka/
      spring.application.name=consumer
      
      #直接URL方式查找配置中心
      #spring.cloud.config.uri=http://localhost:1141/
      #通过注册中心查找
      spring.cloud.config.discovery.enabled=true
      spring.cloud.config.discovery.service-id=config-server
      spring.cloud.config.profile=dev
      spring.cloud.config.label=master
      
      注意
      1. spring.application.name=config-client端服务名配置文件name
      2. spring.cloud.config.discovery.service-id=config-server端服务名
  • 启动日志
    加载了 master分支的consumer-dev配置文件
    在这里插入图片描述

4、刷新配置

  • 手动配置热更新

    1. config-client端开启actuator中的refresh端点
    2. config-client端用到远程配置文件的类添加@RefreshScope注解 //开启更新功能
    3. 发送Post请求config-client端http://localhost:9001/actuator/refresh发送Post请求
  • 自动配置热更新(Spring Cloud Bus + RabbitMQ)

  • pom(server + client)

    <dependency>
    	<groupId>org.springframework.cloud</groupId>
    	<artifactId>spring-cloud-starter-bus-amqp</artifactId>
    </dependency>
    
  • 配置文件(server + client)

    spring.rabbitmq.host=81.70.111.111
    spring.rabbitmq.port=5672
    spring.rabbitmq.username=guest
    spring.rabbitmq.password=guest
    
  • 测试
    启动两个微服务

    1. http://localhost:91/actuator/bus-refresh
      修改配置文件后向其中一个端点发送post请求,观察另一个服务是否也跟着刷新了。
    2. http://localhost:8002/actuator/refresh
      只能刷新当前应用的配置

消息总线Spring Cloud Bus

  • pom(server + client)
    <dependency>
    	<groupId>org.springframework.cloud</groupId>
    	<artifactId>spring-cloud-starter-bus-amqp</artifactId>
    </dependency>
    

消息队列RabbitMQ

  • 配置文件(server + client)
    spring.rabbitmq.host=81.70.111.111
    spring.rabbitmq.port=5672
    spring.rabbitmq.username=guest
    spring.rabbitmq.password=guest
    
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值