Spring Cloud之服务注册

本文详细介绍了Spring Cloud服务注册的三种常见方式:Eureka、Zookeeper和Consul。从单机到集群,演示了服务提供者和消费者如何入驻各个注册中心,并探讨了Eureka的自我保护机制。最后,对比了三个注册中心在CAP原则下的异同点,强调了在分布式系统中选择的重要性。
摘要由CSDN通过智能技术生成

Spring Cloud之服务注册

一、入门

1.1、了解spring微服务

spring微服务文章原文spring cloud官网中文文档;

传统的单体架构:将项目写在一起,写完打war包,发布至tomcat或者其它容器中。

微服务架构:将一个单一的服务开发成多个模块,每个模块运行在单独的进程中,各个服务之间通过HTTP调用。

Spring Cloud:微服务工具包,为开发者提供了在分布式系统的配置管理、服务发现、断路器、智能路由、微代理、控制总线等开发工具包。

入门搭建的简单spring微服务架构还没有用到任何spring cloud的东西,后续会一点一点增加。

1.2、搭建spring cloud项目

创建新的maven项目,maven版本选择自己本机安装的maven,创建成功后打开idea设置,设置Java编译版本,设置字符集编码格式,设置忽略文件格式,设置maven版本。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">
    <modelVersion>4.0.0</modelVersion>

    <!--maven坐标-->
    <groupId>com.atguigu</groupId>
    <artifactId>springcloud</artifactId>
    <version>1.0-SNAPSHOT</version>
    <!--  父工程,pom -->
    <packaging>pom</packaging>

    <!--版本依赖,统一jar包管理-->
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.build.outputEncoding>UTF-8</project.build.outputEncoding>
        <java.version>1.8</java.version>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
        <junit.version>4.12</junit.version>
        <log4j.version>1.2.17</log4j.version>
        <lombok.version>1.16.18</lombok.version>
        <mysql.version>5.7.24</mysql.version>
        <druid.version>1.1.16</druid.version>
        <mybatis.spring.boot.version>1.3.0</mybatis.spring.boot.version>
    </properties>

    <name>Maven</name>
    <!-- FIXME change it to the project's website -->
    <url>http://maven.apache.org/</url>
    <inceptionYear>2001</inceptionYear>
    <!--用于父工程,子工程直接继承,锁定模块和子模块不用谢groupId和version-->
    <dependencyManagement>
        <!--这三个是微服务的标配-->
        <dependencies>
            <!--spring boot版本2.2.2-->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-dependencies</artifactId>
                <version>2.2.2.RELEASE</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <!--spring cloud Hoxton版本SR1-->
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>Hoxton.SR1</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <!--spring cloud alibaba版本2.1.0.RELEASE-->
            <dependency>
                <groupId>com.alibaba.cloud</groupId>
                <artifactId>spring-cloud-alibaba-dependencies</artifactId>
                <version>2.1.0.RELEASE</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <dependency>
                <groupId>mysql</groupId>
                <artifactId>mysql-connector-java</artifactId>
                <version>${mysql.version}</version>
            </dependency>
            <dependency>
                <groupId>com.alibaba</groupId>
                <artifactId>druid</artifactId>
                <version>${druid.version}</version>
            </dependency>
            <dependency>
                <groupId>org.mybatis.spring.boot</groupId>
                <artifactId>mybatis-spring-boot-starter</artifactId>
                <version>${mybatis.spring.boot.version}</version>
            </dependency>
        </dependencies>
    </dependencyManagement>
    <distributionManagement>
        <site>
            <id>website</id>
            <url>scp://webhost.company.com/www/website</url>
        </site>
    </distributionManagement>
            
    <build>
        <pluginManagement>
        <!-- lock down plugins versions to avoid using Maven defaults (may be moved to parent pom) -->
            <plugins>
                <plugin>
                    <artifactId>maven-clean-plugin</artifactId>
                    <version>3.1.0</version>
                </plugin>
                <plugin>
                    <artifactId>maven-site-plugin</artifactId>
                    <version>3.7.1</version>
                </plugin>
                <plugin>
                    <artifactId>maven-project-info-reports-plugin</artifactId>
                    <version>3.0.0</version>
                </plugin>
            </plugins>
        </pluginManagement>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-site-plugin</artifactId>
                <configuration>
                    <locales>en,fr</locales>
                </configuration>
            </plugin>
        </plugins>
    </build>
    <reporting>
        <plugins>
            <plugin>
                <artifactId>maven-project-info-reports-plugin</artifactId>
            </plugin>
        </plugins>
    </reporting>
