SpringCloud 服务的注册与发现

一、前言

        接下来是开展一系列的 SpringCloud 的学习之旅,从传统的模块之间调用,一步步的升级为 SpringCloud 模块之间的调用,此篇文章为第二篇,即使用服务注册和发现的组件,此篇文章会介绍 EurekaZookeeper Consul 分别作为注册中心的使用场景。

二、Eureka 服务注册与发现

2.1 Eureka 基础知识

2.1.1 什么是服务治理

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

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

2.1.2 什么是服务注册

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

        在服务注册与发现中,有一个注册中心。当服务器启动的时候,会把当前自己服务器的信息 比如服务地址通讯地址等以别名方式注册到注册中心上。另一方(消费者|服务提供者),以该别名的方式去注册中心上获取到实际的服务通讯地址,然后再实现本地 RPC 调用 RPC 远程调用。

        框架核心设计思想在于注册中心,因为使用注册中心管理每个服务与服务之间的一个依赖关系(服务治理概念)。在任何 rpc 远程框架中,都会有一个注册中心(存放服务地址相关信息(接口地址))。

2.1.3 Eureka 两组件

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

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

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

2.2 单机 Eureka 构建

2.2.1 修改支付模块

        修改 cloud-provider-payment8001 支付模块,使其成为 EurekaClient 端,并将其注册到 EurekaServer 端中,在 pom.xml 中,添加 eureka 客户端的依赖,如下:

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

        在 application.yml 中添加  eureka 的配置信息,如下:

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

        在启动类上添加 eureka 客户端的注解类,如下:

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

2.2.2 修改订单模块

        修改 cloud-consumer-order80 订单模块,使其成为 EurekaClient 端,并将其注册到 EurekaServer 端中,在 pom.xml 中,添加 eureka 客户端的依赖,如下:

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

        在 application.yml 中添加  eureka 的配置信息,如下:

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

        在启动类上添加 eureka 客户端的注解类,如下:

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

2.2.3 创建 Eureka7001 模块

        创建 cloud-eureka-server7001 模块,使其成为 eurekaServer 端服务注册中心,pom.xml 内容如下所示:

<?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"><modelVersion>4.0.0</modelVersion><parent><groupId>com.springcloud</groupId><artifactId>SpringCloud</artifactId><version>1.0-SNAPSHOT</version></parent><artifactId>cloud-eureka-server7001</artifactId><properties><maven.compiler.source>8</maven.compiler.source><maven.compiler.target>8</maven.compiler.target><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding></properties><dependencies><!--eureka-server--><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-eureka-server</artifactId></dependency><!-- 引入自己定义的api通用包,可以使用Payment支付Entity --><dependency><groupId>com.springcloud</groupId><artifactId>cloud-api-commons</artifactId><version>${project.version}</version></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><optional>true</optional></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency><dependency><groupId>junit</groupId><artifactId>junit</artifactId></dependency></dependencies>
</project>

        application.yml 的内容如下所示:

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

         启动类的代码如下所示,

package com.springcloud;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;@SpringBootApplication
// eureka 服务端的注解
@EnableEurekaServer
public class EurekaMain7001 {public static void main(String[] args){SpringApplication.run(EurekaMain7001.class,args);}
}

2.2.4 测试

        分别启动 cloud-provider-payment8001、cloud-consumer-order80  cloud-eureka-server7001 模块,在浏览器输入 http://localhost:7001,如下图,可以看到,注册成功了。

2.3 集群 Eureka 构建

2.3.1 原理说明

        服务注册:将服务信息注册进注册中心。

        服务发现:从注册中心上获取服务信息。实质上是存储的是 key valuekey 为服务名称,value 为服务地址。

2.3.2 微服务远程调用核心

        微服务 RPC 远程服务调用最核心的是什么?答案为高可用,假设你的注册中心只有一个,如果它发生故障,就会导致整个为服务环境不可用。解决办法是搭建 Eureka 注册中心集群,实现负载均衡 + 故障容错

2.3.3 创建 Eureka7002 模块

         创建 cloud-eureka-server7002 模块,使其成为 eurekaServer 端服务的第二个注册中心,pom.xml 内容如下所示:

<?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"><modelVersion>4.0.0</modelVersion><parent><groupId>com.springcloud</groupId><artifactId>SpringCloud</artifactId><version>1.0-SNAPSHOT</version></parent><artifactId>cloud-eureka-server7002</artifactId><properties><maven.compiler.source>8</maven.compiler.source><maven.compiler.target>8</maven.compiler.target><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding></properties><dependencies><!--eureka-server--><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-eureka-server</artifactId></dependency><!-- 引入自己定义的api通用包,可以使用Payment支付Entity --><dependency><groupId>com.springcloud</groupId><artifactId>cloud-api-commons</artifactId><version>${project.version}</version></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><optional>true</optional></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency><dependency><groupId>junit</groupId><artifactId>junit</artifactId></dependency></dependencies>
</project>

        启动类的代码如下所示,

