springcloudgateway集成hystrix

目录

一,pom引入依赖。

二,RestTemplate开启ribbon的负载均衡,@LoadBalanced

三,yml配置和熔断降级的fallback接口。

四,技术资料(springcloudgateway和Hystrix)


springcloudgateway集成hystrix非常简单,官网的说明很清晰明了。

一,pom引入依赖。


		
			org.springframework.cloud
			spring-cloud-starter-netflix-hystrix
		

网关中用到了ribbon,


			org.springframework.cloud
			spring-cloud-starter-netflix-ribbon
		

二,RestTemplate开启ribbon的负载均衡,@LoadBalanced

package com.example.gate.config;

import java.nio.charset.Charset;

import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.client.ClientHttpRequestFactory;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.http.converter.StringHttpMessageConverter;
import org.springframework.web.client.RestTemplate;

//import com.example.gate.service.DbRouteDefinitionRepository;
//com.netflix.client.config.CommonClientConfigKey
//com.netflix.loadbalancer.RetryRule


/**
 * 这个配置类是公共的配置。
 * 如果某一项配置信息比较多,就单独弄一个配置类。
 * 
 * 
 * @author lsy
 *
 */
@Configuration
public class GateConfig {
	
	@Bean
	@LoadBalanced
	public RestTemplate restTemplate(ClientHttpRequestFactory factory) {
		RestTemplate restTemplate = new RestTemplate(factory);
		// 支持中文编码
		restTemplate.getMessageConverters().set(1, new StringHttpMessageConverter(Charset.forName("UTF-8")));
		return restTemplate;

	}

	@Bean
	public ClientHttpRequestFactory simpleClientHttpRequestFactory() {
//        SimpleClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory();
		HttpComponentsClientHttpRequestFactory httpRequestFactory = new HttpComponentsClientHttpRequestFactory();

		httpRequestFactory.setReadTimeout(5000);// 单位为ms
		httpRequestFactory.setConnectTimeout(5000);// 单位为ms
		return httpRequestFactory;
	}

//	@Bean
//    public RestTemplate restTemplate(RestTemplateBuilder builder){
//        return builder.build();
//    }

//	@Bean
//	public RouteLocator customRouteLocator(RouteLocatorBuilder builder) {
//		return builder.routes()
//			.route("path_route", r -> r.path("/get")
//				.uri("http://httpbin.org"))
//			
//			.route("host_route", r -> r.host("*.myhost.org")
//				.uri("http://httpbin.org"))
//			
//			.route("rewrite_route", r -> r.host("*.rewrite.org")
//				.filters(f -> f.rewritePath("/foo/(?.*)", "/${segment}"))
//				.uri("http://httpbin.org"))
//			
//			.route("hystrix_route", r -> r.host("*.hystrix.org")
//				.filters(f -> f.hystrix(c -> c.setName("slowcmd")))
//				.uri("http://httpbin.org"))
//			
//			.route("hystrix_fallback_route", r -> r.host("*.hystrixfallback.org")
//				.filters(f -> f.hystrix(c -> c.setName("slowcmd").setFallbackUri("forward:/hystrixfallback")))
//				.uri("http://httpbin.org"))
//			
//			.route("limit_route", r -> r
//				.host("*.limited.org").and().path("/anything/**")
//				.filters(f -> f.requestRateLimiter(c -> c.setRateLimiter(redisRateLimiter())))
//				.uri("http://httpbin.org"))
//			
//			.build();
//	}

//	@Bean
//	public RouteDefinitionWriter routeDefinitionWriter() {
//		return new InMemoryRouteDefinitionRepository();
//	}
//
//	@Bean
//	public DbRouteDefinitionRepository dbRouteDefinitionRepository() {
//		return new DbRouteDefinitionRepository();
//	}
}

三,yml配置和熔断降级的fallback接口。

package com.example.gate.hystrix;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.HashMap;
import java.util.Map;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;

import reactor.core.publisher.Mono;

/**
 * HystrixGatewayFilterFactory
 * HystrixCommandProperties
 * 
 * Resilience4JCircuitBreakerFactory 
 * ReactiveResilience4JCircuitBreakerFactory 
 * 
 * 默认降级处理。
 * 当请求在一定时间内没有返回就出发网关的熔断,进行降级处理。
 * 即:请求被替换成这个熔断降级的controller,返回的内容就是这个controller的返回。
 * 这个写在网关里。
 * 
 */
@RestController
public class DefaultHystrixController {

