SpringCloud浅尝(三)——Eureka



Eureka 是 Netflix 出品的用于实现服务注册和发现的工具。 Spring Cloud 使用 Eureka 作为服务注册与发现的组件,并提供了开箱即用的支持。 Eureka 分为 Eureka Server 和 Eureka Client。
下面我们看一张图,下图来源于官方架构图
SpringCloud浅尝(三)——Eureka
文章图片

1.EureKa Server 提供服务注册,各个节点启动后,在EureKa server中进行注册;
2 EureKa Client 是一个Java客户端,用于和服务端进行交互,同时客户端也是一个内置的默认使用轮询负载均衡算法的负载均衡器。在应用启动后,会向Eueka Server发送心跳(默认30秒)。如果EUR额卡 Server在多个心跳周期内没有接受到某个节点的心跳,EureKa Server将会从服务注册表中将这个服务移出(默认90秒)。
在默认配置中,Eureka Server在默认90s没有得到客户端的心跳,则注销该实例,但是往往因为微服务跨进程调用,网络通信往往会面临着各种问题,比如微服务状态正常,但是因为网络分区故障时,Eureka Server注销服务实例则会让大部分微服务不可用,这很危险,因为服务明明没有问题。
为了解决这个问题,Eureka 有自我保护机制,通过在Eureka Server配置如下参数,可启动保护机制

eureka.server.enable-self-preservation=true

它的原理是,当Eureka Server节点在短时间内丢失过多的客户端时,那么这个节点将进入自我保护模式,不再注销任何微服务,当网络故障回复后,该节点会自动退出自我保护模式。
下面我们简单对比一下Zookeeper,这也是经常面试会被问到的
著名的CAP理论指出,一个分布式系统不可能同时满足C(一致性)、A(可用性)和P(分区容错性)。由于分区容错性在是分布式系统中必须要保证的,因此我们只能在A和C之间进行权衡。在此Zookeeper保证的是CP, 而Eureka则是AP。
Zookeeper
当master节点因为网络故障与其他节点失去联系时,剩余节点会重新进行leader选举。问题在于,选举期间整个Zookeeper集群都是不可用的,这就导致在选举期间注册服务是瘫痪状态的。在云部署的环境下,因网络问题使得Zookeeper集群失去master节点是较大概率会发生的事。所以Zookeeper保证的是CP
Eureka
Eureka设计时就优先保证可用性。Eureka各个节点都是平等的,几个节点挂掉不会影响正常节点的工作,剩余的节点依然可以提供注册和查询服务。而Eureka的客户端在向某个Eureka注册或时如果发现连接失败,则会自动切换至其它节点,只要有一台Eureka还在,就能保证注册服务可用(保证可用性),只不过查到的信息可能不是最新的(不保证强一致性)。除此之外,Eureka还有一种自我保护机制,如果在15分钟内超过85%的节点都没有正常的心跳,那么Eureka就认为客户端与注册中心出现了网络故障,此时会出现以下几种情况:
1. Eureka不再从注册列表中移除因为长时间没收到心跳而应该过期的服务
2. Eureka仍然能够接受新服务的注册和查询请求,但是不会被同步到其它节点上(即保证当前节点依然可用)
3. 网络恢复后,当前实例新的注册信息会被同步到其它节点中

接下来我们创建一个EurekaServer
创建成功后,build.gradle 如下,工程引入了spring-cloud-starter-netflix-eureka-server包
plugins { id 'org.springframework.boot' version '2.1.3.RELEASE' id 'java' }apply plugin: 'io.spring.dependency-management'group = 'com.sl' version = '0.0.1-SNAPSHOT' sourceCompatibility = '1.8'repositories { mavenCentral() }ext { set('springCloudVersion', 'Greenwich.SR1') }dependencies { implementation 'org.springframework.cloud:spring-cloud-starter-netflix-eureka-server' testImplementation 'org.springframework.boot:spring-boot-starter-test' }dependencyManagement { imports { mavenBom "org.springframework.cloud:spring-cloud-dependencies:${springCloudVersion}" } }

启动一个服务注册中心,只需要加上一个注解@EnableEurekaServer, 并在application.yml中配置如下
@SpringBootApplication @EnableEurekaServer public class EurekaServerApplication { public static void main(String[] args) { SpringApplication.run(EurekaServerApplication.class, args); }}

server: port: 8081 eureka: instance: hostname: localhost#eureka服务端的实例名称 client: registerWithEureka: false #false表示不向注册中心注册自己 fetchRegistry: false#false表示自己端就是注册中心,并不需要去检索服务 serviceUrl: defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/

下面我们启动一下。Eureka Server,在浏览器中输入http://localhost:8081/
可以看到我们现在注册列表中是空的。
SpringCloud浅尝(三)——Eureka
文章图片

