SpringCloud学习-SpringCloudNetfix

Posted wu6660563

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了SpringCloud学习-SpringCloudNetfix相关的知识,希望对你有一定的参考价值。

Netfix组件是涵盖了构建大型分布式系统的一整套方案。提供的模式包括服务发现(Eureka),断路器(Hystrix),智能路由(Zuul)和客户端负载均衡(Ribbon)

服务发现:Eureka客户端

Netfix服务发现服务器和客户端都是Eureka,可以将服务器配置和部署为高可用性,每个服务器将注册服务的状态复制到其他服务器

  • 通过使用org.springframework.cloudspring-cloud-starter-eureka的库
  • Eureka从属于服务的每个实例接收心跳信息。如果心跳失败超过可配置的时间,直接从注册表删除。客户端加入@EnableEurekaClient,也可以使用@EnableDiscoveryClient,但需要配置serviceUrl.defaultZone,从Environment获取的默认应用程序名称(服务ID),虚拟主机和非安全端口分别为$spring.application.name$spring.application.name$server.port

Eureka进行身份验证

可以使用eureka.client.serviceUrl.defaultZone加入凭证http://user:password@localhost:8761/eureka

状态页和健康指标

指定状态指标,如下:

eureka:
  instance:
    statusPageUrlPath: $management.context-path/info
    healthCheckUrlPath: $management.context-path/health

注册安全应用程序

使用https,可以分别在EurekaInstanceConfig,即eureka.instance.[nonSecurePortEnabled,securePortEnabled]=[false,true]

eureka:
  instance:
    statusPageUrl: https://$eureka.hostname/info
    healthCheckUrl: https://$eureka.hostname/health
    homePageUrl: https://$eureka.hostname/

Eureka的健康检查

如果需要让Eureka自动检测心跳,可以把检测心跳设置为true

eureka:
  client:
    healthcheck:
      enabled: true

如果需要更多的控制健康检测,可以实现接口com.netflix.appinfo.HealthCheckHandler

AWS云上部署Eureka

如果应用程序要部署到AWS云,必须配置为AWS可以识别到,可以通过EurekaInstanceConfigBean

@Bean
@Profile("!default")
public EurekaInstanceConfigBean eurekaInstanceConfig(InetUtils inetUtils) 
  EurekaInstanceConfigBean b = new EurekaInstanceConfigBean(inetUtils);
  AmazonInfo info = AmazonInfo.Builder.newBuilder().autoBuild("eureka");
  b.setDataCenterInfo(info);
  return b;

如果Eureka实例注册了其主机相同的ID,可以如下配置
$spring.cloud.client.hostname:$spring.application.name:$spring.application.instance_id:$server.port,如:myhost:myappname:8080

使用EurekaClient

一旦有通过@EnableDiscoveryClient注解的程序,可以通过Eureka服务器发现服务实例。

@Autowired
private EurekaClient discoveryClient;

public String serviceUrl() 
    InstanceInfo instance = discoveryClient.getNextServerFromEureka("STORES", false);
    return instance.getHomePageUrl();

注册的维持时间为30s,可以通过修改配置eureka.instance.leaseRenewalIntervalInSeconds更改周期

服务发现:Eureka服务器

要使用Eureka服务器,使用group为org.springframework.cloud和artifactId为spring-cloud-starter-eureka-server

运行Eureka服务器

@SpringBootApplication
@EnableEurekaServer
public class Application 

    public static void main(String[] args) 
        new SpringApplicationBuilder(Application.class).web(true).run(args);
    


断路器:Hystrix客户端

断路器就是,当一个请求超时,启用短路以后的策略或者路由逻辑

要在项目中支持Hystrix,使用groupId为org.springframework.cloud和artifactId为spring-cloud-starter-hystrix的启动器

代码如下:

@SpringBootApplication
@EnableCircuitBreaker
public class Application 

    public static void main(String[] args) 
        new SpringApplicationBuilder(Application.class).web(true).run(args);
    



