天天看点

springcloud——Eureka深入

服务治理机制

    我们来进一步了解一下Eureka 基础架构中各个元素的一些通信行为, 以此来理解基于Eureka 实现的服务治理体系是如何运作起来的。以下图为例, 其中有这样几个重要元素:

• "服务注册中心-1" 和“ 服务注册中心-2", 它们互相注册组成了高可用集群。

• "服务提供者” 启动了两个实例, 一个注册到“ 服务注册中心-1" 上, 另外一个注册到“ 服务注册中心-2" 上。

• 还有两个“ 服务消费者“, 它们也都分别只指向了一个注册中心。

一、服务提供者

1.服务注册

    “服务提供者” 在启动的时候会通过发送REST请求的方式将自己注册到Eureka Server上, 同时带上了自身服务的一些元数据信息。Eureka Server接收到这个REST请求之后,将元数据信息存储在一个双层结构Map中, 其中第一层的key是服务名, 第二层的key是具体服务的实例名。(我们可以回想一下之前在实现Ribbon负载均衡的例子中, Eureka信息面板中一个服务有多个实例的清况, 这些内容就是以这样的双层Map形式存储的。)

    在服务注册时, 需要确认一下eureka.cli ent.register-with-eureka=true参数是否正确, 该值默认为true。若设置为false将不会启动注册操作。

2.服务同步

    如架构图中所示, 这里的两个服务提供者分别注册到了两个不同的服务注册中心上,也就是说, 它们的信息分别被两个服务注册中心所维护。此时, 由于服务注册中心之间因互相注册为服务, 当服务提供者发送注册请求到一个服务注册中心时, 它会将该请求转发给集群中相连的其他注册中心, 从而实现注册中心之间的服务同步。通过服务同步,两个服务提供者的服务信息就可以通过这两台服务注册中心中的任意一台获取到。

3.服务续约

    在注册完服务之后,服务提供者会维护一个心跳用来持续告诉EurekaSe1-ver: "我还活着”, 以防止Eureka Server 的“ 剔除任务” 将该服务实例从服务列表中排除出去, 我们称该操作为服务续约(Renew)。

    关千服务续约有两个重要属性,我们可以关注并根据需要来进行调整:

    eureka.instance.lease-renewal-interval-in-seconds=30

    eureka.ins七ance.lease-expiration-duration-in-seconds=90

    eureka.instance.lease-renewal-interval-in-seconds 参数用于定义服务续约任务的调用间隔时间,默认为30秒。eureka.instance.lease-expiration-duration-in-seconds参数用于定义服务失效的时间,默认为90秒。

二、服务消费者

1.获取服务

    到这里, 在服务注册中心已经注册了一个服务, 并且该服务有两个实例。当我们启动服务消费者的时候, 它会发送一个REST请求给服务注册中心,来获取上面注册的服务清单。为了性能考虑, Eureka Server会维护一份只读的服务清单来返回给客户端,同时该缓存清单会每隔30秒更新一次。

    获取服务是服务消费者的基础,所以必须确保eureka.client.fetch-registry=true参数没有被修改成false, 该值默认为七rue。若希望修改缓存清单的更新时间,可以通过eureka.client.registry-fetch-interval-seconds=30参数进行修改,该参数默认值为30, 单位为秒。

2.服务调用

    服务消费者在获取服务清单后,通过服务名可以获得具体提供服务的实例名和该实例的元数据信息。因为有这些服务实例的详细信息, 所以客户端可以根据自己的需要决定具体调用哪个实例,在沁bbon中会默认采用轮询的方式进行调用,从而实现客户端的负载均衡。

    对于访问实例的选择,Eureka中有Region和Zone的概念, 一个Region中可以包含多个Zone, 每个服务客户端需要被注册到一个Zone中, 所以每个客户端对应一个Region和一个Zone。在进行服务调用的时候, 优先访问同处一个Zone 中的服务提供方, 若访问不到,就访问其他的Zone。

3.服务下线

    在系统运行过程中必然会面临关闭或重启服务的某个实例的情况, 在服务关闭期间,我们自然不希望客户端会继续调用关闭了的实例。所以在客户端程序中, 当服务实例进行正常的关闭操作时, 它会触发一个服务下线的REST请求给Eureka Server, 告诉服务注册中心:“我要下线了”。服务端在接收到请求之后, 将该服务状态置为下线(DOWN), 并把该下线事件传播出去。

三、服务注册中心

