irpas技术客

Spring Cloud 学习笔记(1 / 3)_巨輪_sentinel

网络投稿 602

Spring Cloud 学习笔记(2 / 3)

Spring Cloud 学习笔记(3 / 3)

---01_前言闲聊和课程说明02_零基础微服务架构理论入门03_第二季Boot和Cloud版本选型04_Cloud组件停更说明05_父工程Project空间新建06_父工程pom文件07_复习DependencyManagement和Dependencies08_支付模块构建(上)09_支付模块构建(中)10_支付模块构建(下)11_热部署Devtools12_消费者订单模块(上)13_消费者订单模块(下)14_工程重构15_Eureka基础知识16_EurekaServer服务端安装17_支付微服务8001入驻进EurekaServer18_订单微服务80入驻进EurekaServer19_Eureka集群原理说明20_Eureka集群环境构建21_订单支付两微服务注册进Eureka集群22_支付微服务集群配置23_actuator微服务信息完善24_服务发现Discovery25_Eureka自我保护理论知识26_怎么禁止自我保护27_Eureka停更说明28_支付服务注册进zookeeper29_临时还是持久节点30_订单服务注册进zookeeper31_Consul简介32_安装并运行Consul33_服务提供者注册进Consul34_服务消费者注册进Consul35_三个注册中心异同点36_Ribbon入门介绍37_Ribbon的负载均衡和Rest调用38_Ribbon默认自带的负载规则39_Ribbon负载规则替换40_Ribbon默认负载轮询算法原理41_RoundRobinRule源码分析42_Ribbon之手写轮询算法43_OpenFeign是什么44_OpenFeign服务调用45_OpenFeign超时控制46_OpenFeign日志增强47_Hystrix是什么48_Hystrix停更进维49_Hystrix的服务降级熔断限流概念初讲50_Hystrix支付微服务构建51_JMeter高并发压测后卡顿52_订单微服务调用支付服务出现卡顿53_降级容错解决的维度要求54_Hystrix之服务降级支付侧fallback55_Hystrix之服务降级订单侧fallback--
01_前言闲聊和课程说明

教学视频

源码文件1、源码文件2

02_零基础微服务架构理论入门

什么是微服务

In short, the microservice architectural style is an approach to developing a single application as a suite of small services, each running in its own process and communicating with lightweight mechanisms, often an HTTP resource API. These services are built around business capabilities and independently deployable by fully automated deployment machinery. There is a bare minimum of centralized management of these services, which may be written in different programming languages and use different data storage technologies.——James Lewis and Martin Fowler (2014)

微服务是一种架构风格一个应用拆分为一组小型服务每个服务运行在自己的进程内,也就是可独立部署和升级服务之间使用轻量级HTTP交互服务围绕业务功能拆分可以由全自动部署机制独立部署去中心化,服务自治。服务可以使用不同的语言、不同的存储技术

主题词01:现代数字化生活-落地维度

手机PC智能家居…

主题词02:分布式微服务架构-落地维度

满足哪些维度?支撑起这些维度的具体技术?

服务调用服务降级服务注册与发先服务熔断负载均衡服务消息队列服务网关配置中心管理自动化构建部署服务监控全链路追踪服务定时任务调度操作

Spring Cloud简介

是什么?符合微服务技术维度

SpringCloud=分布式微服务架构的站式解决方案,是多种微服务架构落地技术的集合体,俗称微服务全家桶

猜猜SpringCloud这个大集合里有多少种技术?

SpringCloud俨然已成为微服务开发的主流技术栈,在国内开发者社区非常火爆。

“微”力十足,互联网大厂微服务架构案例

京东的:

阿里的:

京东物流的:

Spring Cloud技术栈

总结

03_第二季Boot和Cloud版本选型

Spring Boot 2.X 版

源码地址Spring Boot 2 的新特性通过上面官网发现,Boot官方强烈建议你升级到2.X以上版本

Spring Cloud H版

源码地址官网

Spring Boot 与 Spring Cloud 兼容性查看

文档JSON接口

接下来开发用到的组件版本

Cloud - Hoxton.SR1Boot - 2.2.2.RELEASECloud Alibaba - 2.1.0.RELEASEJava - Java 8Maven - 3.5及以上MySQL - 5.7及以上 04_Cloud组件停更说明

停更引发的“升级惨案”

停更不停用被动修复bugs不再接受合并请求不再发布新版本

Cloud升级

服务注册中心

× Eureka√ Zookeeper√ Consul√ Nacos

服务调用

√ Ribbon√ LoadBalancer

服务调用2

× Feign√ OpenFeign

服务降级

× Hystrix√ resilience4j√ sentienl

服务网关

× Zuul! Zuul2√ gateway

服务配置

× Config√ Nacos

服务总线

× Bus√ Nacos

Spring Cloud官方文档

Spring Cloud中文文档

Spring Boot官方文档

05_父工程Project空间新建

约定 > 配置 > 编码

创建微服务cloud整体聚合父工程Project,有8个关键步骤:

New Project - maven工程 - create from archetype: maven-archetype-site聚合总父工程名字Maven选版本工程名字字符编码 - Settings - File encoding注解生效激活 - Settings - Annotation ProcessorsJava编译版本选8File Type过滤 - Settings - File Type

archetype 英 [?ɑ?kita?p] 美 [?ɑ?rkita?p] n. 典型

site 英 [sa?t] 美 [sa?t] n. (建筑物、城镇等的)地点,位置,建筑工地;现场;发生地;场所;网站;站点 v. 使坐落在;为…选址

06_父工程pom文件 <?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://·piler.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.1.47</mysql.version> <druid.version>1.1.16</druid.version> <mybatis.spring.boot.version>1.3.0</mybatis.spring.boot.version> </properties> <!-- 子模块继承之后,提供作用: 锁定版本+子modlue不用写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> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>${junit.version}</version> </dependency> <dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>${log4j.version}</version> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>${lombok.version}</version> <optional>true</optional> </dependency> </dependencies> </dependencyManagement> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> <configuration> <fork>true</fork> <addResources>true</addResources> </configuration> </plugin> </plugins> </build> </project> 07_复习DependencyManagement和Dependencies

Maven使用dependencyManagement元素来提供了一种管理依赖版本号的方式。

通常会在一个组织或者项目的最顶层的父POM中看到dependencyManagement元素。

使用pom.xml中的dependencyManagement元素能让所有在子项目中引用个依赖而不用显式的列出版本量。

Maven会沿着父子层次向上走,直到找到一个拥有dependencyManagement元素的项目,然后它就会使用这个 dependencyManagement元素中指定的版本号。

<dependencyManagement> <dependencies> <dependency> <groupId>mysq1</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.2</version> </dependency> <dependencies> </dependencyManagement>

然后在子项目里就可以添加mysql-connector时可以不指定版本号,例如:

<dependencies> <dependency> <groupId>mysq1</groupId> <artifactId>mysql-connector-java</artifactId> </dependency> </dependencies>

这样做的好处就是:如果有多个子项目都引用同一样依赖,则可以避免在每个使用的子项目里都声明一个版本号,这样当想升级或切换到另一个版本时,只需要在顶层父容器里更新,而不需要一个一个子项目的修改;另外如果某个子项目需要另外的一个版本,只需要声明version就可。

dependencyManagement里只是声明依赖,并不实现引入,因此子项目需要显示的声明需要用的依赖。如果不在子项目中声明依赖,是不会从父项目中继承下来的;只有在子项目中写了该依赖项,并且没有指定具体版本,才会从父项目中继承该项,并且version和scope都读取自父pom。如果子项目中指定了版本号,那么会使用子项目中指定的jar版本。

IDEA右侧旁的Maven插件有Toggle ' Skip Tests' Mode按钮,这样maven可以跳过单元测试


父工程创建完成执行mvn : install将父工程发布到仓库方便子工程继承。

08_支付模块构建(上)

创建微服务模块套路:

建Module改POM写YML主启动业务类 #mermaid-svg-qDwHCZK29qkSEP6E .label{font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family);fill:#333;color:#333}#mermaid-svg-qDwHCZK29qkSEP6E .label text{fill:#333}#mermaid-svg-qDwHCZK29qkSEP6E .node rect,#mermaid-svg-qDwHCZK29qkSEP6E .node circle,#mermaid-svg-qDwHCZK29qkSEP6E .node ellipse,#mermaid-svg-qDwHCZK29qkSEP6E .node polygon,#mermaid-svg-qDwHCZK29qkSEP6E .node path{fill:#ECECFF;stroke:#9370db;stroke-width:1px}#mermaid-svg-qDwHCZK29qkSEP6E .node .label{text-align:center;fill:#333}#mermaid-svg-qDwHCZK29qkSEP6E .node.clickable{cursor:pointer}#mermaid-svg-qDwHCZK29qkSEP6E .arrowheadPath{fill:#333}#mermaid-svg-qDwHCZK29qkSEP6E .edgePath .path{stroke:#333;stroke-width:1.5px}#mermaid-svg-qDwHCZK29qkSEP6E .flowchart-link{stroke:#333;fill:none}#mermaid-svg-qDwHCZK29qkSEP6E .edgeLabel{background-color:#e8e8e8;text-align:center}#mermaid-svg-qDwHCZK29qkSEP6E .edgeLabel rect{opacity:0.9}#mermaid-svg-qDwHCZK29qkSEP6E .edgeLabel span{color:#333}#mermaid-svg-qDwHCZK29qkSEP6E .cluster rect{fill:#ffffde;stroke:#aa3;stroke-width:1px}#mermaid-svg-qDwHCZK29qkSEP6E .cluster text{fill:#333}#mermaid-svg-qDwHCZK29qkSEP6E div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family);font-size:12px;background:#ffffde;border:1px solid #aa3;border-radius:2px;pointer-events:none;z-index:100}#mermaid-svg-qDwHCZK29qkSEP6E .actor{stroke:#ccf;fill:#ECECFF}#mermaid-svg-qDwHCZK29qkSEP6E text.actor>tspan{fill:#000;stroke:none}#mermaid-svg-qDwHCZK29qkSEP6E .actor-line{stroke:grey}#mermaid-svg-qDwHCZK29qkSEP6E .messageLine0{stroke-width:1.5;stroke-dasharray:none;stroke:#333}#mermaid-svg-qDwHCZK29qkSEP6E .messageLine1{stroke-width:1.5;stroke-dasharray:2, 2;stroke:#333}#mermaid-svg-qDwHCZK29qkSEP6E #arrowhead path{fill:#333;stroke:#333}#mermaid-svg-qDwHCZK29qkSEP6E .sequenceNumber{fill:#fff}#mermaid-svg-qDwHCZK29qkSEP6E #sequencenumber{fill:#333}#mermaid-svg-qDwHCZK29qkSEP6E #crosshead path{fill:#333;stroke:#333}#mermaid-svg-qDwHCZK29qkSEP6E .messageText{fill:#333;stroke:#333}#mermaid-svg-qDwHCZK29qkSEP6E .labelBox{stroke:#ccf;fill:#ECECFF}#mermaid-svg-qDwHCZK29qkSEP6E .labelText,#mermaid-svg-qDwHCZK29qkSEP6E .labelText>tspan{fill:#000;stroke:none}#mermaid-svg-qDwHCZK29qkSEP6E .loopText,#mermaid-svg-qDwHCZK29qkSEP6E .loopText>tspan{fill:#000;stroke:none}#mermaid-svg-qDwHCZK29qkSEP6E .loopLine{stroke-width:2px;stroke-dasharray:2, 2;stroke:#ccf;fill:#ccf}#mermaid-svg-qDwHCZK29qkSEP6E .note{stroke:#aa3;fill:#fff5ad}#mermaid-svg-qDwHCZK29qkSEP6E .noteText,#mermaid-svg-qDwHCZK29qkSEP6E .noteText>tspan{fill:#000;stroke:none}#mermaid-svg-qDwHCZK29qkSEP6E .activation0{fill:#f4f4f4;stroke:#666}#mermaid-svg-qDwHCZK29qkSEP6E .activation1{fill:#f4f4f4;stroke:#666}#mermaid-svg-qDwHCZK29qkSEP6E .activation2{fill:#f4f4f4;stroke:#666}#mermaid-svg-qDwHCZK29qkSEP6E .mermaid-main-font{font-family:"trebuchet ms", verdana, arial;font-family:var(--mermaid-font-family)}#mermaid-svg-qDwHCZK29qkSEP6E .section{stroke:none;opacity:0.2}#mermaid-svg-qDwHCZK29qkSEP6E .section0{fill:rgba(102,102,255,0.49)}#mermaid-svg-qDwHCZK29qkSEP6E .section2{fill:#fff400}#mermaid-svg-qDwHCZK29qkSEP6E .section1,#mermaid-svg-qDwHCZK29qkSEP6E .section3{fill:#fff;opacity:0.2}#mermaid-svg-qDwHCZK29qkSEP6E .sectionTitle0{fill:#333}#mermaid-svg-qDwHCZK29qkSEP6E .sectionTitle1{fill:#333}#mermaid-svg-qDwHCZK29qkSEP6E .sectionTitle2{fill:#333}#mermaid-svg-qDwHCZK29qkSEP6E .sectionTitle3{fill:#333}#mermaid-svg-qDwHCZK29qkSEP6E .sectionTitle{text-anchor:start;font-size:11px;text-height:14px;font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family)}#mermaid-svg-qDwHCZK29qkSEP6E .grid .tick{stroke:#d3d3d3;opacity:0.8;shape-rendering:crispEdges}#mermaid-svg-qDwHCZK29qkSEP6E .grid .tick text{font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family)}#mermaid-svg-qDwHCZK29qkSEP6E .grid path{stroke-width:0}#mermaid-svg-qDwHCZK29qkSEP6E .today{fill:none;stroke:red;stroke-width:2px}#mermaid-svg-qDwHCZK29qkSEP6E .task{stroke-width:2}#mermaid-svg-qDwHCZK29qkSEP6E .taskText{text-anchor:middle;font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family)}#mermaid-svg-qDwHCZK29qkSEP6E .taskText:not([font-size]){font-size:11px}#mermaid-svg-qDwHCZK29qkSEP6E .taskTextOutsideRight{fill:#000;text-anchor:start;font-size:11px;font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family)}#mermaid-svg-qDwHCZK29qkSEP6E .taskTextOutsideLeft{fill:#000;text-anchor:end;font-size:11px}#mermaid-svg-qDwHCZK29qkSEP6E .task.clickable{cursor:pointer}#mermaid-svg-qDwHCZK29qkSEP6E .taskText.clickable{cursor:pointer;fill:#003163 !important;font-weight:bold}#mermaid-svg-qDwHCZK29qkSEP6E .taskTextOutsideLeft.clickable{cursor:pointer;fill:#003163 !important;font-weight:bold}#mermaid-svg-qDwHCZK29qkSEP6E .taskTextOutsideRight.clickable{cursor:pointer;fill:#003163 !important;font-weight:bold}#mermaid-svg-qDwHCZK29qkSEP6E .taskText0,#mermaid-svg-qDwHCZK29qkSEP6E .taskText1,#mermaid-svg-qDwHCZK29qkSEP6E .taskText2,#mermaid-svg-qDwHCZK29qkSEP6E .taskText3{fill:#fff}#mermaid-svg-qDwHCZK29qkSEP6E .task0,#mermaid-svg-qDwHCZK29qkSEP6E .task1,#mermaid-svg-qDwHCZK29qkSEP6E .task2,#mermaid-svg-qDwHCZK29qkSEP6E .task3{fill:#8a90dd;stroke:#534fbc}#mermaid-svg-qDwHCZK29qkSEP6E .taskTextOutside0,#mermaid-svg-qDwHCZK29qkSEP6E .taskTextOutside2{fill:#000}#mermaid-svg-qDwHCZK29qkSEP6E .taskTextOutside1,#mermaid-svg-qDwHCZK29qkSEP6E .taskTextOutside3{fill:#000}#mermaid-svg-qDwHCZK29qkSEP6E .active0,#mermaid-svg-qDwHCZK29qkSEP6E .active1,#mermaid-svg-qDwHCZK29qkSEP6E .active2,#mermaid-svg-qDwHCZK29qkSEP6E .active3{fill:#bfc7ff;stroke:#534fbc}#mermaid-svg-qDwHCZK29qkSEP6E .activeText0,#mermaid-svg-qDwHCZK29qkSEP6E .activeText1,#mermaid-svg-qDwHCZK29qkSEP6E .activeText2,#mermaid-svg-qDwHCZK29qkSEP6E .activeText3{fill:#000 !important}#mermaid-svg-qDwHCZK29qkSEP6E .done0,#mermaid-svg-qDwHCZK29qkSEP6E .done1,#mermaid-svg-qDwHCZK29qkSEP6E .done2,#mermaid-svg-qDwHCZK29qkSEP6E .done3{stroke:grey;fill:#d3d3d3;stroke-width:2}#mermaid-svg-qDwHCZK29qkSEP6E .doneText0,#mermaid-svg-qDwHCZK29qkSEP6E .doneText1,#mermaid-svg-qDwHCZK29qkSEP6E .doneText2,#mermaid-svg-qDwHCZK29qkSEP6E .doneText3{fill:#000 !important}#mermaid-svg-qDwHCZK29qkSEP6E .crit0,#mermaid-svg-qDwHCZK29qkSEP6E .crit1,#mermaid-svg-qDwHCZK29qkSEP6E .crit2,#mermaid-svg-qDwHCZK29qkSEP6E .crit3{stroke:#f88;fill:red;stroke-width:2}#mermaid-svg-qDwHCZK29qkSEP6E .activeCrit0,#mermaid-svg-qDwHCZK29qkSEP6E .activeCrit1,#mermaid-svg-qDwHCZK29qkSEP6E .activeCrit2,#mermaid-svg-qDwHCZK29qkSEP6E .activeCrit3{stroke:#f88;fill:#bfc7ff;stroke-width:2}#mermaid-svg-qDwHCZK29qkSEP6E .doneCrit0,#mermaid-svg-qDwHCZK29qkSEP6E .doneCrit1,#mermaid-svg-qDwHCZK29qkSEP6E .doneCrit2,#mermaid-svg-qDwHCZK29qkSEP6E .doneCrit3{stroke:#f88;fill:#d3d3d3;stroke-width:2;cursor:pointer;shape-rendering:crispEdges}#mermaid-svg-qDwHCZK29qkSEP6E .milestone{transform:rotate(45deg) scale(0.8, 0.8)}#mermaid-svg-qDwHCZK29qkSEP6E .milestoneText{font-style:italic}#mermaid-svg-qDwHCZK29qkSEP6E .doneCritText0,#mermaid-svg-qDwHCZK29qkSEP6E .doneCritText1,#mermaid-svg-qDwHCZK29qkSEP6E .doneCritText2,#mermaid-svg-qDwHCZK29qkSEP6E .doneCritText3{fill:#000 !important}#mermaid-svg-qDwHCZK29qkSEP6E .activeCritText0,#mermaid-svg-qDwHCZK29qkSEP6E .activeCritText1,#mermaid-svg-qDwHCZK29qkSEP6E .activeCritText2,#mermaid-svg-qDwHCZK29qkSEP6E .activeCritText3{fill:#000 !important}#mermaid-svg-qDwHCZK29qkSEP6E .titleText{text-anchor:middle;font-size:18px;fill:#000;font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family)}#mermaid-svg-qDwHCZK29qkSEP6E g.classGroup text{fill:#9370db;stroke:none;font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family);font-size:10px}#mermaid-svg-qDwHCZK29qkSEP6E g.classGroup text .title{font-weight:bolder}#mermaid-svg-qDwHCZK29qkSEP6E g.clickable{cursor:pointer}#mermaid-svg-qDwHCZK29qkSEP6E g.classGroup rect{fill:#ECECFF;stroke:#9370db}#mermaid-svg-qDwHCZK29qkSEP6E g.classGroup line{stroke:#9370db;stroke-width:1}#mermaid-svg-qDwHCZK29qkSEP6E .classLabel .box{stroke:none;stroke-width:0;fill:#ECECFF;opacity:0.5}#mermaid-svg-qDwHCZK29qkSEP6E .classLabel .label{fill:#9370db;font-size:10px}#mermaid-svg-qDwHCZK29qkSEP6E .relation{stroke:#9370db;stroke-width:1;fill:none}#mermaid-svg-qDwHCZK29qkSEP6E .dashed-line{stroke-dasharray:3}#mermaid-svg-qDwHCZK29qkSEP6E #compositionStart{fill:#9370db;stroke:#9370db;stroke-width:1}#mermaid-svg-qDwHCZK29qkSEP6E #compositionEnd{fill:#9370db;stroke:#9370db;stroke-width:1}#mermaid-svg-qDwHCZK29qkSEP6E #aggregationStart{fill:#ECECFF;stroke:#9370db;stroke-width:1}#mermaid-svg-qDwHCZK29qkSEP6E #aggregationEnd{fill:#ECECFF;stroke:#9370db;stroke-width:1}#mermaid-svg-qDwHCZK29qkSEP6E #dependencyStart{fill:#9370db;stroke:#9370db;stroke-width:1}#mermaid-svg-qDwHCZK29qkSEP6E #dependencyEnd{fill:#9370db;stroke:#9370db;stroke-width:1}#mermaid-svg-qDwHCZK29qkSEP6E #extensionStart{fill:#9370db;stroke:#9370db;stroke-width:1}#mermaid-svg-qDwHCZK29qkSEP6E #extensionEnd{fill:#9370db;stroke:#9370db;stroke-width:1}#mermaid-svg-qDwHCZK29qkSEP6E .commit-id,#mermaid-svg-qDwHCZK29qkSEP6E .commit-msg,#mermaid-svg-qDwHCZK29qkSEP6E .branch-label{fill:lightgrey;color:lightgrey;font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family)}#mermaid-svg-qDwHCZK29qkSEP6E .pieTitleText{text-anchor:middle;font-size:25px;fill:#000;font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family)}#mermaid-svg-qDwHCZK29qkSEP6E .slice{font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family)}#mermaid-svg-qDwHCZK29qkSEP6E g.stateGroup text{fill:#9370db;stroke:none;font-size:10px;font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family)}#mermaid-svg-qDwHCZK29qkSEP6E g.stateGroup text{fill:#9370db;fill:#333;stroke:none;font-size:10px}#mermaid-svg-qDwHCZK29qkSEP6E g.statediagram-cluster .cluster-label text{fill:#333}#mermaid-svg-qDwHCZK29qkSEP6E g.stateGroup .state-title{font-weight:bolder;fill:#000}#mermaid-svg-qDwHCZK29qkSEP6E g.stateGroup rect{fill:#ECECFF;stroke:#9370db}#mermaid-svg-qDwHCZK29qkSEP6E g.stateGroup line{stroke:#9370db;stroke-width:1}#mermaid-svg-qDwHCZK29qkSEP6E .transition{stroke:#9370db;stroke-width:1;fill:none}#mermaid-svg-qDwHCZK29qkSEP6E .stateGroup .composit{fill:white;border-bottom:1px}#mermaid-svg-qDwHCZK29qkSEP6E .stateGroup .alt-composit{fill:#e0e0e0;border-bottom:1px}#mermaid-svg-qDwHCZK29qkSEP6E .state-note{stroke:#aa3;fill:#fff5ad}#mermaid-svg-qDwHCZK29qkSEP6E .state-note text{fill:black;stroke:none;font-size:10px}#mermaid-svg-qDwHCZK29qkSEP6E .stateLabel .box{stroke:none;stroke-width:0;fill:#ECECFF;opacity:0.7}#mermaid-svg-qDwHCZK29qkSEP6E .edgeLabel text{fill:#333}#mermaid-svg-qDwHCZK29qkSEP6E .stateLabel text{fill:#000;font-size:10px;font-weight:bold;font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family)}#mermaid-svg-qDwHCZK29qkSEP6E .node circle.state-start{fill:black;stroke:black}#mermaid-svg-qDwHCZK29qkSEP6E .node circle.state-end{fill:black;stroke:white;stroke-width:1.5}#mermaid-svg-qDwHCZK29qkSEP6E #statediagram-barbEnd{fill:#9370db}#mermaid-svg-qDwHCZK29qkSEP6E .statediagram-cluster rect{fill:#ECECFF;stroke:#9370db;stroke-width:1px}#mermaid-svg-qDwHCZK29qkSEP6E .statediagram-cluster rect.outer{rx:5px;ry:5px}#mermaid-svg-qDwHCZK29qkSEP6E .statediagram-state .divider{stroke:#9370db}#mermaid-svg-qDwHCZK29qkSEP6E .statediagram-state .title-state{rx:5px;ry:5px}#mermaid-svg-qDwHCZK29qkSEP6E .statediagram-cluster.statediagram-cluster .inner{fill:white}#mermaid-svg-qDwHCZK29qkSEP6E .statediagram-cluster.statediagram-cluster-alt .inner{fill:#e0e0e0}#mermaid-svg-qDwHCZK29qkSEP6E .statediagram-cluster .inner{rx:0;ry:0}#mermaid-svg-qDwHCZK29qkSEP6E .statediagram-state rect.basic{rx:5px;ry:5px}#mermaid-svg-qDwHCZK29qkSEP6E .statediagram-state rect.divider{stroke-dasharray:10,10;fill:#efefef}#mermaid-svg-qDwHCZK29qkSEP6E .note-edge{stroke-dasharray:5}#mermaid-svg-qDwHCZK29qkSEP6E .statediagram-note rect{fill:#fff5ad;stroke:#aa3;stroke-width:1px;rx:0;ry:0}:root{--mermaid-font-family: '"trebuchet ms", verdana, arial';--mermaid-font-family: "Comic Sans MS", "Comic Sans", cursive}#mermaid-svg-qDwHCZK29qkSEP6E .error-icon{fill:#522}#mermaid-svg-qDwHCZK29qkSEP6E .error-text{fill:#522;stroke:#522}#mermaid-svg-qDwHCZK29qkSEP6E .edge-thickness-normal{stroke-width:2px}#mermaid-svg-qDwHCZK29qkSEP6E .edge-thickness-thick{stroke-width:3.5px}#mermaid-svg-qDwHCZK29qkSEP6E .edge-pattern-solid{stroke-dasharray:0}#mermaid-svg-qDwHCZK29qkSEP6E .edge-pattern-dashed{stroke-dasharray:3}#mermaid-svg-qDwHCZK29qkSEP6E .edge-pattern-dotted{stroke-dasharray:2}#mermaid-svg-qDwHCZK29qkSEP6E .marker{fill:#333}#mermaid-svg-qDwHCZK29qkSEP6E .marker.cross{stroke:#333} :root { --mermaid-font-family: "trebuchet ms", verdana, arial;} #mermaid-svg-qDwHCZK29qkSEP6E { color: rgba(0, 0, 0, 0.75); font: ; } 客户端消费者80 order 微服务提供者8001 payment