@Component
public class StoreIntegration 

    @HystrixCommand(fallbackMethod = "defaultStores")
    public Object getStores(Map<String, Object> parameters) 
        //失败的操作返回
    

    public Object defaultStores(Map<String, Object> parameters) 
        return new Object();
    

传播安全上下文或使用Spring范围

如果希望某些线程传播到@HystrixCommand,默认声明不起作用,因为默认线程已经超时了。

可以使用hystrix.shareSecurityContext设置为true

健康指标

可以通过访问http://ip:port/health来访问健康指标


    "hystrix": 
        "openCircuitBreakers": [
            "StoreIntegration::getStoresByLocationLink"
        ],
        "status": "CIRCUIT_OPEN"
    ,
    "status": "UP"

Hystrix指标流

要用Hystrix的话,需要加入spring-boot-starter-actuator的依赖,将使用/hystrix.stream作为管理端点

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

断路器:Hystrix仪表板

Hystrix的优点是收集每个HystrixCommand的指标,可以有效管理每个断路器的运行状态

Hystrix超时和Ribbon

导入groupId=org.springframework.cloudartifactId=spring-cloud-starter-hystrix-dashboard即可使用仪表盘

在SpringBoot的主类中注解@EnableHystrixDashboard,然后访问/hystrix即可

Turbine

Hystrix在系统整体健康方面不是非常有用。在Maven中引入spring-cloud-starter-turbineTurbine将所有/hystrix.stream聚合到/turbine.stream中。需要使用@EnableTurbine注释主类。区别在于trubine.instanceUrlSuffix不需要预先添加端口,除非turbine.instanceInsertPort=false自动处理

可以通过如下配置重新定义hystrix的端口

eureka:
  instance:
    metadata-map:
      management.port: $management.port:8081

客户端负载均衡器:Ribbon

Ribbon主要的6个组件是:IRule、IPing、ServerList、ServerListUpdater、ILoadBalancer

Ribbon的主要功能:

  • 支持DNS和IP和服务端通信
  • 根据算法从多个服务中选取一个服务进行访问
  • 通过对客户端和服务器分成几个区域(zone)来建立客户端和服务端之间的关系,客户端尽量访问和自己的相同区域的zone服务。减少服务的延迟
  • 保留服务器的统计信息,ribbon可以实现用于避免高延迟或者频繁访问故障的服务器
  • 保留区域的统计数据,ribbon可以实现避免可能访问实现的zone

Ribbon是一个客户端负载均衡器,Feign已经使用Ribbon,所以可以直接使用@FeignClient

如果要使用Ribbon,需要在Maven或者Gradle中加入groupId=org.springframework.cloudartifactId=spring-cloud-starter-ribbon,即可完成依赖加入

自定义Ribbon客户端

可以用<client>.ribbon.*来配置Ribbon客户端。允许使用@RibbonClient声明其他配置

@Configuration
@RibbonClient(name = "foo", configuration = FooConfiguration.class)
public class RibbonConfiguration 

默认提供一下Bean:

IClientConfig ribbonClientConfig:DefaultClientConfigImpl
IRule ribbonRule:ZoneAvoidanceRule
IPing ribbonPing:NoOpPing
ServerList<Server> ribbonServerList:ConfigurationBasedServerList
ServerListFilter<Server> ribbonServerListFilter:ZonePreferenceServerListFilter
ILoadBalancer ribbonLoadBalancer:ZoneAwareLoadBalancer
ServerListUpdater ribbonServerListUpdater:PollingServerListUpdater
@Configuration
public class FooConfiguration 
    @Bean
    public IPing ribbonPing(IClientConfig config) 
        return new PingUrl();
    

这时就是用PingUrl代替NoOpPing

IPing

用于检测服务器是否已经存活,相当于心跳检测

  • NIWSDiscoveryPing不执行真正的PING,如果DiscoveryClient认为是在线,则程序认为本次心跳成功,服务活着
  • PingUrl组成一个HttpClient调用一个服务的URL,如果调用成功,则认为本次心跳成功,表示此服务活着
  • NoOpPing永远返回true,认为服务永远活着
  • DummyPing默认实现,默认返回true,即认为服务永远活着