	Logger logger = LoggerFactory.getLogger(DefaultHystrixController.class);
	
	@RequestMapping("/defaultfallback")
	@ResponseBody
	public Map defaultfallback() {
		DateTimeFormatter df = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss SSS");
		String dateNowStr=LocalDateTime.now().format(df);
        
		logger.info("DefaultHystrixController降级操作...defaultfallback");
		Map map = new HashMap<>();
		map.put("resultCode", "fail");
		map.put("resultMessage", "服务繁忙,请稍后重试defaultfallback");
		map.put("time", dateNowStr);
		return map;
	}
	
	@RequestMapping("/defaultfallback1")
	@ResponseBody
	public Map defaultfallback1() {
		DateTimeFormatter df = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss SSS");
		String dateNowStr=LocalDateTime.now().format(df);
		logger.info("DefaultHystrixController降级操作...defaultfallback111111");
		Map map = new HashMap<>();
		map.put("resultCode", "fail");
		map.put("resultMessage", "服务繁忙,请稍后重试defaultfallback111111");
		map.put("time", dateNowStr);
		return map;
	}
	
	@GetMapping(value="/defaultfallback2")
	public Map defaultfallback2() {
		DateTimeFormatter df = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss SSS");
		String dateNowStr=LocalDateTime.now().format(df);
		logger.info("DefaultHystrixController降级操作...defaultfallback222222");
		Map map = new HashMap<>();
		map.put("resultCode", "fail");
		map.put("resultMessage", "服务繁忙,请稍后重试defaultfallback222222");
		map.put("time", dateNowStr);
		return map;
	}
	
	
	
//	@RequestMapping("/defaultfallback3")
//	public Mono defaultfallback3() {
//		return Mono.just("defaultfallback3");
//	}
	
	
}

yml:

server: 
   port: 8888
 #链接建立超时时间
   connection-timeout: 10000 
   tomcat: 
     max-threads: 6 # 最大线程数
     min-spare-thread: 3 # 最小线程数
     accept-count: 10 # 队列长度
     max-connections: 1000 # 最大链接数
     
spring:
  application:
    name: gate
  servlet: 
    multipart: 
      max-file-size: 50MB #单个文件上传的大小限制,默认1MB
      max-request-size: 150MB #一次请求总共文件大侠限制。 如果用nginx,需要改nginx的限制,在server配置client_max_body_size 300M;
  redis:
    timeout: 6000ms
    database: 10 
    host: localhost #单实例redis用这个配置
    password: #单实例redis用这个配置
    port: 6379 #单实例redis用这个配置
#    password: Redis@123 #集群用这个配置
#    cluster: #集群用这个配置
#      nodes:
#        - 127.0.0.1:7011
#        - 127.0.0.1:7012
#        - 127.0.0.1:7013
#        - 127.0.0.1:7014
#        - 127.0.0.1:7015
#        - 127.0.0.1:7016
#      max-redirects: 2 #获取失败 最大重定向次数
    lettuce:
      pool: 
        max-active: 1000 #连接池最大连接数(使用负值表示没有限制)
        max-idle: 10 #连接池中的最大空闲连接
        min-idle: 3 #连接池中的最小空闲连接
        max-wait: -1 #连接池最大阻塞等待时间(使用负值表示没有限制)
  cloud:
    consul:
      host: 127.0.0.1  #注册中心的ip或host。也是集群地址,配置一个即可。注释掉整个consul这段就可以启动,即使没有注册中心也不报错。有这段就必须有一个可用的注册中心,否则启动报错
      port: 8500
      discovery:
        enabled: true #默认true。Consul Discovery Client是否注册到注册中心。和register同时设置成false,就不需要起consul服务。
        register: true #是否将服务注册到Consul集群中心.。这个参数和上面的enabled参数同时设置成false,应用才不会注册注册中心,才可以不起consul服务!
        deregister: true #默认true,服务停止时注销服务,即从服务列表中删除。设置成false的话,???
        #service-name: ${spring.application.name}  #注册在consul上面的名字,在consul的调用中,是通过此名字调用的。默认服务名,不要改
        instance-id: ${spring.application.name}-${spring.cloud.client.ip-address}:${server.port} #只供显示用,在ID列显示
        health-check-interval: 10s  #配置 Consul 健康检查频率,也就是心跳频率。
        health-check-timeout: 10s #健康检查超时