1.失效剔除

    有些时候, 我们的服务实例并不一定会正常下线, 可能由于内存溢出、网络故障等原因使得服务不能正常工作, 而服务注册中心并未收到“服务下线” 的请求。为了从服务列表中将这些无法提供服务的实例剔除, Eureka Server在启动的时候会创建一个定时任务,默认每隔一段时间(默认为60秒) 将当前清单中超时(默认为90秒)没有续约的服务剔除出去。

2.自我保护

    当我们在本地调试基于Eureka的程序时, 基本上都会碰到这样一个问题, 在服务注册中心的信息面板中出现类似下面的红色警告信息:

EMERGENCY! EUREKA MAY BE INCORRECTLY CLAIMING INSTANCES ARE UP WHEN THEY'RE NOT.RENEWALS ARE LESSER TH邸THRESHOLD AND HENCE THE INSTANCES ARE NOT BEING EXPI邸D JUST TO BE SAFE.

    实际上, 该警告就是触发了EurekaServer的自我保护机制。之前我们介绍过, 服务注册到EurekaServer之后,会维护一个心跳连接,告诉EurekaServer自己还活着。EurekaServer在运行期间,会统计心跳失败的比例在15分钟之内是否低于85%, 如果出现低于的情况(在单机调试的时候很容易满足, 实际在生产环境上通常是由于网络不稳定导致), Eureka Server会将当前的实例注册信息保护起来, 让这些实例不会过期, 尽可能保护这些注册信息。但是, 在这段保护期间内实例若出现问题, 那么客户端很容易拿到实际已经不存在的服务实例, 会出现调用失败的清况, 所以客户端必须要有容错机制, 比如可以使用请求重试、断路器等机制。

    由于本地调试很容易触发注册中心的保护机制, 这会使得注册中心维护的服务实例不那么准确。所以, 我们在本地进行开发的时候, 可以使用eureka.server.enableself-preserva巨=oafn les 参数来关闭保护机制, 以确保注册中心可以将不可用的实例正确剔除。

Eureka常用配置

1.Eureka服务监控

添加依赖

<code>&lt;dependency&gt;</code>

<code>    </code><code>&lt;groupId&gt;org.springframework.boot&lt;/groupId&gt; </code>

<code>    </code><code>&lt;artifactId&gt;spring-boot-starter-actuator&lt;/artifactId&gt;</code>

<code>&lt;/dependency&gt;</code>

注意:服务端已经存在该依赖,可以不用添加。

<code># info自定义</code>

<code>info.build.name=</code><code>@project</code><code>.name@</code>

<code>info.build.description=</code><code>@project</code><code>.description@</code>

<code>info.build.groupId=</code><code>@project</code><code>.groupId@</code>

<code>info.build.artifact=</code><code>@project</code><code>.artifactId@</code>

<code>info.build.version=</code><code>@project</code><code>.version@</code>

<code># 状态页面自定义访问链接</code>

<code>eureka.instance.status-page-url-path=/info</code>

注意:

1、 服务监控依赖于 spring-boot-starter-actuator 这个 jar 

2、 注意 management.context-path 的定义

3、 注意 server.servlet-path 的定义

4、 可以直接定义 eureka.instance.status-page-url=http://www.roncoo.com,这个优先级高

2.Eureka客户端的常用配置

<code># server</code>

<code>server.port=</code><code>8888</code>

<code># spring</code>

<code>spring.application.name=spring-cloud-consumer</code>

<code># eureka</code>

<code>eureka.client.serviceUrl.defaultZone=http:</code><code>//localhost:8761/eureka/</code>

<code>#自定义访问路径</code>

<code>#自定义实例ID</code>

<code>eureka.instance.instanceId=${spring.application.name}:${random.value}</code>

<code>#显示IP地址</code>

<code>eureka.instance.prefer-ip-address=</code><code>true</code>

<code>#设置拉取服务注册信息时间,默认60s</code>

<code>eureka.client.registry-fetch-interval-seconds=</code><code>30</code>

<code>#指定续约更新频率,默认是30s</code>

<code>eureka.instance.lease-renewal-interval-in-seconds=</code><code>15</code>

<code>#设置过期剔除时间,默认90s</code>

<code>eureka.instance.lease-expiration-duration-in-seconds=</code><code>45</code>

3.Eureka服务端的常用配置

<code># server (eureka 默认端口为:</code><code>8761</code><code>)</code>

<code>server.port=</code><code>8761</code>

<code>spring.application.name=spring-cloud-server</code>

<code># 是否注册到eureka</code>

<code>eureka.client.register-with-eureka=</code><code>false</code>

<code># 是否从eureka获取注册信息</code>

<code>eureka.client.fetch-registry=</code><code>false</code>