ServerList

功能:存储服务列表。分为静态和动态,后台有个线程来定时刷新和过滤服务
有以下几种实现:

  • ConfigurationBasedServerList从配置文件中获取所有服务列表,如:sample-client.ribbon.listOfServers=www.xxx.com,www.xxx.com
  • DiscoveryEnabledNIWSServerList从Eureka获取服务列表。此值必须通过属性中VipAddress来标识
  • DomainExtractingServerList代理类,根据ServerList的值实现具体的逻辑

ServerListFilter

该接口允许过滤配置或者动态获取具有特性的服务器列表。ServerListFilter是DynamicServerListLoadBalancer用于过滤ServerList实现返回的服务器组件

  • ZoneAffinityServerListFilter : 过滤掉所有的不和客户端在相同zone的服务,如果和客户端相同的zone不存在,才不过滤服务,通过<clientName>.ribbon.EnableZoneAffinity=true
  • ZonePreferenceServerListFilter: 和ZoneAffinityServerListFilter相似,但是比较的zone是发布环境的zone
  • ServerListSubsetFilter: 此过滤器确保客户端仅能看到由ServerList实现返回的整个服务器的固定子集。可以定期用新服务器替代可用性差的子集中的服务器
<clientName>.ribbon.NIWSServerListClassName=com.netflix.niws.loadbalancer.DiscoveryEnabledNIWSServerList 
# the server must register itself with Eureka server with VipAddress "myservice"
<clientName>.ribbon.DeploymentContextBasedVipAddresses=myservice
<clientName>.ribbon.NIWSServerListFilterClassName=com.netflix.loadbalancer.ServerListSubsetFilter
# only show client 5 servers. default is 20.
<clientName>.ribbon.ServerListSubsetFilter.size=5

ServerListUpdater

DynamicServerListLoadBalancer用于动态的更新服务列表

具体的实现有:
PollingServerListUpdater
默认的实现策略。此对象会启动一个定时线程池,定时执行更新策略
EnrekaNotificationServerListUpdater
当收到缓存刷新的通知,会更新服务列表

IClientConfig

定义各种配置信息,用来初始化ribbon客户端和负载均衡器

常用的IClientConfig有以下几种实现:
DefaultClientConfigImpl

ILoadBalancer

定义软件负载平衡器操作的接口。动态更新一组服务列表及根据指定算法及从现有的服务器列表中选择一个服务
DynamicServerListLoadBalancer
ZoneAwareLoadBalancer

声明式REST客户端:Feign

Feign是一个声明式的Web服务客户端,封装了HTTP请求,默认使用HttpMessageConverters

使用groupId=org.springframework.cloudartifactId=spring-cloud-starter-feign的启动器,在启动主类中添加@EnableFeignClients注解

客户端主要代码

@FeignClient("stores")
public interface StoreClient 
    @RequestMapping(method = RequestMethod.GET, value = "/stores")
    List<Store> getStores();

    @RequestMapping(method = RequestMethod.POST, value = "/stores/storeId", consumes = "application/json")
    Store update(@PathVariable("storeId") Long storeId, Store store);

SpringCloud可以通过FeignClientsConfiguration来声明额外的配置,包括feignDecoderfeignEncoderfeignContract

serviceId属性已经弃用,有利于name属性。以前用url属性,不需要name属性。现在需要使用name

nameurl支持占位符

@FeignClient(name = "$feign.name", url = "$feign.url")
public interface StoreClient 
    //..

Spring Cloud Netflix默认为feign(BeanType beanName:ClassName)提供以下bean:

  • Decoder feignDecoder:ResponseEntityDecoder(其中包含SpringDecoder)
  • Encoder feignEncoder:SpringEncoder
  • Logger feignLogger:Slf4jLogger
  • Contract feignContract:SpringMvcContract
  • Feign.Builder feignBuilder:HystrixFeign.Builder
  • Client feignClient:如果Ribbon启用,则为LoadBalancerFeignClient,否则将使用默认的feign客户端。