创建cloud-provider-payment8001微服务提供者支付Module模块:

1.建名为cloud-provider-payment8001的Maven工程

2.改POM

<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://·piler.source>1.7</maven.compiler.source> <maven.compiler.target>1.7</maven.compiler.target> </properties> <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> </project>

3.写YML

server: port: 80

4.主启动

import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; /** * Hello world! * */ @SpringBootApplication public class OrderMain80 { public static void main( String[] args ){ SpringApplication.run(OrderMain80.class, args); } }

5.业务类

实体类:

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; } import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; @Data @AllArgsConstructor @NoArgsConstructor public class CommonResult<T>{ private Integer code; private String message; private T data; public CommonResult(Integer code, String message){ this(code, message, null); } }

控制层:

import com.lun.springcloud.entities.CommonResult; import com.lun.springcloud.entities.Payment; import lombok.extern.slf4j.Slf4j; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.client.RestTemplate; import javax.annotation.Resource; @Slf4j @RestController public class OrderController { public static final String PAYMENT_URL = "http://localhost:8001"; @Resource private RestTemplate restTemplate; @GetMapping("/consumer/payment/create") public CommonResult<Payment> 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); } }

配置类:

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(); } }

6.测试

运行cloud-consumer-order80与cloud-provider-payment8001两工程

