SpringCloud第二季1-搭建项目、Eureka、Zookeeper

版本的选择
查看SpringCloud和SpringBoot之间版本的依赖关系:

https://spring.io/projects/spring-cloud#overview
在这里插入图片描述

https://start.spring.io/actuator/info,返回详细json信息
在这里插入图片描述

首先连接下各个组件:

  1. 服务注册中心:EUREKA
  2. 服务负载均衡与调用:NETFLIX OSS RIBBON
  3. 服务负载与调用:NETTFLIX
  4. 服务熔断降级:HYSTRIX
  5. 服务网关:Zuul
  6. 服务分布式配置:SpringCloud Config
  7. 服务开发:SpingBoot

SpringCloud升级后,部分组件停用:
在这里插入图片描述

  1. Eureka 停用,可以使用 Zookeeper 作为服务注册中心
  2. 服务调用,Ribbon 准备停更,代替为 LoadBalance
  3. Feign 改为 OpenFeign
  4. Hystrix 停更,改为 resilence4j 或者阿里巴巴的 sentienl
  5. Zuul 改为 gateway
  6. 服务配置 Config 改为 Nacos
  7. 服务总线 Bus 改为 Nacos

技术要求:
java8+maven+git、github+Nginx+RabbitMQ+SpringBoot2.0

1、微服务cloud整体聚合父工程Project

接下来我们会搭建一个订单-支付模块微服务。

1、New Project
maven项目: maven-archetype-site
maven选自己本地的版本
2、字符编码
设置:Editor->File Encodings 里全部设置utf-8,native-to-ascii 打钩
3、注解生效激活
在这里插入图片描述
4、java编译版本选8
在这里插入图片描述
5、File Type过滤
在这里插入图片描述
6、安装插件
在这里插入图片描述

2、父工程POM

1、在pom.xml中 添加 pom
2、删除src文件夹
3、编写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>

    <groupId>com.atguigu.springcloud</groupId>
    <artifactId>cloud2020</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>pom</packaging>

    <!--统一管理jar包和版本-->
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <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>8.0.18</mysql.version>
        <druid.verison>1.1.16</druid.verison>
        <mybatis.spring.boot.verison>1.3.0</mybatis.spring.boot.verison>
    </properties>

    <!--子模块继承之后,提供作用:锁定版本+子module不用谢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.2.0.RELEASE</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <!-- MySql -->
            <dependency>
                <groupId>mysql</groupId>
                <artifactId>mysql-connector-java</artifactId>
                <version>${mysql.version}</version>
            </dependency>
            <!-- Druid -->
            <dependency>
                <groupId>com.alibaba</groupId>
                <artifactId>druid-spring-boot-starter</artifactId>
                <version>${druid.verison}</version>
            </dependency>
            <!-- mybatis-springboot整合 -->
            <dependency>
                <groupId>org.mybatis.spring.boot</groupId>
                <artifactId>mybatis-spring-boot-starter</artifactId>
                <version>${mybatis.spring.boot.verison}</version>
            </dependency>
            <!--lombok-->
            <dependency>
                <groupId>org.projectlombok</groupId>
                <artifactId>lombok</artifactId>
                <version>${lombok.version}</version>
            </dependency>
            <!--junit-->
            <dependency>
                <groupId>junit</groupId>
                <artifactId>junit</artifactId>
                <version>${junit.version}</version>
            </dependency>
            <!-- log4j -->
            <dependency>
                <groupId>log4j</groupId>
                <artifactId>log4j</artifactId>
                <version>${log4j.version}</version>
            </dependency>
        </dependencies>
    </dependencyManagement>
</project>

复习:Maven中的DependencyManagement和Dependencies

    <!--子模块继承之后,提供作用:锁定版本+子module不用谢groupId和version-->
    <dependencyManagement>
        <dependencies>

Maven使用dependencyManagement元素来提供了一种管理依赖版本号方式。
通常会在一个组织或者项目的最顶层中看到dependencyManagement元素。
使用pom.xml中的dependencyManagement元素的项目,然后它就会使用这个dependencyManagement元素中指定的版本号。

maven中跳过单元测试
在这里插入图片描述
发布到maven仓库
父工程创建完成执行mvn:install将父工程发布到仓库方便子工程继承

3、Rest微服务工程构建-订单支付模块

1、cloud-provider-payment8001

微服务模块:
  1. 建Model
  2. 写YML
  3. 主启动类
  4. 业务类
  5. 测试