可以通过将feign.okhttp.enabled或feign.httpclient.enabled设置为true,并将它们放在类路径上来使用OkHttpClient和ApacheHttpClient feign客户端。

Spring允许你放置在@FeignClient配置,允许覆盖每个Bean,如:

@Configuration
public class FooConfiguration 
    @Bean
    public Contract feignContract() 
        return new feign.Contract.Default();
    

    @Bean
    public BasicAuthRequestInterceptor basicAuthRequestInterceptor() 
        return new BasicAuthRequestInterceptor("user", "password");
    

这将SpringMvcContract替换为feign.Contract.Default,并将RequestInterceptor添加到RequestInterceptor的集合中。

可以在@EnableFeignClients属性defaultConfiguration中以与上述相似的方式指定默认配置。不同之处在于,此配置将适用于所有假客户端。

手动创建Feign客户端

在某些情况下,可能需要手动创建Feign客户端。下面是创建两个具有相同接口的Feign客户端的例子。

@Import(FeignClientsConfiguration.class)
class FooController 

	private FooClient fooClient;

	private FooClient adminClient;

    @Autowired
	public FooController(
			Decoder decoder, Encoder encoder, Client client) 
		this.fooClient = Feign.builder().client(client)
				.encoder(encoder)
				.decoder(decoder)
				.requestInterceptor(new BasicAuthRequestInterceptor("user", "user"))
				.target(FooClient.class, "http://PROD-SVC");
		this.adminClient = Feign.builder().client(client)
				.encoder(encoder)
				.decoder(decoder)
				.requestInterceptor(new BasicAuthRequestInterceptor("admin", "admin"))
				.target(FooClient.class, "http://PROD-SVC");
    

断路器Hystrix降级

断路器降级:当电路断开或者出现错误时执行的默认代码路径。要给@FeignClient降级,需要fallback设置降级类名

@FeignClient(name = "hello", fallback = HystrixClientFallback.class)
protected interface HystrixClient 
    @RequestMapping(method = RequestMethod.GET, value = "/hello")
    Hello iFailSometimes();


static class HystrixClientFallback implements HystrixClient 
    @Override
    public Hello iFailSometimes() 
        return new Hello("fallback");
    

当服务降级,有两个实现类的时候,需要标记@Primary,某些情况下,又需要关闭,需要设置@FeiignClientprimary=false

@FeignClient(name = "hello", primary = false)
public interface HelloClient 
	// methods here

Feign请求/响应压缩

可以给请求启动和响应GZIP压缩,通过配置如下:

feign.compression.request.enabled=true
feign.compression.response.enabled=true

# 压缩相关配置,配置压缩类型,最小请求阈值长度
feign.compression.request.enabled=true
feign.compression.request.mime-types=text/xml,application/xml,application/json
feign.compression.request.min-request-size=2048

Feign日志记录

logging.level.project.user.UserClient: DEBUG
  • NONE,无记录(Default)
  • BASIC,只记录请求方法和请求和响应头
  • HEADERS,记录基本的信息以及请求和响应头
  • FULL,记录请求和响应头,正文和元数据
@Configuration
public class FooConfiguration 
    @Bean
    Logger.Level feignLoggerLevel() 
        return Logger.Level.FULL;
    

Zuul路由

在整个微服务体系中,可以通过/api/users映射到用户服务,/api/shop映射到商店服务,可以通过zuul来实现
zuul实现以下操作:

  • 认证
  • 洞察
  • 压力测试
  • 金丝雀测试
  • 动态路由
  • 服务迁移
  • 负载脱落
  • 安全
  • 静态响应处理
  • 主动/主动流量管理

