锐单电子商城 , 一站式电子元器件采购平台!
  • 电话:400-990-0325

SpringCloud 笔记

时间:2022-10-20 11:00:00 zh1032d胀差变送器装置c2h4变送器

SpringCloud
SpringCloud
笔记版本
编码构建微服务架构
IDEA 创建 Project 工作空间
微服务 Cloud 父工程整体聚合 Project
New Project
聚合总父工程名称
Maven选版本
字符编码
注意生效激活
Java 编译版本
父工程 pom
REST 微服务构建
微服务提供商支付 Module 模块
创建 cloud-provider-payment8001 模块
修改 pom 文件
application.yaml
主启动
业务类
建表SQL
entity
mapper
service
controller
热部署 Devtools
添加 Devtools 依赖
修改父工程 pom.xml 文件
修改 IDEA 设置
更新值
微服务消费者订单 Module 模块
创建 cloud-consumer-order81 模块
修改 pom.xml 文件
application.yaml
主启动
业务类
entity
RestTemplate
ApplicationContextConfig
controller
工程重构
观察问题
新建公共工程
修改 pom.xml 文件
写公共部分
maven 打包
81和8001端口服务改造
目前工程样图
Eureka 注册和发现服务
概述
单机 Eureka 构建步骤
创建 EurekaServer 服务注册中心
创建 Module
修改 pom.xml
主启动
application.yaml
测试
注册8001端口服务 EurekaServer 成为服务提供商 provider
修改 pom.xml
修改 application.yaml
修改主启动类
测试
注册81端口服务 EurekaServer 为消费者服务consumer
修改 pom.xml
修改 application.yaml
修改主启动类
测试
集群 Eureka 构建步骤
EurekaServer建设集群环境的步骤
创建 Module
修改 pom.xml
主启动
修改映射配置
application.xml
7001
7002
测试
8001微服务发布 Eureka 集群中
application.yaml
发布81微服务 Eureka 集群中
application.yaml
测试
8001集群环境建设
创建 Module
修改 pom.xml
application.xml
主启动
业务类
修改8001/8002的Controller
测试
问题
负载均衡
修改81服务 Controller
赋予 RestTemplate 负载平衡能力
actuator 完善微服务信息
修改服务名称
IP 信息提示
服务发现 Discovery
修改8001的 Controller
修改8001主启动类
日志打印
Eureka 自我保护
概述
故障现象
导致原因
关闭自我保护
修改7001的 application.yaml
效果
修改8001的 application.yaml
测试
Consul 注册和发现服务
Consul 简介
概述
Spring Cloud Consul 特性
下载地址
官方文档
安装并运行 Consul
服务提供者
新建 Module 支付服务 provider8006
POM
YAML
主启动
Controller
测试
服务消费者
新建 Module 消费服务 order81
POM
YAML
主启动
配置 Bean
Controller
测试
Ribbon 调用负载均衡服务
概述
Ribbon 负载均衡演示
架构说明
POM
二说 RestTemplate 的使用
官网
getForObject方法/getForEntity方法
Ribbon 核心组件 IRule
IRule
如何替换
配置细节
新建 package
新建 MySelfRule 规则类
添加主启动类 @RibbonClient
测试
Ribbon 负载均衡算法
原理
OpenFeign 调用服务接口
概述
OpenFeign 使用步骤
新建 cloud-consumer-feign-order81
POM
YAML
主启动
业务类
业务逻辑接口 @FeignClient 配置调用 provider 服务
Controller
测试
总结
OpenFeign 超时控制
概述
超时设置 故意设置超时演示错误
服务提供商8001故意写暂停程序
服务消费者81添加超时方法PaymentFeignService
服务消费者81添加超时方法OrderFeignController
测试
YML 需要在文件中打开 OpenFeign 客户端超时控制
OpenFeign 日志打印功能
概述
日志级别
启用日志
配置日志 Bean
YAML 打开文件中的日志 Feign 客户端
效果
Hystrix 断路器
分布式系统面临的问题
Hystrix 概述
Hystrix 重要概念
Hystrix 案例
新建 cloud-provider-hystrix-payment8001
POM
YAML
主启动
业务类
service
controller
测试
新建 cloud-consumer-feign-hystrix-order81
POM
YAML
主启动
业务类
service
controller
正常测试
Jmeter高并发测试
如何解决
服务降级
8001fallback
业务类启用
主启动激活
效果
80fallback
主启动
Controller
测试
统一服务降级
解耦合
YAML
创建 Service 实现类
Service 接口
Controller
测试
服务熔断
什么是熔断
实操
PaymentService
PaymentController
测试
总结
熔断类型
断路器打开或关闭的条件
断路器在什么情况下开始工作?
断路器打开后
ALL 配置
服务限流
服务监控 HystrixDashboard
仪表盘9001
新建 cloud-consumer-hystrix-dashboard9001
POM
YAML
主启动
所有 Provider 微服务提供类都需要监控依赖配置
启动9001
断路器演示(服务监控)hystrixDashboard)
修改cloud-provider-hystrix-payment8001
监控测试
9001监控8001
Gateway 新一代网关
概述
三个核心概念
入门配置
新建 cloud-gateway-gateway9527
POM
YAML
主启动
没有业务类
YAML 新网关配置
测试
网关配置在代码中
负载均衡
Predicate 的使用
概述
常用的 Route Predicate
After Route Predicate
Before Route Predicate
Between Route Predicate
时间格式
Cookie Route Predicate
Header Route Predicate
Host Route Predicate
Method Route Predicate
Path Route Predicate
Query Route Predicate
Filter 的使用
定制过滤器
SpringCloud Config 分布式配置中心
概述
Config 配置和测试服务端
创建 springcloud-config 仓库
搭建本地仓库
微服务搭建
新建 cloud-config-center-3344
POM
YAML
主启动
测试
读取规则的配置
Config 配置和测试客户端
新建 cloud-config-client-3355
POM
boostrap.yaml
概述
主启动
业务类
测试
Config 动态刷新客户端
POM 引入 actuator 监控
修改 YAML 暴露监控端口
Controller 上增加 @RefreshScope 注解
测试
SpringCloud Bus 消息总线
SpringCloud Stream 消息驱动
SpringCloud Alibaba
SprngCloud Alibaba Nacos服务注册和配置中心
Nacos 简介
安装并运行 Nacos
Nacos 作为服务注册中心演示
基于Nacos的服务提供者
新建 cloudalibaba-provider-payment9001
父 POM
本 POM
YAML
业务类
测试
新建 cloudalibaba-provider-payment9002
基于 Nacos 的服务消费者
新建 cloudalibaba-consumer-nacos-order83
POM
YAML
主启动
业务类
测试
Nacos 作为服务配置中心演示
Nacos 作为配置中心-基础配置
新建 cloudalibaba-config-nacos-client3377
POM
YAML
主启动
业务类
在 Nacos 中添加配置信息
测试
Nacos 作为配置中心-分类配置
概述
DataID方案
Group方案
Namespace方案
Ncos 作为配置中心-通用配置
Nacos 集群和持久化配置
官网说明
Windows 持久化
derby 到 MySql 切换配置步骤
执行 SQL 脚本
修改配置文件
Linux 版 Nacos + MySQL 生产环境配置
安装 Nacos
切换数据库
Nacos 集群配置
Nginx 配置
测试
SpringCloud Alibaba Sentinel实现熔断与限流
概述
安装 Sentinel 控制台
初始化演示工程
创建 Sentinel 微服务
新建 Module
POM
YAML
主启动
业务类
启动微服务8401
查看 Sentinel 监控页
Sentinel 懒加载
流控规则
基本介绍
流控模式
直接
QPS 的流量控制
线程数的流量控制
关联
操作
测试
流控效果
快速失败
预热
匀速排队
降级规则
官网
熔断策略
慢调用比例
异常比例
异常数
热点 key 限流
Controller
配置
测试
结论
自定义错误方法
测试 RunTimeException
参数例外项
系统规则
概述
配置
@SentinelResource
官网概述
按资源名称限流+后续处理
RateLimitController
配置
测试
按照Url地址限流+后续处理
RateLimitController
配置
测试
自定义兜底方法面临的问题
客户自定义限流处理逻辑
创建 CustomerBlockHandler 类用于自定义限流处理逻辑
RateLimitController
Sentinel 控制台配置
测试
进一步说明
服务熔断功能
Ribbon 系列
服务提供者 9003/9004
创建 Module
POM
YAML
主启动
业务类
服务消费者 84
创建 Module
POM
YAML
主启动
ApplicationContextConfig
业务类
测试
只配置 fallback
Controller
测试
只配置 blockHandler
Controller
配置
测试
fallback 和 blockHandler 都配置
Controller
Sentinel 配置
测试
Feign 系列
POM
YAML
主启动
业务类
Service
Service实现类
Controller
测试
规则持久化
POM
YAML
rule-type 详解
Nacos 配置
flow 模式 json 串属性详解
测试
SpringCloud Alibaba Seata处理分布式事务
Seata 概述
Seata 术语
Seata 处理过程
Seata-TC 事务协调者搭建
下载地址
修改 file.conf 文件
创建数据库
Nacos 创建命名空间
修改 registry.conf 文件
启动 Seata
使用 Nacos 作为 Seata 的配置中心
修改 config.txt
向 Nacos 推送配置
订单/库存/账户业务数据库准备
分布式事务业务说明
创建业务数据库
创建对应的业务表
创建日志回滚表
创建 Maven 父工程
创建公共模块
POM
CommonResult 统一返回结果
Account 实体
Order 实体
Storage 实体
创建账户服务
POM
YAML
主启动
AccountMapper 接口
AccountMapper 配置文件
AccountService 接口
AccountServiceImpl 实现类
AccountController
创建库存服务
POM
YAML
主启动
StorageMapper 接口
StorageMapper 配置文件
StorageService 接口
StorageServiceImpl 实现类
StorageController
创建订单服务
POM
YAML
主启动
DataSourceProxyConfig
OrderMapper
OrderMapper 配置文件
OpenFeign 远程调用接口
AccountServiceOpenFeign
StorageServiceOpenFeign
OrderService 接口
OrderServiceImpl 实现
OrderController
测试
Spring Cloud OSS 文件上传到阿里云
开通 OSS 服务
Hello World
Maven
代码
整合 Spring
Maven
application.yaml
代码

