SpringCloud系列(2)---Netfilx-Eureka

来源:互联网 发布:普通发票软件下载 编辑:程序博客网 时间:2024/05/29 16:37

上一篇笔记写到的两个问题,Netfilx-Eureka和Ribbo会给我们一一解决。如果有看过dubbo 应该知道zookeeper,Eureka的角色就是zookeeper。

Eureka和Zookeeper主要都是作为微服务的注册和发现。

Eureka和Zookeeper不一样的是,Zookeeper是作为一个单独的应用程序,而Eureka是直接嵌套在SpringCloud当中的。所以 Eureka Server本身就是一个SpringBoot的项目。


一、服务注册和发现概念


上面的图是我网上找的。由于微服务的地址变革可能会影响很大,所以就引入了服务注册中心的角色。所有服务提供者必须将IP地址或者主机名注册到服务器注册中心当中,我们使用注册中心就是Eurika Server。服务的消费者在调用服务器之前,先要到服务注册中心查询服务提供者的网络地址信息,然后进行调用,这个原理非常相似于我们的DNS。获得服务提供者的网络地址的操作,我们称为服务发现。服务注册中心一般提供一下功能组件:

1、服务注册表:记录各个微服务的信息,例如名称、网络地址、端口号等。服务器注册表提供查询和管理的API,用于管理和查询可用的微服务实例。

2、服务注册和发现:刚刚已经说过了,微服务在启动时,将自己的信息注册到服务器注册中心当中。在消费者可以通过服务注册中心发现服务实例。

3、服务检查:检查微服务的健康情况,如果微服务实例在一段时间没有心跳信息,就会从服务实例注册表中移除该实例。


二、Eureka

Eureka是Netfilx开源的服务发现组件,本身是基于REST的服务。包含Server和Client两个部分。SpingCloud 将其集成到SpringCloud Netflix子项目中。

Eureka有两个概念分别 Region和Availability Zone。他们都是Amazon AWS的概率。其中,Region表示AWS中的地理位置,每个Region都有多个Availability Zone,各个Region之间完全隔离。

Spring Cloud 默认使用的Region是us-east-1,在非AWS环境下,可以将Availability Zone理解成机房,将Region理解为夸机房的Eureka集群。


三、Eureka Server 和 Client

Eureka Server 提供服务器的发现的能力,各个微服务启动时,都会在Eureka Server中注册自己的信息,Eureka Server 会将这些信息存储到注册表当中。

Eureka Client 这个就是一个JAVA客户端,用于简化于Eureka Server的交互。当然如果你的微服务是跨平台的,各个服务存在不同的开发语言,那就只能通过REST的方式去与Eureka Server进行交互了。REST不是我们的重点,因为我们作为一个JAVA狗,Eureka Client足够简化我们的操作。

以下是笔者的从参考书中摘录的重点概念:

1、微服务启动后,会周期性向Eureka Server 发送心跳信息默认是30秒。如果Eureka在一定的时间内(默认90秒)无法获得实例的心跳信息,Eureka Server 将会注册该实例。

2、默认情况下,Eureka Server 同时也是Eureka Client。多个Eureka Server实例,互相之间通过复制的方式,来实现服务注册表的同步。

3、Eureka Client 会缓存服务注册表中的信息。这样有非常多的好处,微服务无需每次都请求查询Eureka Server,从而降低Eureka Server的服务压力和网络压力;即使所有Eureka Server都挂了,Eureka Client还是可以根据自己的缓存注册表自给自足。


四、动手编写Eureka Server

笔者此事已经开了第三个IDE了,我的MacBook的内存开始吃不消了。建议这些还是在内存比较大的计算机上进行测试,而且同时去编译和加载会导致非常耗时间。唉··· 一会还要再加多一个Eureka Server 做高可用,呵呵!搞事情!

在Maven上我们的依赖配置如下:

<dependency>   <groupId>org.springframework.cloud</groupId>   <artifactId>spring-cloud-starter-eureka-server</artifactId></dependency>
然后在配置类当中打上@EnableEurekaServer 

@SpringBootApplication@EnableEurekaServerpublic class EurekaserveraApplication {   public static void main(String[] args) {      SpringApplication.run(EurekaserveraApplication.class, args);   }}
最后配置一下我们的application.properties

server.port=8761eureka.client.register-with-eureka=falseeureka.client.fetch-registry=falseeureka.client.service-url.defaultZone=http://lcoalhost:8761/eureka/

端口就不说了看看其他配置是什么回事:

1、register-with-eureka 这个配置是否将自己的注册到Eureka Server当中,默认true。由于当前应用就是Eureka Server 所以为false