1、新建子模块:

在这里插入图片描述

2、配置pom
    <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>
            <!--如果没写版本,从父层面找,找到了就直接用,全局统一-->
        </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>
3、写 application.yml
server:
  port: 8001

spring:
  application:
    name: cloud-payment-service
  datasource:
    # 当前数据源操作类型
    type: com.alibaba.druid.pool.DruidDataSource
    # mysql驱动类
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/cloud?useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=GMT%2B8
    username: root
    password: root

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

4、主启动 com.atguigu.springcloud
@SpringBootApplication
public class PaymentMain8001 {

    public static void main(String[] args) {
        SpringApplication.run(PaymentMain8001.class, args);
    }
}
5、业务类

1、建表sql

CREATE TABLE `payment`(
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'ID',
`serial` varchar(200) DEFAULT '',
PRIMARY KEY(`id`)
)ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8

2、entities

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Payment implements Serializable {
    private Long id;
    private String serial;
}
@Data
@AllArgsConstructor
@NoArgsConstructor
public class CommonResult<T> {
    // 404 not_found
    private Integer code;
    private String message;
    private T data;

    public CommonResult(Integer code, String message){
        this(code, message, null);
    }
}

3、dao

@Mapper
public interface PaymentDao {
    public int create(Payment payment);

    public Payment getPaymentById(@Param("id") Long id);
}

建文件夹 mapper
建mapper文件

