关闭
Hit
enter
to search or
ESC
to close
May I Suggest ?
#leanote #leanote blog #code #hello world
Okeeper's Blog
Home
Archives
Tags
DevOps
软件笔记
Spring
学习
JVM系列
关于我
Spring Cloud服务注册发现之Eureka
无
1654
0
0
zhangyue
#什么是服务注册发现??? 服务注册与发现就像是在一个聊天室,每个用户来的时候去服务器上注册,这样他的好友们就能看到你,你同时也将获取好友的上线列表. 在微服务中,服务就相当于聊天室的用户,而服务注册中心就像聊天室服务器一样,目前服务发现的解决方案Eureka,Consul,Etcd,Zookeeper,SmartStack等等,如下图简单对比: ![](https://leanote.com/api/file/getImage?fileId=58d9ffeeab644174dd001ba8) #Eureka Server ## 在Spring Boot项目的pom.xml中加入`spring-cloud-starter-eureka-server` 使用Spring Cloud需要在pom.xml中加入Spring Cloud的父级引用,让Spring帮我们管理依赖版本 ``` <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-eureka-server</artifactId> </dependency> </dependencies> ``` ## 在application.yml中配置 ``` server: host: localhost port: 8761 eureka: instance: hostname: discovery client: registerWithEureka: false #不用将自己注册到Eureka fetchRegistry: false #不用发现Eureka中的服务 serviceUrl: defaultZone: http://${server.host}:${server.port}/eureka/ ``` ## 添加Application.java启动类 添加`@EnableEurekaServer`注解 ``` @SpringBootApplication @EnableEurekaServer public class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); } } ``` > 如果想要搭建高可用的Eureka Server ,见文章:[Spring Cloud Eureka注册服务器高可用配置](http://leanote.com/blog/post/58d4f220ab64417b810025b3) # Eureka Client ##服务注册与服务发现都是使用Eureka Client,所以在Spring Boot项目的pom.xml中加入 ``` <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-eureka</artifactId> </dependency> ``` 在`application.properties`中加入eureka的server配置 ``` #指定Eureka Server的url地址 eureka: client: serviceUrl: defaultZone: http://localhost:8761/eureka/ ``` ## 注册服务,直接启动后默认就会将Controller的resful服务注册到Eureka ``` // @RestController是@controller和@resposeBody的结合体,就不用再方法体上加上@ResponseBody注解了,就是说它会把你的数据返回到你页面的body里面 @RestController public class Controller { @RequestMapping("/") public String hello() { return "hello world"; } @RequestMapping(value="/hello") String hello(String name) { return "hello," + name; } } ``` ## 发现并访问服务,可以有以下几种方式 - 使用原始的Eureka DiscoveryClient 来找到服务实例的主机并且用Spring的RestTemplate来发起调用。 ``` @Autowired DiscoveryClient discoveryClient; @RequestMapping("/testHello") public String testHello() { //打印所有服务 doDiscoveryService(); //查找服务 String serviceRootPath = findServiceRootPath("simple-service1"); RestTemplate restTemplate = new RestTemplate(); //GET String result = restTemplate.getForObject(serviceRootPath + "/hello?name={name}",String.class,"韩梅梅"); return "访问远程服务返回:" + result; } /** * 发现服务 * @param serviceId * @return */ public String findServiceRootPath(String serviceId) { List<ServiceInstance> list = discoveryClient.getInstances(serviceId); if (list != null && list.size() > 0 ) { URI uri = list.get(0).getUri(); if (uri !=null ) { return uri.toString(); } } return null; } /** * 打印出所有注册在Eureka的服务 * @return */ public void doDiscoveryService(){ StringBuilder buf = new StringBuilder(); List<String> serviceIds = discoveryClient.getServices(); if(!CollectionUtils.isEmpty(serviceIds)){ for(String s : serviceIds){ System.out.println("serviceId:" + s); List<ServiceInstance> serviceInstances = discoveryClient.getInstances(s); if(!CollectionUtils.isEmpty(serviceInstances)){ for(ServiceInstance si:serviceInstances){ System.out.println("["+si.getServiceId() +" host=" +si.getHost()+" port="+si.getPort()+" uri="+si.getUri()+"]"); } }else{ System.out.println("no service."); } } } } ``` - 使用Ribbon,一个使用`Eureka DiscoveryClient` 来找到服务实例的客户端结合Ribbon作负载均衡解决方案 - 使用Feigin,它使用了一个说明性的方法来调用服务。它内部使用了Ribbon做从Eureka中获取的服务列表的负载 1.在maven中加入 ``` <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-feign</artifactId> </dependency> ``` 2.在Application.java启动类中加入注解`@EnableEurekaClient` 和 `@EnableFeignClients` 3.通过FeignClient声明一个远程访问的接口 ``` @FeignClient("simple-service1") public interface HelloClient { @RequestMapping(value="/", method= RequestMethod.GET) String index(); @RequestMapping(value="/hello", method= RequestMethod.GET) String hello(@RequestParam("name") String name); } ``` 4.在使用服务注入声明的UserClient接口 ``` @Autowired private HelloClient helloClient; @RequestMapping(value="/sayHello", method= RequestMethod.GET) public String testHello(){ return helloClient.hello("eureka"); } ``` #Eureka特性 Eureka 架构机制 我们的 Eureka 集群服务其实就是靠 Server 与 Client 之间的交互来实现的。 1. 前面说过,Eureka Server 具有服务定位/发现的能力,在各个微服务启动时,会通过Eureka Client向Eureka Server进行注册自己的信息(例如网络信息)。 2. 一般情况下,微服务启动后,Eureka Client 会周期性向 Eureka Server 发送心跳检测(默认周期为30秒)以注册/更新自己的信息。 3. 如果 Eureka Server 在一定时间内(默认90秒)没有收到 Eureka Client 的心跳检测,就会注销掉该微服务点。 可以使用`` 4. 同时,Eureka Server 它本身也是 Eureka Client,多个 Eureka Server 通过复制注册表的方法来完成服务注册表的同步从而达到集群的效果 # 出现问题 > 该状态持续很久,访问该服务也返回错误,但在注册中心界面,该服务却一直存在,且为UP状态,并且在大约十分钟后,出现一行红色大字:EMERGENCY! EUREKA MAY BE INCORRECTLY CLAIMING INSTANCES ARE UP WHEN THEY'RE NOT. RENEWALS ARE LESSER THAN THRESHOLD AND HENCE THE INSTANCES ARE NOT BEING EXPIRED JUST TO BE SAFE. `原因:自我保护机制。Eureka Server在运行期间,会统计心跳成功率在15分钟之内是否低于85%,如果出现低于的情况(在单机调试的时候很容易满足,实际在生产环境上通常是由于网络不稳定导致),Eureka Server会将当前的实例注册信息保护起来,同时提示这个警告。至于为什么需要有这个自我保护机制,官方的解释是:service不是强一致的,所以会有部分情况下没发现新服务导致请求出错,对于Service发现服务而言,宁可返回某服务5分钟之前在哪几个服务器上可用的信息,也不能因为暂时的网络故障而找不到可用的服务器,而不返回任何结果` 在测试环境我们可以关掉Eureka的自我保护机制 Eureka Server的配置如下 ``` eureka: server: enableSelfPreservation: false ``` 为了保证服务的快速发现和注销,在Service 项目`application.yml`中配置 ``` eureka: instance: leaseRenewalIntervalInSeconds: 1 #心跳间隔时间1s leaseExpirationDurationInSeconds: 2 #连续2s未响应时将服务注销 ``` # 为什么选择Eureka - zk是满足CP牺牲A,这个不对,看[ZooKeeper和CAP理论及一致性原则](http://www.cnblogs.com/sunddenly/articles/4072987.html) ,其实zk只是满足最终一致性C,可用性A这个是保证的,并且保证一半的节点是最新的数据,分区性P这个得看节点多少及读写情况,节点多,则写耗时长,另外节点多了Leader选举非常耗时, 就会放大网络的问题,容易分区。 - Eureka处理网络问题导致分区。如果Eureka服务节点在短时间里丢失了大量的心跳连接(注:可能发生了网络故障),那么这个Eureka节点会进入”自我保护模式“,同时保留那些“心跳死亡“的服务注册信息不过期。此时,这个Eureka节点对于新的服务还能提供注册服务,对于”死亡“的仍然保留,以防还有客户端向其发起请求。当网络故障恢复后,这个Eureka节点会退出”自我保护模式“。所以Eureka的哲学是,**同时保留”好数据“与”坏数据“总比丢掉任何”好数据“要更好**,所以这种模式在实践中非常有效。 - Eureka就是为发现服务所设计的,它有独立的客户端程序库,同时提供心跳服务、服务健康监测、自动发布服务与自动刷新缓存的功能。但是,如果使用ZooKeeper你必须自己来实现这些功能。 #Demo https://github.com/okeeper/spring-cloud-eureka-demo.git # 资料参考 使用Eureka注意问题 http://blog.csdn.net/jdhanhua/article/details/55002191 源码分析 http://blog.csdn.net/qq_26562641/article/details/53332308
觉得不错,点个赞?
Please enable JavaScript to view the
comments powered by Disqus.
comments powered by
Disqus
文章目录