• 【微服务】- eurka构建与使用


    1.eureka基础知识

    什么是服务治理

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

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

    什么是服务注册与发现

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

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

    图片

    Eureka包含两个组件: Eureka Server和Eureka Client

    1.Eureka Server提供服务注册服务

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

    2.EurekaClient通过注册中心进行访问

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

    用例项目的构架

    图片

    2.单机eureka的构建

    注册一个简单的Eureka单机配置

    1.建一个空工程工程

    cloud-server-eureka7001

    2.添加依赖

    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
        </dependency>
    
        <!--    引入自定义的api通用包,可以使用Payment支付Entity    -->
        <dependency>
            <groupId>wf.springcloud</groupId>
            <artifactId>cloud-api-commons</artifactId>
            <version>1.0-SNAPSHOT</version>
            <scope>compile</scope>
        </dependency>
    
        <!-- boot web actuator -->
        <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>
        </dependency>
        <!--  热部署      -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <!--   单元测试     -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    
    </dependencies>
    

    3.配置yml文件

    server:
      port: 7001
    
    eureka:
      instance:
    #    hostname: eureka7001.com   #eureka服务端的实例名称
        hostname: localhost   #eureka服务端的实例名称
      client:
        register-with-eureka: false   #false表示不向注册中心注册自己
        fetch-registry: false   #false表示自己端就是注册中心
        service-url:
          defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/   #单机
    #      defaultZone: http://eureka7001.com:7001/eureka/   #单机
    #      defaultZone: http://eureka7002.com:7002/eureka/  #集群
    

    4.写主启动类

    @SpringBootApplication
    @EnableEurekaServer
    public class EurekaMain7001 {
    
        public static void main(String[] args) {
            SpringApplication.run(EurekaMain7001.class,args);
        }
    }
    

    5.运行

    出现以下界面说明配置成功

    图片

    把服务注册到eureka上

    1.先在服务pom文件中添加eureka的client依赖

    我在父工程已经添加了依赖的版本号,所以此处没有版本号。

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

    2.在yml文件中注册eureka

    eureka:
      client:
        register-with-eureka: true   #是否将自己注册到注册中心,集群必须设置为true配合ribbon
        fetch-registry: true    #是否从服务端抓取已有的注册信息
        service-url:
          defaultZone: http://localhost:7001/eureka #eureka服务器中配置的地址#,http://eureka7002.com:7002/eureka
    

    须注意,如果没有给服务的application命名,那么就需要在yml文件中添加如下配置

    spring:
      application:
        name: cloud-order-service
    

    3.在服务的主启动类上添加以下注解

    @SpringBootApplication
    @EnableEurekaClient
    public class OrderMain80 {
    
        public static void main(String[] args) {
            SpringApplication.run(OrderMain80.class,args);
        }
    }
    

    然后启动eureka服务器,在启动服务就可以在eureka页面看到服务以注册
    图片

    3.Eureka集群构建

    图片

    问题:微服务RPC远程服务调用最核心的是什么

    高可用,试想你的注册中心只有一个only one,它出故障了那就呵呵(~一)" 了,会导致整个为服务环境不可用,

    所以解决办法:搭建Eureka注册中心集群,实现负载均衡+故障容错。

    1.搭建eureka集群

    因为是在一台机器上模拟集群所以如果想搭好集群先改hosts文件

    C:WindowsSystem32driversetc目录下修改hosts文件,添加

    127.0.0.1       eureka7001.com
    127.0.0.1       eureka7002.com
    127.0.0.1       eureka7003.com
    

    建项目,改配置

    新建cloud-server-eureka7002项目,添加与cloud-server-eureka7001相同的依赖,此处省略。

    添加yml文件。

    server:
      port: 7002
    
    eureka:
      instance:
        hostname: eureka7002.com   #eureka服务端的实例名称
    #    hostname: localhost   #eureka服务端的实例名称
      client:
        register-with-eureka: false   #false表示不向注册中心注册自己
        fetch-registry: false   #false表示自己端就是注册中心
        service-url:
          defaultZone: http://eureka7001.com:7001/eureka/   #把7002注册给7001
    

    erueka集群的产生就是多个eureka服务间的相互注册。
    同时修改7001的yml文件,把7001注册给7002.

    添加启动类,

    @SpringBootApplication
    @EnableEurekaServer
    public class EurekaMain7002 {
    
        public static void main(String[] args) {
            SpringApplication.run(EurekaMain7002.class,args);
        }
    }
    

    然后启动两个eureka服务就可发现其集群已经建立。图片

    把其他服务添加人eureka集群

    只需要修改yml文件中eureka相关配置即可

    eureka:
      client:
        register-with-eureka: true   #是否将自己注册到注册中心,集群必须设置为true配合ribbon
        fetch-registry: true    #是否从服务端抓取已有的注册信息
        service-url:
          defaultZone: http://eureka7001.com:7001/eureka ,http://eureka7002.com:7002/eureka
    

    启动服务。出现以下即可说明成功图片图片

    2.搭建服务集群

    写两个相同的服务,

    图片

    两个服务功能相同都是简单的查询数据库。然后有一个调用者80来调用8081和8082实现微服务间的调用。8081和8082两个服务之间除了启动类名称不一样其他都相同,简单来说就是把8081进行复制,复制出8082,然后使用 @Value("${server.port}")

    @RestController
    @Slf4j
    public class PaymentController {
    
        @Resource
        private PaymentService paymentService;
    
        @Value("${server.port}")
        private String serverport;
    
        @PostMapping(value = "/payment/creat")
        public CommonResult creat(@RequestBody Payment payment){
            int result = paymentService.creat(payment);
    
            log.info("插入结果:" + payment);
            if (result > 0){
                return new CommonResult(200,"插入数据成功! port:" + serverport,payment);
            }else {
                return new CommonResult(444,"插入数据失败!",null);
            }
        }
    
        @GetMapping(value = "/payment/get/{id}")
        public CommonResult<Payment> getPaymentById(@PathVariable("id") Long id){
            Payment result = paymentService.getPaymentById(id);
            log.info("查询结果:" + result);
            if (result != null){
                return new CommonResult<Payment>(200,"查询成功! port:" + serverport,result);
            }else {
                return new CommonResult<Payment>(444,"查询失败!",null);
            }
        }
    

    }

    获取服务端口号,然后在返回在输出。
    启动全部服务,出现图片

    两个端口都存在即表示构建成功。

    通过eureka来实现多个微服务之间的调用

    上面说过8081和8082是服务的提供者,而80是服务的消费者。所以在80服务的controller中

    @RestController
    @Slf4j
    public class OrderController {
    
        //抛弃之前直接对其他访问的访问,使用eureka中注册的Application来实现多个微服务间的访问
        private final String path = "http://CLOUD-PAYMENT-SERVICE";
        //    private final String path = "http://localhost:8081";
        @Resource
        private RestTemplate template;
    
        @GetMapping("/consumer/payment/get/{id}")
        public CommonResult getPaymentById(@PathVariable("id") Long id){
            log.info("order执行查询");
            return template.getForObject(path + "/payment/get/"+id,CommonResult.class);
        }
    
        @GetMapping("/consumer/payment/creat")
        public CommonResult<Payment> creat(Payment payment){
            log.info("order执行插入");
            return template.postForObject(path+"/payment/creat",payment,CommonResult.class);
        }
    

    }

    一个小问题
    此时如果直接访问会出现错误

    图片

    因为调用服务提供者集群时存在多个服务eureka不知道该调用哪一个服务,使用此处要使用负载均衡来平衡多个服务间的调用。

    在RestTemplate 的bean中添加@LoadBalanced来实现调用集群的有序

    @Configuration
    public class ApplicationConfig {
    
        @Bean
        @LoadBalanced
        public RestTemplate getRestTemplate(){
            return new RestTemplate();
        }
    }
    

    然后重新启动所以服务,通过80端口访问时出现服务提供者端口号重复变化就说明调用集群成功
    第一个访问

    图片

    第二次访问

    图片

    第三次访问

    图片

    轮询调用两个访问,成功

    4.完善actuator信息

    主机名称服务名称的修改

    图片

    此时我们的主机名称和服务名称都是暴露出来的,不好我们可以通过一个配置,来让此处显示我们想要显示的名称

    如何配置

    在yml文件的eureka相关配置添加instance:即可

    eureka:
      client:
        register-with-eureka: true   #是否将自己注册到注册中心,集群必须设置为true配合ribbon
        fetch-registry: true    #是否从服务端抓取已有的注册信息
        service-url:
          defaultZone: http://eureka7001.com:7001/eureka ,http://eureka7002.com:7002/eureka
      instance:
        instance-id: payment8081
    

    此时服务名称就被修改了
    图片

    访问ip地址的显示

    图片

    在yml文件的eureka相关配置添加instance:即可

    eureka:
      client:
        register-with-eureka: true   #是否将自己注册到注册中心,集群必须设置为true配合ribbon
        fetch-registry: true    #是否从服务端抓取已有的注册信息
        service-url:
          defaultZone: http://eureka7001.com:7001/eureka ,http://eureka7002.com:7002/eureka
      instance:
        instance-id: payment8081
        prefer-ip-address: true
    

    修改并重启访问后
    图片

    5.服务发现DisCovery

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

    如何使用

    服务8081的controller添加(篇幅原因我只把需要添加的部分写了出来,其他如get方法等都面响)

    @RestController
    @Slf4j
    public class PaymentController {
        @Resource
        private DiscoveryClient discoveryClient;
    
        @GetMapping("/payment/discovery")
        public Object getDisCovery(){
            List<String> services = discoveryClient.getServices();
            for (String service : services) {
                log.info("---server :" + service);
            }
            List<ServiceInstance> instances = discoveryClient.getInstances("CLOUD-PAYMENT-SERVICE");
            for (ServiceInstance instance : instances) {
                log.info(instance.getServiceId() +"	"+ instance.getHost() +"	"+ instance.getPort() +"	"+ instance.getUri());
            }
            return discoveryClient;
        }
    }
    

    服务对应地址
    图片

    可以看到对应信息,添加日志

    2020-03-31 22:16:24.249  INFO 12068 --- [nio-8081-exec-4] w.s.controller.PaymentController         : ---server :cloud-payment-service
    2020-03-31 22:16:24.249  INFO 12068 --- [nio-8081-exec-4] w.s.controller.PaymentController         : ---server :cloud-order-service
    2020-03-31 22:16:24.251  INFO 12068 --- [nio-8081-exec-4] w.s.controller.PaymentController         : CLOUD-PAYMENT-SERVICE	192.168.211.1	8081	http://192.168.211.1:8081
    2020-03-31 22:16:24.251  INFO 12068 --- [nio-8081-exec-4] w.s.controller.PaymentController         : CLOUD-PAYMENT-SERVICE	192.168.211.1	8082	http://192.168.211.1:8082
    

    DisCovery可以查看注册服务的具体信息,为了是在eureka中还是其他中间件注册。

    6.eureka自我保护

    概述

    保护模式主要用于一组客户端和Eureka Server之间存在网络分区场景下的保护。一旦进入保护模式**,Eureka Server将会尝试保护其服务注册表中的信息,不再删除服务注册表中的数据,也就是不会注销任何微服务。**

    如果在Eureka Server的首页看到以下这段提示,则说明Eureka进入了保护模式:

    EMERGENCY! EUREKA MAY BE INCORRECTLY CLAIMING INSTANCES ARE UP WHEN THEY’RE NOT. RENEWALS ARE LESSER THAN THRESHOLD AND HENCE THE INSTANCES ARE NOT BEING EXPIRED JUST TO BE SAFE.

    图片

    即:某时刻某一个微服务不可用了,Eureka不会立刻清理,依旧会对该微服务的信息进行保存

    属于cap中的ap

    自我保护机制产生原因

    • 为什么会产生Eureka自我保护机制?

    为了防止EurekaClient可以正常运行,但是与EurekaServer网络不通情况下,EurekaServer不会立刻将EurekaClient服务 剔除

    • 什么是自我保护模式?

    默认情况下,如果EurekaServer在一 定时间内没有接收到某个微服务实例的心跳,eurekaServer将会注销该实例 (默认90秒) 。但是当网络分区故障发生(延时、卡顿、拥挤)时,微服务与EurekaServer之间无法正常通信,以上行为可能变得非常危险了——因为微服务本身其实是健康的,此时本不应该注销这个微服务。Eureka通过“自我保护模式”来解决这个问题一一当EurekaServer节点在短时间内丢失过多客户端时(可能发生了网络分区故障), 那么这个节点就会进入自我保护模式。

    在自我保护模式中,Eureka Server会保护服务注册表中的信息,不再注销任何服务实例。

    它的设计哲学就是宁可保留错误的服务注册信息,也不盲目注销任何可能健康的服务实例。一句话讲解**:好死不如赖活着**

    综上,自我保护模式是-种应对网络异常的安全保护措施。它的架构哲学是宁可同时保留所有微服务(健康的微服务和不健康的微服务都会保留)也不盲目注销任何健康的微服务。使用自我保护模式,可以让Eureka集群更加的健壮、 稳定。

    关闭自我保护机制

    服务端配置

    server :
    #关闭自我保护机制,保证不可用服务被及时踢除
    enable-self-preservation: false
    eviction- interval -timer-in-ms: 2000
    

    enable-self-preservation: true自我保护机制,eureka默认为true。
    eviction- interval -timer-in-ms: 2000服务的默认心跳时间90s此处改为2s。调小是为了更好的观察到现象。

    客户端配置

    instance : 
    #Eureka客户端向服务端发送心跳的时间间隔,单位为秒(默认是30秒)
    lease-renewal - interval - in- seconds : 1
    #Eureka服务端在收到最后一次心跳后等待时间上限, 单位为秒默认是90秒),超时将剔除服务
    lease - expir ation - durat ion- in- seconds: 2
    

    启动服务端
    图片

    说明自我保护机制已经关闭

    开启eureka客户端

    图片

    注册成功,关闭客户端,刷新服务端

    图片

    可以看到服务信息被删除了。

    7.eureka停更

    eureka在2.0以后不再更新,故如果要使用服务中心不推荐使用eureka,使用zookeeper或阿里的Nacos会比较好一些。

    图片

  • 相关阅读:
    关于data初始化值
    switch的优化替代写法
    phpstorm安装xdebug
    如何将一个列表封装为一个树形结构
    Win10系统桌面图标距离间距变大的问题
    cnpm无法加载文件的问题
    0、springboot
    1、springboot2新建web项目
    Game游戏分析
    netty学习
  • 原文地址:https://www.cnblogs.com/wf614/p/12919801.html
Copyright © 2020-2023  润新知