package com.springcloud;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;@SpringBootApplication
// eureka 服务端的注解
@EnableEurekaServer
public class EurekaMain7002 {public static void main(String[] args){SpringApplication.run(EurekaMain7002.class,args);}
}

2.3.4 修改配置映射

        找到 C:\Windows\System32\drivers\etc 目录下的 hosts 文件,添加映射配置到 hosts 文件中,如下图:

2.3.5 修改 yml 文件

        修改 cloud-eureka-server7001 模块的 application.yml 文件,使其注册到 7002 服务端上,内容如下:

server:port: 7001eureka:instance:hostname: eureka7001.com # eureka服务端的实例名称client:# false 表示不向注册中心注册自己。register-with-eureka: false# false 表示自己端就是注册中心,我的职责就是维护服务实例,并不需要去检索服务fetch-registry: falseservice-url:# 三台节点的写法# defaultZone: http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/# 设置与 Eureka Server交互的地址查询服务和注册服务都需要依赖这个地址。defaultZone: http://eureka7002.com:7002/eureka/

        修改 cloud-eureka-server7002 模块的 application.yml 文件,使其注册到 7001 服务端上,内容如下:

server:port: 7002eureka:instance:hostname: eureka7002.com # eureka服务端的实例名称client:# false 表示不向注册中心注册自己。register-with-eureka: false# false 表示自己端就是注册中心,我的职责就是维护服务实例,并不需要去检索服务fetch-registry: falseservice-url:# 三台节点的写法# defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7003.com:7003/eureka/# 设置与 Eureka Server交互的地址查询服务和注册服务都需要依赖这个地址。defaultZone: http://eureka7001.com:7001/eureka/

2.3.6 测试

        启动 cloud-eureka-server7001 和 cloud-eureka-server7002 模块在浏览器访问下,如下图,可以看到,互相注册成功了。

2.3.7 将支付模块注册到集群

        将支付模块 cloud-provider-payment8001 发布到上面 2Eureka 集群配置中,修改该模块的 application.yml,内容如下所示:

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

2.3.8 将订单模块注册到集群

        将支付模块 cloud-consumer-order80 发布到上面 2Eureka 集群配置中,修改该模块的 application.yml,内容如下所示:

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

2.3.9 测试

        先启动 EurekaServer 7001 7002 服务,然后再启动服务提供者 payment8001 模块,最后再启动消费者 order80 模块,然后访问 EurekaServer 的管理界面,如下所示,可以看到两个模块均注册成功了。

        并且服务可以正常的提供调用服务,如下图:

2.3.10 构建支付模块集群

        现在的支付模块只有一个 cloud-provider-payment8001,如果它要是宕机了,整个系统也就无法提供服务了,所以我们需要构建支付模块的集群,新建一个子模块 cloud-provider-payment8002

        pom.xml 内容如下所示:

<?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"><modelVersion>4.0.0</modelVersion><parent><groupId>com.springcloud</groupId><artifactId>SpringCloud</artifactId><version>1.0-SNAPSHOT</version></parent><artifactId>cloud-provider-payment8002</artifactId><properties><maven.compiler.source>8</maven.compiler.source><maven.compiler.target>8</maven.compiler.target><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding></properties><dependencies><!--eureka-client--><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-eureka-client</artifactId></dependency><dependency><groupId>com.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.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></dependencies>
</project>

        application.yml 的内容如下所示:

server:port: 8001spring:application:name: cloud-payment-servicedatasource:type: com.alibaba.druid.pool.DruidDataSource            driver-class-name: org.gjt.mm.mysql.Driver             url: jdbc:mysql://localhost:3306/db2019?useUnicode=true&characterEncoding=utf-8&useSSL=falseusername: rootpassword: 123456
eureka:client:# 表示是否将自己注册进EurekaServer默认为true。register-with-eureka: true#是否从EurekaServer抓取已有的注册信息,默认为true。单节点无所谓,集群必须设置为true才能配合ribbon使用负载均衡fetchRegistry: trueservice-url:# defaultZone: http://localhost:7001/eurekadefaultZone: http://eureka7001.com:7001/eureka,http://eureka7002.com:7002/eureka  # 集群版mybatis:mapperLocations: classpath:mapper/*.xmltype-aliases-package: com.springcloud.entities    

        主启动类的内容如下所示:

package com.springcloud;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;@SpringBootApplication
@EnableEurekaClient
public class PaymentMain8082 {public static void main(String[] args) {SpringApplication.run(PaymentMain8082.class,args);}
}

        其他的业务类都从 cloud-provider-payment8001 模块粘贴即可,都是一样的代码。

        修改 cloud-provider-payment8001 模块的 PaymentController 代码,添加一些可以标识出调用信息出自哪个端口的代码,如下:

