带你入门SpringCloud服务发现 | Eurka搭建和使用
前言
服务注册与发现是微服务中最为基础的环节,而 eureka 就是一个可以帮助你实现服务注册与发现的选择之一。如果你对 eureka 和服务发现了解甚少,那么该篇博客将会帮助到你。文中通过具体操作带你了解如下内容:
- 什么是服务注册与发现
- 什么是 eureka
- springcloud eureka 单台环境搭建
- springcloud eureka 高可用环境搭建
- springcloud eureka + resttemplate + ribbion 的使用
- springcloud feign + springcloud eureka 的使用
阅读本文需要你熟悉springboot项目的基本使用即可,还有一点需要注意的是在操作过程中尽量和我本地环境一致,因为环境不一致可能会带来一些问题。我本地环境如下:
springboot version: 2.1.0.release
springcloud version: greenwich.release
apache maven version: 3.6.0
java version: 1.8.0_144
idea:spring tools suite (sts)
服务注册与发现介绍
上面讲到服务发现是微服务中最为基础的环节,什么是服务发现呢 ?我们可以从单体架构说起,单体架构各个服务都在一起,是不需要被发现的。但是在微服务的架构中会出现很多的服务。服务与服务之间怎么获取调用地址url 呢 ?例如 一个商城网站有商品服务和订单服务。查询订单服务时需要从商品服务中获取商品的信息。
如果有1个订单服务和1 个商品服务,订单服务服务在配置文件中将商品服务的 url 配置在配置文件中即可。如果出现 2个商品服务,你可能会想到将2个商品服务url 配置到订单服务中。如果出现上千个服务呢?你可能发现这种方式不是一个好的方案。同时还有一个问题就是:商品服务宕机后。如何将宕机的服务从配置文件中剔除。
我们可以将商品服务的 url 地址信息都注册到统一的服务上,在调用时拉取所有商品服务的 url 信息。订单服务可以自定义负载均衡策略来选取一个 url 地址进行调用,如果注册中心发现某个商品服务已经宕机,可以将其从注册中心剔除。而今天的主角 eureka 就是通过这种机制来完成服务发现的。
接下来就正式开始今天的主角 eureka 的详细介绍!
eureka 是什么 ?
在介绍操作前,首先来了解一下 eureka 是什么?eureka 是 netflix 公司开源的一个基于 rest 服务的服务发现框架,主要用于aws云,用于定位服务,以实现中间层服务器的负载平衡和故障转移。springcloud 对 netflix 众多的开源框架都封装到其子项目spring-cloud-netflix 中,而 eureka 就是其中的一个。springcloud 可以通过 eureka 来完成微服务的服务注册与发现,当然你也可以使用其他的服务发现框架在 springcloud 中。
具体使用和介绍可以访问 eureka 的 github wiki 进行查看
https://github.com/netflix/eureka/wiki/
https://github.com/netflix/eureka/wiki/eureka-at-a-glance
闲话少说,开始我们的 eureka 环境搭建!
springcloud eureka 单台环境搭建
eureka server 端搭建
按下图所示打开springboot starter构建的窗口 file--new--spring starter project
勾选 eureka server
如果不勾选 eureka server 也可以在springboot项目中引入 spring-cloud-starter-netflix-eureka-server 依赖即可。代码如下:
<dependency> <groupid>org.springframework.cloud</groupid> <artifactid>spring-cloud-starter-netflix-eureka-server</artifactid> </dependency>
在 springboot application上声明 @enableeurekaserver
在 application.properties 添加配置信息
server.port=8761 spring.application.name=eurekaserver eureka.client.register-with-eureka=false eureka.client.fetch-registry=false eureka.client.service-url.defaultzone= http://localhost:8761/eureka/ eureka.server.enable-self-preservation=false
server.port: 配置服务端的端口号。
spring.application.name: 配置服务端应用名称.。
eureka.client.register-with-eureka: 是否将自己注册到服务端,eureka 服务端需要配置成false 默认是 true
eureka.client.fetch-registry:是否从其他eureka服务端获取注册信息,默认为true。如过是单台服务器可以设置为false。
eureka.server.enable-self-preservation:开启自我保护模式,默认为 true 表示为开启。开发中为了方便可以将其设置为false。
eureka.client.service-url.defaultzone:设置 eureka 服务端的地址,如果是单体服务就配置该 eureka 单台服务的 ip+端口号+/eureka。需要注意的是 /eureka 一定要加上。
自我保护模式介绍:
默认情况下,如果eureka server在一定时间内(默认90秒)没有接收到某个微服务实例的心跳,eureka server将会移除该实例。但是当网络分区故障发生时,微服务与eureka server之间无法正常通信,而微服务本身是正常运行的,此时不应该移除这个微服务,所以引入了自我保护机制。
自我保护机制的工作机制是如果在15分钟内超过85%的客户端节点都没有正常的心跳,那么eureka就认为客户端与注册中心出现了网络故障,eureka server自动进入自我保护机制,此时会出现以下几种情况:
1、eureka server不再从注册列表中移除因为长时间没收到心跳而应该过期的服务。 2、eureka server仍然能够接受新服务的注册和查询请求,但是不会被同步到其它节点上,保证当前节点依然可用。 3、当网络稳定时,当前eureka server新的注册信息会被同步到其它节点中。
自我保护介绍内容摘抄自 —— java技术栈的博客: spring cloud eureka 自我保护机制 https://segmentfault.com/a/1190000015349644
如果 eureka.client.register-with-eureka=true 或者不配置该信息会,eureka 服务端本身也注册到服务端如下图所示:
eureka client 端搭建
首先在 springboot starter 构建的窗口 勾选 eureka discovery client 和 spring web starter 如下图所示:
需要注意的是如果没有勾选 spring web starter 客户端注册是注册不到服务端的。
如果不勾选,也可以直接在springboot项目中引入下面2个依赖来完成。
<dependency> <groupid>org.springframework.boot</groupid> <artifactid>spring-boot-starter-web</artifactid> </dependency> <dependency> <groupid>org.springframework.cloud</groupid> <artifactid>spring-cloud-starter-netflix-eureka-client</artifactid> </dependency>
然后在 springboot application 上声明 @enablediscoveryclient 如下图所示:
最后在 application.properties 配置如下信息:
server.port=8760 spring.application.name=eurekaclient eureka.client.service-url.defaultzone= http://localhost:8762/eureka/
客户端的 eureka.client.service-url.defaultzone 配置和eureka server(eureka注册中心)配置一样。
访问 eureka server(eureka注册中心)端如下图所示中instances currently registered with eureka中查看注册的客户端。
如果你按照上述方式搭建并未成功,可以请参考我在github 项目 spring-cloud-get-started 仓库中模块名为: spring-cloud-eureka-single-service(eureka server)和 spring-cloud-eureka-single-service-client( eureka client)进行对比查看是否配置有误。
spring-cloud-get-started 项目地址:https://github.com/zhuoqianmingyue/spring-cloud-get-started
搭建高可用的 eureka 服务端
在生产环境中为保证 eureka 服务的高可用,我们需要搭建多台 eureka server(eureka注册中心)。eureka server(eureka注册中心)搭建集群还是比较简单的,只需要让各个服务端互相注册即可。官网搭建集群框架图如下:
我来举个例子,假如你有2台 eureka server 服务,名称分别为 eureka1、eureka2。
eureka1的配置: 需要将 eureka.client.service-url.defaultzone 配置成 eureka2 的服务地址。配置代码如下:
eureka.client.service-url.defaultzone=http://eureka2:8762/eureka/
eureka2 的配置 需要将 eureka.client.service-url.defaultzone 配置成 eureka1 的服务地址。配置代码如下:
eureka.client.service-url.defaultzone=http://eureka1:8761/eureka/
假如你有3台 eureka 服务名称分别为 eureka1、eureka2、eureka3。
eureka1的配置: 需要将 eureka.client.service-url.defaultzone 配置上 eureka2 和 eureka3的服务地址并用逗号分隔。
eureka.client.service-url.defaultzone=http://eureka2:8762/eureka/,http://eureka3:8763/eureka/
eureka2的配置: 需要将 eureka.client.service-url.defaultzone 配置上 eureka1 和 eureka3的服务地址并用逗号分隔。
eureka.client.service-url.defaultzone=http://eureka1:8761/eureka/,http://eureka3:8763/eureka/
eureka3的配置: 需要将 eureka.client.service-url.defaultzone 配置上 eureka1 和 eureka2的服务地址并用逗号分隔。
eureka.client.service-url.defaultzone=http://eureka1:8761/eureka/,http://eureka2:8762/eureka/
需要注意的是如果配置了 eureka.client.fetch-registry 需要将其改为 true,如果没有配置可以忽略。eureka.client.fetch-registry 表示可以从其他 eureka server 获取注册信息。
还有一点需要注意的是,eureka.client.serviceurl.defaultzone 配置不能使用 localhost。
如果你使用的是windows 系统,并且只有一台机器的情况下,需要在 hosts 中配置三个域名信息。
我本地代码服务端和客户端搭建具体配置:
客户端和服务端引入依赖和添加@enablexxx的注解比较简单,我这里就不在详细说明了。可以参考 springcloud eureka 单台环境搭建 中的介绍。
主要需要注意的是 application.properties 中的配置,以下是我本地服务端和客户端配置详细信息:
eureka服务1的配置
server.port=8761 spring.application.name=multiserviceeurekaserver1 eureka.client.register-with-eureka=false eureka.client.fetch-registry=true eureka.client.service-url.defaultzone=http://multiserviceeurekaserver2:8762/eureka/,http://multiserviceeurekaserver3:8763/eureka/ eureka.server.enable-self-preservation=falses
eureka服务2的配置
server.port=8762 spring.application.name=multiserviceeurekaserver2 eureka.client.register-with-eureka=false eureka.client.fetch-registry=true eureka.client.service-url.defaultzone=http://multiserviceeurekaserver1:8761/eureka/,http://multiserviceeurekaserver3:8763/eureka/ eureka.server.enable-self-preservation=false
eureka服务3的配置
server.port=8763 spring.application.name=multiserviceeurekaserver3 eureka.client.register-with-eureka=false eureka.client.fetch-registry=true eureka.client.service-url.defaultzone=http://multiserviceeurekaserver1:8761/eureka/,http://multiserviceeurekaserver2:8762/eureka/ eureka.server.enable-self-preservation=false
客户端的配置
server.port=8760 spring.application.name=multiserviceeurekaclient eureka.client.service-url.defaultzone=http://multiserviceeurekaserver1:8761/eureka/,http://multiserviceeurekaserver2:8762/eureka/,http://multiserviceeurekaserver3:8763/eureka/
eureka服务1 控制台界面信息:
eureka服务2 控制台界面信息:
eureka服务3 控制台界面信息:
如果你按照上述方式搭建并未成功,可以参考我在 github 项目 spring-cloud-get-started 仓库中模块名为:
spring-cloud-eureka-multi-service-server1(multiserviceeurekaserver1)
spring-cloud-eureka-multi-service-server2(multiserviceeurekaserver2)
spring-cloud-eureka-multi-service-server3(multiserviceeurekaserver3)
spring-cloud-eureka-multi-service-client(multiserviceeurekaclient)
进行对比查看是否配置有误。
spring-cloud-get-started 项目地址:https://github.com/zhuoqianmingyue/spring-cloud-get-started
springcloud eureka + resttemplate + ribbion 使用
上面我们介绍如何搭建单机版和高可用版的 eureka 环境,接下来我们来介绍如果通过 resttemplate + ribbion 从 eureka server 调用我们的 eureka 客户端服务的 api 接口。
调用的流程是:消费端从 eureka server 获取我们要调用具体服务生产者(eureka 客户端)的所有 url 地址信息,然后通过 ribbion 的负载策略选取一个服务地址。最后通过resttemplate 进行调用具体服务 api 接口。
我通过一台 eureka server( eureka注册中心服务)端 和 2个商品服务(eureka客户端),外加一个服务消费者订单服务(eureka客户端)。通过订单服务从 eureka 注册中心服务获取2个商品服务(eureka客户端)地址url并通过 ribbion 负载策略选取其中一个商品服务url 进行服务的调用。
** eureka server 注册中心服务的搭建:**
添加 spring-cloud-starter-netflix-eureka-server 依赖,然后再 springboot application 上声明 @enableeurekaserver,最后在 application.properties 中添加相关配置信息。
spring-cloud-starter-netflix-eureka-server 依赖配置如下:
<dependency> <groupid>org.springframework.cloud</groupid> <artifactid>spring-cloud-starter-netflix-eureka-server</artifactid> </dependency>
application.properties 具体配置信息如下:
server.port=8761 spring.application.name=eurekaserver eureka.client.register-with-eureka=false eureka.client.fetch-registry=false eureka.client.service-url.defaultzone=http://localhost:8761/eureka/ eureka.server.enable-self-preservation=false
** 2个 商品服务 (eureka 客户端)搭建:**
添加 spring-cloud-starter-netflix-eureka-client 依赖,然后再 springboot application 上声明 @enablediscoveryclient ,最后在 application.properties 中添加相关配置信息。
分别在商品服务1 和商品服务2 中定义一样的 restful 接口,并通过返回不同的商品名称以示区分。
spring-cloud-starter-netflix-eureka-client 依赖配置如下:
<dependency> <groupid>org.springframework.boot</groupid> <artifactid>spring-boot-starter-web</artifactid> </dependency> <dependency> <groupid>org.springframework.cloud</groupid> <artifactid>spring-cloud-starter-netflix-eureka-client</artifactid> </dependency>
商品服务1 配置信息:
server.port=8760 spring.application.name=productserver eureka.client.service-url.defaultzone=http://localhost:8761/eureka/
商品服务1 api 接口代码如下:
@restcontroller public class productcontroller { @getmapping("/product/{id}") public product productinfo(@pathvariable(name="id")long productid) { product product = new product(); product.setid(productid); product.setname("product 1:"+"苹果"); product.setprice(12d); return product; } }
商品服务 2 配置信息:
server.port=8770 spring.application.name=productserver eureka.client.service-url.defaultzone=http://localhost:8761/eureka/
商品服务 2 api 接口代码如下:
@restcontroller public class productcontroller { @getmapping("/product/{id}") public product productinfo(@pathvariable(name="id")long productid) { product product = new product(); product.setid(productid); product.setname("product 2:"+"苹果"); product.setprice(12d); return product; } }
商品类的代码如下
public class product { private long id; private string name; private double price; //省略 getter 和 setter }
订单服务(eureka客户端)搭建:
添加 spring-cloud-starter-netflix-eureka-client 依赖,然后再 springboot application 上声明 @enablediscoveryclient ,最后在 application.properties 中添加相关配置信息。
server.port=8762 spring.application.name=orderservice eureka.client.service-url.defaultzone=http://localhost:8761/eureka/
商品服务的调用需要使用到 resttemplate,所以需要配置 resttemplate 到spring的上下文中。具体代码如下:
@configuration public class resttemplateconfig { @bean public resttemplate buildresttemplate() { return new resttemplate(); } }
通过 loadbalancerclient 的 choose 方法来获取 serviceinstance,serviceinstance 就是2个 商品服务(productserver)其中一个服务信息,loadbalancerclient 是 springcloud 获取服务的抽象。具体实现是通过 spring-cloud-netflix-ribbon 项目中 ribbonloadbalancerclient 来实现的。通过 serviceinstance 获取商品服务(productserver)的服务地址 url。然后通过 resttemplate 调用 api 接口。具体代码如下:
@restcontroller public class productcontroller { @autowired private loadbalancerclient loadbalancerclient; @autowired private resttemplate resttemplate; @requestmapping("/product/{id}") public string productinfo(@pathvariable(name="id")long productid) { serviceinstance serviceinstance = loadbalancerclient.choose("productserver"); uri uri = serviceinstance.geturi(); string url = uri.tostring()+"/product/"+productid; responseentity<string> forentity = resttemplate.getforentity(url, string.class); string message = forentity.getbody(); return message; } }
我们也可以通过使用 @loadbalanced 注解来完成上述操作,使用@loadbalanced注解的方式相对上面使用 loadbalancerclient 代码简洁了不少。具体操作如下:
在 resttemplateconfig 构建方法上添加 @loadbalanced 注解。具体代码如下:
@configuration public class resttemplateconfig { @bean @loadbalanced public resttemplate buildresttemplate() { return new resttemplate(); } }
在productcontroller 中无需在注入 loadbalancerclient,直接使用 resttemplate 调用即可。具体代码如下:
@restcontroller public class productcontroller { @autowired private resttemplate resttemplate; @requestmapping("/product/{id}") public string productinfo(@pathvariable(name="id")long productid) { string url = "http://productserver/product/"+productid; responseentity<string> forentity = resttemplate.getforentity(url, string.class); string message = forentity.getbody(); return message; } }
测试:
整个测试过程需要启动 一台 注册中心服务、2台商品服务、1台订单服务,个人建议注册中心服务和商品服务通过java -jar的方式启动,而订单服务通过 idea 来启动。当然你可以可以都在idea 中进行启动所有的服务。
启动 eureka 注册中心服务:
进入 eureka 注册中心服务目录执行打包命令 mvn clean package -dmaven.test.skip=true。会生成一个可执行的 jar 包如下图所示:
然后进入 target目录 执行 java -jar jar包的名称,如下图所示:
如下图所示:eureka 注册服务启动成功!
启动商品服务:
进入商品服务项目的目录,打包并且通过 java -jar 启动商品服务1项目。具体操作如下图所示:
商品 2服务操作和上述一致,这里就不再进行演示
最后访问服务注册服务,查看商品1和商品2服务是否注册到注册中心服务中,如下图所示表示注册成功!
启动订单服务:
通过下图的方式启动订单服务:
访问 http://localhost:8762/product/1 从订单服务中获取商品服务的信息,如下图所示它会以轮询的方式调用商品服务1 和商品服务2。
如果你按照上述方式搭建并未成功,可以参考我在github 项目 spring-cloud-get-started 仓库中模块名为:
spring-cloud-eureka-ribbion-service ( eureka server 服务注册中心 eurekaserver )
spring-cloud-eureka-ribbion-product (商品服务1)
spring-cloud-eureka-ribbion-product2(商品服务2)
spring-cloud-eureka-ribbion-service-order-consume(订单服务)
spring-cloud-eureka-ribbion-service-order-consume-annotation(订单服务注解版)
进行对比查看是否配置有误。
spring-cloud-get-started 项目地址:https://github.com/zhuoqianmingyue/spring-cloud-get-started
springcloud feign + springcloud eureka 使用
调用 eureka 客户端服务还可以通过 springcloud feign 来进行操作。feign的底层还是使用ribbion。
接下来我们开始 springcloud feign 是用操作流程介绍,看到这里你有没有发springcloud 使用的套路。这个套路拢共分三步:
1.引入组件 starter依赖。
2.application 上添加@enablexxx注解。
3.appcation.properties上进行添加相关配置信息。
springcloud feign也绕不开这个套路,第一步及先在订单服务添加 feign starter。具体依赖代码如下:
html <dependency> <groupid>org.springframework.boot</groupid> <artifactid>spring-boot-starter-web</artifactid> </dependency> <dependency> <groupid>org.springframework.cloud</groupid> <artifactid>spring-cloud-starter-netflix-eureka-client</artifactid> </dependency> <dependency> <groupid>org.springframework.cloud</groupid> <artifactid>spring-cloud-starter-openfeign</artifactid> </dependency>
第二步是在 springboot application上声明 @enablefeignclients 如下图所示:
第三步是在application.properties中配置 eureka客户端的配置,具体配置信息如下:
html server.port=8762 spring.application.name=orderservice eureka.client.service-url.defaultzone=http://localhost:8761/eureka/
第四步是在 resttemplateconfig 构建方法上声明 @loadbalanced
@configuration public class resttemplateconfig { @bean @loadbalanced public resttemplate buildresttemplate() { return new resttemplate(); } }
第五步是创建调用接口,并在接口上声明 @feignclient(name="productserver") 其中name的值是调用服务的名称。在声明调用的方法 @requestmapping()中配置 url 和商品服务 api 接口一样即可。
@feignclient(name="productserver") public interface productclient { @getmapping("/product/{id}") public product productinfo(@pathvariable(name="id")long productid); }
第六步开始编写调用的测试类,在productcontroller 中引入 personclient 然后调用productclient 调用方法即可。
@restcontroller public class productcontroller { @autowired private productclient personclient; @requestmapping("/product/{id}") public product productinfo(@pathvariable(name="id")long productid) { product product = personclient.productinfo(productid); return product; } }
测试:
feign 使用 和 ribbion 使用是一样的服务注册中心和商品服务,启动方式请参考上面feign 使用操作介绍。
访问 http://localhost:8762/product/1 调用订单服务,和使用ribbion方式效果一致。具体访问结果如下:
springcloud feign + springcloud eureka 使用 和 springcloud eureka + resttemplate + ribbion 使用 共用 eureka 服务端和服务生产者的项目,如果搭建过程中遇到问题可以参考我在github 项目 spring-cloud-get-started 仓库中模块名为: spring-cloud-eureka-feign-service-order-consume 进行对比即可。
spring-cloud-get-started 项目地址:https://github.com/zhuoqianmingyue/spring-cloud-get-started
小结
springcloud eureka 搭建和使用只要你掌握了搭建三步法:1.引入组件 starter依赖、2.application 上添加@enablexxx注解、3.appcation.properties上进行添加相关配置信息。关于具体的配置可以结合 spring 官网文档进行查阅。
参考文献
https://spring.io/guides/gs/service-registration-and-discovery/
https://cloud.spring.io/spring-cloud-netflix/reference/html/
https://cloud.spring.io/spring-cloud-netflix/multi/multi_spring-cloud-ribbon.html
http://seymours.cn/articles/2018/09/19/1537338458105.html
上一篇: 专家解析针灸减肥不反弹
下一篇: 灸法治脂肪肝效果好