笔记版本
name version
Spring Cloud Hoxton.SR1
Spring Boot 2.2.2.RELEASE
Spring Cloud Alibaba 2.1.0.RELEASE
Java Jav8
Maven 3.5及以上
MySQL 5.7及以上
image-20210530212848344

通过查看 Spring 官网选择任意版本的 Spring Cloud 可以查看官方推荐与这个版本的 Spring Cloud 配套使用的 Spring Boot 版本



微服务架构编码构建
IDEA 创建 Project 工作空间
微服务 Cloud 整体聚合父工程 Project
New Project
image-20210531114816847

聚合总父工程名字
image-20210531114938601

Maven选版本
不要使用 IDEA 自带的 Maven,使用自己安装的 Maven。

image-20210531115014315

字符编码
image-20210531115409526

注解生效激活
image-20210531115726938

Java 编译版本
image-20210531115854931

父工程 pom


4.0.0

org.hong
SpringCloud
1.0-SNAPSHOT

pom

org.springframework.boot spring-boot-dependencies 2.2.2.RELEASE pom import org.springframework.cloud spring-cloud-dependencies Hoxton.SR1 pom import com.alibaba.cloud spring-cloud-alibaba-dependencies 2.1.0.RELEASE pom import mysql mysql-connector-java ${mysql.version} com.alibaba druid ${druid.version} org.mybatis.spring.boot mybatis-spring-boot-starter ${mybatis.spring.boot.version} junit junit ${junit.version} log4j log4j ${log4j.version} org.projectlombok lombok ${lombok.version} true org.springframework.boot spring-boot-maven-plugin true true REST 微服务构建 微服务提供者支付 Module 模块 创建 cloud-provider-payment8001 模块 注意:这里使用 Maven 创建,而不是使用 Spring Initializr。使用 Spring Initializr 也行,我习惯用这个。