2、fetch-registry 表示是否从Eureka Server 中获得注册信息,默认为true。目前是单点Eureka Server 所以不需要和其他Eureka Server 节点做同步,所以为false

3、service-url.default-zone 设置与Eureka Server交互的地址,查询服务和注册服务都依赖这个地址。如果多个地址即多个Eureka Server节点需要用“,”分隔。默认是http://localhost:8761/eureka

配置完成,跑起!

需要注意的是,笔者之前是使用最新的SpringCloud版本1.5.4.RELEASE 但是实际当我打开页面的过程当中发现无法打开上面的UI界面,只是有一个XML。笔者在查找了很多网上的资料后,也无法解决。但是在stackoverflow中我找到了一个帖子,说将其降级到1.5.2.RELEASE就正常出现页面了。至于1.5.4为什么不可以显示,可能后续我会有所补充。但是1.5.4其他的功能还是正常可以使用的。

<parent>   <groupId>org.springframework.boot</groupId>   <artifactId>spring-boot-starter-parent</artifactId>   <version>1.5.4.RELEASE</version>   <relativePath/> <!-- lookup parent from repository --></parent>
改成:

<parent>   <groupId>org.springframework.boot</groupId>   <artifactId>spring-boot-starter-parent</artifactId>   <version>1.5.2.RELEASE</version>   <relativePath/> <!-- lookup parent from repository --></parent>

五、Eureka Server 高可用

Eureka Server作为一个服务注册中心当然是不允许出现单点异常的,所以Eureka Server 做高可用是一个必须的操作。上面已经介绍过Eureka Server高可用的理论了,现在就操作一下。环境上笔者就不搞两台设备来做了,笔者会在hosts文件当中添加两条记录,表示当前的两台计算机的主机名:

127.0.0.1       eurekaservera eurekaserverb


然后在同一个项目当中配置两个profile,然后通过不同的profile分别代表eureka-servera、eureka-serverb的配置,然后分别启动。不清楚profile的可以看看我之前的SpringBoot的笔记SpringBoot系列(5)---SpringBoot-Web和SpringBoot基础 搜索profile即可。


application-servera.properties文件配置如下:

server.port=8761eureka.instance.hostname=eurekaserveraeureka.client.service-url.defaultZone=http://eurekaserverb:8762/eureka/
端口号8761 实例名称的主机名称为 eurekaservera。 register-with-eureka 和 fetch-registry 默认为true 所以直接不用配置  default-zone设置为其他的eureka server 这里设置是eureka-serverb 由于是同一台计算机 所以我用了不同的端口号。


application-serverb.properties文件配置如下:

server.port=8762eureka.instance.hostname=eurekaserverbeureka.client.service-url.defaultZone=http://eurekaservera:8761/eureka/

就算端口号成8762 然后实例主机名称改成 eureka-serverb 然后设置default-zone为刚刚设置的eureka-servera


然后application.properties 修改profile.active 分别启动

spring.application.name=tony-mall-discovery-eureka-haspring.profiles.active=servera

可以见到UI界面上出现如下的信息:



高可用已经配置生效了!


六、Eureka Cilent 

说了这么久Eureka Server 连高可用都配置了,总得要用起来吧···  Eureka Client 真的非常简单。你机会除了简单的配置,你就感觉不到它的存在了。

我们分别在 用户服务系统 和 商品服务系统 添加相应的Eureka Client 配置 主要为了将自身信息随SpringBoot项目开启 注册到 Eureka Server当中。

用户服务系统的application.properties 文件如下:

server.port=8801server.context-path=/userspring.datasource.url=jdbc:mysql://localhost:3306/shop_mall?charset=utf8mb4spring.datasource.driver-class-name=com.mysql.jdbc.Driverspring.datasource.username=rootspring.datasource.password=tonyyanspring.application.name=tony-mall-provider-usereureka.client.service-url.defaultZone=http://eurekaservera:8761/eureka/,http://eurekaserverb:8762/eureka/eureka.instance.prefer-ip-address=true
service-url.defaultZone 我们将两个Eureka Server 都注册了。当然你可以注册一个,然后通过指定的Eureka Server 自动获得其他Eureka Server,同样也可以实现高可用。但是最好也是配上,如果正好你指定的那台Eureka Server 挂了,就呵呵了。

prefer-ip-address 为true 这里是代表注册自身的ip地址 而不是主机名称。


商品服务系统的application.properties 文件如下,跟用户差不多:

server.port=8802server.context-path=/productspring.datasource.url=jdbc:mysql://localhost:3306/shop_mall?charset=utf8mb4spring.datasource.driver-class-name=com.mysql.jdbc.Driverspring.datasource.username=rootspring.datasource.password=tonyyanspring.application.name=tony-mall-provider-producteureka.client.service-url.defaultZone=http://eurekaservera:8761/eureka/,http://eurekaserverb:8762/eureka/eureka.instance.prefer-ip-address=true