@RestController
@Slf4j
public class PaymentController {@Value("${server.port}")private String serverPort;@ResourcePaymentService paymentService;@PostMapping("/payment/create")public CommonResult create(@RequestBody Payment payment){int result = paymentService.create(payment);log.info("*****插入操作返回结果:" + result);if(result >0){return new CommonResult(200,"插入成功,返回结果"+result+"服务端口:"+serverPort,payment);}else{return new CommonResult(404,"插入失败",null);}}@GetMapping("/payment/get/{id}")public CommonResult<Payment> selectPaymentById(@PathVariable("id") Long id){Payment payment = paymentService.selectPaymentById(id);log.info("*****查询操作返回结果:" + payment);if(payment != null){int a =2;return new CommonResult(200,"查询成功"+"服务端口:"+serverPort,payment);}else{return new CommonResult(404,"未查询到数据"+id,null);}}
}

         修改 cloud-provider-payment8002 模块的 PaymentController 代码,添加一些可以标识出调用信息出自哪个端口的代码,如下:

@RestController
@Slf4j
public class PaymentController {@Value("${server.port}")private String serverPort;@ResourcePaymentService paymentService;@PostMapping("/payment/create")public CommonResult create(@RequestBody Payment payment){int result = paymentService.create(payment);log.info("*****插入操作返回结果:" + result);if(result >0){return new CommonResult(200,"插入成功,返回结果"+result+"服务端口:"+serverPort,payment);}else{return new CommonResult(404,"插入失败",null);}}@GetMapping("/payment/get/{id}")public CommonResult<Payment> selectPaymentById(@PathVariable("id") Long id){Payment payment = paymentService.selectPaymentById(id);log.info("*****查询操作返回结果:" + payment);if(payment != null){int a =2;return new CommonResult(200,"查询成功"+"服务端口:"+serverPort,payment);}else{return new CommonResult(404,"未查询到数据"+id,null);}}
}

        修改 cloud-consumer-order80 订单模块的 OrderController 类,因为以前这里面服务调用的地址是写死的,现在需要写上如下的地址

@RestController
@Slf4j
public class OrderController {@Resourceprivate RestTemplate restTemplate;// public static final String PaymentSrv_URL = "http://localhost:8001";public static final String PAYMENT_SRV = "http://CLOUD-PAYMENT-SERVICE";@GetMapping("/consumer/payment/create")public CommonResult create(Payment payment){// 客户端用浏览器是get请求,但是底层实质发送post调用服务端8001return restTemplate.postForObject(PAYMENT_SRV+"/payment/create",payment,CommonResult.class);}@GetMapping("/consumer/payment/get/{id}")public CommonResult getPayment(@PathVariable Long id){return restTemplate.getForObject(PAYMENT_SRV + "/payment/get/"+id, CommonResult.class, id);}
}

        修改 cloud-consumer-order80 订单模块的 ApplicationContextConfig 类,给 RestTemplate 添加负载均衡的能力,如下图:

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

        先启动 EurekaServer 7001 7002 服务,然后再启动服务提供者 payment8001 和 payment8002 模块,最后再启动消费者 order80 模块,然后调用方法进行测试,如下图:

2.4 actuator 微服务信息完善

2.4.1 服务名称修改

        访问 Eureka 的管理界面,可以看到里面包含了主机的名称,这个是我们不想要的,如下图:

        那么如何才能不显示我们的主机名称呢?只需要配置一些信息即可。修改 cloud-provider-payment8001 模块的 application.yml,内容如下所示:

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

        修改 cloud-provider-payment8002 模块的 application.yml,内容如下所示:

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

        重启这两个模块,然后刷新 Eureka 的管理界面,如下图,可以看到,不再显示我们的主机名称。

2.4.2 显示 ip 信息

        我们想实现当鼠标放到服务的名称上时显示 ip 信息,现在的效果如下所示:

         那么如何才能显示我们的 ip 信息呢?只需要配置一些信息即可。修改 cloud-provider-payment8001 模块的 application.yml,内容如下所示:

eureka:client:# 表示是否将自己注册进EurekaServer默认为true。register-with-eureka: true#是否从EurekaServer抓取已有的注册信息,默认为true。单节点无所谓,集群必须设置为true才能配合ribbon使用负载均衡fetchRegistry: trueservice-url:# defaultZone: http://localhost:7001/eurekadefaultZone: http://eureka7001.com:7001/eureka,http://eureka7002.com:7002/eureka  # 集群版instance:# 设置名称instance-id: payment8001# 访问路径可以显示IP地址prefer-ip-address: true     

        修改 cloud-provider-payment8002 模块的 application.yml,内容如下所示:

eureka:client:# 表示是否将自己注册进EurekaServer默认为true。register-with-eureka: true#是否从EurekaServer抓取已有的注册信息,默认为true。单节点无所谓,集群必须设置为true才能配合ribbon使用负载均衡fetchRegistry: trueservice-url:# defaultZone: http://localhost:7001/eurekadefaultZone: http://eureka7001.com:7001/eureka,http://eureka7002.com:7002/eureka  # 集群版instance:# 设置名称instance-id: payment8002# 访问路径可以显示IP地址prefer-ip-address: true   

        重启这两个模块,然后刷新 Eureka 的管理界面,如下图,可以看到,当鼠标放上去的时候会显示我们的 ip 地址信息。