</project>

dependencyManagement和dependencies区别:dependencyManagement是父类用的,用来规定依赖版本,子模块会自动继承父工程的版本,但是它只是限制规范不引入依赖,真正引入依赖的是GAV。

设置maven跳过单元测试,忽略版本检测,节约大量时间。点击install打包放入仓库,子工程好继承,build success为成功,clean测试整合结果。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-egcUvD16-1584764885660)(F:\Typora\Spring Cloud\基础\QQ截图20200318105341.png)]

1.3、建module子工程模块—服务提供者

建module,改pom,写yml,主启动,业务类,测试。

创建新的模块cloud-provider-payment8001,支付模块8001端口。在父工程右键创建新的模块,选择maven项目。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>springcloud</artifactId>
        <groupId>com.atguigu</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>
<!--不用G和V-->
    <artifactId>cloud-provider-payment8001</artifactId>

    <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>
        <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>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
        <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>

父工程的pom文件多出来两行

<modules>
   <module>cloud-provider-payment8001</module>
</modules>

yml文件创建:application.yml

server:
  port: 8001

spring:
  application:
    name: cloud-payment-service
  datasource:
    type: com.alibaba.druid.pool.DruidDataSource
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/db2019
    username: root
    password: 123456

mybatis:
  mapper-locations: classpath:mapper/*.xml
  type-aliases-package: com.atguigu.springcloud.entities

创建主启动类

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

controller层 注:service层dao层忽略

@RestController
@Slf4j
public class PaymentController {
    @Resource
    PaymentServiceImpl 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);
        }else {
            return new CommonResult(444,"插入失败",null);
        }
    }
    @GetMapping("/payment/get/{id}")
    public CommonResult getPaymentById(@PathVariable("id") Long id){
        Payment payment = paymentService.getPaymentById(id);
        log.info("插入结果:" + payment );
        if (payment != null){
            return new CommonResult(200,"查询成功",payment);
        }else {
            return new CommonResult(444,"查询失败,根据id:" + id,null);
        }
    }
}

mapper.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.atguigu.springcloud.dao.PaymentDao">
    <insert id="create" parameterType="Payment" useGeneratedKeys="true" keyProperty="id">
        insert into  payment(serial) values (#{serial});
    </insert>
    <resultMap id="BaseResultMap" type="com.atguigu.springcloud.entities.Payment">
        <id column="id" property="id" jdbcType="BIGINT" />
        <id column="serial" property="serial" jdbcType="VARCHAR" />
    </resultMap>
    <select id="getPaymentById" parameterType="Long" resultMap="BaseResultMap">
        select * from payment where id = #{id};
    </select>
</mapper>

开启Run Dashboard空间控制多个模块,新版本是services

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hC4nyvhN-1584764885662)(F:\Typora\Spring Cloud\基础\QQ截图20200318154036.png)]

1.4、建module子工程模块—服务消费者

大致过程与上述差不多,只不过此处controller要通过RestTemplate调用提供者模块,不需要service层和dao层。

注册RestTemplate

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

controller层:

@RestController
@Slf4j
public class OrderController {
    private static final String PAYMENT_URL="http://localhost:8001";
    @Resource
    private RestTemplate restTemplate;

    @GetMapping("/consumer/payment/create")
    public CommonResult create(Payment payment){
        return restTemplate.postForObject(PAYMENT_URL + "/payment/create",payment,CommonResult.class);
    }

    @GetMapping("/consumer/payment/get/{id}")
    public CommonResult<Payment> getPayment(@PathVariable("id") Long id){
        return restTemplate.getForObject(PAYMENT_URL + "/payment/get/" + id , CommonResult.class);
    }
}

1.5、项目重组

因为消费者、提供者所用的实体类都一样,所以可以抽取出来,新建module,打包放入仓库,然后消费者和提供者模块pom文件中引入。

新建项目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>springcloud</artifactId>
        <groupId>com.atguigu</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>
    <artifactId>cloud-api-commons</artifactId>
    <dependencies>
        <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>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>5.1.0</version>
        </dependency>
    </dependencies>
</project>

在模块中引用:

<dependency>
     <groupId>com.atguigu</groupId>
     <artifactId>cloud-api-commons</artifactId>
     <version>1.0-SNAPSHOT</version>
</dependency>

最后结构:[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Spb3ZjlA-1584764885664)(F:\Typora\Spring Cloud\基础\QQ截图20200318153743.png)]

二、服务注册与发现Eureka、Zookeeper、Consul

服务注册中心是微服务不可分离的一部分,现在能够做服务注册中心的有Eureka、Zookeeper、Consul、Nacos。没有服务注册中心时我们使用httpClient也就是上边用的restTemplate依旧能够实现服务调用,但是他们没有办法做到容错、发现、熔断、负载、降级等。

2.1 单机Eureka

C/S架构,三部分组成

Eureka Server :作为一个独立的部署单元,以 REST API 的形式为服务实例提供了注册、管理和查询等操作。同时,Eureka Server 也为我们提供了可视化的监控页面,可以直观地看到各个 Eureka Server 当前的运行状态和所有已注册服务的情况。

Service Provider:服务提供方,将自身服务注册到Eureka,从而使服务消费方能够找到

Service Consumer:服务消费方,从Eureka获取注册服务列表,从而能够消费服务

2.1.1建模块cloud-eureka-server7001

改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>springcloud</artifactId>
        <groupId>com.atguigu</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>
    <artifactId>cloud-eureka-server7001</artifactId>
    <dependencies>
        <!--自定义jar包-->
        <dependency>
            <groupId>com.atguigu</groupId>
            <artifactId>cloud-api-commons</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
        <!--eureka-server-->
        <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>
        <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>

写yml文件

server:
  port: 7001
#配置为Eureka的服务端-服务注册中心
eureka:
  instance:
    hostname: localhost   #eureka注册的服务端实例名
  client:
    register-with-eureka: false    #是否注册自己,false表示不注册
    fetch-registry: false   #自己就是注册中心,职责就是维护实例不需要检索服务。
    #设置uereka交互的地址,查询注册的服务
    service-url: 
      defaultZone: http//${eureka.instance.hostname}:${server.port}/eureka/

主启动

//表示这是eureka server端
@EnableEurekaServer
@SpringBootApplication
public class EurekaMain7001 {
    public static void main(String[] args) {
        SpringApplication.run(EurekaMain7001.class,args);
    }
}

访问http://localhost:7001/,显示eureka的主页面

2.1.2 Payment8001服务入驻

找到8001模块,添加eureka-client依赖。

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

修改yml文件,,添加如下配置

eureka:
  client:
    #表示是否将自己注册进eureka,false不入驻
    register-with-eureka: true
    #表示是否让eureka注册中心抓取自己信息,单点无所谓,集群必须是true
    fetch-registry: true
    service-url:
      defaultZone:  http://localhost:7001/eureka/

主启动类添加

@EnableEurekaClient

访问http://localhost:7001/,显示eureka的主页面,发现有服务注册进来。

#入住注册中心的服务名与这个保持一致
spring:
  application:
    name: cloud-payment-service
2.1.3 Order80服务入驻

细节如上,结果如下

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-og76QncE-1584764885671)(F:\Typora\Spring Cloud\基础\入驻2.png)]

2.2 集群Eureka,高可用

避免单机版eureka出现宕机情况,eureka server为注册中心,consumer server去取,实际上就是服务端存储K-V键值对。服务调用实际上根据服务名通过RPC进行远程调用。底层就是HTTP client。

在这里插入图片描述

集群原理:互相注册,相互守望,对外暴露一个整体。

2.2.1 建模块cloud-eureka-server7002 具体过程同7001

pom同7001,yml文件同7001,但是稍有变化,主启动类省略

改hosts文件加入,假装两台主机

127.0.0.1 eureka7001.com
127.0.0.1 eureka7002.com

yml文件,7001 7002都要改

server:
  port: 7002

#配置为Eureka的服务端-服务注册中心
eureka:
  instance:
    hostname: eureka7002.com   #eureka注册的服务端实例名,集群中不能同名为了区分
  client:
    register-with-eureka: false    #是否注册自己,false表示不注册
    fetch-registry: false   #自己就是注册中心,职责就是维护实例不需要检索服务。
    #设置uereka交互的地址,查询注册的服务
    service-url:
      defaultZone: http://eureka7001.com:7001/eureka/   #相互注册,2入驻1,1入驻2

http://eureka7001.com:7001/ 和http://eureka7002.com:7002/和http://localhost:7001/和http://localhost:7002/都能访问,且2指向1,1指向2

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gcHiLV9q-1584764885677)(F:\Typora\Spring Cloud\基础\集群3.png)]

2.2.2 服务入驻集群

只修改8001和80的yml文件即可

defaultZone:  http://eureka7002.com:7002/eureka/,http://eureka7001.com:7001/eureka/

2.3 支付服务8001集群创建

注册中心现在已经是集群模式,但是服务模块不是,将微服务模块也建成集群模式,那么高可用会大大加强。

新建cloud-provider-payment8002,建model,改pom,写yml,主启动,业务类

去改controller,便于区分来自哪个模块

@RestController
@Slf4j
public class PaymentController {
    @Resource
    PaymentServiceImpl paymentService;
    @Value("${server.port}")
    private String serverPort;
    @PostMapping("/payment/create")
    public CommonResult create(@RequestBody Payment payment){
        int result = paymentService.create(payment);
        log.info("插入结果:" + result );
        if (result >0){
            return new CommonResult(200,"插入成功,端口号:" + serverPort,result);

        }else {
            return new CommonResult(444,"插入失败,端口号:"+ serverPort,null);
        }
    }
    @GetMapping("/payment/get/{id}")
    public CommonResult getPaymentById(@PathVariable("id") Long id){
        Payment payment = paymentService.getPaymentById(id);
        log.info("插入结果:" + payment );
        if (payment != null){
            return new CommonResult(200,"查询成功,端口号:" + serverPort,payment);

        }else {
            return new CommonResult(444,"查询失败,根据id:" + id,null);
        }
    }
}

此时去改order80的controller,把写死的url改了

//传统
//private static final String PAYMENT_URL="http://localhost:8001";
//eureka集群时url不能写死,使用eureka中用的服务名
private static final String PAYMENT_URL = "http://CLOUD-PAYMENT-SERVICE";

还要去改80的ApplicationConfigure,开始RestTemplate负载均衡才行

@Configuration
public class ApplicationConfigure {
    //使用此注解,开始RestTemplate负载均衡才行
    @LoadBalanced
    @Bean
    public RestTemplate getRestTemplate(){
        return new RestTemplate();
    }
}

访问http://localhost/consumer/payment/get/1测试,发现实现了负载均衡

2.4 简单信息完善设置

2.4.1 主机名称修改

修改服务提供者8001 8002yml文件

eureka:	
	instance:
		instance-id:	payment01

http://localhost:8001/actuator/health,能查看服务状态

2.4.2 访问信息有IP信息提示

yml文件中添加

eureka:
  instance:
    #在eureka监控网页鼠标放上去显示IP地址
    prefer-ip-address: true
2.4.3 服务发现Discovery

在服务提供者的controller中注入DiscoveryClient

@Resource
DiscoveryClient discoveryClient;

2.5 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可能会不正确地提出索赔要求。 续订比阈值要少,因此仅出于安全性考虑,实例不会过期。

就是在eureka中注册的服务就算是不可用,eureka也不会注销服务,会保留你的信息。微服务CAP中的A(高可用)P(分支容错率)分支。高可用设计思想。默认eureka server端会收到eureka client端的心跳,就算是短期没有收到心跳,也不会删除服务的实例,可能因为网络拥堵导致假死。宁可保留所有微服务,也不会盲目删除服务。

在这里插入图片描述

怎么关闭自我保护机制,前往eureka的server端的yml文件设置:

eureka:
# 关闭自我保护机制 ,默认为true,是开启的,下边设置超时心跳时间,默认90秒,现在改为2秒
server:
  enable-self-preservation: false
  eviction-interval-timer-in-ms: 2000 

去服务提供模块也就是eureka client端添加yml

#客户端向服务端发送心跳的时间间隔,默认30秒
#    lease-renewal-interval-in-seconds: 30
#     服务端等待时间上限,超时将清除服务
#    lease-expiration-duration-in-seconds:

3. zookeeper

eureka停止更新了,怎么办?使用zookeeper代替,核心就是将eureka server替换为zookeeper。

关闭防火墙,启动zookeeper,

新建module cloud-provider-payment8004,改pom,写yml,主启动,业务类,

pom文件相比于8001只需要删去eureka client,加上zookeeper

<!--spring boot整合zookeeper-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-zookeeper-discovery</artifactId>
            <exclusions>
                <!--排除apache的zookeeper3.5.3-->
                <exclusion>
                    <groupId>org.apache.zookeeper</groupId>
                    <artifactId>zookeeper</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <!--添加和自己zookeeper版本相符合的jar-->
        <dependency>
            <groupId>org.apache.zookeeper</groupId>
            <artifactId>zookeeper</artifactId>
            <version>3.5.6</version>
            <!--排除sl4j-->
            <exclusions>
                <exclusion>
                    <groupId>org.slf4j</groupId>
                    <artifactId>slf4j-log4j12</artifactId>
                </exclusion>
            </exclusions>
        </dependency>

application.yml

server:
  port: 8004

#入住注册中心的服务名
spring:
  application:
    name: cloud-payment-service

#配置zookeeper
  cloud:
    zookeeper:
      #zookeeper的IP+端口号
      connect-string: 192.168.229.130:2181

主启动类

//必须加这个注解,开启服务发现
@EnableDiscoveryClient
@SpringBootApplication
public class Payment8004 {
    public static void main(String[] args) {
        SpringApplication.run(Payment8004.class,args);
    }
}

controller用于测试

@RestController
@Slf4j
public class PaymentController {
    @Value("${server.port}")
    private String serverPort;
    @RequestMapping("/payment/zk")
    public String paymentZk(){
        return "spring cloud with zookeeper:" + serverPort + "\t" + UUID.randomUUID().toString();
    }
}

启动zookeeper的 server和client

[root@localhost bin]# ./zkServer.sh start
ZooKeeper JMX enabled by default
Using config: /opt/software/myzookeeper/apache-zookeeper-3.5.6-bin/bin/../conf/zoo.cfg
Starting zookeeper ... STARTED

WatchedEvent state:SyncConnected type:None path:null
[zk: localhost:2181(CONNECTED) 0] 

查看zookeeper,发现有service成功入驻zookeeper,最后的json串是微服务的信息

[zk: localhost:2181(CONNECTED) 8] ls /
[dubbo, services, zookeeper]
[zk: localhost:2181(CONNECTED) 9] ls /services
[cloud-payment-service]
[zk: localhost:2181(CONNECTED) 10] ls /services/cloud-payment-service
[292ecc2f-177f-4c80-8ba8-29d7e13ac2d2]
[zk: localhost:2181(CONNECTED) 12] get /services/cloud-payment-service/292ecc2f-177f-4c80-8ba8-29d7e13ac2d2
{"name":"cloud-payment-service","id":"292ecc2f-177f-4c80-8ba8-29d7e13ac2d2","address":"localhost","port":8004,"sslPort":null,"payload":{"@class":"org.springframework.cloud.zookeeper.discovery.ZookeeperInstance","id":"application-1","name":"cloud-payment-service","metadata":{}},"registrationTimeUTC":1584613767722,"serviceType":"DYNAMIC","uriSpec":{"parts":[{"value":"scheme","variable":true},{"value":"://","variable":false},{"value":"address","variable":true},{"value":":","variable":false},{"value":"port","variable":true}]}}

json格式化后

{
	"name": "cloud-payment-service",
	"id": "292ecc2f-177f-4c80-8ba8-29d7e13ac2d2",
	"address": "localhost",
	"port": 8004,
	"sslPort": null,
	"payload": {
		"@class": "org.springframework.cloud.zookeeper.discovery.ZookeeperInstance",
		"id": "application-1",
		"name": "cloud-payment-service",
		"metadata": {}
	},
	"registrationTimeUTC": 1584613767722,
	"serviceType": "DYNAMIC",
	"uriSpec": {
		"parts": [{
			"value": "scheme",
			"variable": true
		}, {
			"value": "://",
			"variable": false
		}, {
			"value": "address",
			"variable": true
		}, {
			"value": ":",
			"variable": false
		}, {
			"value": "port",
			"variable": true
		}]
	}
}

问题来了,这是临时节点还是永久节点?服务节点是临时节点,如果挂了就没了,重启就再回来,只不过是一个新的了。

3.2订单入驻zookeeper

新建模块cloud-consumerZk-order80,具体如上,注意写RestTemplate配置

constroller

@Slf4j
@RestController
public class OrderController {
    @Resource
    private RestTemplate restTemplate;
    private static final String INVOKE_URL="http://cloud-payment-service" ;
    @GetMapping("/consumer/payment/zk")
    public String paymentinfo(){
        String result = restTemplate.getForObject(INVOKE_URL + "/payment/zk", String.class);
        return  result;
    }
}

访问:http://localhost/consumer/payment/zk测试

4. Consul

4.1什么是consul

Consul能够做服务注册与发现、健康检测、KV存储、多数据中心、可视化界面,如果不是AlibabaNacos的出现,他就是eureka的接班人Consul官网,下载地址,此处使用Windows版64位,下载之后直接解压就一个exe文件,此处1.6.1版本。

What is Consul?

Consul is a service mesh solution providing a full featured control plane with service discovery, configuration, and segmentation functionality. Each of these features can be used individually as needed, or they can be used together to build a full service mesh. Consul requires a data plane and supports both a proxy and native integration model. Consul ships with a simple built-in proxy so that everything works out of the box, but also supports 3rd party proxy integrations such as Envoy.

什么是Consul?

Consul是一种服务网格解决方案,提供具有服务发现,配置和分段功能的全功能控制平面。这些功能中的每一个都可以根据需要单独使用,也可以一起使用以构建完整的服务网格。领事需要数据平面,并支持代理和本机集成模型。Consul附带了一个简单的内置代理,因此一切都可以直接使用,还支持Envoy等第三方代理集成。

consul agent -dev       打开文件夹所在目录cmd窗口,通过命令运行
访问 http://localhost:8500访问

在这里插入图片描述

4.2 服务提供者cloud-provider-payment8006注册进去,建module,改pom,写yml,主启动,业务类。

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>springcloud</artifactId>
        <groupId>com.atguigu</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>cloud-provider-payment8006</artifactId>

    <dependencies>
        <!--consul-server-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-consul-discovery</artifactId>
        </dependency>
        <!--重组项目,抽取公共部分install仓库的jar包-->
        <dependency>
            <groupId>com.atguigu</groupId>
            <artifactId>cloud-api-commons</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
        <!--web和actuator算是组合jar包-->
        <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>
        <!-- spring boot热部署-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <!--Lombok-->
        <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>

yml

server:
  port: 8006
spring:
  application:
    name: consul-provider-payment
  cloud:
    consul:
      host: localhost
      discovery:
        service-name: ${spring.application.name}
      port: 8500

主启动

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

访问:http://localhost:8006/payment/consul测试,http://localhost:8500查看

在这里插入图片描述

4.3创建消费者cloud-consumerCs-order80,建module,改pom,写yml,主启动,业务类。

pom

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>springcloud</artifactId>
        <groupId>com.atguigu</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>cloud-consumerCs-order80</artifactId>

    <dependencies>
        <!--consul-server-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-consul-discovery</artifactId>
        </dependency>
        <!--重组项目,抽取公共部分install仓库的jar包-->
        <dependency>
            <groupId>com.atguigu</groupId>
            <artifactId>cloud-api-commons</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
        <!--web和actuator算是组合jar包-->
        <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>
        <!-- spring boot热部署-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <!--Lombok-->
        <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>

yml

server:
  port: 80
spring:
  application:
    name: consul-consumer-order
  cloud:
    consul:
      host: localhost
      discovery:
        service-name: ${spring.application.name}
      port: 8500

主启动

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

controller

@Slf4j
@RestController
public class OrderController {
    @Resource
    private RestTemplate restTemplate;
    private static final String INVOKE_URL="http://consul-provider-payment" ;

    @GetMapping("/consumer/payment/consul")
    public String paymentinfo(){

        String result = restTemplate.getForObject(INVOKE_URL + "/payment/consul", String.class);
        return  result;
    }
}

访问http://localhost/consumer/payment/consul,和http://localhost:8500查看

三个注册中心异同点

组件名语言CAP服务健康检查对外暴露接口spring cloud集成
eurekaJavaAP可以配置支持HTTP已集成
zookeeperJavaCP支持客户端已集成
consulGoCP支持HTTP/DNS已集成

CAP原则又称CAP定理,指的是在一个分布式系统中, Consistency(一致性)、 Availability(可用性)、Partition tolerance(分区容错性),三者不可得兼。

一致性(C):在分布式系统中的所有数据备份,在同一时刻是否同样的值。(等同于所有节点访问同一份最新的数据副本)

可用性(A):在集群中一部分节点故障后,集群整体是否还能响应客户端的读写请求。(对数据更新具备高可用性)

分区容忍性(P):以实际效果而言,分区相当于对通信的时限要求。系统如果不能在时限内达成数据一致性,就意味着发生了分区的情况,必须就当前操作在C和A之间做出选择。

CAP原则的精髓就是要么AP,要么CP,要么AC,但是不存在CAP。如果在某个分布式系统中数据无副本, 那么系统必然满足强一致性条件, 因为只有独一数据,不会出现数据不一致的情况,此时C和P两要素具备,但是如果系统发生了网络分区状况或者宕机,必然导致某些数据不可以访问,此时可用性条件就不能被满足,即在此情况下获得了CP系统,但是CAP不可同时满足 。

访问http://localhost/consumer/payment/consul,和http://localhost:8500查看

三个注册中心异同点

组件名语言CAP服务健康检查对外暴露接口spring cloud集成
eurekaJavaAP可以配置支持HTTP已集成
zookeeperJavaCP支持客户端已集成
consulGoCP支持HTTP/DNS已集成

CAP原则又称CAP定理,指的是在一个分布式系统中, Consistency(一致性)、 Availability(可用性)、Partition tolerance(分区容错性),三者不可得兼。

一致性(C):在分布式系统中的所有数据备份,在同一时刻是否同样的值。(等同于所有节点访问同一份最新的数据副本)

可用性(A):在集群中一部分节点故障后,集群整体是否还能响应客户端的读写请求。(对数据更新具备高可用性)

分区容忍性(P):以实际效果而言,分区相当于对通信的时限要求。系统如果不能在时限内达成数据一致性,就意味着发生了分区的情况,必须就当前操作在C和A之间做出选择。

CAP原则的精髓就是要么AP,要么CP,要么AC,但是不存在CAP。如果在某个分布式系统中数据无副本, 那么系统必然满足强一致性条件, 因为只有独一数据,不会出现数据不一致的情况,此时C和P两要素具备,但是如果系统发生了网络分区状况或者宕机,必然导致某些数据不可以访问,此时可用性条件就不能被满足,即在此情况下获得了CP系统,但是CAP不可同时满足 。

CAP关注的粒子颗度是数据,不是架构。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值