最后在两个项目的配置类当中分别打上@EnableDiscoveryClient的 annotation

@SpringBootApplication@EnableDiscoveryClientpublic class ProductsystemApplication {
@SpringBootApplication@EnableDiscoveryClientpublic class UsersystemApplication {


将两个微服务启动,并查看Eureka Server 上的实例信息:


如果你配置了HA,你会发现两台注册中心都会出现同样的实例列表。OK!现在都配置好了,可以调用测试~

@GetMapping("/getProduct/{productId}/userId/{userId}")public Map<String, Object> getProduct(@PathVariable int productId, @PathVariable int userId) {    Map<String, Object> map = new HashMap<>();    String url = "http://tony-mall-provider-user/user/getUserById/" + userId;    User user = this.restTemplate.getForEntity(url, User.class).getBody();    Product product = this.productRepository.getByProductId(productId);    map.put("user",user);    map.put("product",product);    return map;}
可以发现调用其实都一样,只不过URL 从IP地址改成了实例名称了。其实这里就是一个虚拟主机名称。最后测试通过~ 我这里就不贴出返回的JSON了。


六、Eureka Cilent 元数据和实例信息

Eureka Client 还可以获得其他实例的信息:

@GetMapping("/showProvider")public List<ServiceInstance> showInfo(){    return this.discoveryClient.getInstances("tony-mall-provider-user");}

返回如下的JSON:

[
  {
    "host": "192.168.28.100",
    "port": 8801,
    "uri": "http://192.168.28.100:8801",
    "serviceId": "TONY-MALL-PROVIDER-USER",
    "metadata": {},
    "secure": false,
    "instanceInfo": {
      "instanceId": "192.168.28.100:tony-mall-provider-user:8801",
      "app": "TONY-MALL-PROVIDER-USER",
      "appGroupName": null,
      "ipAddr": "192.168.28.100",
      "sid": "na",
      "homePageUrl": "http://192.168.28.100:8801/",
      "statusPageUrl": "http://192.168.28.100:8801/info",
      "healthCheckUrl": "http://192.168.28.100:8801/health",
      "secureHealthCheckUrl": null,
      "vipAddress": "tony-mall-provider-user",
      "secureVipAddress": "tony-mall-provider-user",
      "countryId": 1,
      "dataCenterInfo": {
        "@class": "com.netflix.appinfo.InstanceInfo$DefaultDataCenterInfo",
        "name": "MyOwn"
      },
      "hostName": "192.168.28.100",
      "status": "UP",
      "leaseInfo": {
        "renewalIntervalInSecs": 30,
        "durationInSecs": 90,
        "registrationTimestamp": 1500002506247,
        "lastRenewalTimestamp": 1500002506247,
        "evictionTimestamp": 0,
        "serviceUpTimestamp": 1500002506248
      },
      "isCoordinatingDiscoveryServer": false,
      "metadata": {},
      "lastUpdatedTimestamp": 1500002506248,
      "lastDirtyTimestamp": 1500002506142,
      "actionType": "ADDED",
      "asgName": null,
      "overriddenStatus": "UNKNOWN"
    }
  }
]

除了一些服务信息之外,还看到了这个属性metadata 这个是元数据,又服务提供者提供。以下我们尝试在用户服务系统的application.properties中添加元数据:

eureka.instance.metadata-map.developer=TONYeureka.instance.metadata-map.provider_city=GZ
重新调用我们写的showProvider接口,发现metadata已经添加相应的元数据信息:

     。。。省略。。。
      "isCoordinatingDiscoveryServer": false,
      "metadata": {
        "provider_city": "GZ",
        "developer": "TONY"
      },
      "lastUpdatedTimestamp": 1500003756538,
      。。。省略。。。


七、Eureka Server 的自我保护模式

以下摘录于《SpringCloud和Docker微服务架构实战》

默认情况下,如果Eureka Sever在一定时间内没有接收到某个微服务实例的心跳信息,Eureka Server 会直接注销该实例。但是当网络分区发生故障时,微服务与Eureka Server之间无法通信,直接注销微服务实例就会非常危险。服务本身而言是健康的,不应该直接注销微服务。

Eureka Server 通过 自我保护模式 来解决这个问题。当Eureka Server 节点在短时间内丢失多个客户端时,那么这个节点就会进入自我保护模式。一旦进入该模式,Eureka Server 就会保护服务注册表的信息,不会再删除注册表信息(不会注销实例信息)。当网络故障恢复后,该Eureka Server 节点会自动退出自我保护模式。

自我保护模式是一种应对网络异常的安全保护措施。


在Spring Cloud中,可以使用以下启用或禁用安全保护措施

eureka.server.enable-self-preservation=false

默认为true



八、多网卡环境选择IP

对于多个网卡的服务器,指定IP的需求非常常见。例如某台服务器有多张网卡,但是只有eth1可以被其他服务器访问;如果Eureka Client将其他网卡的IP注册到Eureka Server上,其他服务消费者将无法方位服务提供实例的服务。

各个微服务注册到Eureka Server 上的IP可以有以下操作进行指定:

忽略指定网卡:

eureka.instance.prefer-ip-address=truespring.cloud.inetutils.ignored-interfaces=docker0

使用正则表达式指定使用的网络地址:

spring.cloud.inetutils.preferred-networks=192.168

我还是最喜欢这个方式,直接指定IP地址,简单粗暴:

eureka.instance.ip-address=127.0.0.1

只使用站点的本地地址

spring.cloud.inetutils.use-only-site-local-interfaces=true



九、服务健康检查

SpringBoot Actuator 提供了很多监控REST端点。方位这些断点就可以获得相应的服务运行状况。

以下是SpringBoot Actuator 提供的端点 摘录于SpringBoot官方文档

IDDescriptionSensitive Default

actuator

Provides a hypermedia-based “discovery page” for the other endpoints. Requires Spring HATEOAS to be on the classpath.

true

auditevents

Exposes audit events information for the current application.

true

autoconfig

Displays an auto-configuration report showing all auto-configuration candidates and the reason why they ‘were’ or ‘were not’ applied. 

(显示自动配置信息)

true

beans

Displays a complete list of all the Spring beans in your application. (显示所有Bean信息)

true

configprops

Displays a collated list of all @ConfigurationProperties. (显示所有@ConfigurationProperties的配置属性列表)

true

dump

Performs a thread dump. (显示线程活动快照)

true

env

Exposes properties from Spring’s ConfigurableEnvironment. (显示应用的环境变量)

true

flyway

Shows any Flyway database migrations that have been applied.

true

health

Shows application health information (when the application is secure, a simple ‘status’ when accessed over an unauthenticated connection or full message details when authenticated).(显示应用程序的健康指标,这些值由HealthIndicator的实现类提供)

false

info

Displays arbitrary application info.(显示应用程序的新,可以用info.*属性自定义info端点公开的数据)

false

loggers

Shows and modifies the configuration of loggers in the application. (显示和修改Logger配置)

true

liquibase

Shows any Liquibase database migrations that have been applied.

true

metrics

Shows ‘metrics’ information for the current application.(显示应用程序的度量标准信息)

true

mappings

Displays a collated list of all @RequestMapping paths.(显示所有URL路径)

true

shutdown

Allows the application to be gracefully shutdown (not enabled by default). (关闭应用 默认不启用,如果启用需要配置endpoints.shutdown.enabled=true)

true

trace

Displays trace information (by default the last 100 HTTP requests).(显示跟踪信息,默认情况下为最近100个HTTP请求)

true


之后的笔记也会有相关Actuator的介绍,先整合到SpringCloud当中:

<dependency>   <groupId>org.springframework.boot</groupId>   <artifactId>spring-boot-starter-actuator</artifactId></dependency>
然后就没有然后了,非常简单~ 添加个依赖就将actuator整合到Spring当中。当我们启用了Eureka之后 health接口会出现如下信息:

http://localhost:8802/product/health

{
  "description": "Remote status from Eureka server",
  "status": "DOWN"
}

注销所有Eureka配置之后重新访问http://localhost:8802/product/health获得如下JSON

{"status":"UP"}


info接口会出现如下信息:

http://localhost:8802/product/info

{}

info默认没有返回任何数据,需要我们配置info属性来定义info公开的端点数据。

info.app.name=@project.artifactId@info.app.encoding=@project.build.sourceEncoding@info.app.java=@java.version@

再次调用接口:http://localhost:8802/product/info

{
  "app": {
    "name": "productsystem",
    "java": "1.8.0_121",
    "encoding": "UTF-8"
  }
}


事实上Eureka 已经集成了对实例的健康检查


Status 还有其他取值:DOWN、OUT_OF_SERVICE 、UNKNOWN、UP

当Eureka Server 和 Eureka Client 之间使用心跳机制来确定Eureka Client 的状态。默认情况下,如果Server 和Client 的心跳保持正常,应用程序就会始终保持UP状态。

如果微服务器的数据源发现了问题,根本无法工作。我们希望Eureka Server 可以获得 Client 的SpringBoot Actuator 提供的health端点,可以在Client客户端当中的application.properties配置如下参数:

eureka.client.healthcheck.enable=true

原创粉丝点击