2.5 服务发现 Discovery

        如果我们想获取在 Eureka 上注册的微服务的对外暴露信息,我们该如何获取呢?比如说主机名称、端口号等。其实对于注册进 Eureka 里面的微服务,可以通过服务发现来获得该服务的信息。

        修改 cloud-provider-payment8001 模块的 PaymentController 代码,内容如下所示:

@RestController
@Slf4j
public class PaymentController {@Value("${server.port}")private String serverPort;@ResourcePaymentService paymentService;@Resourceprivate DiscoveryClient discoveryClient;@PostMapping("/payment/create")public CommonResult create(@RequestBody Payment payment){int result = paymentService.create(payment);log.info("*****插入操作返回结果:" + result);if(result >0){return new CommonResult(200,"插入成功,返回结果"+result+"服务端口:"+serverPort,payment);}else{return new CommonResult(404,"插入失败",null);}}@GetMapping("/payment/get/{id}")public CommonResult<Payment> selectPaymentById(@PathVariable("id") Long id){Payment payment = paymentService.selectPaymentById(id);log.info("*****查询操作返回结果:" + payment);if(payment != null){int a =2;return new CommonResult(200,"查询成功"+"服务端口:"+serverPort,payment);}else{return new CommonResult(404,"未查询到数据"+id,null);}}// 对外提供一个获取服务的所有方法@GetMapping(value = "/payment/discovery")public Object discovery(){List<String> services = discoveryClient.getServices();for (String element : services) {System.out.println(element);}List<ServiceInstance> instances = discoveryClient.getInstances("CLOUD-PAYMENT-SERVICE");for (ServiceInstance element : instances) {System.out.println(element.getServiceId() + "\t" + element.getHost() + "\t" + element.getPort() + "\t"+ element.getUri());}return this.discoveryClient;}
}

         修改 cloud-provider-payment8002 模块的 PaymentController 代码,内容如下所示:

@RestController
@Slf4j
public class PaymentController {@Value("${server.port}")private String serverPort;@ResourcePaymentService paymentService;@Resourceprivate DiscoveryClient discoveryClient;@PostMapping("/payment/create")public CommonResult create(@RequestBody Payment payment){int result = paymentService.create(payment);log.info("*****插入操作返回结果:" + result);if(result >0){return new CommonResult(200,"插入成功,返回结果"+result+"服务端口:"+serverPort,payment);}else{return new CommonResult(404,"插入失败",null);}}@GetMapping("/payment/get/{id}")public CommonResult<Payment> selectPaymentById(@PathVariable("id") Long id){Payment payment = paymentService.selectPaymentById(id);log.info("*****查询操作返回结果:" + payment);if(payment != null){int a =2;return new CommonResult(200,"查询成功"+"服务端口:"+serverPort,payment);}else{return new CommonResult(404,"未查询到数据"+id,null);}}// 对外提供一个获取服务的所有方法@GetMapping(value = "/payment/discovery")public Object discovery(){List<String> services = discoveryClient.getServices();for (String element : services) {System.out.println(element);}List<ServiceInstance> instances = discoveryClient.getInstances("CLOUD-PAYMENT-SERVICE");for (ServiceInstance element : instances) {System.out.println(element.getServiceId() + "\t" + element.getHost() + "\t" + element.getPort() + "\t"+ element.getUri());}return this.discoveryClient;}
}

        修改 cloud-provider-payment8001 和 cloud-provider-payment8002 的启动类,分别加上注解,如下:

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

        重启所有的服务,然后输入 http://localhost:8001/payment/discovery ,进行测试,如下图:

2.6 Eureka 自我保护

2.6.1 故障现象

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

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

2.6.2 导致原因

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

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

        在自我保护模式中,Eureka Server 会保护服务注册表中的信息,不再注销任何服务实例。它的设计哲学就是宁可保留错误的服务注册信息,也不盲目注销任何可能健康的服务实例。一句话讲解:好死不如赖活着。

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

2.6.3 禁止自我保护

        首先自我保护机制是默认开启的,可以通过配置来关闭这个机制,修改 cloud-eureka-server7001application.yml 配置文件,如下:

eureka:instance:hostname: eureka7001.com # eureka服务端的实例名称client:# false 表示不向注册中心注册自己。register-with-eureka: false# false 表示自己端就是注册中心,我的职责就是维护服务实例,并不需要去检索服务fetch-registry: falseservice-url:# 设置与 Eureka Server交互的地址查询服务和注册服务都需要依赖这个地址。defaultZone: http://eureka7002.com:7002/eureka/server:# 关闭自我保护机制,保证不可用服务被及时踢除enable-self-preservation: false# 时间间隔调整为 2seviction-interval-timer-in-ms: 2000

        cloud-eureka-server7002 也是如此配置,这里不再赘述。接下来修改 cloud-provider-payment8001 application.yml 配置文件,如下:

eureka:client:# 表示是否将自己注册进EurekaServer默认为true。register-with-eureka: true#是否从EurekaServer抓取已有的注册信息,默认为true。单节点无所谓,集群必须设置为true才能配合ribbon使用负载均衡fetchRegistry: trueservice-url:# defaultZone: http://localhost:7001/eurekadefaultZone: http://eureka7001.com:7001/eureka,http://eureka7002.com:7002/eureka  # 集群版# 心跳检测与续约时间# 开发时设置小些,保证服务关闭后注册中心能即使剔除服务instance:# 设置名称instance-id: payment8001# 访问路径可以显示IP地址prefer-ip-address: true# Eureka客户端向服务端发送心跳的时间间隔,单位为秒(默认是30秒)lease-renewal-interval-in-seconds: 1# Eureka服务端在收到最后一次心跳后等待时间上限,单位为秒(默认是90秒),超时将剔除服务lease-expiration-duration-in-seconds: 2

        cloud-provider-payment8002 也是如此配置,这里不再赘述。 

2.6.4 测试

        分别重启各个服务,然后手动停止 cloud-provider-payment8001 服务,如下图:

三、Zookeeper 服务注册与发现

3.1 Eureka 停止更新

        自从 2018 年后,Eureka 就停止了更新,如下图:

3.2 Zookeeper 代替 Eureka

3.2.1 zookeeper 简介

        zookeeper 是一个分布式协调工具,可以实现注册中心功能。可以使用 zookeeper 服务器取代 Eureka 服务器,zk 作为服务注册中心。

        使用的前提是需要在 linux 服务器上安装 zookeeper,具体按照的步骤,可以参考我的这篇文章,这里不再赘述,记得把 linux 服务器的防火墙先关掉。

3.2.2 创建服务提供者

        创建 cloud-provider-payment8004 模块作为服务的提供者,pom.xml 的内容如下所示:

<?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"><modelVersion>4.0.0</modelVersion><parent><groupId>com.springcloud</groupId><artifactId>SpringCloud</artifactId><version>1.0-SNAPSHOT</version></parent><artifactId>cloud-provider-payment8004</artifactId><properties><maven.compiler.source>8</maven.compiler.source><maven.compiler.target>8</maven.compiler.target><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding></properties><dependencies><!-- SpringBoot整合Web组件 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><!-- 引入自己定义的api通用包,可以使用Payment支付Entity --><groupId>com.springcloud</groupId><artifactId>cloud-api-commons</artifactId><version>${project.version}</version></dependency><!-- SpringBoot整合zookeeper客户端 --><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-zookeeper-discovery</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>
</project>

        application.yml 的内容如下所示:

# 8004表示注册到zookeeper服务器的支付服务提供者端口号
server:port: 8004
#服务别名----注册zookeeper到注册中心名称
spring:application:name: cloud-provider-paymentcloud:zookeeper:connect-string: 192.168.229.167:2181

        主启动类的内容如下所示:

@SpringBootApplication
// 该注解用于向使用consul或者zookeeper作为注册中心时注册服务
@EnableDiscoveryClient 
public class PaymentMain8004 {public static void main(String[] args){SpringApplication.run(PaymentMain8004.class,args);}}

        创建一个 Controller 类,内容如下所示:

package com.springcloud.controller;import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.beans.factory.annotation.Value;import java.util.UUID;@RestController
public class PaymentController
{@Value("${server.port}")private String serverPort;@RequestMapping(value = "/payment/zk")public String paymentzk(){return "springcloud with zookeeper: "+serverPort+"\t"+ UUID.randomUUID().toString();}
}

        启动工程进行测试,如下:

3.2.3 注意

        此时方式创建的 zookeeper 节点为临时节点,当关闭微服务模块后,节点一会就自动消失了

3.2.4 创建服务消费者

        创建 cloud-consumerzk-order80 模块作为服务的提供者,pom.xml 的内容如下所示:

<?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"><modelVersion>4.0.0</modelVersion><parent><groupId>com.springcloud</groupId><artifactId>SpringCloud</artifactId><version>1.0-SNAPSHOT</version></parent><artifactId>cloud-consumer-order80</artifactId><properties><maven.compiler.source>8</maven.compiler.source><maven.compiler.target>8</maven.compiler.target><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding></properties><dependencies><!--eureka-client--><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-eureka-client</artifactId></dependency><dependency><groupId>com.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>
</project>

        application.yml 内容如下所示:

server:port: 80spring:application:name: cloud-consumer-ordercloud:# 注册到zookeeper地址zookeeper:connect-string: 192.168.229.167:2181

        主启动类的内容如下所示:

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

        配置类的代码如下所示:

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

        Controller 的代码如下所示:

@RestController
public class OrderZKController
{public static final String INVOKE_URL = "http://cloud-provider-payment";@Autowiredprivate RestTemplate restTemplate;@RequestMapping(value = "/consumer/payment/zk")public String paymentInfo(){String result = restTemplate.getForObject(INVOKE_URL+"/payment/zk", String.class);System.out.println("消费者调用支付服务(zookeeper)--->result:" + result);return result;}}

        启动服务进行验证,可以在 zookeeper 看到注册的节点,如下图:

         还可以进行接口调用,如下图:

四、Consul 服务注册与发现

4.1 Consul 简介

4.1.1 Consul 是什么

        HashiCorp Consul 是一种服务网络解决方案,使团队能够管理服务之间以及跨本地和多云环境和运行时的安全网络连接。 Consul 提供服务发现、服务网格、流量管理和网络基础设施设备的自动更新。您可以在单个 Consul 部署中单独或一起使用这些功能。

4.1.2 Consul 用途

        1、服务发现,提供 HTTPDNS 两种发现方式。

        2、健康监测,支持多种方式,HTTPTCPDockerShell 脚本定制化监控

        3、KV 存储

        4、支持多数据中心

        5、可视化 Web 界面

4.1.3 Consul 下载

        现在地址在这,选择适合的版本,如下图:

        下载完成后解压,如下图,双击安装包即可运行

4.1.4 Consul 使用

        进入 consul.exe 目录的 cmd 命令行模式下,输入 consul --version 即可查看版本信息,如下图:

        输入 consul agent -dev 使用开发者模式启动,如下图:

        启动成功后,在浏览器输入 http://localhost:8500 即可访问 Consul 的首页信息,如下图:

4.2 创建服务提供者

        新建支付模块 cloud-providerconsul-payment8006pom.xml 内容如下所示:

<?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"><modelVersion>4.0.0</modelVersion><parent><groupId>com.springcloud</groupId><artifactId>SpringCloud</artifactId><version>1.0-SNAPSHOT</version></parent><artifactId>cloud-provider-payment8006</artifactId><properties><maven.compiler.source>8</maven.compiler.source><maven.compiler.target>8</maven.compiler.target><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding></properties><dependencies><!--SpringCloud consul-server --><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-consul-discovery</artifactId></dependency><!-- SpringBoot整合Web组件 --><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><!--日常通用jar包配置--><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></project>

        application.yml 内容如下所示:

# consul服务端口号
server:port: 8006spring:application:name: consul-provider-payment####consul注册中心地址cloud:consul:host: localhostport: 8500discovery:#hostname: 127.0.0.1service-name: ${spring.application.name}

        主启动类代码如下所示:

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

         业务类 Controller 代码如下所示:

@RestController
public class PaymentController {@Value("${server.port}")private String serverPort;@GetMapping("/payment/consul")public String paymentInfo(){return "springcloud with consul: "+serverPort+"\t\t"+ UUID.randomUUID().toString();}
}

        启动工程,打开 Consul 的管理界面,可以看到,微服务注册成功了,如下图:

4.3 创建服务消费者

         新建支付模块 cloud-consumerconsul-order80pom.xml 内容如下所示:

<?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"><modelVersion>4.0.0</modelVersion><parent><groupId>com.springcloud</groupId><artifactId>SpringCloud</artifactId><version>1.0-SNAPSHOT</version></parent><artifactId>cloud-consumerconsul-order80</artifactId><properties><maven.compiler.source>8</maven.compiler.source><maven.compiler.target>8</maven.compiler.target><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding></properties><dependencies><!--SpringCloud consul-server --><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-consul-discovery</artifactId></dependency><!-- SpringBoot整合Web组件 --><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><!--日常通用jar包配置--><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></project>

        application.yml 内容如下所示:

# consul服务端口号
server:port: 80spring:application:name: cloud-consumer-order####consul注册中心地址cloud:consul:host: localhostport: 8500discovery:#hostname: 127.0.0.1service-name: ${spring.application.name}

        主启动类代码如下所示:

@SpringBootApplication
// 该注解用于向使用consul或者zookeeper作为注册中心时注册服务
@EnableDiscoveryClient 
public class OrderConsulMain80
{public static void main(String[] args){SpringApplication.run(OrderConsulMain80.class,args);}
}

         业务类 Controller 代码如下所示:

@RestController
public class OrderConsulController
{public static final String INVOKE_URL = "http://consul-provider-payment"; @Autowiredprivate RestTemplate restTemplate;@GetMapping(value = "/consumer/payment/consul")public String paymentInfo(){String result = restTemplate.getForObject(INVOKE_URL+"/payment/consul", String.class);System.out.println("消费者调用支付服务(consule)--->result:" + result);return result;}
}

        配置类代码如下:

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

         启动工程,打开 Consul 的管理界面,可以看到,微服务注册成功了,如下图:

        输入 http://localhost/consumer/payment/consul,进行测试,如下图:

五、三个注册中心对比

