草庐IT

微服务注册中心:Eureka详解

所遇皆惊喜 2023-04-27 原文

文章目录

Eureka基础概念

Eureka概述

Eureka服务注册与发现提供了一个服务注册中心、服务发现的客户端,还有一个方便查看所有注册的服务的界面。所有的服务使用Eureka的服务发现客户端来将自己注册到Eureka的服务器上。

Eureka架构图

Spring Cloud封装了Netflix 公司开发的Eureka模块来实现服务治理。

在传统的RPC远程调用框架中,管理每个服务与服务之间依赖关系比较复杂,管理比较复杂,所以需要使用服务治理,管理服务于服务之间依赖关系,可以实现服务调用、负载均衡、容错等,实现服务发现与注册。

Eureka采用了CS的设计架构,Eureka Sever作为服务注册功能的服务器,它是服务注册中心。而系统中的其他微服务,使用Eureka的客户端连接到 Eureka Server并维持心跳连接。这样系统的维护人员就可以通过Eureka Server来监控系统中各个微服务是否正常运行。

在服务注册与发现中,有一个注册中心。当服务器启动的时候,会把当前自己服务器的信息比如服务地址通讯地址等以别名方式注册到注册中心上。另一方(消费者\服务提供者),以该别名的方式去注册中心上获取到实际的服务通讯地址,然后再实现本地RPC调用。RPC远程调用框架核心设计思想:在于注册中心,因为使用注册中心管理每个服务与服务之间的一个依赖关系(服务治理概念)。在任何RPC远程框架中,都会有一个注册中心存放服务地址相关信息(接口地址)。

Eureka由两个组件组成: Eureka服务器和Eureka客户端。

Eureka Server提供服务注册服务
各个微服务节点通过配置启动后,会在EurekaServer中进行注册,这样EurekaServer中的服务注册表中将会存储所有可用服务节点的信息,服务节点的信息可以在界面中直观看到。

EurekaClient通过注册中心进行访问
它是一个Java客户端,用于简化Eureka Server的交互,客户端同时也具备一个内置的、使用轮询(round-robin)负载算法的负载均衡器。在应用启动后,将会向Eureka Server发送心跳(默认周期为30秒)。如果Eureka Server在多个心跳周期内没有接收到某个节点的心跳,EurekaServer将会从服务注册表中把这个服务节点移除(默认90秒)。

Eureka集群架构图

Eureka关键概念

  • 服务注册:register
  • 服务续约:renew, 客户端默认每隔30秒向服务器发送一次心跳进行续约,如果服务器90秒内没有收到心跳,则将该客户端剔除
  • 获取服务注册列表信息:fetch registries
  • 服务下线:cancel
  • 服务剔除eviction

Eureka的自我保护模式

  • 默认情况下,如果Eureka Server在一定时间内没有接收到某个微服务实例的心跳,Eureka Server将 会注销该实例(默认90秒)。但是当网络分区故障发生时,微服务与Eureka Server之间无法正常通 信,这就可能变得非常危险了----因为微服务本身是健康的,此时本不应该注销这个微服务。
  • Eureka Server通过“自我保护模式”来解决这个问题- - -当Eureka Server节点在短时间内丢失过多客户端时(可能发生了网络分区故障),那么这个节点就会进入自我保护模式。一旦进入该模式, Eureka Server就会保护服务注册表中的信息,不再删除服务注册表中的数据(也就是不会注销任何微服务)。当网络故障恢复后,该Eureka Server节点会自动退出自我保护模式。
  • 自我保护模式是一种对网络异常的安全保护措施。使用自我保护模式,可以让Eureka集群更加健壮、 稳定。
  • 在Spring Cloud中,可以使用eureka.server.enable-self-preservation=false来禁用自我保护模式(不建议禁用)
  • 简言之:某时刻某一个微服务不可用了,Eureka不会立刻清理,依旧会对该微服务的信息进行保存。

创建Eureka服务端

1.新建Module

创建名为cloud-eureka-server7001的Maven工程。

2.修改pom文件

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>cloud-kernel</artifactId>
        <groupId>com.kernel.springcloud</groupId>
        <version>1.0.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>cloud-eureka-server7001</artifactId>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
    </properties>

    <dependencies>
        <!-- 我们自己的公共模块 -->
        <dependency>
            <groupId>com.kernel.springcloud</groupId>
            <artifactId>cloud-api-common</artifactId>
            <version>${project.version}</version>
        </dependency>

        <!--服务中心 -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>

    </dependencies>