<?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">

    <resultMap id="BaseResultMap" type="com.atguigu.springcloud.entities.Payment">
        <id column="id" property="id" jdbcType="BIGINT" />
        <id column="serial" property="serial" jdbcType="VARCHAR"/>
    </resultMap>

    <insert id="create" parameterType="Payment" useGeneratedKeys="true" keyProperty="id">
        insert into payment(serial) values(#{serial});
    </insert>

    <select id="getPaymentById" parameterType="Long" resultMap="BaseResultMap">
        select * from payment where id=#{id};
    </select>
</mapper>

4、service

public interface PaymentService {
    public int create(Payment payment);

    public Payment getPaymentById(@Param("id") Long id);
}
@Service
public class PaymentServiceImpl implements PaymentService {

    @Resource
    private PaymentDao paymentDao;

    @Override
    public int create(Payment payment) {
        return paymentDao.create(payment);
    }

    @Override
    public Payment getPaymentById(Long id) {
        return paymentDao.getPaymentById(id);
    }
}

5、controller

@RestController
@Slf4j
public class PaymentController {
    
    @Resource
    private PaymentService paymentService;
    
    @PostMapping(value = "/payment/create")
    public CommonResult create(@RequestBody Payment payment){
        int result = paymentService.create(payment);
        log.info("PaymentController create 插入结果 " + result);
        
        if(result > 0){
            return new CommonResult(200, "插入数据库成功", result);
        }else{
            return new CommonResult(444, "插入数据库失败");
        }
    }

    @GetMapping(value = "/payment/get/{id}")
    public CommonResult getPaymentById(@PathVariable("id") Long id){
        Payment payment = paymentService.getPaymentById(id);
        log.info("PaymentController getPaymentById 查询结果 " + payment);

        if(payment != null){
            return new CommonResult(200, "查询成功", payment);
        }else{
            return new CommonResult(444, "没有对应记录,查询ID:" + id);
        }
    }
}
6、运行代码

http://localhost:8001/payment/get/1
http://localhost:8001/payment/create?serial=aaa

2、cloud-consumer-order80

微服务模块:
  1. 建Model
  2. 写YML
  3. 主启动类
  4. 业务类
  5. 测试
1、新建子模块

在这里插入图片描述

2、配置POM
    <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.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、写 application.yml
server:
  port: 80
4、主启动类 com.atguigu.springcloud
@SpringBootApplication
public class OrderMain80 {

    public static void main(String[] args) {
        SpringApplication.run(OrderMain80.class, args);
    }
}
5、业务类

entities
复制entities包下的实体类
CommonResult
Payment

ApplicationContextConfig 配置

@Configuration
public class ApplicationContextConfig {

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

OrderController

@RestController
@Slf4j
@RequestMapping("/consumer")
public class OrderController {

    private static final String PAYMENT_URL = "http://localhost:8001";

    @Resource
    private RestTemplate restTemplate;

    @GetMapping("/payment/create")
    public CommonResult<Payment> create(Payment payment) {
        log.info("method create " + payment);
        return restTemplate.postForObject(PAYMENT_URL + "/payment/create", payment, CommonResult.class);
    }

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

http://localhost/consumer/payment/create?serial=abbb
http://localhost/consumer/payment/get/1

3、项目重构

1、新建子模块

cloud-api-commons
在这里插入图片描述

2、配置POM
    <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.3.10</version>
        </dependency>
    </dependencies>
3、打jar包

使用maven,将commone模块打包(install)

4、导jar包

在其他项目中引入这个jar包

        <!-- 引用自己定义的api通用包,可以使用Payment支付Entity -->
        <dependency>
            <groupId>com.atguigu.springcloud</groupId>
            <artifactId>cloud-api-commons</artifactId>
            <version>${project.version}</version>
        </dependency>

Eureka基础知识

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

服务注册与发现
Eureka采用了CS的设计架构,Eureka Server作为服务注册功能的服务器,它是服务注册中心,而系统中的其他微服务,使用Eureka的客户端连接到Eureka Server并维持心跳连接。这样系统的维护人员就可以通过Eureka Server来监控系统中各个微服务是否正常运行。
在服务注册与发现中有一个注册中心,档服务器启动的时候,会把当前自己服务器的信息 比如服务器地址、通信地址、等以别名方式注册到注册中心上。另一方(消费者 | 服务提供者),以该别名的方式去注册中心上获取到实际的服务器通讯地址,然后在实现本地RPC调用、RPC远程调用框架核心设计思想:在于注册中心。因为使用注册中心管理每个服务于服务之间的一个依赖关系(服务治理概念)。在任何RPC远程框架中,都会有一个注册中心存放服务地址相关信息。

Eureka包含了两个组件:

  • Eureka Server:提供注册服务,各个微服务节点会在其中进行注册。
  • Eureka Client:一个Java客户端,用于简化与Eureka Server 的交互,同时会定时向Eureka Server发送心跳,如果Eureka Server 在多个心跳周期内没有接收到某个节点的心跳则会将该节点移除。
    在这里插入图片描述

单机版eureka

1、新建子模块

cloud-eureka-server7001

2、配置POM

    <dependencies>
        <!--eureka server-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
        </dependency>
        <!--引入自己定义的api通用包,可以使用payment支付Entity-->
        <dependency>
            <groupId>com.atguigu.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>

3、写application.yml

server:
  port: 7001

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

4、主启动类

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

5、业务类

6、运行代码

访问 http://localhost:7001 就可以看到如下页面,可以看到当前没有服务注册进来
在这里插入图片描述

7、支付微服务8001入驻进eurekaServer

1、配置pom

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

2、写application.yml

spring:
  application:
    name: cloud-payment-service

eureka:
  client:
    # 不注册自己
    register-with-eureka: true
    # 表示自己是注册中心,不用检索服务
    fetch-registry: true
    service-url:
      defaultZone: http://localhost:7001/eureka

3、开启eureka服务

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

8、订单微服务80入驻进eurekaServer

1、配置pom

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

2、写application.yml

spring:
  application:
    name: cloud-order-service
    
eureka:
  client:
    # 不注册自己
    register-with-eureka: true
    # 表示自己是注册中心,不用检索服务
    fetch-registry: true
    service-url:
      defaultZone: http://localhost:7001/eureka

3、开启eureka服务

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

9、测试

访问 http://localhost:7001 可以看到程序被注册进euraka
访问 http://localhost/consumer/payment/get/1
在这里插入图片描述

Eureka集群原理

在这里插入图片描述
服务注册:将服务信息注册到注册中心
服务发现:从注册中心上获取到服务信息
其实质就是:key-value形式的。Key:服务的名字 value:服务调用地址

执行步骤:
1:先启动eureka注册中心
2:启动服务提供者(我们这里的服务提供者就是payment支付服务)
3:服务提供者在启动后会把自身的信息(如服务地址,以别名方式注册到)注册到eureka中
4:消费者(我们这里是order服务)在需要调用接口的时候,使用服务别名去注册中心获取到实际的RPC远程调用地址
5:消费者获取到调用地址后,底层实际是利用HttpClient技术实现远程调用的
6:消费者获得服务地址后会缓存在本地的JVM内存中,默认每隔30秒更新移除服务调用地址。

问题:微服务RPC远程调用最核心的是什么?
高可用。试想下,如果你的注册中心有且仅有一个 only One.那么,如果注册中心故障了,那就呵呵了,会导致整个服务的不可用。后果可是很严重的。所以,解决办法就是:搭建Eureka注册中心集群。实现负载均衡+故障容错(其实从上图中也可以看出,eureka server是多个,provider也是多个)

集群版eureka

1、建模

块 cloud-eureka-server7002
新建 cloud-eureka-server7002
复制 cloud-eureka-server7001的pom.xml
复制 cloud-eureka-server7001的application.yml
复制 Main.java 启动类

2、修改hosts文件

C:\Windows\System32\drivers\etc

127.0.0.1 eureka7001.com
127.0.0.1 eureka7002.com

3、修改7001和7002的application.yml

server:
  port: 7001

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

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

在这里插入图片描述

4、启动7001和7002

同时看到Eureka图标,且7001指着7002,7002指着7001,说明Eureka集群搭建成功。
在这里插入图片描述

5、payment 发布Eureka集群模式,payment支持集群模式

修改application.yml

eureka:
  client:
    # 不注册自己
    register-with-eureka: true
    # 表示自己是注册中心,不用检索服务
    fetch-registry: true
    service-url:
      defaultZone: http://eureka7001.com:7001/eureka,http://eureka7002.com:7002/eureka

在这里插入图片描述
修改PaymentController 访问返回端口

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

    @PostMapping(value = "/payment/create")
    public CommonResult create(@RequestBody Payment payment){
        log.info("method create " + payment);
        int result = paymentService.create(payment);
        log.info("PaymentController create 插入结果 " + result);

        if(result > 0){
            return new CommonResult(200, "插入数据库成功,serverPort:" + serverPort, result);
        }else{
            return new CommonResult(444, "插入数据库失败");
        }
    }

将payment8001模块复制 到 payment8002
在这里插入图片描述

6、order模块 发布到Eureka集群模式

开启@LoadBalanced注解,使RestTemplate开启负载均衡(可以指定负载均衡算法,默认轮询)

@Configuration
public class ApplicationContextConfig {

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

OrderController中接口访问,用服务器名的形式

public class OrderController {

    //private static final String PAYMENT_URL="http://localhost:8001";
    //通过在eureka上注册过的微服务名称调用
    private static final String PAYMENT_URL = "http://cloud-payment-service";

    @Resource
    private RestTemplate restTemplate;

    @GetMapping("/payment/create")
    public CommonResult<Payment> create(Payment payment) {
        log.info("method create " + payment);
        return restTemplate.postForObject(PAYMENT_URL + "/payment/create", payment, CommonResult.class);
    }

7、集群测试

访问 http://localhost/consumer/payment/get/1 多次执行后会轮询调用
{“code”:200,“message”:“查询成功,serverPort:8001”,“data”:{“id”:1,“serial”:“aaa”}}
{“code”:200,“message”:“查询成功,serverPort:8002”,“data”:{“id”:1,“serial”:“aaa”}}

8、自我保护

为什么有自我保护机制?
为了防止EurekaClient可以正常运行,但是与EurekaServer网络不同的情况下,将EurekaClient服务剔除。

自我保护模式

正常情况下,如果EurekaServer在一定时间内没有接收到某个微服务实例的心跳,就会注销该实例。
而自我保护模式就是某时刻某个微服务不可用了,Eureka不会立即进行清理,依旧会对该微服务的信息进行保存,属于CAP里面的AP分支(下文补充)。当EurekaServer节点在短时间内丢失过多客户端时(网络故障),节点就会进入自我保护模式。

自我保护模式配置
默认自我保护模式是开启的,可以通过配置进行禁用:

Eureka Server 端操作添加的配置:

#7001、7002 服务端配置
eureka:
  server:
    #关闭自我保护机制,保证不可用服务被及时剔除
    enable-self-preservation: false
    #清理无效节点的时间间隔,默认60000毫秒,即60秒 (此处时间间隔设置为2s)
    eviction-interval-timer-in-ms: 2000

Eureka Client 端操作添加的配置:

#8001、8002服务中配置
eureka:
  instance:
    # Eureka客户端向服务端发送心跳的时间间隔,单位为妙(默认是30s)
    lease-renewal-interval-in-seconds: 1
    # Eureka服务端在收到最后一次心跳后的等待时间上限,单位为秒(默认90s),超时将移除服务
    lease-expiration-duration-in-seconds: 2

Zookeeper

Zookeeper是一个分布式协调工具,可以实现注册中心功能,所以可以取代Eureka服务器,作为服务注册与发现中心。
为了方便我们接下来的测试,通过 Docker 方式在远程服务器上以单机形式安装 Zookeeper,并启动。
在这里插入图片描述

支付模块入驻zookeeper

1、新建子模块

cloud-provider-payment8004

2、配置POM

    <dependencies>
        <dependency><!-- 引用自己定义的api通用包,可以使用Payment支付Entity -->
            <groupId>com.atguigu.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>
        <!--SpringBoot整合Zookeeper客户端-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-zookeeper-discovery</artifactId>
            <exclusions>
                <!--先排除自带的zookeeper3.5.3-->
                <exclusion>
                    <groupId>org.apache.zookeeper</groupId>
                    <artifactId>zookeeper</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <!--添加zookeeper3.4.14版本-->
        <dependency>
            <groupId>org.apache.zookeeper</groupId>
            <artifactId>zookeeper</artifactId>
            <version>3.4.14</version>
            <exclusions>
                <exclusion>
                    <groupId>log4j</groupId>
                    <artifactId>log4j</artifactId>
                </exclusion>
                <exclusion>
                    <groupId>org.slf4j</groupId>
                    <artifactId>slf4j-log4j12</artifactId>
                </exclusion>
            </exclusions>
        </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、写application.yml

server:
  port: 8004

spring:
  application:
    name: cloud-provider-payment
  cloud:
    zookeeper:
      connect-string: localhost:2181

4、主启动类

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

5、业务类

@RestController
@Slf4j
public class PaymentController {

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

    @GetMapping("/payment/zk")
    public String paymentzk(){
        return "springcloud with zookeeper"+serverPort+"\t"+ UUID.randomUUID().toString();
    }
}

6、运行代码

http://localhost:8004/payment/zk

7、zookeeper版本不一致

修改pom依赖,排除3.5.3版本的,并引入3.4.14版本的

<!--springboot整合zookeeper客户端-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-zookeeper-discovery</artifactId>
            <!--先排除自带的zookeeper3.5.3-->
            <exclusions>
                <exclusion>
                    <groupId>org.apache.zookeeper</groupId>
                    <artifactId>zookeeper</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <!--添加zookeeper3.4.14版本-->
        <dependency>
            <groupId>org.apache.zookeeper</groupId>
            <artifactId>zookeeper</artifactId>
            <version>3.4.14</version>
        </dependency>

8、slf4j和log4j包冲突

排除zookeeper自带的log架包

<dependency>
	<groupId>org.apache.zookeeper</groupId>
    	<artifactId>zookeeper</artifactId>
        <version>3.4.14</version>
        <exclusions>
        	<exclusion>
            	<groupId>log4j</groupId>
                <artifactId>log4j</artifactId>
            </exclusion>
            <exclusion>
            	<groupId>org.slf4j</groupId>
                <artifactId>slf4j-log4j12</artifactId>
            </exclusion>
     </exclusions>
</dependency>

订单模块入驻zookeeper

1、新建子模块

cloud-consumerzk-order80

2、配置POM

    <dependencies>
        <!--springboot整合zookeeper客户端-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-zookeeper-discovery</artifactId>
            <!--排除自带的zookeeper-->
            <exclusions>
                <exclusion>
                    <groupId>org.apache.zookeeper</groupId>
                    <artifactId>zookeeper</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <!--添加zookeeper3.4.14版本-->
        <dependency>
            <groupId>org.apache.zookeeper</groupId>
            <artifactId>zookeeper</artifactId>
            <version>3.4.14</version>
            <exclusions>
                <exclusion>
                    <groupId>log4j</groupId>
                    <artifactId>log4j</artifactId>
                </exclusion>
                <exclusion>
                    <groupId>org.slf4j</groupId>
                    <artifactId>slf4j-log4j12</artifactId>
                </exclusion>
            </exclusions>
        </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-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、写application.yml

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

4、主启动类

@SpringBootApplication
@EnableDiscoveryClient
public class OrderZKMain80 {

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

5、业务类

@RestController
@Slf4j
public class OrderZKController {

    private static  final String INVOKE_URL = "http://cloud-provider-payment";

    @Resource
    private RestTemplate restTemplate;

    @GetMapping(value = "/consumer/payment/zk")
    public String paymentInfo() {
        String result = restTemplate.getForObject(INVOKE_URL+"/payment/zk",String.class);
        return result;
    }
}

6、运行代码

http://localhost/consumer/payment/zk

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值