5.1 CAP 简介

        C:Consistency 的缩写,表示强一致性

        A:Availability 的缩写,表示可用性

        PPartition tolerance 的缩写,表示分区容错性

5.2 经典 CAP 图

        CAP 理论关注粒度是数据,而不是整体系统设计的策略。

        CAP 理论的核心是:一个分布式系统不可能同时很好的满足一致性,可用性和分区容错性这三个需求,因此,根据 CAP 原理将 NoSQL 数据库分成了满足 CA 原则、满足 CP 原则和满足 AP 原则三大类,如下,其实在实际的环境中最多只能同时较好的满足两个。

        CA - 单点集群,满足一致性,可用性的系统,通常在可扩展性上不太强大。

        CP - 满足一致性,分区容忍必的系统,通常性能不是特别高。

         AP - 满足可用性,分区容忍性的系统,通常可能对一致性要求低一些       

5.3 AP 架构(Eureka)

        当网络分区出现后,为了保证可用性,系统 B 可以返回旧值,保证系统的可用性。违背了一致性 C 的要求,只满足可用性和分区容错,即 AP,如下图:

5.4 CP 架构(Zookeeper/Consul)

        当网络分区出现后,为了保证一致性,就必须拒接请求,否则无法保证一致性,违背了可用性 A 的要求,只满足一致性和分区容错,即 CP,如下图:

5.5 三个注册中心比较

组件名语言CAP健康服务检查对外暴露接口SpringCloud 集成
EurekaJavaAP可配支持HTTP已集成
ConsulgoCP支持HTTP/DNS已集成
ZookeeperJavaCP支持客户端已集成

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/729008.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

环境音效生成器Moodist

什么是 Moodist &#xff1f; Moodist 是免费、开源的环境音效生成器。拥有 54 种精选的音效&#xff0c;轻松为专注或放松创建自定义混合音效。无需账户&#xff0c;无需繁琐操作&#xff0c;尽享纯净宁静。探索大自然的宁静和城市的韵律。在 Moodist 中提升你的氛围&#xff…

Node 旧淘宝源 HTTPS 过期处理

今天拉取老项目更新依赖&#xff0c;出现 urlshttps%3A%2F%2Fregistry.npm.taobao.org%2Fegg-logger%2Fdownload%2Fegg-logger-2.6.1.tgz: certificate has expired 类似报错。即使删除 node_modules 重新安装&#xff0c;问题依然无法解决。 一、问题演示 二、原因分析 1、淘…

平台工程指南:从架构构建到职责分工

平台工程只是 DevOps 专业化的另一个术语&#xff0c;还是另有所指&#xff1f;事实可能介于两者之间。DevOps 及其相关的 DevXOps 有着浓厚的文化色彩&#xff0c;以各个团队为中心。不幸的是&#xff0c;在许多地方&#xff0c;DevOps 引发了新的问题&#xff0c;如工具激增和…

【云原生】kubeadm快速搭建K8s集群Kubernetes1.19.0

目录 一、 Kubernetes 的概述 二、服务器配置 2.1 服务器部署规划 2.2服务器初始化配置 三、安装Docker/kubeadm/kubelet【所有节点】 3.1 安装Docker 3.2 添加阿里云YUM软件源 3.3 安装kubeadm&#xff0c;kubelet和kubectl 四、部署Kubernetes Master 五、部署Kube…

网络入侵检测系统之Suricata(十四)--匹配流程

其实规则的匹配流程和加载流程是强相关的&#xff0c;你如何组织规则那么就会采用该种数据结构去匹配&#xff0c;例如你用radix tree组织海量ip规则&#xff0c;那么匹配的时候也是采用bit test确定前缀节点&#xff0c;然后逐一左右子树查询&#xff0c;Suricata也是如此&…

基于Spring Boot的图书个性化推荐系统 ,计算机毕业设计(带源码+论文)

源码获取地址&#xff1a; 码呢-一个专注于技术分享的博客平台一个专注于技术分享的博客平台,大家以共同学习,乐于分享,拥抱开源的价值观进行学习交流http://www.xmbiao.cn/resource-details/1765769136268455938

Doris实战——特步集团零售数据仓库项目实践

目录 一、背景 二、总体架构 三、ETL实践 3.1 批量数据的导入 3.2 实时数据接入 3.3 数据加工 3.4 BI 查询 四、实时需求响应 五、其他经验 5.1 Doris BE内存溢出 5.2 SQL任务超时 5.3 删除语句不支持表达式 5.4 Drop 表闪回 六、未来展望 原文大佬的这篇Doris数…

离散数学——(3)联结词及对应的真值指派,最小全功能联结词集,对偶式,范式,范式存在定理,小项

目录 1.联结词及对应的真值指派 2.最小全功能联结词集 3.对偶式 4.范式 1.析取范式 5.范式存在定理 6.小项 1.联结词及对应的真值指派 2.最小全功能联结词集 3.对偶式 4.范式 1.析取范式 5.范式存在定理 6.小项

