前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >微服务架构与springcloud04——Eureka服务注册与发现

微服务架构与springcloud04——Eureka服务注册与发现

作者头像
用户10127530
发布2022-10-26 17:38:23
1860
发布2022-10-26 17:38:23
举报
文章被收录于专栏:半旧的技术栈
4.1 Eureka的基础知识

如果你有自己的私人医生,那么你需要时直接与医生进行联系就可以。但大多数人都需要去医院,医院有很多病人,也有很多医生,那么就需要一个窗口来挂号、取号、管理余号等等。同样的道理,当我们的服务数量变得多起来,就需要进行服务注册与发现的管理了。

注:心跳连接就是指像心跳一样周期性的监测服务是否可用。

它与服务提供者、消费者的关系如下图。

server与client的说明如下。

4.2 Eureka服务端安装

(1)建cloud-eureka-server7001模块

(2)写pom

代码语言:javascript
复制
<dependencies>
        <!-- eureka-server -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
        </dependency>
        <!--引入自定义的api通用包,可以使用Payment支付bean-->
        <dependency>
            <groupId>com.wangzhou.springcloud</groupId>
            <artifactId>cloud-api-commons</artifactId>
            <version>${project.version}</version>
        </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>
        <!-- 一般通用配置 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

(3)写yml

application.yml

代码语言:javascript
复制
server:
  port: 7001

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

(4)主启动

代码语言:javascript
复制
@SpringBootApplication
@EnableEurekaServer
public class EurekaMain7001 {
    public static void main(String[] args) {
        SpringApplication.run(EurekaMain7001.class ,args);
    }
}

(5)测试

启动模块,访问Eureka,可以看到如下界面。

4.3 支付微服务入驻

我们要把服务的提供者:支付微服务入驻到EurekaServer。这很像培训机构(如尚硅谷)向物业公司进行注册。

(1)引入依赖

代码语言:javascript
复制
 <!-- eureka-client -->
 <dependency>
     <groupId>org.springframework.cloud</groupId>
     <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
 </dependency>

(2)标注解

主启动类标注解@EnableEurekaClient

代码语言:javascript
复制
@EnableEurekaClient
@SpringBootApplication
public class PaymentMain8001 {
    public static void main(String[] args) {
        SpringApplication.run(PaymentMain8001.class, args);
    }
}

(3)改yaml

代码语言:javascript
复制
eureka:
  client:
    #true表示向注册中心注册自己,默认为true
    register-with-eureka: true
    #是否从EurekaServer抓取已有的注册信息,默认为true。单节点无所谓,集群必须设置为true才能配合ribbon使用负载均衡
    fetch-registry: true
    service-url:
      defaultZone: http://localhost:7001/eureka

访问:Eureka,可以看到8001服务已经入驻。

4.4 订单微服务入驻

服务的消费者:订单微服务也需要入驻到Eureka.

(1)改pom

代码语言:javascript
复制
 <!-- eureka-client -->
 <dependency>
     <groupId>org.springframework.cloud</groupId>
     <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
 </dependency>

(2)改yaml

代码语言:javascript
复制
spring:
  application:
    name: cloud-order-service

eureka:
  client:
    register-with-eureka: true
    fetch-registry: true
    service-url:
      defaultZone: http://localhost:7001/eureka

(3)主启动

代码语言:javascript
复制
@EnableEurekaClient
@SpringBootApplication
public class OrderMain80 {
    public static void main(String[] args) {
        SpringApplication.run(OrderMain80.class, args);
    }
}

(4)测试

4.5 Eureka集群
4.5.1 集群原理

Eureka工作流程可以参考下图。

微服务RPC的核心就是高可用,如果某个Eureka服务节点出现故障,不能够影响整体的服务环境。我们可以搭建Euraka注册中心集群,实现负载均衡和故障容错。参考下图,7001和7002互相注册,然后对外暴露出一个整体。集群主机数量可以随着业务量而定。

4.5.2 搭建集群

(1)建module

cloud-eureka-server7002

(2)写pom

直接cv7001

代码语言:javascript
复制
 <dependencies>
        <!-- eureka-server -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
        </dependency>
        <!--引入自定义的api通用包,可以使用Payment支付bean-->
        <dependency>
            <groupId>com.wangzhou.springcloud</groupId>
            <artifactId>cloud-api-commons</artifactId>
            <version>${project.version}</version>
        </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>
        <!-- 一般通用配置 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

(3)改yaml

是不是也可以直接cv7001呢?

代码语言:javascript
复制
server:
  port: 7002

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

读者看看看7001与7002配置文件hostname完全相同,无法进行区分。

由于我们现在只有一个主机,我们可以修改C:\Windows\System32\drivers\etc\hosts实现将1个ip地址映射为多个网址。

代码语言:javascript
复制
127.0.0.1       eureka7001.com
127.0.0.1       eureka7002.com

