[Spring Cloud] 4.1 Spring Cloud Netflix : Netflix 实现

原创
2016/11/17 21:42
阅读数 506

Spring Cloud Netflix : Netflix 实现

Netflix是一家在线影片租赁提供商。

Netflix 开源软件

NetflixOSS

Spring Cloud Netflix 通过自动配置以及绑定Spring环境中的其他模块的方式将Netflix OSS与Spring Boot 应用进行整合。

通过简单的注解就可以快速在应用中开启一个标准配置的大型分布式及高可用的Netflix组件。

标准配置 包括:服务发现(Eureka);断路器(Hystrix);智能路由(Zuul);客户端负载均衡(Ribbon

4.1 Service Discovery: Eureka Clients 服务发现:Eureka客户端

服务发现是微服务架构中重要的一个概念。一般来说,在每个客户端进行配置或者某种形式的约定来进行服务调用是很麻烦的,而且需要频繁修改。 Eureka 是Netflix服务发现服务以及客户端的实现。服务能够以一种高可用的方式进行配置和部署,对于每个注册的服务彼此间都会进行状态复制。

4.1.1 Registering with Eureka 通过Eureka进行服务注册

当一个注册器客户端通过Eureka进行注册时,它会带上一些描述自己情况的元数据,如:地址、端口、健康指示器地址、主页等等。Eureka会接收每一个服务实例发送的心跳包。如果心跳包超过配置的间隔时间,那这个服务实例就会被移除。

Eureka客户端代码示例:

@Configuration
@ComponentScan
@EnableAutoConfiguration
@EnableEurekaClient
@RestController
public class Application {

    @RequestMapping("/")
    public String home() {
        return "Hello world";
    }

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

}

可见,这就是一个普通的Spring Boot 应用。例子中使用了@EnableEurekaClient,当Eureka可用时,也可以使用@EnableDiscoveryClient。此外还需要在本地配置一个Eureka服务。例如:

application.yml

eureka:
  client:
    serviceUrl:
      defaultZone: http://localhost:8761/eureka/

这里的defaultZone,表示任何处理任何没有匹配上的url请求。(默认请求处理地址)

默认应用名(服务ID)、虚拟地址和端口,会从Environment中获取:${spring.application.name}${spring.application.name}${server.port}

@EnableEurekaClient会让应用既做为一个Eurake实例,同时也作为一个Eurake的客户端(能够通过这个客户端,查询到注册的本地其他服务)。Eurake实例可以通过eureka.instance.*相关配置项进行配置。默认情况下使用spring.application.name作为注册服务的service ID 和 虚拟IP

具体配置相可以参见 EurekaInstanceConfigBeanEurekaClientConfigBean

4.1.2 Authenticating with the Eureka Server :Eureka服务的身份认证

如果eureka.client.serviceUrl.defaultZone的URL中嵌入了账号信息则Eurake客户端会自动使用HTTP basic 认证。(如:http://user:password@localhost:8761/eureka

如果需要更为复杂的认证方式,可以自己实现一个DiscoveryClientOptionalArgs然后注入一个ClientFilter实例,这样客户端与服务端的调用都会经过这个Filter。

注意: 由于Eurake的限制,不可能为每一个服务配置单独的认证,因此第一个被发现的认证方式会被使用。

4.1.3 Status Page and Health Indicator 状态页和健康指示器

一个Eurake实例的状态页和健康指示器默认为:/info/health,这两个是由Spring Boot Actuator应用提供的访问端点。可以通过以下方式进行修改:

application.yml

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

这些地址将会被用于客户端元数据的获取,以及必要的检测时使用。因此,这些端点是很有用的。

4.1.4 Registering a Secure Application 注册一个安全的应用

如果你想让应用之间通过HTTPS通讯,那可以在EurekaInstanceConfig中配置两个开关: eureka.instance.[nonSecurePortEnabled,securePortEnabled]=[false,true]。 这样Eureka就会通过安全方式发布实例信息。 这样的话,Spring Cloud 的DiscoveryClient将会为已注册的服务返回一个https://…URI, 同时Eureka实例信息将会提供一个安全的健康检查URL。

由于Eureka的内部机制,使得还会为状态和主页提供一个非安全的URL,当然,这也是可以通过额外的配置关闭掉。

application.yml

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

注意: ${eureka.hostname} 是一个Eureka的原生占位符,以后的版本才可用。所以,可以使用spring的占位符来替代,如:${eureka.instance.hostName}

注意: 如果你运行在代理的网络情况,那SSL可能被代理清理掉。而且,代理可能导致你获得的来源端口、地址不正确

4.1.5 Eureka’s Health Checks : Eureka的健康检查

默认情况下,Eureka通过客户端心跳包来检测客户端状态。没有额外配置的情况下Discovery客户端不会为每一个Spring Boot 应用发起额外的健康检查。这样,也就意味着,一旦服务注册成功后,Eureka总会认为应用是在线状态。 当然,也可以开启Eureka的健康检查,这样应用状态就可以转播给Eureka了。

application.yml

eureka:
  client:
    healthcheck:
      enabled: true

警告:eureka.client.healthcheck.enabled=true只能在application.yml中设置,如果在bootstrap.yml中设置,会导致Eureka在注册时得到一个UNKNOWN的状态

如果需要更多的健康检查控制,可以自己实现一个com.netflix.appinfo.HealthCheckHandler.

4.1.6 Eureka Metadata for Instances and Clients : Eureka实例和客户端的元数据

花些时间去了解Eureka的元数据是值得的,你可以在这个过程中对自己平台有更清楚的认识。标准的元数据例如:主机名,IP地址,端口号,状态页,健康检查。这些会在服务注册以及客户端直连服务端时被发布出来。对于实例注册时,可以通过eureka.instance.metadataMap配置额外的元数据信息,这样不会对客户端有啥影响,除非客户端能自己处理某些特殊元数据。后面还会继续说明元数据在Spring Cloud 中的意义。

4.1.6.1 Using Eureka on Cloudfoundry : 在Cloudfoundry中使用Eureka

Cloudfoundry提供了针对所有实例中相同主机名相同应用的全局路由功能。类似一个小型PaaS平台。这个不是Eureka必要的功能,但还是建议开启此功能。开启时,需要明确指定主机名和端口号。可以通过设置实例的元数据来让客户端区分不同的实例,默认通过eureka.instance.instanceIdvcap.application.instance_id来区分。例如:

application.yml

eureka:
  instance:
    hostname: ${vcap.application.uris[0]}
    nonSecurePort: 80

通过这种方式来设置Cloudfoundry实例的安全规则,你可以注册并使用虚拟主机的IP地址进行服务之间的调用。这个特性还不能在PWS(Pivotal Web Services)环境下使用。

4.1.6.2 Using Eureka on AWS : 在AWS中使用Eureka

如果需要在AWS中部署Eureka,可以定制一个EurekaInstanceConfigBean

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

4.1.6.3 Changing the Eureka Instance ID : 修改Eureka实例ID

普通的Netflix Eureka实例注册时使用主机名作为实例ID。Spring Cloud Eureka提供了一个更为合理的ID策略:${spring.cloud.client.hostname}:${spring.application.name}:${spring.application.instance_id:${server.port}}} 例如:myhost:myappname:8080

使用Spring Cloud时,可以覆盖这个值,通过eureka.instance.instanceId这个配置。例如:

application.yml

eureka:
  instance:
    instanceId: ${spring.application.name}:${vcap.application.instance_id:${spring.application.instance_id:${random.value}}}

如果多个服务实例部署在同一个主机上,那这个元数据会加上一个随机数,保证实例唯一性。 在一个Spring Boot 应用中,Cloudfoundry的vcap.application.instance_id会被自动赋值,不需要随机数。

4.1.7 Using the EurekaClient

一旦在应用中使用了@EnableDiscoveryClient 或者@EnableEurekaClient,那你就可以从Eureka Server中使用服务发现功能。 还有一种方法就是直接使用原生的com.netflix.discovery.EurekaClient(对应Spring Cloud的DiscoveryClient)。例如:

@Autowired
private EurekaClient discoveryClient;

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

提示:不要在@PostConstruct方法以及@Scheduled中(或者任何ApplicationContext还没初始完成的地方)使用EurekaClient。其需要等待SmartLifecyclephase=0)初始化完成才可以