配置属性zuul.max.host.connections已被两个新属性zuul.host.maxTotalConnections和zuul.host.maxPerRouteConnections替换,分别默认为200和20。
所有路由的默认Hystrix隔离模式(ExecutionIsolationStrategy)为SEMAPHORE。如果此隔离模式是首选,则zuul.ribbonIsolationStrategy可以更改为THREAD。

  • 使用groupId=org.springframework.cloudartifactId=spring-cloud-starter-zuul加入zuul组件
  • 使用@EnableZuulProxy来启动zuul代理,可以不用给每个服务单独CORS处理和验证

默认情况下,将X-Forwarded-Host标头添加到转发的请求中。关闭set zuul.addProxyHeaders = false。默认情况下,前缀路径被删除,对后端的请求会拾取一个标题“X-Forwarded-Prefix”(上述示例中的“/ myusers”)

通过Zuul上传文件

如果您@EnableZuulProxy您可以使用代理路径上传文件,只要文件很小,它就应该工作。对于大文件,有一个替代路径绕过“/ zuul / *”中的Spring DispatcherServlet(以避免多部分处理)。也就是说,如果zuul.routes.customers=/customers/**则可以将大文件发送到“/ zuul / customers / *”。servlet路径通过zuul.servletPath进行外部化。如果代理路由引导您通过Ribbon负载均衡器,例如,超大文件也将需要提升超时设置

hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds: 60000
ribbon:
  ConnectTimeout: 3000
  ReadTimeout: 60000

ZuulServlet

Zuul实现了Servlet接口,Zuul嵌入到Spring调度机制。可以使用zuul.servlet-path来更改路径

ZuulRequestContext

如果想要过滤器之间传递信息,Zuul使用RequestContext。按照每个请求的ThreadLocal进行。关于路由请求,根据实际的HttpServletRequestHttpServletResponse的路由信息。RequestContext扩展ConcurrentHashMap,所有的东西都存储在上下文中。

@EnableZuulProxy@EnableZuulServer
@EnableZuulServer过滤器
创建从SpringBoot配置文件中加载路由定义的SimpleRouteLocator

前置过滤器

  • ServletDetectionFilter:检测请求是否通过Spring调度程序。使用键FilterConstants.IS_DISPATCHER_REQUEST_KEY设置布尔值。
  • FormBodyWrapperFilter:解析表单数据,对下游请求进行重新编码。
  • DebugFilter:如果设置了debug请求参数,则此过滤器将RequestContext.setDebugRouting()RequestContext.setDebugRequest()设置为true

路由过滤器

  • SendForwardFilter:此过滤器使用ServletRequestDispatcher转发请求。转发位置存储在RequestContext属性FilterConstants.FORWARD_TO_KEY。对于转发在端点很有用。

过滤器

  • SendResponseFilter:将代理请求的响应放入当前响应。

错误过滤器

  • SendErrorFilter:如果RequestContext.getThrowable()部位null,则转发到/错误(默认情况下)。如果设置为error.path属性来更改默认转发路径/error

@EnableZuulProxy过滤器
创建从DiscoveryClient以及属性加载路由定义的DiscoveryClientRouterLocator。每个serviceIdDiscoveryClient创建路由。

前置路由器

  • PreDecorationFilter:此过滤器根据提供的RouteLocator确定在哪和如何路由。为下游请求设置各种代理相关的头
    路由过滤器
  • RibbonRoutingFilter:此过滤器使用Ribbon,Hystrix等发送请求,有HttpClientOkHttpClient v3(类路径设置com.squareup.okhttp3:okhttp设置ribbon.okhttp.enabled=true)、Ribbon Http客户端(通过设置ribbon.restclient.enabled=true启动)
  • SimpleHostRoutingFilter:此过滤器通过HttpClient发送请求到预定的URL

以上是关于SpringCloud学习-SpringCloudNetfix的主要内容,如果未能解决你的问题,请参考以下文章

springcloud学习02-对springcloud的理解的记录

如何学习SpringCloud?(SpringCloud模板)

SpringCloud 学习笔记总结

SpringCloud学习—— SpringCloud Stream 消息驱动

🧊SpringCloud学习

SpringCloud学习笔记1:什么是SpringCloud