Eureka
what? why? how?
一句话概括
Eureka是Netflix开发的服务发现框架(注册中心)
为什么需要注册中心?
由原因来解释注册中心的作用、含义
从根源说起,原来为什么把一个单体项目做成微服务项目。其中一个原因就是解耦,把原来单体项目的强耦合,拆分成一个一个不同的模块化服务,来降低耦合,最后底层通过Http的方式来进行服务间的调用。我们以这个基础来一步一步的推理:为什么一个微服务项目设计了注册中心的存在。
在一个微服务项目中,相当于由原来的单体项目按需按功能解耦拆分,肯定有许多服务:比如(A)用户服务,(B)订单服务,(C)物流服务等等..。并且这个服务一般会部署在不同的服务器上,比如A服务部署在了162.x.x.x,B服务部署在了168.x.x.x 。解耦不是一刀切断了,原来在单体项目中模块之间通过调用互相的Service来进行数据交流。那么在拆分成微服务之后必然也需要互相调用,这是业务决定的。
我们先假设不用注册中心,思考如何互相调用?
可以使用SpringCloud提供的RestTemplate或者HttpCLient来进行服务间的通信,比如A服务调B服务,就需要写上固定一个B服务的IP地址。这时就会产生一系列问题
那假如有多个B服务如何实现负载均衡调用呢,难道需要再HTTP请求处来遍历每个IP地址吗?
每加一个B服务就需要改动一次A服务的代码,重新部署?
A服务调用B时如何负载均衡呢?
B服务关闭(下线)了,服务开启(上线)了,A服务又如何只知道和解决的呢?
注册中心的出现就是为了解决这些问题的。
主流的注册中心有:Eureka、ZooKeeper、Consul 、Nacos。区别以后再说..
关于Eureka的详细介绍,下面这篇博客总结的非常好,我就直接引用过来了。
原文地址:SpringCloud之Eureka注册中心原理及其搭建
一、Eureka简介
Eureka是Netflix开发的服务发现框架,本身是一个基于REST的服务,主要用于定位运行在AWS域中的中间层服务,以达到负载均衡和中间层服务故障转移的目的。SpringCloud将它集成在其子项目spring-cloud-netflix中,以实现SpringCloud的服务发现功能。
1、Eureka组件
Eureka包含两个组件:Eureka Server和Eureka Client。
1.1 Eureka Server
Eureka Server提供服务注册服务,各个节点启动后,会在Eureka Server中进行注册,这样Eureka Server中的服务注册表中将会存储所有可用服务节点的信息,服务节点的信息可以在界面中直观的看到。
Eureka Server本身也是一个服务,默认情况下会自动注册到Eureka注册中心。
如果搭建单机版的Eureka Server注册中心,则需要配置取消Eureka Server的自动注册逻辑。毕竟当前服务注册到当前服务代表的注册中心中是一个说不通的逻辑。
Eureka Server通过Register、Get、Renew等接口提供服务的注册、发现和心跳检测等服务。
2.1 Eureka Client
Eureka Client是一个java客户端,用于简化与Eureka Server的交互,客户端同时也具备一个内置的、使用轮询(round-robin)负载算法的负载均衡器。在应用启动后,将会向Eureka Server发送心跳,默认周期为30秒,如果Eureka Server在多个心跳周期内没有接收到某个节点的心跳,Eureka Server将会从服务注册表中把这个**服务节点移除(默认90秒)**。
Eureka Client分为两个角色,分别是:Application Service(Service Provider)和Application Client(Service Consumer)
2.1.1 Application Service
服务提供方,是注册到Eureka Server中的服务。
2.1.2 Application Client
服务消费方,通过Eureka Server发现服务,并消费。
在这里,Application Service和Application Client不是绝对上的定义,因为Provider在提供服务的同时,也可以消费其他Provider提供的服务;Consumer在消费服务的同时,也可以提供对外服务。
2、Eureka Server架构原理简介
Register(服务注册):把自己的IP和端口注册给Eureka。
Renew(服务续约):发送心跳包,每30秒发送一次。告诉Eureka自己还活着。
Cancel(服务下线):当provider关闭时会向Eureka发送消息,把自己从服务列表中删除。防止consumer调用到不存在的服务。
Get Registry(获取服务注册列表):获取其他服务列表。
Replicate(集群中数据同步):eureka集群中的数据复制与同步。
Make Remote Call(远程调用):完成服务的远程调用。
Eureka Server
Eureka Server既是一个注册中心,同时也是一个服务。那么搭建Eureka Server的方式和以往搭建Dubbo注册中心ZooKeeper的方式必然不同,那么首先搭建一个单机版的Eureka Server注册中心。
二、搭建单机版Eureka Server
Eureka已经被Spring Cloud继承在其子项目spring-cloud-netflix中,搭建Eureka Server的方式还是非常简单的。只需要通过一个独立的maven工程即可搭建Eureka Server。pom依赖如下:
1 | <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |
全局配置文件:
而Eureka Server本身也是一个服务,同时又是一个注册中心。在Spring Cloud中,启动的微服务会自动的搜索注册中心并注册服务,那么在单机版Eureka Server环境中,当前服务注册到当前服务中,明显是不合适的。所以搭建Eureka Server单机版时,需要提供特殊的全局配置,避免回路注册逻辑。
同理,Eureka Server服务在注册中心中发现服务列表逻辑也是不必要的。毕竟注册中心是一个中立的服务管理平台,如果是单机版Eureka Server环境中,Eureka Server服务再去发现服务列表,明显也是不必要的。也需要通过全局配置,避免回路发现逻辑。
1 | # 设置spring应用命名,可以自定义,非必要 |
启动类配置:
启动Eureka Server注册中心,和普通的SpringBoot应用的启动没有太大的区别。只需要在启动类上增加@EnableEurekaServer注解,来开启Eureka Server服务即可。
注意:此处@SpringCloudApplication注解定义启动类。@SpringCloudApplication注解定义启动类涉及到hystrix相关内容。
1 |
|
访问Eureka Server WEB控制台:通过IP和端口,使用浏览器访问即可查看Eureka Server中的信息。本例中访问地址为:http://localhost:8761/
三、搭建集群版Eureka Server
注册中心作为微服务架构中的核心功能,其重要性不言而喻。所以单机版的Eureka Server在可靠性上并不符合现在的互联网开发环境。集群版的Eureka Server才是商业开发中的选择。
Eureka Server注册中心的集群和Dubbo的ZooKeeper注册中心集群在结构上有很大的不同。
ZooKeeper注册中心集群搭建后,集群中各节点呈现主从关系,集群中只有主节点对外提供服务的注册和发现功能,从节点相当于备份节点,只有主节点宕机时,从节点会选举出一个新的主节点,继续提供服务的注册和发现功能。
而Eureka Server注册中心集群中每个节点都是平等的,集群中的所有节点同时对外提供服务的发现和注册等功能。同时集群中每个Eureka Server节点又是一个微服务,也就是说,每个节点都可以在集群中的其他节点上注册当前服务。又因为每个节点都是注册中心,所以节点之间又可以相互注册当前节点中已注册的服务,并发现其他节点中已注册的服务。所以Eureka Server注册中心集群版在搭建过程中有很多的方式,找到一个最合适最可靠的搭建方式才能称为一个称职的程序员。
集群版Eureka Server可以通过Spring Boot多环境配置方式快速搭建。只要创建一个合适的Eureka Server工程,通过多个全局配置即可完成快速搭建。
本案例中搭建一个双节点的Eureka Server集群。
Linux版本为: CentOS 6.5
JDK版本为: 1.8
POM依赖
和单机版Eureka Server相同。
全局配置文件
本例中的两个节点分别会搭建在两个Linux系统中,为这两个Linux系统分别定义域名为eurekaserver1和eurekaserver2。
在集群搭建过程中,全局配置文件的定义非常重要。其中euraka.client.serviceUrl.defaultZone属性是用于配置集群中其他节点的。如果有多个节点,使用逗号’,’分隔。
有部分程序员只配置某一个集群节点信息,通过集群节点间的注册通讯实现节点的全面发现。这种配置形式是不推荐的。因为Eureka Server在服务管理上,会根据连带责任来维护服务列表,如果某集群节点宕机,那么通过这个节点注册过来的服务都会连带删除。
1 | #eurekaserver1配置 |
打包工程形成jar文件
使用run -> maven install即可实现打包过程。打包后的jar文件保存在工程中的target目录中,并上传打包后的jar文件到Linux系统。
设置Linux主机域名
修改/etc/hosts文件,设置主机域名。将主机域名和IP进行绑定。新增内容如下:两个Linux系统修改内容相同。
1 | 192.168.2.115 eurekaserver1 |
使用命令启动Eureka Server
可以在Linux终端中,通过java命令来启动Eureka Server。在启动的时候,可以通过启动参数来设置有效的配置环境。具体命令如下:
1 | java -jar -Dspring.profiles.active=eurekaserver1 spring-cloud-eureka-server-cluster-1.0.jar |
其中-Dspring.profiles.active启动参数,用于定义本次启动的Eureka Server应用的有效全局配置命名,也就是全局配置文件的后缀。SpringBOOT在启动的时候,会根据启动参数来决定读取的有效全局配置文件是哪一个。
也可以定义一个shell文件来简化操作。具体shell内容如下:
1 | !/bin/bash |
设置好shell启动脚本后,需要提供可执行权限:shell脚本文件名自己修改:chmod 755 xxx.sh
脚本使用方式为:
1 | #启动Eureka Server |
四、Eureka Server安全认证
Eureka Server作为Spring Cloud中的服务注册中心,如果可以任意访问的话,那么其安全性太低。所以Spring Cloud中也有为Eureka Server提供安全认证的方式。可以使用spring-boot-starter-security组件来为Eureka Server增加安全认证。
POM依赖:
1 | <!-- spring boot security安全认证启动器 --> |
修改全局配置文件,在全局配置文件中,开启基于http basic的安全认证。
1 | # eurekaserver1配置 |
五、CAP定理
CAP原则又称CAP定理,指的是在一个分布式系统中,Consistency(数据一致性)、 Availability(服务可用性)、Partition tolerance(分区容错性),三者不可兼得。CAP由Eric Brewer在2000年PODC会议上提出。该猜想在提出两年后被证明成立,成为我们熟知的CAP定理。
分布式系统CAP定理 | |
---|---|
数据一致性(Consistency) | 数据一致性(Consistency)也叫做数据原子性系统在执行某项操作后仍然处于一致的状态。在分布式系统中,更新操作执行成功后所有的用户都应该读到最新的值,这样的系统被认为是具有强一致性的。等同于所有节点访问同一份最新的数据副本。优点: 数据一致,没有数据错误可能。缺点: 相对效率降低。 |
服务可用性(Availablity) | 每一个操作总是能够在一定的时间内返回结果,这里需要注意的是”一定时间内”和”返回结果”。一定时间内指的是,在可以容忍的范围内返回结果,结果可以是成功或者是失败。 |
分区容错性(Partition-torlerance) | 在网络分区的情况下,被分隔的节点仍能正常对外提供服务(分布式集群,数据被分布存储在不同的服务器上,无论什么情况,服务器都能正常被访问) |
定律:任何分布式系统只可同时满足二点,没法三者兼顾。 | |
---|---|
CA,放弃P | 如果想避免分区容错性问题的发生,一种做法是将所有的数据(与事务相关的)/服务都放在一台机器上。虽然无法100%保证系统不会出错,但不会碰到由分区带来的负面效果。当然这个选择会严重的影响系统的扩展性。 |
CP,放弃A | 相对于放弃”分区容错性”来说,其反面就是放弃可用性。一旦遇到分区容错故障,那么受到影响的服务需要等待一定时间,因此在等待时间内系统无法对外提供服务。 |
AP,放弃C | 这里所说的放弃一致性,并不是完全放弃数据一致性,而是放弃数据的强一致性,而保留数据的最终一致性。以网络购物为例,对只剩下一件库存的商品,如果同时接受了两个订单,那么较晚的订单将被告知商品告罄。 |
Eureka和ZooKeeper的特性
六、Eureka Client
在Spring Cloud中,开发Eureka Client组件还是非常方便的。我们在开发过程中,不需要像Dubbo那样关注服务的角色。无论是Provider还是Consumer都是一个微服务客户端,只是在编码层面上,服务消费者代码比较麻烦。
1、Application Service服务提供者开发
POM依赖:
如果Eureka 开启了security安全校验机制,那么Eureka Client在开发的时候,依赖的jar包需要额外依赖一个actuator插件。那么可以修改Eureka Client工程中的启动器,把spring-cloud-starter-eureka改为spring-cloud-starter-eureka-server。Eureka-server启动器中包含HTTP Basic安全认证相关的jar包,实际上spring-cloud-starter-eureka-server启动器包含启动器spring-cloud-starter-eureka中的所有的包。
1 | <!-- spring cloud Eureka Client 启动器,因为Eureka Server开启了安全校验, |
全局配置:
在配置Eureka Server信息时,建议将Eureka Server集群中的所有节点依次配置,Eureka Client在注册服务的时候,会根据节点列表依次访问Eureka Server集群节点,只要注册成功,后续Eureka Server节点不再访问注册。虽然Eureka Server集群各节点可以相互发现服务,但是Eureka Server集群中每个节点对服务的管理都使用连带责任,及从某Eureka Server节点发现服务A,如果这个Eureka Server节点宕机,则A服务同时从服务列表中删除。
1 | # 定义SpringBoot应用的名称,建议必须提供。在SpringCloud中,对服务的最大粒度的管理是使用应用命名的 |
建议:如果有多个服务功能需要注册,那么在设置Eureka Server信息的时候,推荐异序排列。如:现在有3个工程A、B、C需要注册服务到Eureka Server集群中,集群节点有三个,分别是e1、e2、e3,那么在工程中推荐配置为,A工程配置-e1,e2,e3,B工程配置e2,e3,e1,C工程配置e3,e1,e2。这样可以更好的利用Eureka Server集群的特性。
启动类:
需要在启动类上新增注解@EnableEurekaClient,代表当前应用开启Eureka客户端,应用启动后,会自动将服务注册到Eureka Server中。
1 | /** |
对外接口:
Eureka Client的Application Server对外需要暴露接口方法,接口定义如Rest请求定义方式:
1 |
|
因此服务也可以作为url请求直接调用(Security Basic安全认证导致返回结果为XML类型,而不是JSON类型):
2、Application Client服务消费者开发
在Spring Cloud中,服务消费方代码的开发确实比较麻烦,并不像Dubbo那么直接注入服务接口代理对象,通过代理对象方法直接访问远程服务。在Spring Cloud中,微服务的提供是通过REST风格提供的,也就是服务的调用是基于HTTP协议的,所以在服务调用上比较麻烦,具体详见案例代码。
POM依赖:
同Application Service工程。
全局配置:
因为都是本地启动,需要修改服务端口。推荐修改spring应用命名。在Eureka Server中,对服务的管理是基于spring应用名称的,所以不同的服务推荐使用不同的应用名称。
1 | spring.application.name=eureka-application-client |
启动类:
同Applicaiton Service一致。
请求调用类:
1 | /** |
LoadBanlancerClient中包含了所有的服务注册信息,如下图示例:
七、服务保护
1 服务保护模式
服务保护模式(自我保护模式):一般情况下,微服务在Eureka上注册后,会每30秒发送心跳包,Eureka通过心跳来判断服务时候健康,同时会定期删除超过90秒没有发送心跳服务。
导致Eureka Server接收不到心跳包的可能:一是微服务自身的原因,二是微服务与Eureka之间的网络故障。通常微服务的自身的故障只会导致个别服务出现故障,一般不会出现大面积故障,而网络故障通常会导致Eureka Server在短时间内无法收到大批心跳。虑到这个区别,Eureka设置了一个阀值,当判断挂掉的服务的数量超过阀值时,Eureka Server认为很大程度上出现了网络故障,将不再删除心跳过期的服务。
那么这个阀值是多少呢?Eureka Server在运行期间,会统计心跳失败的比例在15分钟内是否低于85%,如果低于85%,Eureka Server则任务是网络故障,不会删除心跳过期服务。
这种服务保护算法叫做Eureka Server的服务保护模式。
这种不删除的,90秒没有心跳的服务,称为无效服务,但是还是保存在服务列表中。如果Consumer到注册中心发现服务,则Eureka Server会将所有好的数据(有效服务数据)和坏的数据(无效服务数据)都返回给Consumer。
2 服务保护模式的存在必要性
因为同时保留”好数据”与”坏数据”总比丢掉任何数据要更好,当网络故障恢复后,Eureka Server会退出”自我保护模式”。
Eureka还有客户端缓存功能(也就是微服务的缓存功能)。即便Eureka Server集群中所有节点都宕机失效,微服务的Provider和Consumer都能正常通信。
微服务的负载均衡策略会自动剔除死亡的微服务节点(Robbin)。
只要Consumer不关闭,缓存始终有效,直到一个应用下的所有Provider访问都无效的时候,才会访问Eureka Server重新获取服务列表。
3 关闭服务保护模式
可以通过全局配置文件来关闭服务保护模式,商业项目中不推荐关闭服务保护,因为网络不可靠很容易造成网络波动、延迟、断线的可能。如果关闭了服务保护,可能导致大量的服务反复注册、删除、再注册。导致效率降低。在商业项目中,服务的数量一般都是几十个,大型的商业项目中服务的数量可能上百、数百,甚至上千:
1 | # 关闭自我保护:true为开启自我保护,false为关闭自我保护 |
4 优雅关闭服务(优雅停服)
在Spring Cloud中,可以通过HTTP请求的方式,通知Eureka Client优雅停服,这个请求一旦发送到Eureka Client,那么Eureka Client会发送一个shutdown请求到Eureka Server,Eureka Server接收到这个shutdown请求后,会在服务列表中标记这个服务的状态为down,同时Eureka Client应用自动关闭。这个过程就是优雅停服。
如果使用了优雅停服,则不需要再关闭Eureka Server的服务保护模式。
POM依赖:
优雅停服是通过Eureka Client发起的,所以需要在Eureka Client中增加新的依赖,这个依赖是autuator组件,添加下述依赖即可。
1 | <dependency> |
修改全局配置文件:
Eureka Client默认不开启优雅停服功能,需要在全局配置文件中新增如下内容:
1 | # 启用shutdown,优雅停服功能 |
发起shutdown请求:
必须通过POST请求向Eureka Client发起一个shutdown请求。请求路径为:http://ip:port/shutdown。可以通过任意技术实现,如:HTTPClient、form表单,AJAX等。
建议使用优雅停服方式来关闭Application Service/Application Client服务。
Stay hungry,stay foolish !