4.1.8 Alternatives to the native Netflix EurekaClient : 如何决定是否使用原生Netflix Eureka客户端

通常来说,不需要直接使用原始的Netflix 的EurekaClient ,因为,提供了很多更方便使用的包装器。 Spring Cloud支持Feign(一个REST客户端)以及Spring自己的RestTemplate来使用Eureka服务的逻辑标识符,而不是通过物理URL。 可以为物理服务简单的配置一个固定列表集合:<client>.ribbon.listOfServers用逗号分割物理地址或者主机名,<client>指的是客户端ID。

你也可以使用org.springframework.cloud.client.discovery.DiscoveryClient,这个客户端提供了一套简单的API来操作客户端,不需要专门去使用Netflix。例如:

@Autowired
private DiscoveryClient discoveryClient;

public String serviceUrl() {
    List<ServiceInstance> list = discoveryClient.getInstances("STORES");
    if (list != null && list.size() > 0 ) {
        return list.get(0).getUri();
    }
    return null;
}

4.1.9 Why is it so Slow to Register a Service? 注册一个服务为啥慢如狗

作为一个实例涉及到一个心跳机制去注册(通过serviceUrl),默认持续30秒。直到实例自身,服务端,客户端各自元数据本地缓存同步完成后,服务才可用(至少需要3次心跳周期)。 可以通过eureka.instance.leaseRenewalIntervalInSeconds修改这个周期,改善客户端链接到服务的速度。不过,考虑到短期的波动以及服务续期等情况,在生产环境最好还是用默认设定。

展开阅读全文
打赏
0
2 收藏
分享
加载中
更多评论
打赏
0 评论
2 收藏
0
分享
返回顶部
顶部