浏览器 - http://localhost/consumer/payment/get/1

RestTemplate

RestTemplate提供了多种便捷访问远程Http服务的方法,是一种简单便捷的访问restful服务模板类,是Spring提供的用于访问Rest服务的客户端模板工具集

官网地址

使用:

使用restTemplate访问restful接口非常的简单粗暴无脑。(url, requestMap, ResponseBean.class)这三个参数分别代表。REST请求地址、请求参数、HTTP响应转换被转换成的对象类型。 13_消费者订单模块(下)

浏览器 - http://localhost/consumer/payment/create?serial=lun3

虽然,返回成功,但是观测数据库中,并没有创建serial为lun3的行。

解决之道:在loud-provider-payment8001工程的PaymentController中添加@RequestBody注解。

public class PaymentController { @PostMapping(value = "/payment/create") public CommonResult create(@RequestBody/*添加到这里*/ Payment payment){ ... } }

通过修改idea的workspace.xml的方式来快速打开Run Dashboard窗口(这个用来显示哪些Spring Boot工程运行,停止等信息。我idea 2020.1版本在名为Services窗口就可以显示哪些Spring Boot工程运行,停止等信息出来,所以这仅作记录参考)。

开启Run DashBoard

打开工程路径下的.idea文件夹的workspace.xml

在<component name="RunDashboard">中修改或添加以下代码:

<option name="configurationTypes"> <set> <option value="SpringBootApplicationConfigurationType"/> </set> </option>

由于idea版本差异,可能需要关闭重启。

14_工程重构

观察cloud-consumer-order80与cloud-provider-payment8001两工程有重复代码(entities包下的实体)(坏味道),重构。

1.新建 - cloud-api-commons

2.POM

<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://·mit-id,#mermaid-svg-E28nidbn8ZpE73mT .commit-msg,#mermaid-svg-E28nidbn8ZpE73mT .branch-label{fill:lightgrey;color:lightgrey;font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family)}#mermaid-svg-E28nidbn8ZpE73mT .pieTitleText{text-anchor:middle;font-size:25px;fill:#000;font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family)}#mermaid-svg-E28nidbn8ZpE73mT .slice{font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family)}#mermaid-svg-E28nidbn8ZpE73mT g.stateGroup text{fill:#9370db;stroke:none;font-size:10px;font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family)}#mermaid-svg-E28nidbn8ZpE73mT g.stateGroup text{fill:#9370db;fill:#333;stroke:none;font-size:10px}#mermaid-svg-E28nidbn8ZpE73mT g.statediagram-cluster .cluster-label text{fill:#333}#mermaid-svg-E28nidbn8ZpE73mT g.stateGroup .state-title{font-weight:bolder;fill:#000}#mermaid-svg-E28nidbn8ZpE73mT g.stateGroup rect{fill:#ECECFF;stroke:#9370db}#mermaid-svg-E28nidbn8ZpE73mT g.stateGroup line{stroke:#9370db;stroke-width:1}#mermaid-svg-E28nidbn8ZpE73mT .transition{stroke:#9370db;stroke-width:1;fill:none}#mermaid-svg-E28nidbn8ZpE73mT .stateGroup .composit{fill:white;border-bottom:1px}#mermaid-svg-E28nidbn8ZpE73mT .stateGroup .alt-composit{fill:#e0e0e0;border-bottom:1px}#mermaid-svg-E28nidbn8ZpE73mT .state-note{stroke:#aa3;fill:#fff5ad}#mermaid-svg-E28nidbn8ZpE73mT .state-note text{fill:black;stroke:none;font-size:10px}#mermaid-svg-E28nidbn8ZpE73mT .stateLabel .box{stroke:none;stroke-width:0;fill:#ECECFF;opacity:0.7}#mermaid-svg-E28nidbn8ZpE73mT .edgeLabel text{fill:#333}#mermaid-svg-E28nidbn8ZpE73mT .stateLabel text{fill:#000;font-size:10px;font-weight:bold;font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family)}#mermaid-svg-E28nidbn8ZpE73mT .node circle.state-start{fill:black;stroke:black}#mermaid-svg-E28nidbn8ZpE73mT .node circle.state-end{fill:black;stroke:white;stroke-width:1.5}#mermaid-svg-E28nidbn8ZpE73mT #statediagram-barbEnd{fill:#9370db}#mermaid-svg-E28nidbn8ZpE73mT .statediagram-cluster rect{fill:#ECECFF;stroke:#9370db;stroke-width:1px}#mermaid-svg-E28nidbn8ZpE73mT .statediagram-cluster rect.outer{rx:5px;ry:5px}#mermaid-svg-E28nidbn8ZpE73mT .statediagram-state .divider{stroke:#9370db}#mermaid-svg-E28nidbn8ZpE73mT .statediagram-state .title-state{rx:5px;ry:5px}#mermaid-svg-E28nidbn8ZpE73mT .statediagram-cluster.statediagram-cluster .inner{fill:white}#mermaid-svg-E28nidbn8ZpE73mT .statediagram-cluster.statediagram-cluster-alt .inner{fill:#e0e0e0}#mermaid-svg-E28nidbn8ZpE73mT .statediagram-cluster .inner{rx:0;ry:0}#mermaid-svg-E28nidbn8ZpE73mT .statediagram-state rect.basic{rx:5px;ry:5px}#mermaid-svg-E28nidbn8ZpE73mT .statediagram-state rect.divider{stroke-dasharray:10,10;fill:#efefef}#mermaid-svg-E28nidbn8ZpE73mT .note-edge{stroke-dasharray:5}#mermaid-svg-E28nidbn8ZpE73mT .statediagram-note rect{fill:#fff5ad;stroke:#aa3;stroke-width:1px;rx:0;ry:0}:root{--mermaid-font-family: '"trebuchet ms", verdana, arial';--mermaid-font-family: "Comic Sans MS", "Comic Sans", cursive}#mermaid-svg-E28nidbn8ZpE73mT .error-icon{fill:#522}#mermaid-svg-E28nidbn8ZpE73mT .error-text{fill:#522;stroke:#522}#mermaid-svg-E28nidbn8ZpE73mT .edge-thickness-normal{stroke-width:2px}#mermaid-svg-E28nidbn8ZpE73mT .edge-thickness-thick{stroke-width:3.5px}#mermaid-svg-E28nidbn8ZpE73mT .edge-pattern-solid{stroke-dasharray:0}#mermaid-svg-E28nidbn8ZpE73mT .edge-pattern-dashed{stroke-dasharray:3}#mermaid-svg-E28nidbn8ZpE73mT .edge-pattern-dotted{stroke-dasharray:2}#mermaid-svg-E28nidbn8ZpE73mT .marker{fill:#333}#mermaid-svg-E28nidbn8ZpE73mT .marker.cross{stroke:#333} :root { --mermaid-font-family: "trebuchet ms", verdana, arial;} #mermaid-svg-E28nidbn8ZpE73mT { color: rgba(0, 0, 0, 0.75); font: ; } Eureka 7001 Eureka 7002 找到C:\Windows\System32\drivers\etc路径下的hosts文件,修改映射配置添加进hosts文件 127.0.0.1 eureka7001.com 127.0.0.1 eureka7002.com 修改cloud-eureka-server7001配置文件 server: port: 7001 eureka: instance: hostname: eureka7001.com #eureka服务端的实例名称 client: register-with-eureka: false #false表示不向注册中心注册自己。 fetch-registry: false #false表示自己端就是注册中心,我的职责就是维护服务实例,并不需要去检索服务 service-url: #集群指向其它eureka defaultZone: http://eureka7002.com:7002/eureka/ #单机就是7001自己 #defaultZone: http://eureka7001.com:7001/eureka/ 修改cloud-eureka-server7002配置文件 server: port: 7002 eureka: instance: hostname: eureka7002.com #eureka服务端的实例名称 client: register-with-eureka: false #false表示不向注册中心注册自己。 fetch-registry: false #false表示自己端就是注册中心,我的职责就是维护服务实例,并不需要去检索服务 service-url: #集群指向其它eureka defaultZone: http://eureka7001.com:7001/eureka/ #单机就是7002自己 #defaultZone: http://eureka7002.com:7002/eureka/