现在修改两个模块的yaml文件的hostname,并且让他们相互注册。

7001

代码语言:javascript
复制
server:
  port: 7001

eureka:
  instance:
    hostname: eureka7001.com #eureka服务端的实例名称
  client:
    #false表示不向注册中心注册自己(想注册也可以,不过没必要)
    register-with-eureka: false
    #false表示自己端就是注册中心,职责就是维护服务实例,并不需要去检索服务
    fetch-registry: false
    service-url:
      #设置与eurekaServer交互的地址查询服务和注册服务都需要依赖这个地址
      defaultZone: http://eureka7002.com:7002/eureka/

7002

代码语言:javascript
复制
server:
  port: 7002

eureka:
  instance:
    hostname: eureka7002.com #eureka服务端的实例名称
  client:
    #false表示不向注册中心注册自己(想注册也可以,不过没必要)
    register-with-eureka: false
    #false表示自己端就是注册中心,职责就是维护服务实例,并不需要去检索服务
    fetch-registry: false
    service-url:
      #设置与eurekaServer交互的地址查询服务和注册服务都需要依赖这个地址
      defaultZone: http://eureka7001.com:7001/eureka/

(4)主启动

代码语言:javascript
复制
@EnableEurekaServer
@SpringBootApplication
public class EurekaMain7002 {
    public static void main(String[] args) {
            SpringApplication.run(EurekaMain7002.class ,args);
    }
}

(5)测试

访问http://eureka7001.com:7001/,http://eureka7002.com:7002/

4.5.3 订单、支付服务发布到集群

将80,8001模块yaml文件修改如下。

测试,重启各个服务,注意先启动EurekaServer(7001/7002),再启动服务提供模块(8001),再启动服务消费模块(80)。

测试结果如下。

4.6 支付服务集群

现在Eureka服务注册中心已经是集群服务了,我们还要把支付服务也变成支付集群服务。

(1)建module

新建cloud-provider-payment8002

(2)改pom

代码语言:javascript
复制
 <dependencies>

        <!-- 这两个依赖一般绑定在一起使用       -->
        <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>

        <!--    整合mybatis与springboot    -->
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid-spring-boot-starter</artifactId>
            <!--子工程写了版本号,就使用子工程的版本号,如果没写版本,找父工程中规定的版本号-->
            <version>1.1.10</version>
        </dependency>
        <!--mysql-connector-java-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
        <!--jdbc-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jdbc</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <!--引入自定义的api通用包,可以使用Payment支付bean-->
        <dependency>
            <groupId>com.wangzhou.springcloud</groupId>
            <artifactId>cloud-api-commons</artifactId>
            <version>${project.version}</version>
        </dependency>

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

(3)写yaml

代码语言:javascript
复制
# 服务端口号
server:
  port: 8002

# 服务名称
spring:
  application:
    name: cloud-payment-service

  #数据库配置
  datasource:
    type: com.alibaba.druid.pool.DruidDataSource  # 当前数据源操作类型
    driver-class-name: com.mysql.jdbc.Driver      # mysql驱动包
    url: jdbc:mysql://localhost:3306/cloud2021?useUnicode=true&characterEncoding=UTF-8&useSSL=false
    username: "root"
    password: "123456"

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