</project>

3.编写application.yml配置文件

server:
  port: 7001

eureka:
  instance:
    hostname: localhost # eureka服务端的实例名称
  client:
    # false表示不向注册中心注册自己。
    register-with-eureka: false
    # false表示自己端就是注册中心,我的职责就是维护服务实例,并不需要去检索服务
    fetch-registry: false
    service-url:
      # 设置与Eureka server交互的地址查询服务和注册服务都需要依赖这个地址。
      defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/

4.编写启动类

@EnableEurekaServer注解 表示 Eureka服务端

@SpringBootApplication
@EnableEurekaServer
public class EurekaMainApplication {

    public static void main(String[] args) {

        SpringApplication.run(EurekaMainApplication.class,args);

    }
}

5.测试
测试运行EurekaMainApplication,浏览器输入http://localhost:7001/回车,会查看到Spring Eureka服务主页。

服务提供者cloud-provider-8001入驻进EurekaServer

EurekaClient端cloud-provider-8001将注册进EurekaServer成为服务提供者provider。

1.修改cloud-provider-8001的pom文件

添加spring-cloud-starter-netflix-eureka-client依赖

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>

2.修改application.yml配置文件

server:
  port: 8001

spring:
  application:
    name: cloud-provider-service
  datasource:
    type: com.alibaba.druid.pool.DruidDataSource            # 当前数据源操作类型
    driver-class-name: com.mysql.jdbc.Driver                # mysql驱动包
    url: jdbc:mysql://localhost:3306/idata_baiir?useUnicode=true&characterEncoding=utf8&serverTimezone=GMT
    username: ******
    password: ******