实践的时候,遇到异常情况

在开启cloud-eureka-server7002时,开启失败,说7002端口被占用,然后在cmd中输入netstat -ano | find "7002",查不到任何东西。

纳闷一阵,重启电脑,问题解决。

21_订单支付两微服务注册进Eureka集群 将支付服务8001微服务,订单服务80微服务发布到上面2台Eureka集群配置中

将它们的配置文件的eureka.client.service-url.defaultZone进行修改

eureka: client: #表示是否将自己注册进Eurekaserver默认为true。 register-with-eureka: true #是否从EurekaServer抓取已有的注册信息,默认为true。单节点无所谓,集群必须设置为true才能配合ribbon使用负载均衡 fetchRegistry: true service-url: defaultZone: http://eureka7001.com:7001/eureka, http://eureka7002.com:7002/eureka 测试01 先要启动EurekaServer,7001/7002服务再要启动服务提供者provider,8001再要启动消费者,80浏览器输入 - http://localhost/consumer/payment/get/1 22_支付微服务集群配置

支付服务提供者8001集群环境构建

参考cloud-provicer-payment8001

1.新建cloud-provider-payment8002

2.改POM

3.写YML - 端口8002

4.主启动

5.业务类

6.修改8001/8002的Controller,添加serverPort

@RestController @Slf4j public class PaymentController{ @Value("${server.port}") private String serverPort;//添加serverPort @PostMapping(value = "/payment/create") public CommonResult create(@RequestBody Payment payment) { int result = paymentService.create(payment); log.info("*****插入结果:" + result); if(result > 0) { return new CommonResult(200,"插入数据库成功,serverPort: "+serverPort/*添加到此处*/, result); }else{ return new CommonResult(444,"插入数据库失败",null); } } }

负载均衡

cloud-consumer-order80订单服务访问地址不能写死

@Slf4j @RestController public class OrderController { //public static final String PAYMENT_URL = "http://localhost:8001"; public static final String PAYMENT_URL = "http://CLOUD-PAYMENT-SERVICE"; ... }

使用@LoadBalanced注解赋予RestTemplate负载均衡的能力

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(); } }

ApplicationContextBean - 提前说一下Ribbon的负载均衡功能

测试

先要启动EurekaServer,7001/7002服务

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

浏览器输入 - http://localhost/consumer/payment/get/31

结果:负载均衡效果达到,8001/8002端口交替出现

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

相互注册,相互守望

23_actuator微服务信息完善

主机名称:服务名称修改(也就是将IP地址,换成可读性高的名字)

修改cloud-provider-payment8001,cloud-provider-payment8002

修改部分 - YML - eureka.instance.instance-id

eureka: ... instance: instance-id: payment8001 #添加此处 eureka: ... instance: instance-id: payment8002 #添加此处

修改之后

eureka主页将显示payment8001,payment8002代替原来显示的IP地址。


访问信息有IP信息提示,(就是将鼠标指针移至payment8001,payment8002名下,会有IP地址提示)

修改部分 - YML - eureka.instance.prefer-ip-address

eureka: ... instance: instance-id: payment8001 prefer-ip-address: true #添加此处 eureka: ... instance: instance-id: payment8002 prefer-ip-address: true #添加此处 24_服务发现Discovery

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

修改cloud-provider-payment8001的Controller @RestController @Slf4j public class PaymentController{ ... @Resource private DiscoveryClient discoveryClient; ... @GetMapping(value = "/payment/discovery") public Object discovery() { List<String> services = discoveryClient.getServices(); for (String element : services) { log.info("*****element: "+element); } List<ServiceInstance> instances = discoveryClient.getInstances("CLOUD-PAYMENT-SERVICE"); for (ServiceInstance instance : instances) { log.info(instance.getServiceId()+"\t"+instance.getHost()+"\t"+instance.getPort()+"\t"+instance.getUri()); } return this.discoveryClient; } } 8001主启动类 @SpringBootApplication @EnableEurekaClient @EnableDiscoveryClient//添加该注解 public class PaymentMain001 { public static void main(String[] args) { SpringApplication.run(PaymentMain001.class, args); } } 自测

先要启动EurekaSeryer

再启动8001主启动类,需要稍等一会儿

浏览器输入http://localhost:8001/payment/discovery

浏览器输出:

{"services":["cloud-payment-service"],"order":0}

后台输出:

*****element: cloud-payment-service CLOUD-PAYMENT-SERVICE 192.168.199.218 8001 http://192.168.199.218:8001 25_Eureka自我保护理论知识

概述

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

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

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

导致原因

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

属于CAP里面的AP分支。

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

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

什么是自我保护模式?

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

自我保护机制∶默认情况下EurekaClient定时向EurekaServer端发送心跳包

如果Eureka在server端在一定时间内(默认90秒)没有收到EurekaClient发送心跳包,便会直接从服务注册列表中剔除该服务,但是在短时间( 90秒中)内丢失了大量的服务实例心跳,这时候Eurekaserver会开启自我保护机制,不会剔除该服务(该现象可能出现在如果网络不通但是EurekaClient为出现宕机,此时如果换做别的注册中心如果一定时间内没有收到心跳会将剔除该服务,这样就出现了严重失误,因为客户端还能正常发送心跳,只是网络延迟问题,而保护机制是为了解决此问题而产生的)。

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

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

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

26_怎么禁止自我保护 在eurekaServer端7001处设置关闭自我保护机制

出厂默认,自我保护机制是开启的

使用eureka.server.enable-self-preservation = false可以禁用自我保护模式

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

关闭效果:

spring-eureka主页会显示出一句:

THE SELF PRESERVATION MODE IS TURNED OFF. THIS MAY NOT PROTECT INSTANCE EXPIRY IN CASE OF NETWORK/OTHER PROBLEMS.


生产者客户端eureakeClient端8001

默认:

eureka.instance.lease-renewal-interval-in-seconds=30

eureka.instance.lease-expiration-duration-in-seconds=90

eureka: ... instance: instance-id: payment8001 prefer-ip-address: true #心跳检测与续约时间 #开发时没置小些,保证服务关闭后注册中心能即使剔除服务 #Eureka客户端向服务端发送心跳的时间间隔,单位为秒(默认是30秒) lease-renewal-interval-in-seconds: 1 #Eureka服务端在收到最后一次心跳后等待时间上限,单位为秒(默认是90秒),超时将剔除服务 lease-expiration-duration-in-seconds: 2
测试 7001和8001都配置完成先启动7001再启动8001