mybatis:
  mapper-locations: classpath:mapper/*.xml
  type-aliases-package: com.wangzhou.springcloud.entities  # 所有Bean 别名类所在包

(4)主启动与业务类

直接在存储目录进行cv(如下图),注意,不要在Idea中进行拷贝,可能会爆红。把主启动类的名字改为PaymentMain8002

8001,8002模块对于外部暴露的服务名称是一样的,如何区分是哪个服务模块进行请求的响应呢?

可以在两个模块的controller中增加serverPort属性,在请求方法中使用。

代码语言:javascript
复制
@Value("${server.port}")
private String serverPort;

@PostMapping("/create")
    public CommonResult create(@RequestBody Payment payment) {
        int result = service.create(payment);
        log.info("插入结果是:" + result);
        if(result > 0) {
            return new CommonResult(200, "插入数据成功, serverPort:" + serverPort, result);
        } else {
            return new CommonResult(444, "插入数据失败");
        }
    }

 @GetMapping(value = "/get/{id}")
    public CommonResult getPaymentById(@PathVariable("id")Long id){
        Payment result = service.getPaymentById(id);
        log.info("-----查询结果----: "+ result);

        if (result != null){
            //查询成功
            return new CommonResult(200,"查询成功, serverPort:" + serverPort,result);
        }else {
            return new CommonResult(444,"没有对应记录,查询id: "+id,null);
        }
    }

serverPort其实是从yml文件中读取的。

按顺序(Eureka服务7001,7002、服务提供模块8001,8002、服务消费模块80,后面不再赘述)启动各个服务模块。

(5)测试

看上去没有问题,不过您如果多尝试发几次上面的请求,会发现每次使用的端口都是8001.这是因为我们订单服务把访问的url写死了。

可以将其改为支付微服务统一暴露的服务名称.

代码语言:javascript
复制
public static final String PAYMENT_URL = "http://CLOUD-PAYMENT-SERVICE";

改完以后测试,发现程序奔溃。

这是因为我们使用支付微服务统一暴露的名称CLOUD-PAYMENT-SERVICE进行访问,但是我们程序并不知道需要8001还是8002响应服务.也就是说很多老师在一起办了学校,现在学校办好了,可以统一使用学校的招牌招生了,但具体哪个老师教哪个学生的分配机制我们还没有确立。

现在我们来实现这个机制:负载均衡机制。在OrderPayment模块的ApplicationContextConfig类中添加注解@LoadBalanced

添加后测试发现8001端口测试跑通,8002响应时还是返回异常页面。可以仔细比对两个模块,发现原来少拷贝了内容、将8001中的PaymentMapper.xml拷贝到8002模块,重新启动服务即可。

4.7 actutor微服务完善

不知您是否发现下图暴露了我们电脑的主机名称。我们认为,我们暴露主机名称毫无意义,而且我们希望将ip地址暴露出去。

在8001,8002,80模块的配置类中增加instance属性即可。

当鼠标放到8001上去,左下角出现了ip地址。

4.8 服务发现

现在Eureka就像一个大的中介公司,里面注册许多服务,比如payment服务集群8001,8002。不过目前为止我们的服务对于其它服务的细节并不清楚,我们有必要提供一个机制把相关信息暴露出去,为此Eureka提供了服务发现机制。这很类似于我们在租房中介公司看各个房源的信息。

在8001模块的PaymentController中增加如下代码。

代码语言:javascript
复制
 @Resource
 private DiscoveryClient discoveryClient;

  @GetMapping("/discovery")
    public Object Discovery() {
        List<String> services = discoveryClient.getServices();
        for (String service : services) {
            log.info("****service:****" + service);
        }
        List<ServiceInstance> instances = discoveryClient.getInstances("cloud-payment-service");
        for (ServiceInstance instance : instances) {
            log.info(instance.getServiceId() + "\t" + instance.getHost() + "\t" +instance.getUri());
        }
        return this.discoveryClient;
    }

注:import org.springframework.cloud.client.discovery.DiscoveryClient;导包不要导错。

在主启动类中增加注解@EnableDiscoveryClient

访问localhost:8001/payment/discovery

idea后台可以看到。

事实上,我们可以让80Order端口获得payment服务的信息。这更加贴近实际的需求场景。

4.9 自我保护机制

细心的同学可能发现,访问Eureka (eureka7002.com),会有如下提醒.

如果出现上面的提醒,说明Eureka进入了保护模式,这说明即使某一刻一个微服务变得不可用了,因为可能因为网络延时,卡顿等各种原因没有收到微服务的心跳连接,Eureka也不会立刻清理该服务,这是Eureka对于该服务存在重新恢复可能性的一种现场保护机制,比如疫情期间某商铺无法缴纳租金费,房东可能可以允许其拖欠几天,而不是立刻清理出户.

在7001模块中可以添加如下内容关闭自我保护机制.

在8001模块配置如下

代码语言:javascript
复制
eureka:
  instance:
    #Eureka客户端向服务端发送心跳的时间间隔,单位秒(默认30秒)
    lease-renewal-interval-in-seconds: 1
    #Eureka服务端在收到最后一次心跳后等待的时间上限,单位秒(默认90秒),超时剔除服务
    lease-expiration-duration-in-seconds: 2

访问Eureka (eureka7001.com),提示自我保护机制关闭.

停掉8001服务.可以看到果然服务立刻被清理了.

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2022-03-23,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 4.1 Eureka的基础知识
  • 4.2 Eureka服务端安装
  • 4.3 支付微服务入驻
  • 4.4 订单微服务入驻
  • 4.5 Eureka集群
    • 4.5.1 集群原理
      • 4.5.2 搭建集群
        • 4.5.3 订单、支付服务发布到集群
        • 4.6 支付服务集群
        • 4.7 actutor微服务完善
        • 4.8 服务发现
        • 4.9 自我保护机制
        相关产品与服务
        微服务引擎 TSE
        微服务引擎(Tencent Cloud Service Engine)提供开箱即用的云上全场景微服务解决方案。支持开源增强的云原生注册配置中心(Zookeeper、Nacos 和 Apollo),北极星网格(腾讯自研并开源的 PolarisMesh)、云原生 API 网关(Kong)以及微服务应用托管的弹性微服务平台。微服务引擎完全兼容开源版本的使用方式,在功能、可用性和可运维性等多个方面进行增强。
        领券
        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档