mybatis:
  mapperLocations: classpath:mapper/*.xml
  type-aliases-package: com.kernel.entity    # 所有Entity别名类所在包

eureka:
  client:
    # 表示是否将自己注册进Eurekaserver默认为true。
    register-with-eureka: true
    # 是否从EurekaServer抓取已有的注册信息,默认为true。单节点无所谓,集群必须设置为true才能配合ribbon使用负载均衡
    fetchRegistry: true
    service-url:
      defaultZone: http://localhost:7001/eureka

3.修改主启动类

@SpringBootApplication
@EnableEurekaClient //<-----添加该注解
public class ProviderApplication {

    public static void main(String[] args) {
        SpringApplication.run(ProviderApplication.class,args);
    }

}

4.测试
启动cloud-provider-8001和cloud-eureka-server7001工程。

浏览器输入 http://localhost:7001/ 主页内的Instances currently registered with Eureka会显示cloud-provider-8001的配置文件application.yml设置的应用名cloud-provider-service

消费者模块入驻进EurekaServer

EurekaClient端cloud-consumer-80将注册进EurekaServer成为服务消费者consumer。

1.修改cloud-consumer-80的pom文件

添加spring-cloud-starter-netflix-eureka-client依赖

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>

2.修改application.yml配置文件

server:
  port: 80

spring:
  application:
    name: cloud-consumer-service
    
eureka:
  client:
    #表示是否将自己注册进Eurekaserver默认为true。
    register-with-eureka: true
    #是否从EurekaServer抓取已有的注册信息,默认为true。单节点无所谓,集群必须设置为true才能配合ribbon使用负载均衡
    fetchRegistry: true
    service-url:
      defaultZone: http://localhost:7001/eureka

3.修改主启动类

@SpringBootApplication
@EnableEurekaClient//<--- 添加该注解
public class ConsumerApplication {

    public static void main(String[] args) {
        SpringApplication.run(ConsumerApplication.class,args);
    }

}

4.测试

启动cloud-provider-8001、cloud-eureka-server7001和cloud-consumer-80这三工程。

浏览器输入 http://localhost:7001 , 在主页的Instances currently registered with Eureka将会看到cloud-provider-8001、cloud-consumer-80两个工程名。

Eureka工作原理

Eureka集群环境构建

Eureka server搭建集群不同与传统集群,每个server是互等的1在向23注册时1就相当于客户端,需要向23注册信息的同时还要获取信息。所以 defaultZone注册时如1需注册23的server地址(不能注册自己的地址)注册完123会在系统趋于平稳进行复制 达到信息共享统一


创建cloud-eureka-server7002工程 步骤同上

hosts文件,修改映射配置添加进hosts文件

127.0.0.1 eureka7001.com
127.0.0.1 eureka7002.com

修改cloud-eureka-server7001配置文件

server:
  port: 7001

eureka:
  instance:
    hostname: eureka7001.com #eureka服务端的实例名称
  client:
    register-with-eureka: false     #false表示不向注册中心注册自己。
    fetch-registry: false     #false表示自己端就是注册中心,我的职责就是维护服务实例,并不需要去检索服务
    service-url:
    #集群指向其它eureka
      defaultZone: http://eureka7002.com:7002/eureka/
    #单机就是7001自己
      #defaultZone: http://eureka7001.com:7001/eureka/

修改cloud-eureka-server7002配置文件

server:
  port: 7002

eureka:
  instance:
    hostname: eureka7002.com #eureka服务端的实例名称
  client:
    register-with-eureka: false     #false表示不向注册中心注册自己。
    fetch-registry: false     #false表示自己端就是注册中心,我的职责就是维护服务实例,并不需要去检索服务
    service-url:
    #集群指向其它eureka
      defaultZone: http://eureka7001.com:7001/eureka/
    #单机就是7002自己
      #defaultZone: http://eureka7002.com:7002/eureka/

将服务注册进Eureka集群

将它们的配置文件的eureka.client.service-url.defaultZone进行修改

eureka:
  client:
    #表示是否将自己注册进Eurekaserver默认为true。
    register-with-eureka: true
    #是否从EurekaServer抓取已有的注册信息,默认为true。单节点无所谓,集群必须设置为true才能配合ribbon使用负载均衡
    fetchRegistry: true
    service-url:
      defaultZone: http://eureka7001.com:7001/eureka, http://eureka7002.com:7002/eureka

服务提供端搭建集群

前边已经将eureka注册中心搭建成集群,现在把我们的服务端也搭建为集群环境。

参考cloud-provider-8001 新建 cloud-provider-8002

1.新建cloud-provider-8002 模块
2.修改POM
3.写YML - 端口改为8002 (除了端口号其余全一样)

server:
  port: 8002

spring:
  application:
    name: cloud-provider-service
  datasource:
    type: com.alibaba.druid.pool.DruidDataSource            # 当前数据源操作类型
    driver-class-name: com.mysql.jdbc.Driver                # mysql驱动包
    url: jdbc:mysql://localhost:3306/idata_baiir?useUnicode=true&characterEncoding=utf8&serverTimezone=GMT
    username: ******
    password: ******

mybatis:
  mapperLocations: classpath:mapper/*.xml
  type-aliases-package: com.kernel.entity    # 所有Entity别名类所在包

eureka:
  client:
    # 表示是否将自己注册进Eurekaserver默认为true。
    register-with-eureka: true
    # 是否从EurekaServer抓取已有的注册信息,默认为true。单节点无所谓,集群必须设置为true才能配合ribbon使用负载均衡
    fetchRegistry: true
    service-url:
      defaultZone: http://localhost:7001/eureka

4.编写主启动类
5.编写业务代码

为了测试,我们在代码里加入调用的端口号

可以看到 cloud-provider-service 下有俩个服务

负载均衡

cloud-consumer-80服务访问地址不能写死

使用@LoadBalanced注解赋予RestTemplate负载均衡的能力

@Configuration
public class ApplicationContextConfig {

    @Bean
    @LoadBalanced //使用@LoadBalanced注解赋予RestTemplate负载均衡的能力
    public RestTemplate getRestTemplate(){
        return new RestTemplate();
    }

}

测试
结果:负载均衡效果达到,8001/8002端口交替出现

actuator微服务信息完善

instance-id:主机名称:服务名称修改(也就是将IP地址,换成可读性高的名字)

prefer-ip-address:访问信息有IP信息提示

eureka:
  client:
    # 表示是否将自己注册进Eurekaserver默认为true。
    register-with-eureka: true
    # 是否从EurekaServer抓取已有的注册信息,默认为true。单节点无所谓,集群必须设置为true才能配合ribbon使用负载均衡
    fetchRegistry: true
    service-url:
      defaultZone: http://localhost:7001/eureka
  instance:
    instance-id: ${spring.application.name}:${server.port}
    prefer-ip-address: true     #访问路径可以显示IP地址

服务发现Discovery

对于注册进eureka里面的微服务,可以通过服务发现来获得该服务的信息

修改cloud-provider-8001的Controller

@Api(tags = "用户管理接口")
@RestController
@Slf4j
@RequestMapping("/user")
public class UserController {

    @Autowired
    private IUserTestService userTestService;

    @Autowired
    private DiscoveryClient discoveryClient;


    @Value("${server.port}")
    private Integer serverPort;

    @ApiOperation(value = "服务发现Discovery")
    @GetMapping(value = "/get/discovery")
    public Object discovery() {

        List<String> services = discoveryClient.getServices();
        for (String element : services) {
            log.info("*****element: " + element);
        }

        List<ServiceInstance> instances = discoveryClient.getInstances("CLOUD-PROVIDER-SERVICE");
        for (ServiceInstance instance : instances) {
            log.info(instance.getServiceId() + "\t" + instance.getHost() + "\t" + instance.getPort() + "\t" + instance.getUri());
        }

        return this.discoveryClient;
    }

}

修改主启动类

@SpringBootApplication
@EnableEurekaClient 
@EnableDiscoveryClient//添加该注解
public class ProviderApplication {

    public static void main(String[] args) {
        SpringApplication.run(ProviderApplication.class,args);
    }

}


禁用自我保护模式

在eurekaServer端7001处设置关闭自我保护机制

默认,自我保护机制是开启的
使用eureka.server.enable-self-preservation = false可以禁用自我保护模式

eureka:
  ...
  server:
    #关闭自我保护机制,保证不可用服务被及时踢除
    enable-self-preservation: false
    eviction-interval-timer-in-ms: 2000 # 清理间隔(单位毫秒,默认是60*1000)

生产者客户端eurekaClient端8001

eureka:
  ...
  instance:
    instance-id:  ${spring.application.name}:${server.port}
    prefer-ip-address: true
    #心跳检测与续约时间
    #开发时没置小些,保证服务关闭后注册中心能即使剔除服务
    #Eureka客户端向服务端发送心跳的时间间隔,单位为秒(默认是30秒)
    lease-renewal-interval-in-seconds: 1
    #Eureka服务端在收到最后一次心跳后等待时间上限,单位为秒(默认是90秒),超时将剔除服务
    lease-expiration-duration-in-seconds: 2

结果:先关闭8001,马上被删除了

有关微服务注册中心:Eureka详解的更多相关文章

  1. Observability:从零开始创建 Java 微服务并监控它 (二) - 2

    这篇文章是继上一篇文章“Observability:从零开始创建Java微服务并监控它(一)”的续篇。在上一篇文章中,我们讲述了如何创建一个Javaweb应用,并使用Filebeat来收集应用所生成的日志。在今天的文章中,我来详述如何收集应用的指标,使用APM来监控应用并监督web服务的在线情况。源码可以在地址 https://github.com/liu-xiao-guo/java_observability 进行下载。摄入指标指标被视为可以随时更改的时间点值。当前请求的数量可以改变任何毫秒。你可能有1000个请求的峰值,然后一切都回到一个请求。这也意味着这些指标可能不准确,你还想提取最小/

  2. 阿里云国际版免费试用:如何注册以及注意事项 - 2

    作为新的阿里云用户,您可以50免费试用多种优惠,价值高达1,700美元(或8,500美元)。这将让您了解和体验阿里云平台上提供的一系列产品和服务。如果您以个人身份注册免费试用,您将获得价值1,700美元的优惠。但是,如果您是注册公司,您可以选择企业免费试用,提交基本信息通过企业实名注册验证,即可开始价值$8,500的免费试用!本教程介绍了如何设置您的帐户并使用您的免费试用版。​关于免费试用在我们开始此试用之前,您还必须遵守以下条款和条件才能访问您的免费试用:只有在一年内创建的账户才有资格获得阿里云免费试用。通过此免费试用优惠,用户可以免费试用免费试用活动页面上列出的每种产品一次。如果您有多个帐

  3. ruby-on-rails - 设计注册确认 - 2

    我在我的项目中有一个用户和一个管理员角色。我使用Devise创建了身份验证。在我的管理员角色中,我没有任何确认。在我的用户模型中,我有以下内容:devise:database_authenticatable,:confirmable,:recoverable,:rememberable,:trackable,:validatable,:timeoutable,:registerable#Setupaccessible(orprotected)attributesforyourmodelattr_accessible:email,:username,:prename,:surname,:

  4. ruby-on-rails - 特征未注册 : attribute name - 2

    完成这个有困难。我正在使用seed.rb+factory_girl来使用rakedb:seed填充数据库。(我知道固定装置存在,但我想以这种方式完成,这只是一个示例,数据库将填充复杂的关联对象。)我的种子.rb:require'factory_girl_rails'["QM","CDC","SI","QS"].eachdo|n|FactoryGirl.create(:grau,nome:n)end还有我的/factories/graus.rbFactoryGirl.definedofactory:graudonomeendend但是当我运行时:rakedb:seed我得到:rakeab

  5. 物联网MQTT协议详解 - 2

    一、什么是MQTT协议MessageQueuingTelemetryTransport:消息队列遥测传输协议。是一种基于客户端-服务端的发布/订阅模式。与HTTP一样,基于TCP/IP协议之上的通讯协议,提供有序、无损、双向连接,由IBM(蓝色巨人)发布。原理:(1)MQTT协议身份和消息格式有三种身份:发布者(Publish)、代理(Broker)(服务器)、订阅者(Subscribe)。其中,消息的发布者和订阅者都是客户端,消息代理是服务器,消息发布者可以同时是订阅者。MQTT传输的消息分为:主题(Topic)和负载(payload)两部分Topic,可以理解为消息的类型,订阅者订阅(Su

  6. Tcl脚本入门笔记详解(一) - 2

    TCL脚本语言简介•TCL(ToolCommandLanguage)是一种解释执行的脚本语言(ScriptingLanguage),它提供了通用的编程能力:支持变量、过程和控制结构;同时TCL还拥有一个功能强大的固有的核心命令集。TCL经常被用于快速原型开发,脚本编程,GUI和测试等方面。•实际上包含了两个部分:一个语言和一个库。首先,Tcl是一种简单的脚本语言,主要使用于发布命令给一些互交程序如文本编辑器、调试器和shell。由于TCL的解释器是用C\C++语言的过程库实现的,因此在某种意义上我们又可以把TCL看作C库,这个库中有丰富的用于扩展TCL命令的C\C++过程和函数,所以,Tcl是

  7. ruby-on-rails - 带有自定义处理器的 CarrierWave 未注册 - 2

    我正在使用carrierwave上传视频然后有一个名为thumb的版本,带有自定义处理器,可以获取视频并使用streamio-ffmpeg创建屏幕截图。视频和文件都已正确上传,但在调用uploader.url(:thumb)时我得到:ArgumentError:Versionthumbdoesn'texist!VideoUploader.rbrequire'carrierwave/processing/mime_types'require'streamio-ffmpeg'classVideoUploader5)File.renamethumb_path,current_pathendd

  8. ruby-on-rails - 如何访问设计 token 授权注册 Controller ? - 2

    我正在使用Deviseauthtokengem用于验证我的Rails应用程序的某些部分。但是,当我尝试使用注册路径创建新用户时,出现以下错误{"errors":["Authorizedusersonly."]}。这是我用于测试的rspec代码,it'createsauserusingemail/passwordcombo'dopostapi_user_registration_path,{email:'xxx',password:'yyy',password_confirmation:'yyy'}putslast_response.bodyexpect(last_response.bo

  9. ruby - 如何将 Thor::Group 注册为带参数的子命令 - 2

    这道题开始于here.但随着我对雷神的了解越来越多,情况发生了很大变化。我正在尝试创建一个带参数的Thor::Group子命令。奇怪的是,如果没有参数,它就可以工作。我可以使用Thor::Group作为子命令吗?这在我输入时有效:foocounterfoo/bin/foomoduleFooclassCLI但是当我输入时这不起作用:foocounter5moduleFooclassCLI','Countupfromtheinput.')endclassCounter:numeric,:desc=>"Thenumbertostartcounting"desc"Prints2numbersb

  10. 【详解】Docker安装Elasticsearch7.16.1集群 - 2

    开门见山|拉取镜像dockerpullelasticsearch:7.16.1|配置存放的目录#存放配置文件的文件夹mkdir-p/opt/docker/elasticsearch/node-1/config#存放数据的文件夹mkdir-p/opt/docker/elasticsearch/node-1/data#存放运行日志的文件夹mkdir-p/opt/docker/elasticsearch/node-1/log#存放IK分词插件的文件夹mkdir-p/opt/docker/elasticsearch/node-1/plugins若你使用了moba,直接右键新建即可如上图所示依次类推创建

随机推荐