hfish蜜罐搭建与使用

本次是对自己在学习蓝队过程中的一次对安全设备 hfish蜜罐的搭建和使用考核记录,距离之前已 经过去很久了,对之前在考核过程中的操作进行回顾和总结. 蜜罐在这里我进行免费分享 hfish-3.1.4-windows-amd64.zip官方版下载丨最新版下载丨绿色版下载丨APP下载-123云…

Visual Studio如何进行类文件的管理(类文件的分离)

大家好&#xff1a; 衷心希望各位点赞。 您的问题请留在评论区&#xff0c;我会及时回答。 一、问题背景 实际开发中&#xff0c;类的声明放在头文件中&#xff0c;给程序员看类的成员和方法。比如&#xff1a;Dog.h&#xff08;类的声明文件&#xff09; 类的成员函数的具体…

继承,切片,隐藏

定义&#xff1a; 子类&#xff08;派生类&#xff09;继承了父类&#xff08;基类&#xff09;的成员函数和成员变量&#xff08;类层次的复用&#xff09; 赋值 子类可以赋值给父类。父类不可以直接复制给子类 &#xff08;不像不同内置类型的赋值要转化为临时变量&#xf…

U盘上文件夹突然空了?掌握3个方法,轻松找回数据!

“我的u盘插上之后&#xff0c;不知道为什么就空了&#xff0c;里面所有的文件都没有了&#xff0c;有什么方法可以找回u盘里丢失的文件吗&#xff1f;” 在日常使用U盘的过程中&#xff0c;我们有时会遇到一个令人头疼的问题&#xff0c;U盘上的文件夹突然空了。这究竟是怎么回…

Windows系统安装MongoDB并结合内网穿透实现公网访问本地数据库

文章目录 前言1. 安装数据库2. 内网穿透2.1 安装cpolar内网穿透2.2 创建隧道映射2.3 测试随机公网地址远程连接 3. 配置固定TCP端口地址3.1 保留一个固定的公网TCP端口地址3.2 配置固定公网TCP端口地址3.3 测试固定地址公网远程访问 前言 MongoDB是一个基于分布式文件存储的数…

DHCP部署与安全

在当今快速发展的网络世界中&#xff0c;动态主机配置协议&#xff08;DHCP&#xff09;扮演着至关重要的角色。这项技术不仅简化了网络管理&#xff0c;还提高了网络资源的利用率。本文旨在深入探讨DHCP的工作原理、优势以及如何有效部署和保护DHCP服务器。 一、DHCP作用 自…

Flutter的线程模型

在Flutter框架中&#xff0c;Embedder层负责把Flutter嵌入到各个平台上去&#xff0c;其所做的主要工作包括线程设置、渲染Surface设置&#xff0c;以及插件等。因此&#xff0c; Embedder负责线程的创建和管理&#xff0c;并且提供Task Runner给Engine使用。Engine则是负责提供…

Mysql深入学习 基础篇 Ss.05多表查询语法及案例

世界总是在推着我走&#xff0c;我自己一个人也能站稳 —— 24.3.7 一、多表关系 1.概述 项目开发中&#xff0c;在进行数据库表结构设计时&#xff0c;会根据业务需求及业务模块之间的关系&#xff0c;分析并设计表结构&#xff0c;由于业务之间相互关联&#xff0c;所以各个…

Croissant:Google新推出的一个为机器学习准备的数据集元数据格式

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗&#xff1f;订阅我们的简报&#xff0c;深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同&#xff0c;从行业内部的深度分析和实用指南中受益。不要错过这个机会&#xff0c;成为AI领…

【易飞】易飞ERP自动审核程序功能

易飞ERP自动审核程序功能 一、 使用场景二、 操作说明三、 安装方式 一、 使用场景 OA系统集成 与第三方OA系统软件集成&#xff0c;在OA软件审核完成后&#xff0c;直接将ERP中的单据审核。MES系统集成 MES系统生成单据写入到易飞ERP中&#xff0c;并需要自动审核单据&#x…

如何学习、上手点云算法(三):用VsCode、Visual Studio来debug基于PCL、Open3D的代码

写在前面 本文内容 以PCL 1.14.0&#xff0c;Open3D0.14.1为例&#xff0c;对基于PCL、Open3D开发的代码进行源码debug&#xff1b; 如何学习、上手点云算法系列&#xff1a; 如何学习、上手点云算法(一)&#xff1a;点云基础 如何学习、上手点云算法(二)&#xff1a;点云处理相…

跟无神学AI之Tensorflow笔记搭建网络八股

虽然Pytorch在论文中使用较多&#xff0c;但是像Alphafold在蛋白质结构预测的模型&#xff0c;仍然是用Tensorflow写成&#xff0c;遂近期在学其中的语法。 本系列来自慕课北大软微曹健老师的Tensorflow笔记&#xff0c;摘选其中重要部分。 1.导包 2.定义训练集测试集和数据…