<code># eureka服务器的地址(注意:地址最后面的 /eureka/ 这个是固定值)</code>

<code>eureka.client.serviceUrl.defaultZone=http:</code><code>//localhost:${server.port}/eureka/</code>

<code># info自定义,读取pom文件中的内容</code>

<code># 指定环境</code>

<code>eureka.environment=dev</code>

<code>#指定数据中心</code>

<code>eureka.datacenter=roncoo</code>

<code># 关闭自我保护模式</code>

<code>eureka.server.enable-self-preservation=</code><code>false</code>

<code>#设置清理无效节点的时间间隔,默认</code><code>60000</code><code>,即是60s</code>

<code>eureka.server.eviction-interval-timer-in-ms=</code><code>5000</code>

Eureka服务认证

1.指定注册中心

<code>private</code> <code>Map&lt;String, String&gt; serviceUrl = </code><code>new</code> <code>HashMap&lt;&gt; ();</code>

<code>this</code><code>.serviceUrl.put(DEFAULT_ZONE, DEFAULT_URL);</code>

<code>public</code> <code>static</code><code>丘nal String DEFAULT_URL = </code><code>"http://localhost:8761"</code> <code>+ DEFAULT_PREFIX + </code><code>"/"</code><code>;</code>

<code>public</code> <code>static</code> <code>final</code> <code>String DEFAULT_ZONE = </code><code>"defaultZone"</code><code>;</code>

所以我们做了如下配置, 来将应用注册到对应的Eureka 服务端中。

当构建了高可用的服务注册中心集群时, 我们可以为参数的value 值配置多个注册中心的地址(通过逗号分隔)。比如下面的例子:

<code>eureka.client.serviceUrl.defaultZone=http:</code><code>//peerl:8761/eureka/, http://peer2:8762/eureka/</code>

另外, 为了服务注册中心的安全考虑, 很多时候我们都会为服务注册中心加入安全校验。这个时候,在配置serviceUrl 时, 需要在value 值的URL 中加入相应的安全校验信息, 比如http://&lt;username&gt;:&lt;password&gt;@localhost:1111/eureka。其中,&lt;username&gt;为安全校验信息的用户名, &lt;password&gt;为该用户的密码。

2.服务认证

1、服务端添加依赖

<code>    </code><code>&lt;artifactId&gt;spring-boot-starter-security&lt;/artifactId&gt;</code>

2、服务端添加配置

<code># 服务认证</code>

<code>security.basic.enabled=</code><code>true</code>

<code>security.user.name=qb</code>

<code>security.user.password=</code><code>123456</code>

3、修改服务端和客户端的配置

<code>eureka.client.serviceUrl.defaultZone=http:</code><code>//qb:123456@localhost:8761/eureka/</code>

建议:能在内网的,尽量在内网,这样既可以保障安全,也能降低复杂度。

Eureka高可用集群配置

说明:启动3个注册中心,我们将cloudtest1、cloudtest2、cloudtest3 各自都将serviceUrl 指向另外两个节点,即是 cloudtest1、cloudtest2、cloudtest3 是两两互相注册的。

步骤:

1、设置 hosts:C:\Windows\System32\drivers\etc\hosts;

<code># Cluster hosts</code>

<code>127.0</code><code>.</code><code>0.1</code> <code>cloudtest1</code>

<code>127.0</code><code>.</code><code>0.1</code> <code>cloudtest2</code>

<code>127.0</code><code>.</code><code>0.1</code> <code>cloudtest3</code>

2、修改配置

每个服务都需要相应的修改,服务-01 

<code>spring.application.name=spring-cloud-server-</code><code>01</code>

<code>eureka.instance.hostname=cloudtest1</code>

<code>eureka.client.serviceUrl.defaultZone=http:</code><code>//qb:123456@cloudtest2:8762/eureka/,http://qb:123456@cloudtest3:8763/eureka/</code>

同理:服务-02,服务-03 都做相对应的修改

3、配置修改

<code>#这里是为了测试,生产应该保持默认值:30s </code>

<code>eureka.instance.lease-renewal-interval-in-seconds=</code><code>5</code>

<code>#剔除失效服务的检测时间,默认值:</code><code>60000</code><code>,即 60s </code>

声明:"服务治理机制"这部分是截取《springcloud微服务实战(翟永超)》,我本人觉得他讲解的很到位,也很容易理解;至于常用配置、服务认证、高可用注册是经过实践总结的。

本文转自 叫我北北 51CTO博客,原文链接:http://blog.51cto.com/qinbin/2068036

继续阅读