# **注册中心** >Eureka是Netflix开发的服务发现框架,本身是一个基于REST的服务,主要用于定位运行在AWS域中的中间层服务,以达到负载均衡和中间层服务故障转移的目的。SpringCloud将它集成在其子项目spring-cloud-netflix中,以实现SpringCloud的服务发现功能。 Eureka包含两个组件:Eureka Server和Eureka Client。 Eureka Server提供服务注册服务,各个节点启动后,会在Eureka Server中进行注册,这样EurekaServer中的服务注册表中将会存储所有可用服务节点的信息,服务节点的信息可以在界面中直观的看到。 Eureka Client是一个java客户端,用于简化与Eureka Server的交互,客户端同时也就是一个内置的、使用轮询(round-robin)负载算法的负载均衡器。 在应用启动后,将会向Eureka Server发送心跳,默认周期为30秒,如果Eureka Server在多个心跳周期内没有接收到某个节点的心跳,Eureka Server将会从服务注册表中把这个服务节点移除(默认90秒)。 Eureka Server之间通过复制的方式完成数据的同步,Eureka还提供了客户端缓存机制,即使所有的Eureka Server都挂掉,客户端依然可以利用缓存中的信息消费其他服务的API。综上,Eureka通过心跳检查、客户端缓存等机制,确保了系统的高可用性、灵活性和可伸缩性。 # 服务治理:Spring Cloud Eureka ![](https://box.kancloud.cn/7de989eb386719347faf4750b3baeb58_1279x719.png) ![](https://box.kancloud.cn/15791e832df3566278bccc9b05c63026_898x499.png) ## 什么是服务治理 服务治理可以说是微服务架构中最为核心和基础的模块,它主要用来实现各个微服务实例的自动化注册与发现。 ## 为什么需要服务治理模块 在最初构建微服务系统的时候可能服务并不多,我们可以通过做一些静态配置来完成服务调用 ![](https://i.imgur.com/ASRyYWJ.png) 此时看着一切都还正常。 随着项目逐渐接近尾声,维护人员需要维护的服务越来越多,越来越复杂,最终形成大量的配置文件,维护将会变得越来越困难。此时,微服务应用实例自动化管理框架变得至关重要。 ## 服务治理框架需要完成什么任务 ● 服务注册:在服务治理框架中,通常都会构建一个注册中心,每个服务单元向注册中心登记自己提供的服务,将主机与端口号、版本号、通信协议等一些附加信息告知注册中心,注册中心按服务名分类组织服务清单。 ![](https://i.imgur.com/lFXx64x.png) ● 服务发现:我们的所有服务都已经注册到注册中心,并且在注册中心是按照服务名分类,并且由注册中心维护者服务的具体位置。所以调用方需要调用某个服务时,需要先和注册中心咨询,注册中心会返回被调用方服务的所有具体位置,调用方在根据某种轮询策略选择一个具体位置进行服务调用。 ![](https://i.imgur.com/tvnjhZD.png) ## Netflix Eureka   Spring Cloud Eureka,使用Netflix Eureka来实现服务注册与发现,它既包含了服务端组件,也包含了客户端组件。 ## Eureka服务端   Eureka服务端,我们也称为服务注册中心,他同其他服务注册中心一样,支持高可用配置。它依托于强一致性提供良好的服务实例可用性,可以应对多种不同的故障场景。   如果Eureka以集群方式部署,当集群中有分片出现故障时,那么Eureka就转入自我保护模式。它允许在分片故障期间继续提供服务的发现和注册,当故障分片恢复运行时,集群中的其他分片会把它们的状态再次同步回来。 ## Eureka客户端   Eureka客户端,主要处理服务的注册与发现。客户端服务通过注解和参数配置的方式,嵌入在客户端应用程序的代码中,在应用程序运行时,Eureka客户端向注册中心注册自身提供的服务并周期性地发送心跳来更新它的服务租约。同时,他也能从服务端查询当前注册的服务信息并把它们缓存到本地并周期性地刷新服务状态。 ## 服务端与客户端的关系 ![](https://i.imgur.com/oPDCh7u.png) # 注册中心代码详解 ## 配置文件 ``` eureka:   server:     shouldUseReadOnlyResponseCache: true #eureka是CAP理论种基于AP策略,为了保证强一致性关闭此切换CP 默认不关闭 false关闭     enable-self-preservation: false    #关闭服务器自我保护,客户端心跳检测15分钟内错误达到80%服务会保护,导致别人还认为是好用的服务     eviction-interval-timer-in-ms: 60000 #清理间隔(单位毫秒,默认是60\*1000)5秒将客户端剔除的服务在服务注册列表中剔除#     response-cache-update-interval-ms: 3000  ##eureka server刷新readCacheMap的时间,注意,client读取的是readCacheMap,这个时间决定了多久会把readWriteCacheMap的缓存更新到readCacheMap上 #eureka server刷新readCacheMap的时间,注意,client读取的是readCacheMap,这个时间决定了多久会把readWriteCacheMap的缓存更新到readCacheMap上默认30s     response-cache-auto-expiration-in-seconds: 180   ##eureka server缓存readWriteCacheMap失效时间,这个只有在这个时间过去后缓存才会失效,失效前不会更新,过期后从registry重新读取注册服务信息,registry是一个ConcurrentHashMap。   client:     register-with-eureka: true  #false:不作为一个客户端注册到注册中心     fetch-registry: false      #为true时,可以启动,但报异常:Cannot execute request on any known server     instance-info-replication-interval-seconds: 10     service-url:       defaultZone: [http://127.0.0.1:1111/eureka](http://127.0.0.1:1111/eureka)   instance:     prefer-ip-address: true     instance-id: ${spring.application.name}:${spring.cloud.client.ip-address}:${spring.application.instance\_id:${server.port}}     lease-renewal-interval-in-seconds: 30    ## 续约更新时间间隔(默认30秒)     lease-expiration-duration-in-seconds: 90 # 续约到期时间(默认90秒)  ribbon:   ServerListRefreshInterval: 1000    ```    org.springframework.boot    spring-boot-starter-actuator    左侧2.0.x版本 右侧1.5.9版本差异 ![](https://box.kancloud.cn/8c3ea07388bed5d137748773f1bcd1d9_1174x256.png) ![](https://box.kancloud.cn/9dffaf5f95441920d3154c00466083a3_1201x272.png) ## 核心代码@EnableEurekaServer注解 ``` /** * @author 作者 owen E-mail: 624191343@qq.com * @version 创建时间:2017年11月28日 下午22:50:29 * 类说明 * eureka高可用三台机器 */ @EnableEurekaServer @SpringBootApplication //@EnableHystrixDashboard //@EnableTurbine public class EurekaServerApp { public static void main(String[] args) { // 1本地启动采用此方法加载profiles文件 // ConfigurableApplicationContext context = new SpringApplicationBuilder(EurekaServerApp.class). // profiles("slave0").run(args); SpringApplication.run(EurekaServerApp.class, args); // 2服务器采用此方法 java -jar --spring.profiles.active=slave3; // SpringApplication.run(EurekaServerApp.class, args); } } ``` # OCP服务治理 ![](https://box.kancloud.cn/930781f0f54f3bbe3f883c971d35925d_1893x753.png) ## eureka重要源码 com.netflix.eureka.resources.ServerInfoResource com.netflix.eureka.resources.ApplicationsResource com.netflix.eureka.resources.InstancesResource com.netflix.eureka.resources.InstanceResource com.netflix.eureka.resources.StatusResource ## 服务治理api 获取服务列表 ![](https://box.kancloud.cn/3c0b7707b304caec02d27488b76239b6_1074x534.png) ## 获取某个服务的实例列表 ![](https://box.kancloud.cn/4c2234f164c15bb4a2a68022ba76b87c_1072x599.png) ## 服务下线 ![](https://box.kancloud.cn/7dd8ffaf176877565a05046fbf811793_1098x620.png) ![](https://box.kancloud.cn/968ed25f9123efed077cc0ca3683a887_1090x415.png) ## 服务上线 ![](https://box.kancloud.cn/9250a8601de41b115b4bf654eb8b6195_1081x742.png) ## 服务发现负载均衡 ![](https://img.kancloud.cn/23/32/2332cdcba7764921d2d1e446b875c2c5_1292x605.png) ## 指定负载均衡算法 ![](https://img.kancloud.cn/77/48/774801cb894f28399fb9e32450df799e_1464x224.png) ## 负载均衡器通过Eureka获取动态后端服务列表 Netflix源码解析之Ribbon:负载均衡器通过Eureka获取动态后端服务列表 - 为程序员服务 Ribbon是一种客户端的负载均衡,本质上是跑在服务消费者的进程里。服务消费者要访问服务时,通过ribbon向一个服务注册的列表查询,然后以配置的负载均衡策略选择一个后端服务发起请求。 前面 [ribbon的实现](http://juke.outofmemory.cn/entry/253610) ,讲到LB的定义的两个主要方法,分别是后端服务相关的调用: ~~~ public void addServers(List<Server> newServers); public List<Server> getServerList(boolean availableOnly); ~~~ 在netflix中这个服务注册列表其实就是eureka服务端集中管理的注册服务列表。获取这个列表应该就是是通过eureka的client来完成的。 ![](https://img.kancloud.cn/ac/a0/aca0314692453a8eba6d6543c361c8a7_695x295.png) Netflix源码解析之Ribbon:负载均衡器通过Eureka获取动态后端服务列表 - 为程序员服务 也就是ribbon中应该在某个地方集成了eureka client来维护服务列表。这里尝试追踪细这个过程,确认下猜想。 [ribbon的实现](http://juke.outofmemory.cn/entry/253610) 的继承图上可以看到除了介绍的基本实现LoadBalancer外,还有DynamicServerListLoadBalancer的实现,可以动态的加载后端服务列表。正如名所示,可以动态的加载后端的服务列表。 DynamicServerListLoadBalancer中使用一个ServerListRefreshExecutorThread任务线程定期的更新后端服务列表。 ~~~ class ServerListRefreshExecutorThread implements Runnable { public void run() { updateListOfServers(); } } public void updateListOfServers() { servers = serverListImpl.getUpdatedListOfServers(); updateAllServerList(servers); } ~~~ 其实是通过com.netflix.loadbalancer.ServerList.getUpdatedListOfServers() 方法加载后端服务列表。ServerList这个接口正是用来获取加载后端服务列表。 ![](https://img.kancloud.cn/55/22/55224b75c4cdea35b64921b4a3a5f847_701x170.png) Netflix源码解析之Ribbon:负载均衡器通过Eureka获取动态后端服务列表 - 为程序员服务 看到ConfigurationBasedServerList是从配置中(可以是通过Archaius这样的集中配置)加载的。 而DiscoveryEnabledNIWSServerList这个实现中包含DiscoveryEnabled猜想应该就是服务发现框架里的服务吧。看进去果然是通过eureka client 从eureka server获取服务列表进而在ribbon中可以动态的加载。 从声明 ~~~ public class DiscoveryEnabledNIWSServerList extends AbstractServerList<DiscoveryEnabledServer>{ ~~~ 能看到管理的服务不是一般的服务,是DiscoveryEnabledServer的服务。观察List com.netflix.niws.loadbalancer.DiscoveryEnabledNIWSServerList.obtainServersViaDiscovery() 的实现可以了解整个过程。 ~~~ private List<DiscoveryEnabledServer> obtainServersViaDiscovery() { List<DiscoveryEnabledServer> serverList = new ArrayList<DiscoveryEnabledServer>(); DiscoveryClient discoveryClient = DiscoveryManager.getInstance().getDiscoveryClient(); if (vipAddresses!=null){ for (String vipAddress : vipAddresses.split(“,”)) { // if targetRegion is null, it will be interpreted as the same region of client List<InstanceInfo> listOfinstanceInfo = discoveryClient.getInstancesByVipAddress(vipAddress, isSecure, targetRegion); for (InstanceInfo ii : listOfinstanceInfo) { if (ii.getStatus().equals(InstanceStatus.UP)) { DiscoveryEnabledServer des = new DiscoveryEnabledServer(ii, isSecure, shouldUseIpAddr); des.setZone(DiscoveryClient.getZone(ii)); serverList.add(des); } } return serverList; } ~~~ 可以看到就是通过一个com.netflix.discovery.EurekaClient作为一个句柄来获取eureka中注册的服务列表。获取活的服务,并根据instanceInfo 构造成ribbon需要的DiscoveryEnabledServer并加到服务列表中。 ## 常见问题 ![](https://box.kancloud.cn/f128077bbcf974d08fd2069931079195_877x452.png) # 项目pom依赖关系 ![](https://box.kancloud.cn/ed7f173d31522be4dab8ebda1ab69fad_1755x561.png) # 左侧2.0.x版本cp项目,右侧ocp1.5.9版本 ![](https://box.kancloud.cn/7445f9b1d69aa634ef6c8e8512ee4867_1124x513.png)