结果:先关闭8001,马上被删除了

27_Eureka停更说明

https://github.com/Netflix/eureka/wiki

Eureka 2.0 (Discontinued)

The existing open source work on eureka 2.0 is discontinued. The code base and artifacts that were released as part of the existing repository of work on the 2.x branch is considered use at your own risk.

Eureka 1.x is a core part of Netflix’s service discovery system and is still an active project.

我们用ZooKeeper代替Eureka功能。

28_支付服务注册进zookeeper 注册中心Zookeeper

zookeeper是一个分布式协调工具,可以实现注册中心功能

关闭Linux服务器防火墙后,启动zookeeper服务器

用到的Linux命令行:

systemctl stop firewalld关闭防火墙systemctl status firewalld查看防火墙状态ipconfig查看IP地址ping查验结果

zookeeper服务器取代Eureka服务器,zk作为服务注册中心


视频里是用虚拟机CentOS开启ZooKeeper,我打算在本机启动ZooKeeper,具体操作参考ZooKeeper学习笔记。

服务提供者

1.新建名为cloud-provider-payment8004的Maven工程。

2.POM

<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://·> * */ public class RoundRobinRule extends AbstractLoadBalancerRule { private AtomicInteger nextServerCyclicCounter; private static final boolean AVAILABLE_ONLY_SERVERS = true; private static final boolean ALL_SERVERS = false; private static Logger log = LoggerFactory.getLogger(RoundRobinRule.class); public RoundRobinRule() { nextServerCyclicCounter = new AtomicInteger(0); } public RoundRobinRule(ILoadBalancer lb) { this(); setLoadBalancer(lb); } //重点关注这方法。 public Server choose(ILoadBalancer lb, Object key) { if (lb == null) { log.warn("no load balancer"); return null; } Server server = null; int count = 0; while (server == null && count++ < 10) { List<Server> reachableServers = lb.getReachableServers(); List<Server> allServers = lb.getAllServers(); int upCount = reachableServers.size(); int serverCount = allServers.size(); if ((upCount == 0) || (serverCount == 0)) { log.warn("No up servers available from load balancer: " + lb); return null; } int nextServerIndex = incrementAndGetModulo(serverCount); server = allServers.get(nextServerIndex); if (server == null) { /* Transient. */ Thread.yield(); continue; } if (server.isAlive() && (server.isReadyToServe())) { return (server); } // Next. server = null; } if (count >= 10) { log.warn("No available alive servers after 10 tries from load balancer: " + lb); } return server; } /** * Inspired by the implementation of {@link AtomicInteger#incrementAndGet()}. * * @param modulo The modulo to bound the value of the counter. * @return The next value. */ private int incrementAndGetModulo(int modulo) { for (;;) { int current = nextServerCyclicCounter.get(); int next = (current + 1) % modulo;//求余法 if (nextServerCyclicCounter.compareAndSet(current, next)) return next; } } @Override public Server choose(Object key) { return choose(getLoadBalancer(), key); } @Override public void initWithNiwsConfig(IClientConfig clientConfig) { } } 42_Ribbon之手写轮询算法

自己试着写一个类似RoundRobinRule的本地负载均衡器。

7001/7002集群启动

8001/8002微服务改造- controller