image-20210531151533848

修改 pom 文件



springcloud
org.hong
1.0-SNAPSHOT

4.0.0

cloud-provider-payment8001


    
        org.springframework.boot
        spring-boot-starter-web
    
    
        org.springframework.boot
        spring-boot-starter-actuator
    
    
        org.mybatis.spring.boot
        mybatis-spring-boot-starter
    
    
        com.alibaba
        druid-spring-boot-starter
        1.1.10
    
    
    
        mysql
        mysql-connector-java
    
    
    
        org.springframework.boot
        spring-boot-starter-jdbc
    
    
        org.springframework.boot
        spring-boot-devtools
        runtime
        true
    
    
    
        org.projectlombok
        lombok
        true
    
    
        org.springframework.boot
        spring-boot-starter-test
        test
    

application.yaml server: port: 8001

spring:
application:
name: cloud-payment-service
datasource:
type: com.alibaba.druid.pool.DruidDataSource # 当前数据源操作类型
driver-class-name: org.gjt.mm.mysql.Driver # mysql驱动包 com.mysql.jdbc.Driver
url: jdbc:mysql://localhost:3306/springcloud?useUnicode=true&characterEncoding=utf-8&useSSL=false
username: root
password: 1234

mybatis:
mapperLocations: classpath:mapper/*.xml
type-aliases-package: org.hong.springcloud.entity # 所有Entity别名类所在包
主启动
package org.hong.springcloud;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class PaymentMain8001 {
public static void main(String[] args) {
SpringApplication.run(PaymentMain8001.class, args);
}
}
业务类
建表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
– 自己加几条数据
entity
主实体 Payment

package org.hong.springcloud.entity;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.io.Serializable;

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Payment implements Serializable {
private Long id;
private String serial;
}
json 封装体 CommonResult

package org.hong.springcloud.entity;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@AllArgsConstructor
@NoArgsConstructor
public class CommonResult {
private Integer code;
private String message;
private T data;

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

}
mapper
mapper 接口 PaymentMapper

package org.hong.springcloud.mapper;

import org.apache.ibatis.annotations.Mapper;
import org.hong.springcloud.entity.Payment;

@Mapper
public interface PaymentMapper {
int save(Payment payment);

Payment getPaymentById(Long Id);

}
mapper 映射文件 PaymentMapper.xml

INSERT INTO payment(serial) VALUES (#{serial}); SELECT id, serial FROM payment WHERE id = #{id} service 接口 PaymentService

package org.hong.springcloud.service;

import org.hong.springcloud.entity.Payment;

public interface PaymentService {
int save(Payment payment);

Payment getPaymentById(Long id);

}
实现类

package org.hong.springcloud.service.serviceimpl;

import org.hong.springcloud.entity.Payment;
import org.hong.springcloud.mapper.PaymentMapper;
import org.hong.springcloud.service.PaymentService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class PaymentServiceImpl implements PaymentService {
@Autowired
private PaymentMapper paymentMapper;

@Override
public int save(Payment payment) {
    return paymentMapper.save(payment);
}

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

}
controller
package org.hong.springcloud.controller;

import lombok.extern.slf4j.Slf4j;
import org.hong.springcloud.entity.CommonResult;
import org.hong.springcloud.entity.Payment;
import org.hong.springcloud.service.PaymentService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping("/payment")
@Slf4j
public class PaymentController {
@Autowired
private PaymentService paymentService;

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

@GetMapping("/{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, null);
    }
}

}
测试运行,没问题

热部署 Devtools
不配也行

添加 Devtools 依赖
哪个微服务需要使用就添加到哪个微服务的 pom.xml 文件中

org.springframework.boot spring-boot-devtools runtime true 修改父工程的 pom.xml 文件 把下面这一段粘贴到聚合父类总工程的pom.xml里 org.springframework.boot spring-boot-maven-plugin true true 修改 IDEA 设置 image-20210531170533030

更新值
使用快捷键 ctrl + shift + alt + / 打开如下对话框

image-20210531171340731

image-20210531171612298

微服务消费者订单 Module 模块
创建 cloud-consumer-order81 模块
步骤跟上面一样

修改 pom.xml 文件



springcloud
org.hong
1.0-SNAPSHOT

4.0.0

cloud-consumer-order81


    
        org.springframework.boot
        spring-boot-starter-web
    
    
        org.springframework.boot
        spring-boot-starter-actuator
    

    
        org.springframework.boot
        spring-boot-devtools
        runtime
        true
    
    
        org.projectlombok
        lombok
        true
    
    
        org.springframework.boot
        spring-boot-starter-test
        test
    

application.yaml # 端口被占用就使用别的端口 server: port: 81 主启动 package org.hong.springcloud;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class OrderMain81 {
public static void main(String[] args) {
SpringApplication.run(OrderMain81.class, args);
}
}
业务类
entity
81端口需要进行支付操作,支付操作在8001端口,而支付操作的业务在8001端口,因此81端口不应该出现与支付相关的 service、mapper

81端口需要去调用8001端口暴露的接口,因此81端口需要 controller

81端口的 controller 也需要接收值和返回值,因此81端口需要 entity

主实体 Payment

package org.hong.springcloud.entity;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.io.Serializable;

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Payment implements Serializable {
private Long id;
private String serial;
}
json 封装体 CommonResult

package org.hong.springcloud.entity;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@AllArgsConstructor
@NoArgsConstructor
public class CommonResult {
private Integer code;
private String message;
private T data;

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

}
RestTemplate
RestTemplate 提供了多种便捷访问远程Http服务的方法, 是一种简单便捷的访问 restful 服务模板类,是 Spring 提供的用于访问 Rest服务的客户端模板工具集。简单的说,通过 RestTemplate 可以让81端口调用到8001端口暴露的接口。与 JdbcTemplate、RedisTemplate 一样,RestTemplate 也需要注入到 IOC 容器中。

ApplicationContextConfig
package org.hong.springcloud.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;

@Configuration
public class ApplicationContextConfig {
@Bean
public RestTemplate getRestTemplate(){
return new RestTemplate();
}
}
controller
package org.hong.springcloud.controller;

import lombok.extern.slf4j.Slf4j;
import org.hong.springcloud.entity.CommonResult;
import org.hong.springcloud.entity.Payment;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.client.RestTemplate;

@RestController
@RequestMapping("/consumer")
@Slf4j
public class OrderController {
public static final String PAYMENT_URL = “http://localhost:8001/”;

@Autowired
private RestTemplate restTemplate;

@PostMapping("/payment")
public CommonResult save(@RequestBody Payment payment){
    return restTemplate.postForObject(PAYMENT_URL + "payment", payment, CommonResult.class);
}

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

}
工程重构
观察问题
两个微服务中都有一个公共的部分,造成了代码的冗余

image-20210531213734650

新建公共工程
新建 cloud-api-commons 工程,公共部分写这个工程里面。怎么创建就不演示了,跟上面一样。

修改 pom.xml 文件



springcloud
org.hong
1.0-SNAPSHOT

4.0.0

cloud-api-commons


    
        org.springframework.boot
        spring-boot-devtools
        runtime
        true
    
    
        org.projectlombok
        lombok
        true
    
    
        cn.hutool
        hutool-all
        5.1.0
    

编写公共部分 从任意一个微服务中,复制一份 entity 包下的内容到 cloud-api-commons 中。

maven 打包
先运行 clean,再运行 install,打包到本地仓库。

image-20210531215631198

改造81和8001端口服务
删除各自的原先有过的 entity 文件夹

在各自的 pom.xml 添加依赖

org.hong cloud-api-commons ${project.version} 将报错的地方导入正确的类路径

目前工程样图
image-20210601102216200



Eureka 服务注册与发现
Eureka 已经停止更新了,进入了维护状态

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

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

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

单机 Eureka 构建步骤
创建 EurekaServer 服务注册中心
创建 Module
cloud-eureka-server7001

修改 pom.xml



springcloud
org.hong
1.0-SNAPSHOT

4.0.0

cloud-eureka-server7001


    
    
        org.springframework.cloud
        spring-cloud-starter-netflix-eureka-server
    
    
    
        org.hong
        cloud-api-commons
        ${project.version}
    
    
    
        org.springframework.boot
        spring-boot-starter-web
    
    
        org.springframework.boot
        spring-boot-starter-actuator
    
    
    
        org.springframework.boot
        spring-boot-devtools
        runtime
        true
    
    
        org.projectlombok
        lombok
    
    
        org.springframework.boot
        spring-boot-starter-test
        test
    
    
        junit
        junit
    

主启动 package org.hong.springcloud;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;

@SpringBootApplication
// @EnableEurekaServer: 表明当前服务是服务注册中心
@EnableEurekaServer
public class EurekaMain7001 {
public static void main(String[] args) {
SpringApplication.run(EurekaMain7001.class, args);
}
}
application.yaml
server:
port: 7001

eureka:
instance:
hostname: localhost #eureka服务端的实例名称
client:
#false表示不向注册中心注册自己。
register-with-eureka: false
#false表示自己端就是注册中心,我的职责就是维护服务实例,并不需要去检索服务
fetch-registry: false
service-url:
#设置与Eureka Server交互的地址查询服务和注册服务都需要依赖这个地址。
defaultZone: http:// e u r e k a . i n s t a n c e . h o s t n a m e : {eureka.instance.hostname}: eureka.instance.hostname:{server.port}/eureka/
测试
浏览器访问 http://localhost:7001/

image-20210601114911166

No instances available 没有服务被发现,因为没有注册服务进来当然不可能有服务被发现

将8001端口服务注册进 EurekaServer 成为服务提供者 provider
修改 pom.xml

org.springframework.cloud spring-cloud-starter-netflix-eureka-client 修改 application.yaml 直接粘贴到 applicaiton.yaml 文件中,eureka 节点就是根节点

eureka:
client:
#表示是否将自己注册进EurekaServer默认为true。
register-with-eureka: true
#是否从EurekaServer抓取已有的注册信息,默认为true。单节点无所谓,集群必须设置为true才能配合ribbon使用负载均衡
fetchRegistry: true
#服务注册地址
service-url:
defaultZone: http://localhost:7001/eureka
修改主启动类
package org.hong.springcloud;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;

@SpringBootApplication
// 只加了这一个注解, 表明当前服务是Client
@EnableEurekaClient
public class PaymentMain8001 {
public static void main(String[] args) {
SpringApplication.run(PaymentMain8001.class, args);
}
}
测试
先要启动 EurekaServe,再启动 EurekaClient,访问 http://localhost:7001/

image-20210601120854556

如果出现了服务名称代表成功,这个服务名称就是我们在 yaml 中配置的 spring.appliction.name 的值。

spring:
application:
name: cloud-payment-service
将81端口服务注册进 EurekaServer 成为服务服务消费者consumer
修改 pom.xml

org.springframework.cloud spring-cloud-starter-netflix-eureka-client 修改 application.yaml spring: application: name: cloud-order-service

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

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;

@SpringBootApplication
@EnableEurekaClient
public class OrderMain81 {
public static void main(String[] args) {
SpringApplication.run(OrderMain81.class, args);
}
}
测试
先启动 EurekaServer,7001服务;再要启动服务提供者provider,8001服务;访问 http://localhost:7001/

image-20210601122502892

浏览器访问 http://localhost:81/consumer/payment/1 进行测试

集群 Eureka 构建步骤
Eureka 系统架构,Eureka Server 使用集群方式 ( 如果使用单机,Eureka 服务器一旦宕机,所有的服务都无法调用 ),Service Provider ( 服务提供者 )也使用集群;Service Consumer ( 服务使用者 ) 就不管我们的事情了。

image-20210601203157910

EurekaServer集群环境构建步骤
创建 Module
新建 cloud-eureka-server7002

修改 pom.xml



springcloud
org.hong
1.0-SNAPSHOT

4.0.0

cloud-eureka-server7002


    
    
        org.springframework.cloud
        spring-cloud-starter-netflix-eureka-server
    
    
    
        org.hong
        cloud-api-commons
        ${project.version}
    
    
    
        org.springframework.boot
        spring-boot-starter-web
    
    
        org.springframework.boot
        spring-boot-starter-actuator
    
    
    
        org.springframework.boot
        spring-boot-devtools
        runtime
        true
    
    
        org.projectlombok
        lombok
    
    
        org.springframework.boot
        spring-boot-starter-test
        test
    
    
        junit
        junit
    

主启动 package org.hong.springcloud;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;

@SpringBootApplication
@EnableEurekaServer
public class EurekaMain7002 {
public static void main(String[] args) {
SpringApplication.run(EurekaMain7002.class, args);
}
}
修改映射配置
打开 C:\Windows\System32\drivers\etc 文件夹下的 host 文件添加如下配置

直接添加到host文件的最后面

作用: 浏览器访问eureka7001.com相当于访问127.0.0.1, 同理eureka7002.com也是

127.0.0.1 eureka7001.com
127.0.0.1 eureka7002.com
添加完后打开 cmd 刷新 dns 缓存,ipconfig/flushdns

application.xml
7001
server:
port: 7001

eureka:
instance:
hostname: eureka7001.com #eureka服务端的实例名称
client:
register-with-eureka: false #false表示不向注册中心注册自己。
fetch-registry: false #false表示自己端就是注册中心,我的职责就是维护服务实例,并不需要去检索服务
service-url:
# 7001与7002相互守望, 相互注册, 如果有多个用逗号分割
defaultZone: http://eureka7002.com:7002/eureka/
7002
server:
port: 7002

eureka:
instance:
hostname: eureka7002.com #eureka服务端的实例名称
client:
register-with-eureka: false #false表示不向注册中心注册自己。
fetch-registry: false #false表示自己端就是注册中心,我的职责就是维护服务实例,并不需要去检索服务
service-url:
defaultZone: http://eureka7001.com:7001/eureka/
测试
启动 7001 和 7002,并访问 http://eureka7001.com:7001/ 和 http://eureka7002.com:7002/

image-20210601174654616

image-20210601174725185

7001访问页面可以看到7002,反之7002可以看到7001,环境构建成功

8001微服务发布到 Eureka 集群中
application.yaml
eureka:
client:
service-url:
# 将8001微服务发布到到Eureka集群的每个节点中
defaultZone: http://eureka7001.com:7001/eureka,http://eureka7002.com:7002/eureka # 集群版
81微服务发布到 Eureka 集群中
application.yaml
eureka:
client:
service-url:
# 将81微服务发布到到Eureka集群的每个节点中
defaultZone: http://eureka7001.com:7001/eureka,http://eureka7002.com:7002/eureka # 集群版
测试
先要启动 EurekaServer,7001/7002服务;

再要启动服务提供者 provider,8001

再要启动消费者,81

访问 http://eureka7001.com:7001/、http://eureka7002.com:7002/,观察注册进去的服务

image-20210601202841098

出现上述的2个服务代表搭建成功

支付服务提供者8001集群环境构建
创建 Module
新建 cloud-provider-payment8002

修改 pom.xml



springcloud
org.hong
1.0-SNAPSHOT

4.0.0

cloud-provider-payment8002


    
    
        org.springframework.cloud
        spring-cloud-starter-netflix-eureka-client
    
    
        org.springframework.boot
        spring-boot-starter-web
    
    
        org.springframework.boot
        spring-boot-starter-actuator
    
    
        org.mybatis.spring.boot
        mybatis-spring-boot-starter
    
    
        com.alibaba
        druid-spring-boot-starter
        1.1.10
    
    
    
        mysql
        mysql-connector-java
    
    
    
        org.springframework.boot
        spring-boot-starter-jdbc
    
    
        org.springframework.boot
        spring-boot-devtools
        runtime
        true
    
    
        org.projectlombok
        lombok
        true
    
    
        org.springframework.boot
        spring-boot-starter-test
        test
    
    
    
        org.hong
        cloud-api-commons
        ${project.version}
    

application.xml server: port: 8002

spring:
application:
# 服务名称不用改, 与8001一致
name: cloud-payment-service
datasource:
type: com.alibaba.druid.pool.DruidDataSource # 当前数据源操作类型
driver-class-name: org.gjt.mm.mysql.Driver # mysql驱动包 com.mysql.jdbc.Driver
url: jdbc:mysql://localhost:3306/springcloud?useUnicode=true&characterEncoding=utf-8&useSSL=false
username: root
password: 1234

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

mybatis:
mapperLocations: classpath:mapper/*.xml
type-aliases-package: org.hong.springcloud.entity # 所有Entity别名类所在包
主启动
package org.hong.springcloud;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;

@SpringBootApplication
@EnableEurekaClient
public class PaymentMain8002 {
public static void main(String[] args) {
SpringApplication.run(PaymentMain8002.class, args);
}
}
业务类
直接从8001微服务中粘贴过来

修改8001/8002的Controller
修改的目的:查看当前调用的是哪个端口的服务

package org.hong.springcloud.controller;

import lombok.extern.slf4j.Slf4j;
import org.hong.springcloud.entity.CommonResult;
import org.hong.springcloud.entity.Payment;
import org.hong.springcloud.service.PaymentService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping("/payment")
@Slf4j
public class PaymentController {
@Autowired
private PaymentService paymentService;

// 当前服务的端口号
@Value("${server.port}")
private String serverPort;

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

@GetMapping("/{id}")
public CommonResult getPaymentById(@PathVariable Long id){
    Payment payment = paymentService.getPaymentById(id);
    log.info("****查询结果:" + payment);
    if(payment != null){
        return new CommonResult(200, "查询成功, serverPort: " + this.serverPort, payment);
    }else{
        return new CommonResult(444, "没有对应记录, 查询" + id, null);
    }
}

}
测试
先要启动 EurekaServer,7001/7002服务;

再要启动服务提供者 provider,8001

再要启动消费者,81

访问 http://eureka7001.com:7001/、http://eureka7002.com:7002/,观察注册进去的服务

image-20210601214232401

可以看到 cloud-payment-service 服务一共有2个,此时我们的支付服务提供者集群环境搭建成功

问题
访问 http://localhost:81/consumer/payment/1,观察返回的 json 数据。

{“code”:200,“message”:“查询成功, serverPort: 8001”,“data”:{“id”:1,“serial”:“hong”}}
无论我们发送多少次,真正执行查询的端口总是为8001端口。因为我们在进行服务调用的代码是写死的。

负载均衡
订单服务访问地址不能写死,应该使用微服务名称来进行访问。

修改81服务 Controller
// 通过在eureka上注册过的微服务名称调用
public static final String PAYMENT_URL = “http://CLOUD-PAYMENT-SERVICE”;
我们再次访问 http://localhost:81/consumer/payment/1

image-20210601215439100

直接就 GG 了,因为我们少开启了一个功能。

赋予 RestTemplate 负载均衡的能力
在配置 RestTemplate 的方法上加上 @LoadBalanced 注解即可。这是 Ribbon 里面的东西。

package org.hong.springcloud.config;

import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;

@Configuration
public class ApplicationContextConfig {
@Bean
@LoadBalanced //使用@LoadBalanced注解赋予RestTemplate负载均衡的能力
public RestTemplate getRestTemplate(){
return new RestTemplate();
}
}
再次访问 http://localhost:81/consumer/payment/1,每次访问8001/8002都是交替出现

Ribbon 和 Eureka 整合后 Consumer 可以直接调用服务而不用再关心地址和端口号,且该服务还有负载功能了。

actuator 微服务信息完善
服务名称修改
修改 cloud-provider-payment8002 服务的 application.yaml

eureka:
instance:
# 自定义信息
instance-id: payment8001
效果

image-20210602103517161

IP 信息提示
修改 cloud-provider-payment8002 服务的 application.yaml

eureka:
instance:
# IP 信息显示
prefer-ip-address: true
效果

image-20210602104339897

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

修改8001的 Controller
// import org.springframework.cloud.client.discovery.DiscoveryClient; 注意别导错包
// 容器里面已经有的, 我们获取就行
@Autowired
private DiscoveryClient discoveryClient;

@GetMapping("/discovery")
public Object discovery(){
// 获取注册到Eureka中的所有微服务名称
List services = discoveryClient.getServices();
services.forEach(element -> {
log.info("****element:" + element);
});

// 获得指定微服务名称下的所有实例
List instances = discoveryClient.getInstances("CLOUD-PAYMENT-SERVICE");
instances.forEach(instance -> {
    log.info(instance.getServiceId() + "\t" + instance.getHost() + "\t" + instance.getPort() + "\t" + instance.getUri());
});
return discoveryClient;

}
修改8001的主启动类
package org.hong.springcloud;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;

@SpringBootApplication
@EnableEurekaClient
@EnableDiscoveryClient // 添加@EnableDiscoveryClient注解
public class PaymentMain8001 {
public static void main(String[] args) {
SpringApplication.run(PaymentMain8001.class, args);
}
}
日志打印
2021-06-02 11:21:15.078 INFO 4756 — [nio-8001-exec-1] o.h.s.controller.PaymentController : ****element:cloud-payment-service
2021-06-02 11:21:15.079 INFO 4756 — [nio-8001-exec-1] o.h.s.controller.PaymentController : ****element:cloud-order-service
2021-06-02 11:21:15.080 INFO 4756 — [nio-8001-exec-1] o.h.s.controller.PaymentController : CLOUD-PAYMENT-SERVICE 192.168.200.1 8002 http://192.168.200.1:8002
2021-06-02 11:21:15.081 INFO 4756 — [nio-8001-exec-1] o.h.s.controller.PaymentController : CLOUD-PAYMENT-SERVICE 192.168.200.1 8001 http://192.168.200.1:8001
image-20210602112318899

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

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

image-20210602112754416

导致原因
为了防止 Eureka Client 可以正常运行,但是 与 Eureka Server 网络不通情况下,Eureka Server 不会立刻将 Eureka Client 服务剔除

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

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

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

关闭自我保护
演示案例只启用7001和8001

修改7001的 application.yaml
eureka:
server:
#关闭自我保护机制,保证不可用服务被及时踢除
enable-self-preservation: false
#检测微服务存活的时间间隔, 单位为毫秒, 为了测试才改的, 不一定非要改
eviction-interval-timer-in-ms: 2000
效果
image-20210602120657459

修改8001的 application.yaml
为了测试才改的,缩小时间间隔

eureka:
instance:
#Eureka客户端向服务端发送心跳的时间间隔,单位为秒(默认是30秒)
lease-renewal-interval-in-seconds: 1
#Eureka服务端在收到最后一次心跳后等待时间上限,单位为秒(默认是90秒),超时将剔除服务
lease-expiration-duration-in-seconds: 2
测试
先启动7001再启动8001

image-20210602121615323

再关闭8001

image-20210602121717159



Consul 服务注册与发现
Consul 简介
概述
Consul 是一套开源的分布式服务发现和配置管理系统,由 HashiCorp 公司用 Go 语言开发。

提供了微服务系统中的服务治理、配置中心、控制总线等功能。这些功能中的每一个都可以根据需要单独使用,也可以一起使用以构建全方位的服务网格,总之Consul提供了一种完整的服务网格解决方案。

它具有很多优点。包括: 基于 raft 协议,比较简洁; 支持健康检查, 同时支持 HTTP 和 DNS 协议 支持跨数据中心的 WAN 集群 提供图形界面 跨平台,支持 Linux、Mac、Windows

Spring Cloud Consul 特性
服务发现:提供HTTP和DNS两种发现方式。

健康监测:支持多种方式,HTTP、TCP、Docker、Shell脚本定制化监控

KV存储:Key、Value的存储方式

多数据中心:Consul支持多数据中心

可视化Web界面

下载地址
https://www.consul.io/downloads

官方文档
https://www.springcloud.cc/spring-cloud-consul.html

安装并运行 Consul
官网安装说明:https://learn.hashicorp.com/consul/getting-started/install.html

下载完成后只有一个consul.exe文件,硬盘路径下双击运行,查看版本号信息

image-20210602151911375

使用开发模式启动

cmd 窗口输入 consul agent -dev 命令

通过以下地址可以访问 Consul 的首页:http://localhost:8500

image-20210602162654997.png

服务提供者
新建 Module 支付服务 provider8006
cloud-providerconsul-payment8006

POM



springcloud
org.hong
1.0-SNAPSHOT

4.0.0

cloud-providerconsul-payment8006


    
    
        org.springframework.cloud
        spring-cloud-starter-consul-discovery
    
    
    
        org.springframework.boot
        spring-boot-starter-web
    
    
        org.springframework.boot
        spring-boot-starter-actuator
    
    
    
        org.springframework.boot
        spring-boot-devtools
        runtime
        true
    
    
        org.projectlombok
        lombok
        true
    
    
        org.springframework.boot
        spring-boot-starter-test
        test
    

YAML #consul服务端口号 server: port: 8006

spring:
application:
name: cloud-provider-payment
#consul注册中心地址
cloud:
consul:
host: localhost
port: 8500
discovery:
#hostname: 127.0.0.1
service-name: ${spring.application.name}
主启动
package org.hong.springcloud;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;

@SpringBootApplication
@EnableDiscoveryClient //该注解用于向使用consul或者zookeeper作为注册中心时注册服务
public class PaymentMain8006 {
public static void main(String[] args) {
SpringApplication.run(PaymentMain8006.class, args);
}
}
Controller
我们主要还是想把微服务注册到 Consul 中,所以就写个简单的 Controller

package org.hong.springcloud.controller;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.UUID;

@RestController
@RequestMapping("/payment")
@Slf4j
public class PaymentController {
@Value("${server.port}")
private String serverPort;

@GetMapping("/consul")
public String paymentConsul(){
    return "springcloud with consul " + serverPort + "\t" + UUID.randomUUID().toString();
}

}
测试
运行 Consul 进入开发者模式,再启动8006,并访问 http://localhost:8500/ui/dc1/services

可以看到 consul-provider-payment 注册到的 Consul 中

image-20210602162814966

服务消费者
新建 Module 消费服务 order81
cloud-consumerconsul-order81

POM



springcloud
org.hong
1.0-SNAPSHOT

4.0.0

cloud-consumerconsul-order81


    
    
        org.springframework.cloud
        spring-cloud-starter-consul-discovery
    
    
    
        org.springframework.boot
        spring-boot-starter-web
    
    
        org.springframework.boot
        spring-boot-starter-actuator
    
    
    
        org.springframework.boot
        spring-boot-devtools
        runtime
        true
    
    
        org.projectlombok
        lombok
        true
    
    
        org.springframework.boot
        spring-boot-starter-test
        test
    

YAML ###consul服务端口号 server: port: 81

spring:
application:
name: cloud-consumer-order
####consul注册中心地址
cloud:
consul:
host: localhost
port: 8500
discovery:
#hostname: 127.0.0.1
service-name: ${spring.application.name}
主启动
package org.hong.springcloud;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;

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

import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;

@Configuration
public class ApplicationContextBean {
@Bean
@LoadBalanced
public RestTemplate getRestTemplate(){
return new RestTemplate();
}
}
Controller
package org.hong.springcloud.controller;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

@RestController
@RequestMapping

相关文章