下面我们创建一个EurekaDiscovery
创建成功后,build.gradle 如下,工程引入了spring-cloud-starter-netflix-eureka-client包
plugins { id 'org.springframework.boot' version '2.1.3.RELEASE' id 'java' }apply plugin: 'io.spring.dependency-management'group = 'com.sl' version = '0.0.1-SNAPSHOT' sourceCompatibility = '1.8'repositories { mavenCentral() }ext { set('springCloudVersion', 'Greenwich.SR1') }dependencies { implementation 'org.springframework.boot:spring-boot-starter-web' implementation 'org.springframework.cloud:spring-cloud-starter-netflix-eureka-client' testImplementation 'org.springframework.boot:spring-boot-starter-test' }dependencyManagement { imports { mavenBom "org.springframework.cloud:spring-cloud-dependencies:${springCloudVersion}" } }

在主程序中添加 @EnableEurekaClient
@SpringBootApplication @EnableEurekaClient public class EurekaDiscoveryApplication { public static void main(String[] args) { SpringApplication.run(EurekaDiscoveryApplication.class, args); }}

添加配置文件
spring: application: name: eurekadiscovery server: port:8001 eureka: client: serviceUrl: defaultZone: http://localhost:8081/eureka/

实现一个控制层组件
@RestController public class HelloController { @Value("${server.port}") String port; @GetMapping("/hi") private String home(@RequestParam String name) { return "hi "+name+",i am from port:" +port; }}

在浏览器中输入http://localhost:8001/hi?name=ls
SpringCloud浅尝(三)——Eureka
文章图片

我们再看一下EurekaServer中的注册列表,此实例已成功注册了上去
SpringCloud浅尝(三)——Eureka
文章图片

接下来我们,配置改一个端口8002,再启动一个实例,可以看到这个实例也被注册了上去
SpringCloud浅尝(三)——Eureka
文章图片


下面我们要新建一个实例,通过注册到Eureka,并发现我们上面的实例,并且进行接口调用。我们下面还将使用到另一个组件OpenFeign。OpenFeign是Netflix开发的声明式、模板化的HTTP客户端, Feign可以帮助我们更快捷、优雅地调用HTTP API。我们将使Feign进行API的调用。
下面我们创建一个EurekaDiscovery2
创建成功后,build.gradle 如下,工程引入了spring-cloud-starter-netflix-eureka-client,spring-cloud-starter-openfeign
plugins { id 'org.springframework.boot' version '2.1.3.RELEASE' id 'java' }apply plugin: 'io.spring.dependency-management'group = 'com.sl' version = '0.0.1-SNAPSHOT' sourceCompatibility = '1.8'repositories { mavenCentral() }ext { set('springCloudVersion', 'Greenwich.SR1') }dependencies { implementation 'org.springframework.boot:spring-boot-starter-web' implementation 'org.springframework.cloud:spring-cloud-starter-netflix-eureka-client' implementation 'org.springframework.cloud:spring-cloud-starter-openfeign' testImplementation 'org.springframework.boot:spring-boot-starter-test' }dependencyManagement { imports { mavenBom "org.springframework.cloud:spring-cloud-dependencies:${springCloudVersion}" } }


在主程序中添加 @EnableEurekaClient@EnableFeignClients
@SpringBootApplication @EnableEurekaClient @EnableFeignClients public class EurekaDiscovery2Application { public static void main(String[] args) { SpringApplication.run(EurekaDiscovery2Application.class, args); }}

下面我们创建一个,接口@FeignClient(name= "eurekadiscovery") ,声明访问的web服务为 eurekadiscovery
@FeignClient(name= "eurekadiscovery") public interface HelloRemote { @GetMapping("/hi") public String home(@RequestParam String name); }

创建一个控制层
@RestController public class HelloController { @GetMapping("/sayHello") public String sayHello(@RequestParam String name) { return "hello "+name; }@Autowired private HelloRemote helloRemote; @GetMapping("/hi") public String home(@RequestParam String name) { return helloRemote.home(name); } }


启动实例后,我们发现也成功的注册了上去
SpringCloud浅尝(三)——Eureka
文章图片

我们测试一下,可以看出我们第一次调用的是8001的实例第二次调用的是8002的实例。我们通过使用EurekaClient发现服务并实现了负载均衡。其实帮我们实现负载均衡的是Ribbon组件,我们可以看一下我们的项目jar包在引入EurekaClient时就已经把Ribbon引入了进来,这个Ribbon。我们后面再单独进行讲解分析。
SpringCloud浅尝(三)——Eureka
文章图片

【SpringCloud浅尝(三)——Eureka】SpringCloud浅尝(三)——Eureka
文章图片

    推荐阅读