@RestController @Slf4j public class PaymentController{ ... @GetMapping(value = "/payment/lb") public String getPaymentLB() { return serverPort;//返回服务接口 } ... } 80订单微服务改造

1.ApplicationContextConfig去掉注解@LoadBalanced,OrderMain80去掉注解@RibbonClient

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 public RestTemplate getRestTemplate(){ return new RestTemplate(); } }

2.创建LoadBalancer接口

import org.springframework.cloud.client.ServiceInstance; import java.util.List; /** */ public interface LoadBalancer { ServiceInstance instances(List<ServiceInstance> serviceInstances); }

3.MyLB

实现LoadBalancer接口

import org.springframework.cloud.client.ServiceInstance; import org.springframework.stereotype.Component; import java.util.List; import java.util.concurrent.atomic.AtomicInteger; /** */ @Component//需要跟主启动类同包,或者在其子孙包下。 public class MyLB implements LoadBalancer { private AtomicInteger atomicInteger = new AtomicInteger(0); public final int getAndIncrement() { int current; int next; do { current = this.atomicInteger.get(); next = current >= 2147483647 ? 0 : current + 1; }while(!this.atomicInteger.compareAndSet(current,next)); System.out.println("*****第几次访问,次数next: "+next); return next; } //负载均衡算法:rest接口第几次请求数 % 服务器集群总数量 = 实际调用服务器位置下标 ,每次服务重启动后rest接口计数从1开始。 @Override public ServiceInstance instances(List<ServiceInstance> serviceInstances) { int index = getAndIncrement() % serviceInstances.size(); return serviceInstances.get(index); } }

4.OrderController

import org.springframework.cloud.client.ServiceInstance; import org.springframework.cloud.client.discovery.DiscoveryClient; import com.lun.springcloud.lb.LoadBalancer; @Slf4j @RestController public class OrderController { //public static final String PAYMENT_URL = "http://localhost:8001"; public static final String PAYMENT_URL = "http://CLOUD-PAYMENT-SERVICE"; ... @Resource private LoadBalancer loadBalancer; @Resource private DiscoveryClient discoveryClient; ... @GetMapping(value = "/consumer/payment/lb") public String getPaymentLB() { List<ServiceInstance> instances = discoveryClient.getInstances("CLOUD-PAYMENT-SERVICE"); if(instances == null || instances.size() <= 0){ return null; } ServiceInstance serviceInstance = loadBalancer.instances(instances); URI uri = serviceInstance.getUri(); return restTemplate.getForObject(uri+"/payment/lb",String.class); } }

5.测试 不停地刷新http://localhost/consumer/payment/lb,可以看到8001/8002交替出现。

43_OpenFeign是什么

官方文档

Github地址

Feign is a declarative web service client. It makes writing web service clients easier. To use Feign create an interface and annotate it. It has pluggable annotation support including Feign annotations and JAX-RS annotations. Feign also supports pluggable encoders and decoders. Spring Cloud adds support for Spring MVC annotations and for using the same HttpMessageConverters used by default in Spring Web. Spring Cloud integrates Ribbon and Eureka, as well as Spring Cloud LoadBalancer to provide a load-balanced http client when using Feign. link

Feign是一个声明式WebService客户端。使用Feign能让编写Web Service客户端更加简单。它的使用方法是定义一个服务接口然后在上面添加注解。Feign也支持可拔插式的编码器和解码器。Spring Cloud对Feign进行了封装,使其支持了Spring MVC标准注解和HttpMessageConverters。Feign可以与Eureka和Ribbon组合使用以支持负载均衡。

Feign能干什么

Feign旨在使编写Java Http客户端变得更容易。

前面在使用Ribbon+RestTemplate时,利用RestTemplate对http请求的封装处理,形成了一套模版化的调用方法。但是在实际开发中,由于对服务依赖的调用可能不止一处,往往一个接口会被多处调用,所以通常都会针对每个微服务自行封装一些客户端类来包装这些依赖服务的调用。所以,Feign在此基础上做了进一步封装,由他来帮助我们定义和实现依赖服务接口的定义。在Feign的实现下,我们只需创建一个接口并使用注解的方式来配置它(以前是Dao接口上面标注Mapper注解,现在是一个微服务接口上面标注一个Feign注解即可),即可完成对服务提供方的接口绑定,简化了使用Spring cloud Ribbon时,自动封装服务调用客户端的开发量。

Feign集成了Ribbon

利用Ribbon维护了Payment的服务列表信息,并且通过轮询实现了客户端的负载均衡。而与Ribbon不同的是,通过feign只需要定义服务绑定接口且以声明式的方法,优雅而简单的实现了服务调用。

Feign和OpenFeign两者区别

Feign是Spring Cloud组件中的一个轻量级RESTful的HTTP服务客户端Feign内置了Ribbon,用来做客户端负载均衡,去调用服务注册中心的服务。Feign的使用方式是:使用Feign的注解定义接口,调用这个接口,就可以调用服务注册中心的服务。

<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-feign</artifactId> </dependency>

OpenFeign是Spring Cloud在Feign的基础上支持了SpringMVC的注解,如@RequesMapping等等。OpenFeign的@Feignclient可以解析SpringMVc的@RequestMapping注解下的接口,并通过动态代理的方式产生实现类,实现类中做负载均衡并调用其他服务。

<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> </dependency>

feign 英 [fe?n] 美 [fe?n] v. 假装,装作,佯装(有某种感觉或生病、疲倦等)

44_OpenFeign服务调用

接口+注解:微服务调用接口 + @FeignClient

1.新建cloud-consumer-feign-order80

2.POM

<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://·:7001/eureka/,http://eureka7002.com:7002/eureka/

4.主启动

import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.openfeign.EnableFeignClients; @SpringBootApplication @EnableFeignClients public class OrderFeignMain80 { public static void main(String[] args) { SpringApplication.run(OrderFeignMain80.class, args); } }

5.业务类

业务逻辑接口+@FeignClient配置调用provider服务

新建PaymentFeignService接口并新增注解@FeignClient

import com.lun.springcloud.entities.CommonResult; import com.lun.springcloud.entities.Payment; import org.springframework.cloud.openfeign.FeignClient; import org.springframework.stereotype.Component; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; @Component @FeignClient(value = "CLOUD-PAYMENT-SERVICE") public interface PaymentFeignService { @GetMapping(value = "/payment/get/{id}") public CommonResult<Payment> getPaymentById(@PathVariable("id") Long id); }

控制层Controller

import com.lun.springcloud.entities.CommonResult; import com.lun.springcloud.entities.Payment; import com.lun.springcloud.service.PaymentFeignService; import lombok.extern.slf4j.Slf4j; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RestController; import javax.annotation.Resource; @RestController @Slf4j public class OrderFeignController { @Resource private PaymentFeignService paymentFeignService; @GetMapping(value = "/consumer/payment/get/{id}") public CommonResult<Payment> getPaymentById(@PathVariable("id") Long id) { return paymentFeignService.getPaymentById(id); } }

6.测试

先启动2个eureka集群7001/7002

再启动2个微服务8001/8002

启动OpenFeign启动

http://localhost/consumer/payment/get/1

Feign自带负载均衡配置项

45_OpenFeign超时控制

超时设置,故意设置超时演示出错情况

1.服务提供方8001/8002故意写暂停程序

@RestController @Slf4j public class PaymentController { ... @Value("${server.port}") private String serverPort; ... @GetMapping(value = "/payment/feign/timeout") public String paymentFeignTimeout() { // 业务逻辑处理正确,但是需要耗费3秒钟 try { TimeUnit.SECONDS.sleep(3); } catch (InterruptedException e) { e.printStackTrace(); } return serverPort; } ... }

2.服务消费方80添加超时方法PaymentFeignService

@Component @FeignClient(value = "CLOUD-PAYMENT-SERVICE") public interface PaymentFeignService{ ... @GetMapping(value = "/payment/feign/timeout") public String paymentFeignTimeout(); }

3.服务消费方80添加超时方法OrderFeignController

@RestController @Slf4j public class OrderFeignController { @Resource private PaymentFeignService paymentFeignService; ... @GetMapping(value = "/consumer/payment/feign/timeout") public String paymentFeignTimeout() { // OpenFeign客户端一般默认等待1秒钟 return paymentFeignService.paymentFeignTimeout(); } }

4.测试:

多次刷新http://localhost/consumer/payment/feign/timeout

将会跳出错误Spring Boot默认错误页面,主要异常:feign.RetryableException:Read timed out executing GET http://CLOUD-PAYMENT-SERVCE/payment/feign/timeout。

OpenFeign默认等待1秒钟,超过后报错

YML文件里需要开启OpenFeign客户端超时控制

#设置feign客户端超时时间(OpenFeign默认支持ribbon)(单位:毫秒) ribbon: #指的是建立连接所用的时间,适用于网络状况正常的情况下,两端连接所用的时间 ReadTimeout: 5000 #指的是建立连接后从服务器读取到可用资源所用的时间 ConnectTimeout: 5000 46_OpenFeign日志增强

日志打印功能

Feign提供了日志打印功能,我们可以通过配置来调整日恙级别,从而了解Feign 中 Http请求的细节。

说白了就是对Feign接口的调用情况进行监控和输出

日志级别

NONE:默认的,不显示任何日志;BASIC:仅记录请求方法、URL、响应状态码及执行时间;HEADERS:除了BASIC中定义的信息之外,还有请求和响应的头信息;FULL:除了HEADERS中定义的信息之外,还有请求和响应的正文及元数据。

配置日志bean

import feign.Logger; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration public class FeignConfig { @Bean Logger.Level feignLoggerLevel() { return Logger.Level.FULL; } }

YML文件里需要开启日志的Feign客户端

logging: level: # feign日志以什么级别监控哪个接口 com.lun.springcloud.service.PaymentFeignService: debug

后台日志查看

得到更多日志信息。

47_Hystrix是什么

概述

分布式系统面临的问题

复杂分布式体系结构中的应用程序有数十个依赖关系,每个依赖关系在某些时候将不可避免地失败。

服务雪崩

多个微服务之间调用的时候,假设微服务A调用微服务B和微服务C,微服务B和微服务C又调用其它的微服务,这就是所谓的“扇出”。如果扇出的链路上某个微服务的调用响应时间过长或者不可用,对微服务A的调用就会占用越来越多的系统资源,进而引起系统崩溃,所谓的“雪崩效应”. 对于高流量的应用来说,单一的后避依赖可能会导致所有服务器上的所有资源都在几秒钟内饱和。比失败更糟糕的是,这些应用程序还可能导致服务之间的延迟增加,备份队列,线程和其他系统资源紧张,导致整个系统发生更多的级联故障。这些都表示需要对故障和延迟进行隔离和管理,以便单个依赖关系的失败,不能取消整个应用程序或系统。

所以,通常当你发现一个模块下的某个实例失败后,这时候这个模块依然还会接收流量,然后这个有问题的模块还调用了其他的模块,这样就会发生级联故障,或者叫雪崩。

Hystrix是什么

Hystrix是一个用于处理分布式系统的延迟和容错的开源库,在分布式系统里,许多依赖不可避免的会调用失败,比如超时、异常等,Hystrix能够保证在一个依赖出问题的情况下,不会导致整体服务失败,避免级联故障,以提高分布式系统的弹性。

"断路器”本身是一种开关装置,当某个服务单元发生故障之后,通过断路器的故障监控(类似熔断保险丝),向调用方返回一个符合预期的、可处理的备选响应(FallBack),而不是长时间的等待或者抛出调用方无法处理的异常,这样就保证了服务调用方的线程不会被长时间、不必要地占用,从而避免了故障在分布式系统中的蔓延,乃至雪崩。

hystrix n. 豪猪属;猬草属;豪猪;豪猪亚属

48_Hystrix停更进维

能干嘛

服务降级服务熔断接近实对的监控…

官网资料

link

Hystrix官宣,停更进维

link

被动修bugs不再接受合并请求不再发布新版本 49_Hystrix的服务降级熔断限流概念初讲

服务降级

服务器忙,请稍后再试,不让客户端等待并立刻返回一个友好提示,fallback

哪些情况会出发降级

程序运行导常超时服务熔断触发服务降级线程池/信号量打满也会导致服务降级

服务熔断

类比保险丝达到最大服务访问后,直接拒绝访问,拉闸限电,然后调用服务降级的方法并返回友好提示。

服务的降级 -> 进而熔断 -> 恢复调用链路

服务限流

秒杀高并发等操作,严禁一窝蜂的过来拥挤,大家排队,一秒钟N个,有序进行。

50_Hystrix支付微服务构建

将cloud-eureka-server7001改配置成单机版

1.新建cloud-provider-hygtrix-payment8001

2.POM

<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://·:7001/eureka,http://eureka7002.com:7002/eureka defaultZone: http://eureka7001.com:7001/eureka

4.主启动

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

5.业务类

service

import org.springframework.stereotype.Service; import java.util.concurrent.TimeUnit; /** */ @Service public class PaymentService { /** */ public String paymentInfo_OK(Integer id) { return "线程池: "+Thread.currentThread().getName()+" paymentInfo_OK,id: "+id+"\t"+"O(∩_∩)O哈哈~"; } public String paymentInfo_TimeOut(Integer id) { try { TimeUnit.MILLISECONDS.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); } return "线程池: "+Thread.currentThread().getName()+" id: "+id+"\t"+"O(∩_∩)O哈哈~"+" 耗时(秒): 3"; } }

controller

import com.lun.springcloud.service.PaymentService; 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.PathVariable; import org.springframework.web.bind.annotation.RestController; import javax.annotation.Resource; /** */ @RestController @Slf4j public class PaymentController { @Resource private PaymentService paymentService; @Value("${server.port}") private String serverPort; @GetMapping("/payment/hystrix/ok/{id}") public String paymentInfo_OK(@PathVariable("id") Integer id) { String result = paymentService.paymentInfo_OK(id); log.info("*****result: "+result); return result; } @GetMapping("/payment/hystrix/timeout/{id}") public String paymentInfo_TimeOut(@PathVariable("id") Integer id) { String result = paymentService.paymentInfo_TimeOut(id); log.info("*****result: "+result); return result; } }

6.正常测试

启动eureka7001

启动cloud-provider-hystrix-payment8001

访问

success的方法 - http://localhost:8001/payment/hystrix/ok/1 每次调用耗费5秒钟 - http://localhost:8001/payment/hystrix/timeout/1

上述module均OK

以上述为根基平台,从正确 -> 错误 -> 降级熔断 -> 恢复。

51_JMeter高并发压测后卡顿

上述在非高并发情形下,还能勉强满足

Jmeter压测测试

JMeter官网

The Apache JMeter? application is open source software, a 100% pure Java application designed to load test functional behavior and measure performance. It was originally designed for testing Web Applications but has since expanded to other test functions.

开启Jmeter,来20000个并发压死8001,20000个请求都去访问paymentInfo_TimeOut服务

1.测试计划中右键添加-》线程-》线程组(线程组202102,线程数:200,线程数:100,其他参数默认)

2.刚刚新建线程组202102,右键它-》添加-》取样器-》Http请求-》基本 输入http://localhost:8001/payment/hystrix/ok/1

3.点击绿色三角形图标启动。

看演示结果:拖慢,原因:tomcat的默认的工作线程数被打满了,没有多余的线程来分解压力和处理。

Jmeter压测结论

上面还是服务提供者8001自己测试,假如此时外部的消费者80也来访问,那消费者只能干等,最终导致消费端80不满意,服务端8001直接被拖慢。

52_订单微服务调用支付服务出现卡顿

看热闹不嫌弃事大,80新建加入

1.新建 - cloud-consumer-feign-hystrix-order80

2.POM

<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://·:7001/eureka/

4.主启动

import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.netflix.hystrix.EnableHystrix; import org.springframework.cloud.openfeign.EnableFeignClients; /** */ @SpringBootApplication @EnableFeignClients //@EnableHystrix public class OrderHystrixMain80 { public static void main(String[] args) { SpringApplication.run(OrderHystrixMain80.class,args); } }

5.业务类

import org.springframework.cloud.openfeign.FeignClient; import org.springframework.stereotype.Component; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; /** */ @Component @FeignClient(value = "CLOUD-PROVIDER-HYSTRIX-PAYMENT" /*,fallback = PaymentFallbackService.class*/) public interface PaymentHystrixService { @GetMapping("/payment/hystrix/ok/{id}") public String paymentInfo_OK(@PathVariable("id") Integer id); @GetMapping("/payment/hystrix/timeout/{id}") public String paymentInfo_TimeOut(@PathVariable("id") Integer id); } import com.lun.springcloud.service.PaymentHystrixService; import lombok.extern.slf4j.Slf4j; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RestController; import javax.annotation.Resource; @RestController @Slf4j public class OrderHystirxController { @Resource private PaymentHystrixService paymentHystrixService; @GetMapping("/consumer/payment/hystrix/ok/{id}") public String paymentInfo_OK(@PathVariable("id") Integer id) { String result = paymentHystrixService.paymentInfo_OK(id); return result; } @GetMapping("/consumer/payment/hystrix/timeout/{id}") public String paymentInfo_TimeOut(@PathVariable("id") Integer id) { String result = paymentHystrixService.paymentInfo_TimeOut(id); return result; } }

6.正常测试

http://localhost/consumer/payment/hystrix/ok/1

7.高并发测试

2W个线程压8001

消费端80微服务再去访问正常的Ok微服务8001地址

http://localhost/consumer/payment/hystrix/ok/32

消费者80被拖慢

原因:8001同一层次的其它接口服务被困死,因为tomcat线程池里面的工作线程已经被挤占完毕。

正因为有上述故障或不佳表现才有我们的降级/容错/限流等技术诞生。

53_降级容错解决的维度要求

超时导致服务器变慢(转圈) - 超时不再等待

出错(宕机或程序运行出错) - 出错要有兜底

解决:

对方服务(8001)超时了,调用者(80)不能一直卡死等待,必须有服务降级。对方服务(8001)down机了,调用者(80)不能一直卡死等待,必须有服务降级。对方服务(8001)OK,调用者(80)自己出故障或有自我要求(自己的等待时间小于服务提供者),自己处理降级。 54_Hystrix之服务降级支付侧fallback

降级配置 - @HystrixCommand

8001先从自身找问题

设置自身调用超时时间的峰值,峰值内可以正常运行,超过了需要有兜底的方法处埋,作服务降级fallback。

8001fallback

业务类启用 - @HystrixCommand报异常后如何处理

—旦调用服务方法失败并抛出了错误信息后,会自动调用@HystrixCommand标注好的fallbackMethod调用类中的指定方法

@Service public class PaymentService{ @HystrixCommand(fallbackMethod = "paymentInfo_TimeOutHandler"/*指定善后方法名*/,commandProperties = { @HystrixProperty(name="execution.isolation.thread.timeoutInMilliseconds",value="3000") }) public String paymentInfo_TimeOut(Integer id) { //int age = 10/0; try { TimeUnit.MILLISECONDS.sleep(5000); } catch (InterruptedException e) { e.printStackTrace(); } return "线程池: "+Thread.currentThread().getName()+" id: "+id+"\t"+"O(∩_∩)O哈哈~"+" 耗时(秒): "; } //用来善后的方法 public String paymentInfo_TimeOutHandler(Integer id) { return "线程池: "+Thread.currentThread().getName()+" 8001系统繁忙或者运行报错,请稍后再试,id: "+id+"\t"+"o(╥﹏╥)o"; } }

上面故意制造两种异常:

int age = 10/0,计算异常我们能接受3秒钟,它运行5秒钟,超时异常。

当前服务不可用了,做服务降级,兜底的方案都是paymentInfo_TimeOutHandler

主启动类激活

添加新注解@EnableCircuitBreaker

import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker; import org.springframework.cloud.netflix.eureka.EnableEurekaClient; @SpringBootApplication @EnableEurekaClient @EnableCircuitBreaker//添加到此处 public class PaymentHystrixMain8001{ public static void main(String[] args) { SpringApplication.run(PaymentHystrixMain8001.class, args); } } 55_Hystrix之服务降级订单侧fallback

80订单微服务,也可以更好的保护自己,自己也依样画葫芦进行客户端降级保护

题外话,切记 - 我们自己配置过的热部署方式对java代码的改动明显

但对@HystrixCommand内属性的修改建议重启微服务

YML

server: port: 80 eureka: client: register-with-eureka: false service-url: defaultZone: http://eureka7001.com:7001/eureka/ #开启 feign: hystrix: enabled: true

主启动

import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.netflix.hystrix.EnableHystrix; import org.springframework.cloud.openfeign.EnableFeignClients; @SpringBootApplication @EnableFeignClients @EnableHystrix//添加到此处 public class OrderHystrixMain80{ public static void main(String[] args){ SpringApplication.run(OrderHystrixMain80.class,args); } }

业务类

import com.lun.springcloud.service.PaymentHystrixService; import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand; import com.netflix.hystrix.contrib.javanica.annotation.HystrixProperty; import lombok.extern.slf4j.Slf4j; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RestController; import javax.annotation.Resource; @RestController @Slf4j public class OrderHystirxController { @Resource private PaymentHystrixService paymentHystrixService; @GetMapping("/consumer/payment/hystrix/timeout/{id}") @HystrixCommand(fallbackMethod = "paymentTimeOutFallbackMethod",commandProperties = { @HystrixProperty(name="execution.isolation.thread.timeoutInMilliseconds",value="1500") }) public String paymentInfo_TimeOut(@PathVariable("id") Integer id) { //int age = 10/0; String result = paymentHystrixService.paymentInfo_TimeOut(id); return result; } //善后方法 public String paymentTimeOutFallbackMethod(@PathVariable("id") Integer id){ return "我是消费者80,对方支付系统繁忙请10秒钟后再试或者自己运行出错请检查自己,o(╥﹏╥)o"; } }


1.本站遵循行业规范,任何转载的稿件都会明确标注作者和来源;2.本站的原创文章,会注明原创字样,如未注明都非原创,如有侵权请联系删除!;3.作者投稿可能会经我们编辑修改或补充;4.本站不提供任何储存功能只提供收集或者投稿人的网盘链接。

标签: #Sentinel #Spring #Cloud #学习笔记2 #3Spring #学习笔记3