#        health-check-critical-timeout: 10s #注册成功之后,如果关闭微服务,consul将检测60s,如果60s之后还检测不到此服务,将会把此服务从注册列表中移除.如果想重启consul,服务能主动注册到consul,这个参数必须注释掉!!!
        #health-check-path: /tmp #健康检查路径
        prefer-ip-address: true #表示注册时使用IP而不是hostname
      retry:
        initial-interval: 1000   # 初始重试间隔(以毫秒为单位
        max-attempts: 3
        max-interval: 2000
        multiplier: 1.1
    gateway:
#      default-filters: 
#      - name: Hystrix
#        args: 
#          name: myfallback
#          fallbackUri: forward:/defaultfallback
      routes:
      - id: one
        uri: lb://one
        predicates: 
          - Path=/one/**
        filters:
        - StripPrefix=1
        - AddRequestHeader=X-Request-color, blue
        - AddRequestHeader=X-Request-temp, blue
        - name: RequestRateLimiter
          args:
            rate-limiter: "#{@urlAndChannelRedisRateLimiter}"
            key-resolver: "#{@selfUrlAndChannelKeyResolver}"
        - name: Hystrix
          args:  
            name: commandone
            fallbackUri: forward:/defaultfallback1
      - id: two
        uri: lb://two
        predicates: 
          - Path=/two/**
        filters:
        - StripPrefix=1
        - name: RequestRateLimiter
          args:
            rate-limiter: "#{@urlAndChannelRedisRateLimiter}"
            key-resolver: "#{@selfUrlAndChannelKeyResolver}" 
        - name: Hystrix
          args:  
            name: commandtwo
            fallbackUri: forward:/defaultfallback2


# hystrix 信号量隔离,timeoutInMilliseconds毫秒后自动超时.第3个值跟Hystrix的name属性是对应的。比如,你配置的是fallbackone,name就该这样配置fallbackone.也可以平铺,例如上面
       
hystrix:
  threadpool: 
    default: 
      coreSize: 10 
      maxQueueSize: -1 
      queueSizeRejectionThreshold: 1000 
  command: 
    myfallback: 
      metrics: 
        rollingStats: 
          timeInMilliseconds: 10000 #默认10000即10秒
      execution: 
        isolation: 
          strategy: THREAD # THREAD SEMAPHORE
          thread: 
            timeoutInMilliseconds: 5000
        timeout: 
          enabled: true #默认true,使用timeoutInMilliseconds作为超时时间,否则使用ribbon的超时
      circuitBreaker:
        forceClosed: false #默认false,想强制关闭熔断就改成true
        requestVolumeThreshold: 2 #窗口采样大小20
        sleepWindowInMilliseconds: 6000 #短路后休眠时间毫秒
        errorThresholdPercentage: 30 #判断出错百分比50
    commandone: 
      metrics: 
        rollingStats: 
          timeInMilliseconds: 10000 #默认10000即10秒
      execution: 
        isolation: 
          strategy: THREAD # THREAD SEMAPHORE
          thread: 
            timeoutInMilliseconds: 6000
        timeout: 
          enabled: true #默认true,使用timeoutInMilliseconds作为超时时间,否则使用ribbon的超时
      circuitBreaker:
        forceClosed: false #默认false,想强制关闭熔断就改成true
        requestVolumeThreshold: 2 #窗口采样大小20
        sleepWindowInMilliseconds: 6000 #短路后休眠时间毫秒
        errorThresholdPercentage: 30 #判断出错百分比50
    commandtwo: 
      metrics: 
        rollingStats: 
          timeInMilliseconds: 10000 #默认10000即10秒
      execution: 
        isolation: 
          strategy: THREAD # THREAD SEMAPHORE
          thread: 
            timeoutInMilliseconds: 3000
        timeout: 
          enabled: true #默认true,使用timeoutInMilliseconds作为超时时间,否则使用ribbon的超时
      circuitBreaker:
        forceClosed: false #默认false,想强制关闭熔断就改成true
        requestVolumeThreshold: 2 #窗口采样大小20
        sleepWindowInMilliseconds: 12000 #短路后休眠时间毫秒
        errorThresholdPercentage: 50 #判断出错百分比50

#实际的超时时间是(ReadTimeout+ConnectTimeout)*(MaxAutoRetries+1)*(MaxAutoRetriesNextServer+1)
#如果MaxAutoRetries和MaxAutoRetriesNextServer都设为0,那么实际超时就是(ReadTimeout+ConnectTimeout)了
ribbon: 
  eureka: 
    enabled: false
  eager-load: 
    enabled: true #饥饿加载,系统启动时创建好ribbon客户端而不是在使用时去创建
  ConnectTimeout: 2000 #单位ms,请求连接超时时间
  ReadTimeout: 4000 #单位ms,请求处理的超时时间
  OkToRetryOnAllOperations: false #对所有操作请求都进行重试
  MaxAutoRetriesNextServer: 0 #切换实例的重试次数
  MaxAutoRetries: 0 #对当前实例的重试次数
  ServerListRefreshInterval: 2000 #Interval to refresh the server list from the source
  NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RetryRule
#  listofServers:localhost:8001,localhost:8002,localhost:8003

one:
  ribbon: 
    eureka: 
      enabled: false
    eager-load: 
      enabled: true #饥饿加载,系统启动时创建好ribbon客户端而不是在使用时去创建
    ConnectTimeout: 2000 #单位ms,请求连接超时时间
    ReadTimeout: 4000 #单位ms,请求处理的超时时间
    OkToRetryOnAllOperations: false #对所有操作请求都进行重试
    MaxAutoRetriesNextServer: 0 #切换实例的重试次数
    MaxAutoRetries: 0 #对当前实例的重试次数
    ServerListRefreshInterval: 2000 #Interval to refresh the server list from the source
    NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RetryRule
    
    
feign:
  hystrix: 
    enabled: false

#eureka:
#  instance:
#    prefer-ip-address: true
#    instance-id: ${spring.application.name}:${spring.cloud.client.ip-address}:${server.port}
#    lease-expiration-duration-in-seconds: 10
#    lease-renewal-interval-in-seconds: 3
#  client:
#    registry-fetch-interval-seconds: 5
#    serviceUrl:
#      defaultZone: http://localhost:8761/eureka/

#启用监控.开启监控后,可直接通过actuator的rest接口查看服务的详细信息。例如查看网关的路由:http://localhost:8888/actuator/gateway/routes
management:
  endpoints:
    web:
      exposure:
        include: 
        - "*"  # 开放所有端点health,info,metrics,通过actuator/+端点名就可以获取相应的信息。默认打开health和info
  endpoint:
    health:
      show-details: always  #未开启actuator/health时,我们获取到的信息是{"status":"UP"},status的值还有可能是 DOWN。开启后打印详细信息

logging: 
  # logback.xml路径,默认为classpath:logback.xml
  pattern:  
    file: "%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n"
    console: "%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n"
  path: D:\cloudlogs\
  file: D:\cloudlogs\gate.log
  file.max-size: 3MB
  level: 
    root: info
    #com.bestvike: debug
#是否启动注册状态检查,启动后发现在注册中心状态有问题就不停的注册自己,直至成功。
my: 
  consul: 
    check: 
      register: false
      interval: 10
   
#限流参数格式: 系统名称_限流key: 限流速率@令牌桶大小.并有一个default配置。  
selfratelimiter:
  rateLimitChannel:
    default: 5@10
    one_channelA: 2@3
    one_channelB: 1@2
    two_channelA: 1@2
    two_channelB: 2@4
  rateLimitIP:
    default: 55@70
    one_192.168.124.17: 2@3
    two_192.168.124.18: 1@2
    two_192.168.124.19: 5@10
  rateLimitUrlAndChannel:
    default: 6600@8000
    url_1: /one/limit/sprint
    channel_url_1: channelA
    limit_url_1: 1@2
    url_2: /one/limit/sprint2
    channel_url_2: channelA
    limit_url_2: 2@3
    url_3: /one/limit/sprint
    channel_url_3: channelB
    limit_url_3: 3@4
   
#系统启动后调用的service进行初始化数据,按顺序执行InitDataService 
initservicelist:
  servicesMap: 
    1: initSysDataService 
    2: initRedisDataService
#    12: paramService2 
#    37: userServicegg 
#    3: userService3 


#jasypt加密后的密码
mypass:
  pass1: ENC(NfA+LtBfc26xLiHLb0EGXeNfU9TaE2tQIt7X94DrodPcUKV/tnTKQLz7bcLSM3i0)
  
  
#jasypt加密配置
jasypt:
  encryptor:
    password: miyao
    algorithm: PBEWITHHMACSHA512ANDAES_256
#    property:
#      prefix: "ENC@["
#      suffix: "]"

 

注意,每个微服务,我单独配置了Hystrix的一套配置参数。也可以把每个微服务的Hystrix去掉,用一个总的默认的配置:

    gateway:
#      default-filters: 
#      - name: Hystrix
#        args: 
#          name: myfallback
#          fallbackUri: forward:/defaultfallback

 

关于ribbon的配置,也是支持默认配置和具体微服务的配置:

#实际的超时时间是(ReadTimeout+ConnectTimeout)*(MaxAutoRetries+1)*(MaxAutoRetriesNextServer+1)
#如果MaxAutoRetries和MaxAutoRetriesNextServer都设为0,那么实际超时就是(ReadTimeout+ConnectTimeout)了
ribbon: 
  eureka: 
    enabled: false
  eager-load: 
    enabled: true #饥饿加载,系统启动时创建好ribbon客户端而不是在使用时去创建
  ConnectTimeout: 2000 #单位ms,请求连接超时时间
  ReadTimeout: 4000 #单位ms,请求处理的超时时间
  OkToRetryOnAllOperations: false #对所有操作请求都进行重试
  MaxAutoRetriesNextServer: 0 #切换实例的重试次数
  MaxAutoRetries: 0 #对当前实例的重试次数
  ServerListRefreshInterval: 2000 #Interval to refresh the server list from the source
  NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RetryRule
#  listofServers:localhost:8001,localhost:8002,localhost:8003

one:
  ribbon: 
    eureka: 
      enabled: false
    eager-load: 
      enabled: true #饥饿加载,系统启动时创建好ribbon客户端而不是在使用时去创建
    ConnectTimeout: 2000 #单位ms,请求连接超时时间
    ReadTimeout: 4000 #单位ms,请求处理的超时时间
    OkToRetryOnAllOperations: false #对所有操作请求都进行重试
    MaxAutoRetriesNextServer: 0 #切换实例的重试次数
    MaxAutoRetries: 0 #对当前实例的重试次数
    ServerListRefreshInterval: 2000 #Interval to refresh the server list from the source
    NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RetryRule

到此,Hystrxi的配置就完成了。

可以通过写一个测试controller进行测试,比如超时timeoutInMilliseconds是否生效。

我在微服务one里写一个测试controller:

package com.example.one.controller;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;

/**
 * 一个普通的controller,用于测试Hystrix熔断。 
 * 
 * 
 * @author lsy
 *
 */
@RestController
//@Controller
//@RequestMapping("/beat")
public class TestHystrixController {

	@Value("${spring.cloud.client.ip-address}")
	private String ip;

	@Value("${spring.application.name}")
	private String servername;

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

	//RequestMapping千万别叫这个名字 waitFail ,有问题!!!!
	
	@RequestMapping(value = "/testhy0",method = RequestMethod.GET)
	@ResponseBody
	public String testhy0() {
		try {
			// 直接正常返回,用于填充熔断采样请求的百分比
			DateTimeFormatter df = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss SSS");
			String info="【testhy0】0000000 直接返回===  hello !  I am   [" + servername + ":" + ip + ":" + port + "]" + "..."
					+ LocalDateTime.now().format(df);
			System.out.println(info);
			return info;
		} catch (Exception e) {
			e.printStackTrace();
			return "异常testhy0";
		}
	}
	
	@RequestMapping(value = "/testhy1",method = RequestMethod.GET)
	@ResponseBody
	public String testhy1(@RequestParam(required=false) String time) throws Exception {
		int timeout=3000;
		
		if(time!=null && time.trim().equals("error")) {
			throw new Exception("error主动异常!");
		}
		
		try {
			try {
				if(time!=null && !time.trim().equals("")) {
					timeout = Integer.valueOf(time.trim());
				}
			} catch (Exception e) {
				timeout=3000;
				e.printStackTrace();
			}
			Thread.sleep(timeout*1000);//转化成毫秒
			
			DateTimeFormatter df = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss SSS");
			String info="【testhy1】 ===timeout==["+timeout+"]  hello !  I am   [" + servername + ":" + ip + ":" + port + "]" + "..."
					+ LocalDateTime.now().format(df);
			System.out.println(info);
			return info;
		} catch (Exception e) {
			e.printStackTrace();
			return "异常testhy1";
		}
	}
	
}

通过测试,yml中的配置是生效的。

熔断可以通过jmeter压测一下。

四,技术资料(springcloudgateway和Hystrix)

https://spring.io/projects/spring-cloud-gateway

https://github.com/Netflix/Hystrix/wiki/Configuration

 

 

  

 

 

 

 

 

 

 

 

 

 

 

 

你可能感兴趣的:(springcloud)