diff --git "a/12 \344\272\277\347\272\247\346\265\201\351\207\217\345\244\232\347\272\247\347\274\223\345\255\230\351\253\230\345\271\266\345\217\221\347\263\273\347\273\237\346\236\266\346\236\204\345\256\236\346\210\230/12 \344\272\277\347\272\247\346\265\201\351\207\217\345\244\232\347\272\247\347\274\223\345\255\230\351\253\230\345\271\266\345\217\221\347\263\273\347\273\237\346\236\266\346\236\204\345\256\236\346\210\230.rar" "b/12 \344\272\277\347\272\247\346\265\201\351\207\217\345\244\232\347\272\247\347\274\223\345\255\230\351\253\230\345\271\266\345\217\221\347\263\273\347\273\237\346\236\266\346\236\204\345\256\236\346\210\230/12 \344\272\277\347\272\247\346\265\201\351\207\217\345\244\232\347\272\247\347\274\223\345\255\230\351\253\230\345\271\266\345\217\221\347\263\273\347\273\237\346\236\266\346\236\204\345\256\236\346\210\230.rar"
deleted file mode 100644
index e6b3954..0000000
Binary files "a/12 \344\272\277\347\272\247\346\265\201\351\207\217\345\244\232\347\272\247\347\274\223\345\255\230\351\253\230\345\271\266\345\217\221\347\263\273\347\273\237\346\236\266\346\236\204\345\256\236\346\210\230/12 \344\272\277\347\272\247\346\265\201\351\207\217\345\244\232\347\272\247\347\274\223\345\255\230\351\253\230\345\271\266\345\217\221\347\263\273\347\273\237\346\236\266\346\236\204\345\256\236\346\210\230.rar" and /dev/null differ
diff --git "a/18 \347\250\213\345\272\217\345\221\230\350\213\261\350\257\255/spring-quickstart-img/image-20200324153553651.png" "b/18 \347\250\213\345\272\217\345\221\230\350\213\261\350\257\255/spring-quickstart-img/image-20200324153553651.png"
new file mode 100644
index 0000000..c67fbe3
Binary files /dev/null and "b/18 \347\250\213\345\272\217\345\221\230\350\213\261\350\257\255/spring-quickstart-img/image-20200324153553651.png" differ
diff --git "a/18 \347\250\213\345\272\217\345\221\230\350\213\261\350\257\255/spring-quickstart-img/quick-img-1-e0f70cc841acda493440a5560cbc66da.png" "b/18 \347\250\213\345\272\217\345\221\230\350\213\261\350\257\255/spring-quickstart-img/quick-img-1-e0f70cc841acda493440a5560cbc66da.png"
new file mode 100644
index 0000000..2e620c6
Binary files /dev/null and "b/18 \347\250\213\345\272\217\345\221\230\350\213\261\350\257\255/spring-quickstart-img/quick-img-1-e0f70cc841acda493440a5560cbc66da.png" differ
diff --git "a/18 \347\250\213\345\272\217\345\221\230\350\213\261\350\257\255/spring.ioquickstart.md" "b/18 \347\250\213\345\272\217\345\221\230\350\213\261\350\257\255/spring.ioquickstart.md"
new file mode 100644
index 0000000..fec4638
--- /dev/null
+++ "b/18 \347\250\213\345\272\217\345\221\230\350\213\261\350\257\255/spring.ioquickstart.md"
@@ -0,0 +1,217 @@
+# spring.io/quickstart
+
+本期课程讲解Spring官网的`快速上手`页面
+
+官网地址 https://spring.io/quickstart
+
+## Spring Quickstart Guide
+
+Spring 快速开始指南
+
+**Guide**
+
+指南
+
+### What you'll build
+
+接下来你将要构建的是什么?
+
+**build**
+
+构建
+
+#### You will build a classic “Hello World!” endpoint which any browser can connect to. You can even tell it your name, and it will respond in a more friendly way.
+
+您将构建一个经典的“Hello World!”任何浏览器都可以连接的端点。你甚至可以告诉它你的名字,它会以一种更友好的方式回应你。
+
+#### **You will build a classic “Hello World!”** **endpoint which any browser can connect to**
+
+你将要构建的是一个经典的 helloworld端点,任何浏览器都可以连接上。
+
+**classic** 经典的
+
+**endpoint** 端点,终端
+
+**browser** 浏览器
+
+**connect** 连接
+
+#### **You can even tell it your name, and it will respond in a more friendly way.**
+
+你甚至可以告诉它你的名字,它会以一种更友好的方式回应你。
+
+**respond** 应答
+
+### What you’ll need
+
+你需要什么
+
+#### An Integrated Developer Environment (IDE)
+
+一个集成开发环境
+
+**Integrated** 集成
+
+**Developer** 开发
+
+**Environment** 环境
+
+#### Popular choices include [IntelliJ IDEA](https://www.jetbrains.com/idea/), [Spring Tools](https://spring.io/tools), [Visual Studio Code](https://code.visualstudio.com/docs/languages/java), or [Eclipse](https://www.eclipse.org/downloads/packages/), and many more.
+
+比较流行的选择包括 IntelliJ IDEA, Spring Tools, Visual Studio Code, 或者Eclipse,等等。
+
+**include** 包含,包括
+
+#### A Java™ Development Kit (JDK)
+
+对jdk的要求
+
+We recommend [AdoptOpenJDK](https://adoptopenjdk.net/) version 8 or version 11.
+
+我们推荐使用 **AdoptOpenJDK** 8 或者 11版。
+
+**recommend** 建议,推荐
+
+## Step 1: Start a new Spring Boot project
+
+第一步,创建一个新的springboot项目
+
+**Step** 步骤
+
+**project** 项目
+
+#### Use [start.spring.io](https://start.spring.io/) to create a “web” project.
+
+使用**start.spring.io**这个网站创建一个web项目
+
+**create** 创建
+
+#### In the “Dependencies” section search for and add the “web” dependency as shown in the screenshot.
+
+在“依赖项”部分,搜索并添加“web”依赖,如屏幕截图所示。
+
+**Dependencies** 依赖
+
+**section** 一部分
+
+**search**搜索
+
+**shown in ....** 如xx所示
+
+**screenshot** 屏幕截图
+
+
+
+Hit the green “Generate” button, download the zip, and unpack it into a folder on your computer.
+
+点击绿色的**生成**按钮,下载zip文件,并将其解压缩到你电脑上上的一个文件夹里。
+
+**Hit** 点击
+
+**Generate**生成
+
+**button** 按钮
+
+**download** 下载
+
+**zip** 压缩格式
+
+**unpack** 解开,解压缩
+
+**folder** 文件夹
+
+## Step 2: Add your code
+
+第二步,添加你的代码
+
+#### Open up the project in your IDE and locate the `DemoApplication.java` file in the `src/main/java/com/example/demo`folder.
+
+用ide打开刚下载的项目,并在`src/main/java/com/example/demo`文件夹中找到`DemoApplication.java`文件
+
+**locate** 定位,位于
+
+#### Now change the contents of the file by adding the extra method and annotations shown in the code below.
+
+现在,修改文件内容,添加一些额外的方法和注解,如下代码所示
+
+**change** 改变,修改
+
+**contents** 内容
+
+**file** 文件
+
+**extra** 额外,扩展
+
+**method** 方法
+
+**annotations** 注解(不是注释)
+
+```java
+ package com.example.demo;
+ import org.springframework.boot.SpringApplication;
+ import org.springframework.boot.autoconfigure.SpringBootApplication;
+ import org.springframework.web.bind.annotation.GetMapping;
+ import org.springframework.web.bind.annotation.RequestParam;
+ import org.springframework.web.bind.annotation.RestController;
+
+ @SpringBootApplication
+ @RestController
+ public class DemoApplication {
+
+
+ public static void main(String[] args) {
+ SpringApplication.run(DemoApplication.class, args);
+ }
+
+ @GetMapping("/hello")
+ public String hello(@RequestParam(value = "name", defaultValue = "World") String name) {
+ return String.format("Hello %s!", name);
+ }
+
+ }
+
+```
+
+
+
+#### You can copy and paste the code or just type it.
+
+你可以直接复制粘贴代码,或者自己敲。
+
+#### The `hello()` method we’ve added is designed to take a String parameter called `name`, and then combine this parameter with the word `"Hello"` in the code.
+
+`hello()`这个方法是我们添加的,我们把它设计成了一个可以接受String类型参数的方法,这个参数名是`name`,在方法体里,连接了`"Hello"`这个词。
+
+**designed** 设计的
+
+**take a String parameter** 获取到一个String类型的参数
+
+**combine** 连接,联合
+
+#### This means that if you set your name to `“Amy”` in the request, the response would be `“Hello Amy”`.
+
+这么写的意思是,如果在请求发过来的时候`name`这个参数被设置成了`amy`,那么响应的结果就是`“Hello Amy”`
+
+**request** 请求
+
+**response** 响应
+
+#### The `@RestController` annotation tells Spring that this code describes an endpoint that should be made available over the web.
+
+`@RestController`这个注解告诉Spring,我们的这些代码想要开启一个可用的web服务端点
+
+**describes** 描述
+
+#### The `@GetMapping(“/hello”)` tells Spring to use our `hello()` method to answer requests that get sent to the `http://localhost:8080/hello` address.
+
+`@GetMapping(“/hello”)` 这个注解写在了`hello()`这个方法上,告诉Spring我们想用这个方法应答请求,当请求地址为`http://localhost:8080/hello`时会执行这个方法
+
+**address** 地址
+
+#### Finally, the `@RequestParam` is telling Spring to expect a `name` value in the request, but if it’s not there, it will use the word “World” by default.
+
+最后,`@RequestParam` 告诉Spring在处理请求时,期望接收到一个传递过来的`'name'`值,但是如果没有传值过来那么就使用`' World '`这个词作为默认值。
+
+**expect** 期望
+
+**default** 默认
\ No newline at end of file
diff --git "a/18 \347\250\213\345\272\217\345\221\230\350\213\261\350\257\255/spring.ioquickstart.pdf" "b/18 \347\250\213\345\272\217\345\221\230\350\213\261\350\257\255/spring.ioquickstart.pdf"
new file mode 100644
index 0000000..4e40da8
Binary files /dev/null and "b/18 \347\250\213\345\272\217\345\221\230\350\213\261\350\257\255/spring.ioquickstart.pdf" differ
diff --git "a/20 \346\236\266\346\236\204\345\270\210\344\270\211\346\234\237 SpringCloud\345\276\256\346\234\215\345\212\241\346\236\266\346\236\204/SpringCloud01.pptx" "b/20 \346\236\266\346\236\204\345\270\210\344\270\211\346\234\237 SpringCloud\345\276\256\346\234\215\345\212\241\346\236\266\346\236\204/SpringCloud01.pptx"
new file mode 100644
index 0000000..db7d885
Binary files /dev/null and "b/20 \346\236\266\346\236\204\345\270\210\344\270\211\346\234\237 SpringCloud\345\276\256\346\234\215\345\212\241\346\236\266\346\236\204/SpringCloud01.pptx" differ
diff --git "a/20 \346\236\266\346\236\204\345\270\210\344\270\211\346\234\237 SpringCloud\345\276\256\346\234\215\345\212\241\346\236\266\346\236\204/SpringCloud02.md" "b/20 \346\236\266\346\236\204\345\270\210\344\270\211\346\234\237 SpringCloud\345\276\256\346\234\215\345\212\241\346\236\266\346\236\204/SpringCloud02.md"
new file mode 100644
index 0000000..d3a2d68
--- /dev/null
+++ "b/20 \346\236\266\346\236\204\345\270\210\344\270\211\346\234\237 SpringCloud\345\276\256\346\234\215\345\212\241\346\236\266\346\236\204/SpringCloud02.md"
@@ -0,0 +1,710 @@
+# SpringCloud 02
+
+## Spring Cloud
+
+Spring Cloud 自 2016 年 1 月发布第一个 Angel.SR5 版本,到目前 2020 年 3 月发布 Hoxton.SR3 版本,已经历经了 4 年时间。这 4 年时间里,Spring Cloud 一共发布了 46 个版本,支持的组件数从 5 个增加到 21 个。Spring Cloud 在 2019 年 12 月对外宣布后续 RoadMap:
+
+- 下一个版本 Ilford 版本是一个大版本。这个版本基于 Spring Framework 5.3 & Spring Boot 2.4,会在 2020 Q4 左右发布;
+- Ilford 版本会删除处于维护模式的项目。目前处于维护模式的 Netflix 大部分项目都会被删除(spring-cloud-netflix Github 项目已经删除了这些维护模式的项目);
+- 简化 Spring Cloud 发布列车。后续 IaasS 厂商对应的 Spring Cloud 项目会移出 Spring Cloud 组织,各自单独维护(spring-cloud-azure 一直都是单独维护,spring-cloud-alibaba 孵化在 Spring Cloud 组织,毕业后单独维护);
+- API 重构,会带来重大的改变(Spring Cloud Hoxton 版本新增了 Spring Cloud Circuit Breaker 用于统一熔断操作的编程模型和 Spring Cloud LoadBalanacer 用于处理客户端负载均衡并代替 Netflix Ribbon)。
+
+这个 RoadMap 可以说是对 Spring Cloud 有着非常大的变化。
+
+### SpringCloud替代实现
+
+
+
+
+
+### SpringCloud Alibaba
+
+## 组件
+
+**[Sentinel](https://github.com/alibaba/Sentinel)**:把流量作为切入点,从流量控制、熔断降级、系统负载保护等多个维度保护服务的稳定性。
+
+**[Nacos](https://github.com/alibaba/Nacos)**:一个更易于构建云原生应用的动态服务发现、配置管理和服务管理平台。
+
+**[RocketMQ](https://rocketmq.apache.org/)**:一款开源的分布式消息系统,基于高可用分布式集群技术,提供低延时的、高可靠的消息发布与订阅服务。
+
+**[Dubbo](https://github.com/apache/dubbo)**:Apache Dubbo™ 是一款高性能 Java RPC 框架。
+
+**[Seata](https://github.com/seata/seata)**:阿里巴巴开源产品,一个易于使用的高性能微服务分布式事务解决方案。
+
+**[Alibaba Cloud ACM](https://www.aliyun.com/product/acm)**:一款在分布式架构环境中对应用配置进行集中管理和推送的应用配置中心产品。
+
+**[Alibaba Cloud OSS](https://www.aliyun.com/product/oss)**: 阿里云对象存储服务(Object Storage Service,简称 OSS),是阿里云提供的海量、安全、低成本、高可靠的云存储服务。您可以在任何应用、任何时间、任何地点存储和访问任意类型的数据。
+
+**[Alibaba Cloud SchedulerX](https://help.aliyun.com/document_detail/43136.html)**: 阿里中间件团队开发的一款分布式任务调度产品,提供秒级、精准、高可靠、高可用的定时(基于 Cron 表达式)任务调度服务。
+
+**[Alibaba Cloud SMS](https://www.aliyun.com/product/sms)**: 覆盖全球的短信服务,友好、高效、智能的互联化通讯能力,帮助企业迅速搭建客户触达通道。
+
+
+
+## 第一阶段课程Spring Cloud技术点
+
+Eureka:服务注册与发现,用于服务管理。
+
+Feign: web调用客户端,能够简化HTTP接口的调用。
+
+Ribbon:基于客户端的负载均衡。
+
+Hystrix:熔断降级,防止服务雪崩。
+
+Zuul:网关路由,提供路由转发、请求过滤、限流降级等功能。
+
+Config:配置中心,分布式配置管理。
+
+Sleuth:服务链路追踪
+
+Admin:健康管理
+
+## 服务进化概述
+
+1. 传统服务到微服务进化。
+
+ > 《传统到分布式演进》
+
+2. 单体应用-> SOA ->微服务(下面讲)
+
+```
+课外扩展:
+持续集成,持续部署,持续交付。
+集成:是指软件个人研发的部分向软件整体部分集成,以便尽早发现个人开发部分的问题;
+部署: 是代码尽快向可运行的开发/测试节交付,以便尽早测试;
+交付: 是指研发尽快向客户交付,以便尽早发现生产环境中存在的问题。
+ 如果说等到所有东西都完成了才向下个环节交付,导致所有的问题只能在最后才爆发出来,解决成本巨大甚至无法解决。而所谓的持续,就是说每完成一个完整的部分,就向下个环节交付,发现问题可以马上调整。使问题不会放大到其他部分和后面的环节。
+ 这种做法的核心思想在于:既然事实上难以做到事先完全了解完整的、正确的需求,那么就干脆一小块一小块的做,并且加快交付的速度和频率,使得交付物尽早在下个环节得到验证。早发现问题早返工。
+
+上面的3个持续,也都随着微服务的发展而发展,当架构师的同学,可以参考这种方式。
+
+持续集成的工具,向大家推荐:https://jenkins.io/doc/book/pipeline/
+```
+
+### 单体应用
+
+1. 概念:所有功能全部打包在一起。应用大部分是一个war包或jar包。我参与网约车最开始架构是:一个乘客项目中有 用户、订单、消息、地图等功能。随着业务发展,功能增多,这个项目会越来越臃肿。
+
+2. 好处:容易开发、测试、部署,适合项目初期试错。
+
+3. 坏处:
+
+ 随着项目越来越复杂,团队不断扩大。坏处就显现出来了。
+
+ - 复杂性高:代码多,十万行,百万行级别。加一个小功能,会带来其他功能的隐患,因为它们在一起。
+ - 技术债务:人员流动,不坏不修,因为不敢修。
+ - 持续部署困难:由于是全量应用,改一个小功能,全部部署,会导致无关的功能暂停使用。编译部署上线耗时长,不敢随便部署,导致部署频率低,进而又导致两次部署之间 功能修改多,越不敢部署,恶性循环。
+ - 可靠性差:某个小问题,比如小功能出现OOM,会导致整个应用崩溃。
+ - 扩展受限:只能整体扩展,无法按照需要进行扩展, 不能根据计算密集型(派单系统)和IO密集型(文件服务) 进行合适的区分。
+ - 阻碍创新:单体应用是以一种技术解决所有问题,不容易引入新技术。但在高速的互联网发展过程中,适应的潮流是:用合适的语言做合适的事情。比如在单体应用中,一个项目用spring MVC,想换成spring boot,切换成本很高,因为有可能10万,百万行代码都要改,而微服务可以轻松切换,因为每个服务,功能简单,代码少。
+
+### SOA
+
+ 对单体应用的改进:引入SOA(Service-Oriented Architecture)面向服务架构,拆分系统,用服务的流程化来实现业务的灵活性。服务间需要某些方法进行连接,面向接口等,它是一种设计方法,其中包含多个服务, 服务之间通过相互依赖最终提供一系列的功能。一个服务 通常以独立的形式存在于操作系统进程中。各个服务之间 通过网络调用。但是还是需要用些方法来进行服务组合,有可能还是个单体应用。
+
+
+
+所以要引入微服务,是SOA思想的一种具体实践。
+
+微服务架构 = 80%的SOA服务架构思想 + 100%的组件化架构思想
+
+### 微服务
+
+#### 微服务概况
+
+- 无严格定义。
+- 微服务是一种架构风格,将单体应用划分为小型的服务单元。
+- 微服务架构是一种使用一系列粒度较小的服务来开发单个应用的方式;每个服务运行在自己的进程中;服务间采用轻量级的方式进行通信(通常是HTTP API);这些服务是基于业务逻辑和范围,通过自动化部署的机制来独立部署的,并且服务的集中管理应该是最低限度的,即每个服务可以采用不同的编程语言编写,使用不同的数据存储技术。
+- 英文定义:
+
+```sh
+看这篇文章:
+http://www.martinfowler.com/articles/microservices.html
+```
+
+- 小类比
+
+ 合久必分。分开后通信,独立部署,独立存储。
+
+```sh
+分封制:
+服从天子命令:服从服务管理。
+有为天子镇守疆土的义务:各自完成各自的一块业务。
+随从作战:服务调用。
+交纳贡献:分担流量压力。
+```
+
+- 段子(中台战略)
+
+```
+Q:大师大师,服务拆多了怎么办?
+A:那就再合起来。
+Q:那太没面子了。
+A:那就说跨过了微服务初级阶段,在做中台(自助建站系统)。
+```
+
+
+
+#### 微服务特性
+
+独立运行在自己进程中。
+
+一系列独立服务共同构建起整个系统。
+
+一个服务只关注自己的独立业务。
+
+轻量的通信机制RESTful API
+
+使用不同语言开发
+
+全自动部署机制
+
+#### 微服务组件介绍
+
+不局限与具体的微服务实现技术。
+
+- 服务注册与发现:服务提供方将己方调用地址注册到服务注册中心,让服务调用方能够方便地找到自己;服务调用方从服务注册中心找到自己需要调用的服务的地址。
+
+- 负载均衡:服务提供方一般以多实例的形式提供服务,负载均衡功能能够让服务调用方连接到合适的服务节点。并且,服务节点选择的过程对服务调用方来说是透明的。
+
+- 服务网关:服务网关是服务调用的唯一入口,可以在这个组件中实现用户鉴权、动态路由、灰度发布、A/B测试、负载限流等功能。
+
+ ```
+ 灰度发布(又名金丝雀发布)是指在黑与白之间,能够平滑过渡的一种发布方式。在其上可以进行A/B testing,即让一部分用户继续用产品特性A,一部分用户开始用产品特性B,如果用户对B没有什么反对意见,那么逐步扩大范围,把所有用户都迁移到B上面来。灰度发布可以保证整体系统的稳定,在初始灰度的时候就可以发现、调整问题,以保证其影响度。
+ ```
+
+- 配置中心:将本地化的配置信息(Properties、XML、YAML等形式)注册到配置中心,实现程序包在开发、测试、生产环境中的无差别性,方便程序包的迁移,也是无状态特性。
+
+- 集成框架:微服务组件都以职责单一的程序包对外提供服务,集成框架以配置的形式将所有微服务组件(特别是管理端组件)集成到统一的界面框架下,让用户能够在统一的界面中使用系统。Spring Cloud就是一个集成框架。
+
+- 调用链监控:记录完成一次请求的先后衔接和调用关系,并将这种串行或并行的调用关系展示出来。在系统出错时,可以方便地找到出错点。
+
+- 支撑平台:系统微服务化后,各个业务模块经过拆分变得更加细化,系统的部署、运维、监控等都比单体应用架构更加复杂,这就需要将大部分的工作自动化。现在,Docker等工具可以给微服务架构的部署带来较多的便利,例如持续集成、蓝绿发布、健康检查、性能监控等等。如果没有合适的支撑平台或工具,微服务架构就无法发挥它最大的功效。
+
+ ```
+ 1. 蓝绿部署是不停老版本,部署新版本然后进行测试,确认OK,将流量切到新版本,然后老版本同时也升级到新版本。
+ 2. 灰度是选择部分部署新版本,将部分流量引入到新版本,新老版本同时提供服务。等待灰度的版本OK,可全量覆盖老版本。
+
+ 灰度是不同版本共存,蓝绿是新旧版本切换,2种模式的出发点不一样。
+ ```
+
+
+
+#### 微服务优点
+
+1. 独立部署。不依赖其他服务,耦合性低,不用管其他服务的部署对自己的影响。
+2. 易于开发和维护:关注特定业务,所以业务清晰,代码量少,模块变的易开发、易理解、易维护。
+3. 启动块:功能少,代码少,所以启动快,有需要停机维护的服务,不会长时间暂停服务。
+4. 局部修改容易:只需要部署 相应的服务即可,适合敏捷开发。
+5. 技术栈不受限:java,node.js等
+6. 按需伸缩:某个服务受限,可以按需增加内存,cpu等。
+7. 职责专一。专门团队负责专门业务,有利于团队分工。
+8. 代码复用。不需要重复写。底层实现通过接口方式提供。
+9. 便于团队协作:每个团队只需要提供API就行,定义好API后,可以并行开发。
+
+#### 微服务缺点
+
+1. 分布式固有的复杂性:容错(某个服务宕机),网络延时,调用关系、分布式事务等,都会带来复杂。
+
+2. 分布式事务的挑战:每个服务有自己的数据库,有点在于不同服务可以选择适合自身业务的数据库。订单用MySQL,评论用Mongodb等。目前最理想解决方案是:柔性事务的最终一致性。
+
+ ```sh
+ 刚性事务:遵循ACID原则,强一致性。
+ 柔性事务:遵循BASE理论,最终一致性;与刚性事务不同,柔性事务允许一定时间内,不同节点的数据不一致,但要求最终一致。
+
+ BASE 是 Basically Available(基本可用)、Soft state(软状态)和 Eventually consistent (最终一致性)三个短语的缩写。BASE理论是对CAP中AP的一个扩展,通过牺牲强一致性来获得可用性,当出现故障允许部分不可用但要保证核心功能可用,允许数据在一段时间内是不一致的,但最终达到一致状态。满足BASE理论的事务,我们称之为“柔性事务”。
+ ```
+
+3. 接口调整成本高:改一个接口,调用方都要改。
+
+4. 测试难度提升:一个接口改变,所有调用方都得测。自动化测试就变的重要了。API文档的管理也尤为重要。推荐:yapi。
+
+5. 运维要求高:需要维护 几十 上百个服务。监控变的复杂。并且还要关注多个集群,不像原来单体,一个应用正常运行即可。
+
+6. 重复工作:比如java的工具类可以在共享common.jar中,但在多语言下行不通,C++无法直接用java的jar包。
+
+#### 设计原则
+
+单一职责原则:关注整个系统功能中单独,有界限的一部分。
+
+服务自治原则:可以独立开发,测试,构建,部署,运行,与其他服务解耦。
+
+轻量级通信原则:轻,跨平台,跨语言。REST,AMQP 等。
+
+粒度把控:与自己实际相结合。 不要追求完美,随业务进化而调整。《淘宝技术这10年》。
+
+## 技术选型
+
+1. Spring Cloud和dubbo组件比较
+
+ ```sh
+ dubbo:zookeeper+dubbo+springmvc/springboot
+ 通信方式:rpc
+ 注册中心:zookeeper,nacos
+ 配置中心:diamond(淘宝开发)
+
+ spring cloud:spring+Netflix
+ 通信方式:http restful
+ 注册中心:eureka,consul,nacos
+ 配置中心:config
+ 断路器:hystrix
+ 网关:zuul,gateway
+ 分布式追踪系统:sleuth+zipkin
+
+ ```
+
+2. 差别
+
+ | | **dubbo** | **spring cloud** | |
+ | ---------- | --------------------------------------------------------- | ------------------------------------------------------------ | --------- |
+ | 背景 | 国内影响大 | 国外影响大 | 平手 |
+ | 社区活跃度 | 低(现在又好了) | 高 | cloud胜出 |
+ | 架构完整度 | 不完善(dubbo有些不提供,需要用第三方,它只关注服务治理) | 比较完善,微服务组件应有尽有。 | cloud胜出 |
+ | 学习成本 | dubbo需要配套学习 | 无缝spring | cloud胜出 |
+ | 性能 | 高。(基于Netty) | 低。(基于http,每次都要创建)。 此性能的损耗对大部分应用是可以接受的。而HTTP风格的API,是很方便的。用小的性能损耗换来了方便。 | dubbo胜出 |
+
+## Spring Cloud
+
+### 概念
+
+Spring Cloud是实现微服务架构的一系列框架的有机集合。
+
+是在Spring Boot基础上构建的,用于简化分布式系统构建的工具集。是拥有众多子项目的项目集合。利用Spring Boot的开发便利性,巧妙地简化了分布式系统基础设施(服务注册与发现、熔断机制、网关路由、配置中心、消息总线、负载均衡、链路追踪等)的开发。
+
+
+
+### 版本演进
+
+1. 版本过程:版本名.版本号。
+
+2. 版本名:伦敦地铁字母顺序。
+
+3. 版本号:M(milestone):里程碑,
+
+ SR(Service Releases):稳定版,
+
+ RC(Release Candidate):稳定版的候选版,也就是稳定版的最后一个版本。
+
+```
+看官网:查询每个cloud版本下面的子模块的版本。
+https://spring.io/projects/spring-cloud
+此网页的最下面,目前最新的SpringCloud最新版本是:Greenwich.SR2
+```
+
+
+
+```sh
+版本记录
+https://github.com/spring-cloud/spring-cloud-release/releases
+```
+
+### 整体架构
+
+> 《Spring Cloud整体架构图》
+
+组成:
+
+1. 服务注册与发现组件:Eureka,Zookeeper,Consul,Nacos等。Eureka基于REST风格的。
+
+2. 服务调用组件:Hystrix(熔断降级,在出现依赖服务失效的情况下,通过隔离 系统依赖服务 的方式,防止服务级联失败,同时提供失败回滚机制,使系统能够更快地从异常中恢复),Ribbon(客户端负载均衡,用于提供客户端的软件负载均衡算法,提供了一系列完善的配置项:连接超时、重试等),OpenFeign(优雅的封装Ribbon,是一个声明式RESTful网络请求客户端,它使编写Web服务客户端变得更加方便和快捷)。
+
+3. 网关:路由和过滤。Zuul,Gateway。
+
+4. 配置中心:提供了配置集中管理,动态刷新配置的功能;配置通过Git或者其他方式来存储。
+
+5. 消息组件:Spring Cloud Stream(对分布式消息进行抽象,包括发布订阅、分组消费等功能,实现了微服务之间的异步通信)和Spring Cloud Bus(主要提供服务间的事件通信,如刷新配置)
+
+6. 安全控制组件:Spring Cloud Security 基于OAuth2.0开放网络的安全标准,提供了单点登录、资源授权和令牌管理等功能。
+
+7. 链路追踪组件:Spring Cloud Sleuth(收集调用链路上的数据),Zipkin(对Sleuth收集的信息,进行存储,统计,展示)。
+
+
+
+ 每个点中的内容,后面都会讲到。
+
+## 独立微服务编写
+
+### 开发工具
+
+STS
+
+https://spring.io/tools
+
+### 目的
+
+通过这个服务来看eureka注册中心的效果。
+
+复习Spring Boot。
+
+减少了大量配置。快速开发。
+
+用Starter集成一个新框架。比如redis,web等。添加依赖,加配置文件。
+
+嵌入式服务器,令开发和部署变的方便。
+
+```
+Spring Boot介绍:
+https://docs.spring.io/spring-boot/docs/2.1.7.RELEASE/
+```
+
+### 代码步骤
+
+1. pom.xml
+2. application.yml
+3. java代码
+
+看代码。
+
+## 服务注册与发现
+
+### Eureka 单节点搭建
+
+1. pom.xml
+
+ ```sh
+
+ org.springframework.cloud
+ spring-cloud-starter-netflix-eureka-server
+
+
+ 有的教程中还引入spring-boot-starter-web,其实不用。因为上面的依赖已经包含了它。在pom中点此依赖进去,一共点4次spring-cloud-netflix-eureka-server,发现web的依赖。
+
+ ```
+
+2. application.yml
+
+ ```sh
+ eureka:
+ client:
+ #是否将自己注册到Eureka Server,默认为true,由于当前就是server,故而设置成false,表明该服务不会向eureka注册自己的信息
+ register-with-eureka: false
+ #是否从eureka server获取注册信息,由于单节点,不需要同步其他节点数据,用false
+ fetch-registry: false
+ #设置服务注册中心的URL,用于client和server端交流
+ service-url:
+ defaultZone: http://localhost:7900/eureka/
+ ```
+
+3. application.properties
+
+ ```properties
+ #是否将自己注册到Eureka Server,默认为true,由于当前就是server,故而设置成false,表明该服务不会向eureka注册自己的信息
+ eureka.client.register-with-eureka=false
+ #是否从eureka server获取注册信息,由于单节点,不需要同步其他节点数据,用false
+ eureka.client.fetch-registry=false
+ #设置服务注册中心的URL,用于client和server端交流
+ eureka.client.service-url.defaultZone=http://localhost:7900/eureka/
+ ```
+
+
+
+4. 代码
+
+ ```sh
+ 启动类上添加此注解标识该服务为配置中心
+ @EnableEurekaServer
+ ```
+
+5. PS:Eureka会暴露一些端点。端点用于Eureka Client注册自身,获取注册表,发送心跳。
+
+6. 简单看一下eureka server控制台,实例信息区,运行环境信息区,Eureka Server自身信息区。
+
+
+
+### Eureka 介绍
+
+#### 整体介绍
+
+1. 背景:在传统应用中,组件之间的调用,通过有规范的约束的接口来实现,从而实现不同模块间良好的协作。但是被拆分成微服务后,每个微服务实例的网络地址都可能动态变化,数量也会变化,使得原来硬编码的地址失去了作用。需要一个中心化的组件来进行服务的登记和管理。
+2. 概念:实现服务治理,即管理所有的服务信息和状态。
+
+```sh
+注册中心相当于买票乘车,只看有没有票(有没有服务),有就去买票(获取注册列表),然后乘车(调用)。不必关心有多少火车在运行。
+```
+
+3. 注册中心好处:不用关心有多少提供方。
+
+4. 注册中心有哪些:Eureka,Nacos,Consul,Zookeeper等。
+
+5. 服务注册与发现包括两部分,一个是服务器端,另一个是客户端。
+
+ Server是一个公共服务,为Client提供服务注册和发现的功能,维护注册到自身的Client的相关信息,同时提供接口给Client获取注册表中其他服务的信息,使得动态变化的Client能够进行服务间的相互调用。
+
+ Client将自己的服务信息通过一定的方式登记到Server上,并在正常范围内维护自己信息一致性,方便其他服务发现自己,同时可以通过Server获取到自己依赖的其他服务信息,完成服务调用,还内置了负载均衡器,用来进行基本的负载均衡。
+
+6. 我们课程的Spring Cloud是用Eureka作为服务注册中心。
+
+7. Eureka:是一个RESTful风格的服务,是一个用于服务发现和注册的基础组件,是搭建Spring Cloud微服务的前提之一,它屏蔽了Server和client的交互细节,使得开发者将精力放到业务上。
+
+8. serverA从serverB同步信息,则serverB是serverA的peer。
+
+9. 上面例子中如果service-url为空,且register-with-eureka,fetch-registry为true,则会报错,Cannot execute request on any known server,因为server同时也是一个client,他会尝试注册自己,所以要有一个注册中心url去注册。
+
+10. Netflix开源的组件。包括server和client两部分。
+
+ ```sh
+ https://github.com/Netflix/Eureka
+ ```
+
+#### 注册中心和微服务间的关系
+
+> 《服务注册与发现关系图》
+
+#### client功能
+
+1. 注册:每个微服务启动时,将自己的网络地址等信息注册到注册中心,注册中心会存储(内存中)这些信息。
+2. 获取服务注册表:服务消费者从注册中心,查询服务提供者的网络地址,并使用该地址调用服务提供者,为了避免每次都查注册表信息,所以client会定时去server拉取注册表信息到缓存到client本地。
+3. 心跳:各个微服务与注册中心通过某种机制(心跳)通信,若注册中心长时间和服务间没有通信,就会注销该实例。
+4. 调用:实际的服务调用,通过注册表,解析服务名和具体地址的对应关系,找到具体服务的地址,进行实际调用。
+
+#### server注册中心功能
+
+1. 服务注册表:记录各个微服务信息,例如服务名称,ip,端口等。
+
+ 注册表提供 查询API(查询可用的微服务实例)和管理API(用于服务的注册和注销)。
+
+2. 服务注册与发现:注册:将微服务信息注册到注册中心。发现:查询可用微服务列表及其网络地址。
+
+3. 服务检查:定时检测已注册的服务,如发现某实例长时间无法访问,就从注册表中移除。
+
+组件:Eureka , Consul , ZooKeeper,nacos等。
+
+### 服务注册
+
+例子:api-listen-order
+
+1. pom.xml
+
+```sh
+
+ org.springframework.cloud
+ spring-cloud-starter-netflix-eureka-client
+
+```
+
+2. application.yml
+
+```sh
+#注册中心
+eureka:
+ client:
+ #设置服务注册中心的URL
+ service-url:
+ defaultZone: http://root:root@localhost:7900/eureka/
+```
+
+ps:不想注册,设置成false即可,实例演示结果:注册中心没有实例信息。找控制台204信息也没有找到。
+
+```sh
+spring:
+ cloud:
+ service-registry:
+ auto-registration:
+ enabled: false
+```
+
+注册成功:
+
+```sh
+DiscoveryClient_API-LISTEN-ORDER/api-listen-order:30.136.133.9:port - registration status: 204
+```
+
+后面源码讲手动注册。
+
+PS:
+
+Eureka Server与Eureka Client之间的联系主要通过心跳的方式实现。心跳(Heartbeat)即Eureka Client定时向Eureka Server汇报本服务实例当前的状态,维护本服务实例在注册表中租约的有效性。
+
+Eureka Client将定时从Eureka Server中拉取注册表中的信息,并将这些信息缓存到本地,用于服务发现。
+
+### 服务调用
+
+### Eureka高可用
+
+高可用:可以通过运行多个Eureka server实例并相互注册的方式实现。Server节点之间会彼此增量地同步信息,从而确保节点中数据一致。
+
+
+
+#### 搭建步骤
+
+##### 1.准备
+
+准备2个节点部署eureka,也可以单机部署
+
+修改本机host文件,绑定一个主机名,单机部署时使用ip地址会有问题
+
+##### 2.配置文件
+
+**节点 1:**
+
+```
+#是否将自己注册到其他Eureka Server,默认为true 需要
+eureka.client.register-with-eureka=true
+#是否从eureka server获取注册信息, 需要
+eureka.client.fetch-registry=true
+#设置服务注册中心的URL,用于client和server端交流
+#此节点应向其他节点发起请求
+eureka.client.serviceUrl.defaultZone=http://ek2.com:7902/eureka/
+#主机名,必填
+eureka.instance.hostname=ek1.com
+management.endpoint.shutdown.enabled=true
+#web端口,服务是由这个端口处理rest请求的
+server.port=7901
+
+```
+
+**节点 2:**
+
+```
+#是否将自己注册到其他Eureka Server,默认为true 需要
+eureka.client.register-with-eureka=true
+#是否从eureka server获取注册信息, 需要
+eureka.client.fetch-registry=true
+#设置服务注册中心的URL,用于client和server端交流
+#此节点应向其他节点发起请求
+eureka.client.serviceUrl.defaultZone=http://ek1.com:7902/eureka/
+#主机名,必填
+eureka.instance.hostname=ek2.com
+management.endpoint.shutdown.enabled=true
+#web端口,服务是由这个端口处理rest请求的
+server.port=7902
+```
+
+**节点 1:**
+
+如果有节点3,配置同上 改一下主机名和端口
+
+略。。。
+
+
+
+两个节点的话,如下图内容 就算成功了
+
+
+
+
+
+## 使用Spring Boot2.x Actuator监控应用
+
+### 开启监控
+
+ ```xml
+
+ org.springframework.boot
+ spring-boot-starter-actuator
+
+ ```
+
+
+
+
+
+### 默认端点
+
+Spring Boot 2.0 的Actuator只暴露了health和info端点,提供的监控信息无法满足我们的需求
+
+在1.x中有n多可供我们监控的节点,官方的回答是为了安全….
+
+
+
+### 开启所有端点
+
+在application.yml中加入如下配置信息
+
+*代表所有节点都加载
+
+```properties
+#开启所有端点
+management.endpoints.web.exposure.include=*
+```
+
+
+
+所有端点都开启后的api列表
+
+```
+{"_links":{"self":{"href":"http://localhost:8080/actuator","templated":false},"archaius":{"href":"http://localhost:8080/actuator/archaius","templated":false},"beans":{"href":"http://localhost:8080/actuator/beans","templated":false},"caches-cache":{"href":"http://localhost:8080/actuator/caches/{cache}","templated":true},"caches":{"href":"http://localhost:8080/actuator/caches","templated":false},"health":{"href":"http://localhost:8080/actuator/health","templated":false},"health-path":{"href":"http://localhost:8080/actuator/health/{*path}","templated":true},"info":{"href":"http://localhost:8080/actuator/info","templated":false},"conditions":{"href":"http://localhost:8080/actuator/conditions","templated":false},"configprops":{"href":"http://localhost:8080/actuator/configprops","templated":false},"env":{"href":"http://localhost:8080/actuator/env","templated":false},"env-toMatch":{"href":"http://localhost:8080/actuator/env/{toMatch}","templated":true},"loggers":{"href":"http://localhost:8080/actuator/loggers","templated":false},"loggers-name":{"href":"http://localhost:8080/actuator/loggers/{name}","templated":true},"heapdump":{"href":"http://localhost:8080/actuator/heapdump","templated":false},"threaddump":{"href":"http://localhost:8080/actuator/threaddump","templated":false},"metrics":{"href":"http://localhost:8080/actuator/metrics","templated":false},"metrics-requiredMetricName":{"href":"http://localhost:8080/actuator/metrics/{requiredMetricName}","templated":true},"scheduledtasks":{"href":"http://localhost:8080/actuator/scheduledtasks","templated":false},"mappings":{"href":"http://localhost:8080/actuator/mappings","templated":false},"refresh":{"href":"http://localhost:8080/actuator/refresh","templated":false},"features":{"href":"http://localhost:8080/actuator/features","templated":false},"service-registry":{"href":"http://localhost:8080/actuator/service-registry","templated":false}}}
+```
+
+
+
+### api端点功能
+
+#### Health
+
+会显示系统状态
+
+{"status":"UP"}
+
+
+
+#### shutdown
+
+用来关闭节点
+
+开启远程关闭功能
+
+```properties
+management.endpoint.shutdown.enabled=true
+```
+
+
+
+使用Post方式请求端点
+
+{
+
+ "message": "Shutting down, bye..."
+
+}
+
+
+
+ autoconfig
+
+获取应用的自动化配置报告
+ beans
+
+获取应用上下文中创建的所有Bean
+
+
+
+#### configprops
+
+获取应用中配置的属性信息报告
+
+
+
+#### env
+
+获取应用所有可用的环境属性报告
+
+#### Mappings
+
+ 获取应用所有Spring Web的控制器映射关系报告
+
+#### info
+
+获取应用自定义的信息
+
+#### metrics
+
+返回应用的各类重要度量指标信息
+
+**Metrics**节点并没有返回全量信息,我们可以通过不同的**key**去加载我们想要的值
+
+ metrics/jvm.memory.max
+
+
+
+### Threaddump
+
+1.x中为**dump**
+
+返回程序运行中的线程信息
+
+
+
+
+
+
\ No newline at end of file
diff --git "a/20 \346\236\266\346\236\204\345\270\210\344\270\211\346\234\237 SpringCloud\345\276\256\346\234\215\345\212\241\346\236\266\346\236\204/SpringCloud03.md" "b/20 \346\236\266\346\236\204\345\270\210\344\270\211\346\234\237 SpringCloud\345\276\256\346\234\215\345\212\241\346\236\266\346\236\204/SpringCloud03.md"
new file mode 100644
index 0000000..1dfa606
--- /dev/null
+++ "b/20 \346\236\266\346\236\204\345\270\210\344\270\211\346\234\237 SpringCloud\345\276\256\346\234\215\345\212\241\346\236\266\346\236\204/SpringCloud03.md"
@@ -0,0 +1,753 @@
+# SpringCloud 03
+
+## Eureka原理
+
+eureka来源于古希腊词汇,意为“发现了”
+
+eureka分为两部分,Server端和Client端
+
+### Register
+
+**服务注册**
+
+想要参与服务注册发现的实例首先需要向Eureka服务器注册信息
+
+注册在第一次心跳发生时提交
+
+## Renew
+
+**续租,心跳**
+
+Eureka客户需要每30秒发送一次心跳来续租
+
+10:00 00 第一次
+
+10:00 30
+
+10:01
+
+10:01 30 最后
+
+更新通知Eureka服务器实例仍然是活动的。如果服务器在90秒内没有看到更新,它将从其注册表中删除实例
+
+## Fetch Registry
+
+Eureka客户端从服务器获取注册表信息并将其缓存在本地。
+
+之后,客户端使用这些信息来查找其他服务。
+
+通过获取上一个获取周期和当前获取周期之间的增量更新,可以定期(每30秒)更新此信息。
+
+节点信息在服务器中保存的时间更长(大约3分钟),因此获取节点信息时可能会再次返回相同的实例。Eureka客户端自动处理重复的信息。
+
+在获得增量之后,Eureka客户机通过比较服务器返回的实例计数来与服务器协调信息,如果由于某种原因信息不匹配,则再次获取整个注册表信息。
+
+## Cancel
+
+Eureka客户端在关闭时向Eureka服务器发送取消请求。这将从服务器的实例注册表中删除实例,从而有效地将实例从通信量中取出。
+
+## Time Lag
+
+同步时间延迟
+
+来自Eureka客户端的所有操作可能需要一段时间才能反映到Eureka服务器上,然后反映到其他Eureka客户端上。这是因为eureka服务器上的有效负载缓存,它会定期刷新以反映新信息。Eureka客户端还定期地获取增量。因此,更改传播到所有Eureka客户机可能需要2分钟。
+
+## Communication mechanism
+
+通讯机制
+
+Http协议下的Rest请求
+
+默认情况下Eureka使用Jersey和Jackson以及JSON完成节点间的通讯
+
+## 服务注册
+
+新建一个web项目,引入starter`spring-cloud-starter-netflix-eureka-client`
+
+### 客户端配置选项
+
+```
+#续约发送间隔默认30秒,心跳间隔
+eureka.instance.lease-renewal-interval-in-seconds=5
+#表示eureka client间隔多久去拉取服务注册信息,默认为30秒,对于api-gateway,如果要迅速获取服务注册状态,可以缩小该值,比如5秒
+eureka.client.registry-fetch-interval-seconds=5
+# 续约到期时间(默认90秒)
+eureka.instance.lease-expiration-duration-in-seconds=60
+```
+
+### 服务器端配置选项
+
+```
+#关闭自我保护模式
+eureka.server.enable-self-preservation=false
+#失效服务间隔
+eureka.server.eviction-interval-timer-in-ms=3000
+```
+
+
+
+## Eureka单独使用
+
+### Rest服务调用
+
+官方文档
+
+https://github.com/Netflix/eureka/wiki/Eureka-REST-operations
+
+| **Operation** | **HTTP action** | **Description** |
+| ------------------------------------------------------------ | ------------------------------------------------------------ | ------------------------------------------------------------ |
+| Register new application instance | POST /eureka/v2/apps/**appID** | Input: JSON/XMLpayload HTTPCode: 204 on success |
+| De-register application instance | DELETE /eureka/v2/apps/**appID**/**instanceID** | HTTP Code: 200 on success |
+| Send application instance heartbeat | PUT /eureka/v2/apps/**appID**/**instanceID** | HTTP Code: * 200 on success * 404 if **instanceID**doesn’t exist |
+| Query for all instances | GET /eureka/v2/apps | HTTP Code: 200 on success Output: JSON/XML |
+| Query for all **appID** instances | GET /eureka/v2/apps/**appID** | HTTP Code: 200 on success Output: JSON/XML |
+| Query for a specific **appID**/**instanceID** | GET /eureka/v2/apps/**appID**/**instanceID** | HTTP Code: 200 on success Output: JSON/XML |
+| Query for a specific **instanceID** | GET /eureka/v2/instances/**instanceID** | HTTP Code: 200 on success Output: JSON/XML |
+| Take instance out of service | PUT /eureka/v2/apps/**appID**/**instanceID**/status?value=OUT_OF_SERVICE | HTTP Code: * 200 on success * 500 on failure |
+| Move instance back into service (remove override) | DELETE /eureka/v2/apps/**appID**/**instanceID**/status?value=UP (The value=UP is optional, it is used as a suggestion for the fallback status due to removal of the override) | HTTP Code: * 200 on success * 500 on failure |
+| Update metadata | PUT /eureka/v2/apps/**appID**/**instanceID**/metadata?key=value | HTTP Code: * 200 on success * 500 on failure |
+| Query for all instances under a particular **vip address** | GET /eureka/v2/vips/**vipAddress** | * HTTP Code: 200 on success Output: JSON/XML * 404 if the **vipAddress**does not exist. |
+| Query for all instances under a particular **secure vip address** | GET /eureka/v2/svips/**svipAddress** | * HTTP Code: 200 on success Output: JSON/XML * 404 if the **svipAddress**does not exist. |
+
+#### /eureka/status 服务状态
+
+使用浏览器请求url会返回服务器状态信息
+
+```xml
+
+
+
+ test
+ 16
+ 526mb
+ 183mb (34%)
+ 00:00
+
+
+
+
+
+
+
+ localhost
+ localhost
+ UNKNOWN
+ 192.168.29.1
+ UP
+ UNKNOWN
+ 8080
+ 443
+ 1
+
+ MyOwn
+
+
+ 30
+ 90
+ 0
+ 0
+ 0
+ 0
+
+
+ 8080
+ 7649
+
+ http://localhost:8080/
+ http://localhost:8080/actuator/info
+ http://localhost:8080/actuator/health
+ unknown
+ unknown
+ false
+ 1586328420409
+ 1586328420519
+
+
+```
+
+如果需要json格式 可以加个请求头`Accept:application/json`
+
+```json
+{
+ "generalStats": {
+ "environment": "test",
+ "num-of-cpus": "16",
+ "total-avail-memory": "517mb",
+ "current-memory-usage": "45mb (8%)",
+ "server-uptime": "00:03"
+ },
+ "applicationStats": {
+ "registered-replicas": "",
+ "available-replicas": "",
+ "unavailable-replicas": ""
+ },
+ "instanceInfo": {
+ "instanceId": "localhost",
+ "hostName": "localhost",
+ "app": "UNKNOWN",
+ "ipAddr": "192.168.29.1",
+ "status": "UP",
+ "overriddenStatus": "UNKNOWN",
+ "port": {
+ "$": 8080,
+ "@enabled": "true"
+ },
+ "securePort": {
+ "$": 443,
+ "@enabled": "false"
+ },
+ "countryId": 1,
+ "dataCenterInfo": {
+ "@class": "com.netflix.appinfo.InstanceInfo$DefaultDataCenterInfo",
+ "name": "MyOwn"
+ },
+ "leaseInfo": {
+ "renewalIntervalInSecs": 30,
+ "durationInSecs": 90,
+ "registrationTimestamp": 0,
+ "lastRenewalTimestamp": 0,
+ "evictionTimestamp": 0,
+ "serviceUpTimestamp": 0
+ },
+ "metadata": {
+ "management.port": "8080",
+ "jmx.port": "7649"
+ },
+ "homePageUrl": "http://localhost:8080/",
+ "statusPageUrl": "http://localhost:8080/actuator/info",
+ "healthCheckUrl": "http://localhost:8080/actuator/health",
+ "vipAddress": "unknown",
+ "secureVipAddress": "unknown",
+ "isCoordinatingDiscoveryServer": "false",
+ "lastUpdatedTimestamp": "1586328420409",
+ "lastDirtyTimestamp": "1586328420519"
+ }
+```
+
+#### 注册到eureka的服务信息查看
+
+ get: {ip:port}/eureka/apps
+
+#### 注册到eureka的具体的服务查看
+
+ get: {ip:port}/eureka/apps/{appname}/{id}
+
+#### 服务续约
+
+ put:{ip:port}/eureka/apps/{appname}/{id}?lastDirtyTimestamp={}&status=up
+
+#### 更改服务状态
+
+ put:{ip:port}/eureka/apps/{appname}/{id}/status?lastDirtyTimestamp={}&value={UP/DOWN}
+ 对应eureka源码的:InstanceResource.statusUpdate
+
+#### 删除状态更新
+
+ delete:{ip:port}/eureka/apps/{appname}/{id}/status?lastDirtyTimestamp={}&value={UP/DOWN}
+
+#### 删除服务
+
+ delete: {ip:port}/eureka/apps/{appname}/{id}
+
+
+
+
+### 元数据
+
+Eureka的元数据有两种:标准元数据和自定义元数据。
+标准元数据:主机名、IP地址、端口号、状态页和健康检查等信息,这些信息都会被发布在服务注册表中,用于服务之间的调用。
+自定义元数据:可以使用eureka.instance.metadata-map配置,这些元数据可以在远程客户端中访问,但是一般不改变客户端行为,除非客户端知道该元数据的含义。
+
+可以在配置文件中对当前服务设置自定义元数据,可后期用户个性化使用
+
+元数据可以配置在eureka服务器和eureka的客户端上
+
+```
+eureka.instance.metadata-map.dalao=mashibing
+
+```
+
+#### 服务端:
+
+
+
+#### 客户端:
+
+```json
+{
+ "applications": {
+ "versions__delta": "1",
+ "apps__hashcode": "UP_2_",
+ "application": [
+ {
+ "name": "EUREKA-CONSUMER",
+ "instance": [
+ {
+ "instanceId": "localhost:Eureka-Consumer:9001",
+ "hostName": "localhost",
+ "app": "EUREKA-CONSUMER",
+ "ipAddr": "192.168.29.1",
+ "status": "UP",
+ "overriddenStatus": "UNKNOWN",
+ "port": {
+ "$": 9001,
+ "@enabled": "true"
+ },
+ "securePort": {
+ "$": 443,
+ "@enabled": "false"
+ },
+ "countryId": 1,
+ "dataCenterInfo": {
+ "@class": "com.netflix.appinfo.InstanceInfo$DefaultDataCenterInfo",
+ "name": "MyOwn"
+ },
+ "leaseInfo": {
+ "renewalIntervalInSecs": 30,
+ "durationInSecs": 90,
+ "registrationTimestamp": 1586331982283,
+ "lastRenewalTimestamp": 1586331982283,
+ "evictionTimestamp": 0,
+ "serviceUpTimestamp": 1586331982283
+ },
+ "metadata": {
+ "dalao": "mashibing666",
+ "management.port": "9001",
+ "jmx.port": "10158"
+ },
+ "homePageUrl": "http://localhost:9001/",
+ "statusPageUrl": "http://localhost:9001/actuator/info",
+ "healthCheckUrl": "http://localhost:9001/actuator/health",
+ "vipAddress": "Eureka-Consumer",
+ "secureVipAddress": "Eureka-Consumer",
+ "isCoordinatingDiscoveryServer": "false",
+ "lastUpdatedTimestamp": "1586331982283",
+ "lastDirtyTimestamp": "1586331982260",
+ "actionType": "ADDED"
+ },
+ {
+ "instanceId": "localhost:Eureka-Consumer:9000",
+ "hostName": "localhost",
+ "app": "EUREKA-CONSUMER",
+ "ipAddr": "192.168.29.1",
+ "status": "UP",
+ "overriddenStatus": "UNKNOWN",
+ "port": {
+ "$": 9000,
+ "@enabled": "true"
+ },
+ "securePort": {
+ "$": 443,
+ "@enabled": "false"
+ },
+ "countryId": 1,
+ "dataCenterInfo": {
+ "@class": "com.netflix.appinfo.InstanceInfo$DefaultDataCenterInfo",
+ "name": "MyOwn"
+ },
+ "leaseInfo": {
+ "renewalIntervalInSecs": 30,
+ "durationInSecs": 90,
+ "registrationTimestamp": 1586331637223,
+ "lastRenewalTimestamp": 1586332057220,
+ "evictionTimestamp": 0,
+ "serviceUpTimestamp": 1586331637223
+ },
+ "metadata": {
+ "dalao": "mashibing",
+ "management.port": "9000",
+ "jmx.port": "10000"
+ },
+ "homePageUrl": "http://localhost:9000/",
+ "statusPageUrl": "http://localhost:9000/actuator/info",
+ "healthCheckUrl": "http://localhost:9000/actuator/health",
+ "vipAddress": "Eureka-Consumer",
+ "secureVipAddress": "Eureka-Consumer",
+ "isCoordinatingDiscoveryServer": "false",
+ "lastUpdatedTimestamp": "1586331637223",
+ "lastDirtyTimestamp": "1586331637182",
+ "actionType": "ADDED"
+ }
+ ]
+ }
+ ]
+ }
+}
+```
+
+
+
+## EurekaClient
+
+EurekaClient 可以在客户端获取eureka服务器上的注册者信息
+
+**org.springframework.cloud.client.discovery与com.netflix.discovery.DiscoveryClient**
+
+
+
+
+
+org.springframework.cloud.client.discovery是SpringCloud对注册中心client的抽象封装,提供公用功能
+
+org.springframework.cloud.client.discovery定义用来服务发现的客户端接口,是客户端进行服务发现的核心接口,是spring cloud用来进行服务发现的顶级接口,在common中可以看到其地位。在Netflix Eureka和Consul中都有具体的实现类。
+
+代表通用于服务发现的读操作,例如在 eureka或consul中。
+
+```
+有
+ String description();//获取实现类的描述。
+ List getServices();//获取所有服务实例id。
+ List getInstances(String serviceId);//通过服务id查询服务实例信息列表。
+```
+
+
+
+
+
+com.netflix.discovery.DiscoveryClient为Eureka注册中心客户端的接口,功能更丰富
+
+## 自我保护机制
+
+### 机制
+
+Eureka在CAP理论当中是属于AP , 也就说当产生网络分区时,Eureka保证系统的可用性,但不保证系统里面数据的一致性
+
+默认开启,服务器端容错的一种方式,即短时间心跳不到达仍不剔除服务列表里的节点
+
+```
+EMERGENCY! EUREKA MAY BE INCORRECTLY CLAIMING INSTANCES ARE UP WHEN THEY'RE NOT. RENEWALS ARE LESSER THAN THRESHOLD AND HENCE THE INSTANCES ARE NOT BEING EXPIRED JUST TO BE SAFE.
+```
+
+默认情况下,Eureka Server在一定时间内,没有接收到某个微服务心跳,会将某个微服务注销(90S)。但是当网络故障时,微服务与Server之间无法正常通信,上述行为就非常危险,因为微服务正常,不应该注销。
+
+Eureka Server通过自我保护模式来解决整个问题,当Server在短时间内丢失过多客户端时,那么Server会进入自我保护模式,会保护注册表中的微服务不被注销掉。当网络故障恢复后,退出自我保护模式。
+
+**思想:宁可保留健康的和不健康的,也不盲目注销任何健康的服务。**
+
+#### 自我保护触发
+
+**客户端每分钟续约数量小于客户端总数的85%时会触发保护机制**
+
+
+
+自我保护机制的触发条件:
+(当每分钟心跳次数( renewsLastMin ) 小于 numberOfRenewsPerMinThreshold 时,并且开启自动保护模式开关( eureka.server.enable-self-preservation = true ) 时,触发自我保护机制,不再自动过期租约。)
+numberOfRenewsPerMinThreshold = expectedNumberOfRenewsPerMin * 续租百分比( eureka.server.renewalPercentThreshold, 默认0.85 )
+expectedNumberOfRenewsPerMin = 当前注册的应用实例数 x 2
+为什么乘以 2:
+默认情况下,注册的应用实例每半分钟续租一次,那么一分钟心跳两次,因此 x 2 。
+
+服务实例数:10个,期望每分钟续约数:10 * 2=20,期望阈值:20*0.85=17,自我保护少于17时 触发。
+
+剔除:
+
+```sh
+ AbstractInstanceRegistry
+
+ public void evict(long additionalLeaseMs) {
+ logger.debug("Running the evict task");
+
+ if (!isLeaseExpirationEnabled()) {
+ logger.debug("DS: lease expiration is currently disabled.");
+ return;
+ }
+ 此代码意思:if中判断为true,不走此逻辑,走下面的剔除。如果if为false。走此逻辑,不剔除。
+```
+
+
+
+```sh
+PeerAwareInstanceRegistryImpl
+
+ @Override
+ public boolean isLeaseExpirationEnabled() {
+ if (!isSelfPreservationModeEnabled()) {
+ //如果打开自我保护,不进入此逻辑。
+ // The self preservation mode is disabled, hence allowing the instances to expire.
+ return true;
+ }
+ return numberOfRenewsPerMinThreshold > 0 && getNumOfRenewsInLastMin() > numberOfRenewsPerMinThreshold;
+ }
+```
+
+
+
+### 关闭
+
+```properties
+eureka.server.enable-self-preservation=false
+```
+
+
+
+关闭后会提示
+
+
+
+### 清理时间
+
+默认60秒
+
+```
+eureka.server.eviction-interval-timer-in-ms=3000
+```
+
+
+
+## 多网卡选择
+
+1. ip注册
+
+```sh
+eureka:
+ instance:
+ prefer-ip-address: true
+表示将自己的ip注册到EurekaServer上。不配置或false,表示将操作系统的hostname注册到server
+```
+
+2. 服务器有多个网卡,eh0,eh1,eh2,只有eh0可以让外部其他服务访问进来,而Eureka client将eh1和eh2注册到Eureka server上,这样其他服务就无法访问该微服务了。
+
+3. 指定Ip
+
+ ```sh
+ eureka:
+ instance:
+ prefer-ip-address: true
+ ip-address: 实际能访问到的Ip
+ ```
+
+ 如果设置了此时的ip-address,在元数据查看到就是此ip,其他服务也通过此ip来调用。
+
+ ```sh
+ {
+ "host": "127.0.0.1",
+ "port": 8084,
+ "metadata": {
+ "yueyi": "2019",
+ "user.password": "root",
+ "management.port": "8084",
+ "jmx.port": "61378",
+ "user.name": "root"
+ },
+ "secure": false,
+ "uri": "http://127.0.0.1:8084",
+ "instanceId": "api-listen-order:30.136.133.11:port",
+ "serviceId": "API-LISTEN-ORDER",
+ "instanceInfo": {
+ "instanceId": "api-listen-order:30.136.133.11:port",
+ "app": "API-LISTEN-ORDER",
+ "appGroupName": null,
+ "ipAddr": "127.0.0.1",
+ "sid": "na",
+ "homePageUrl": "http://127.0.0.1:8084/",
+ "statusPageUrl": "http://127.0.0.1:8084/actuator/info",
+ "healthCheckUrl": "http://127.0.0.1:8084/actuator/health",
+ "secureHealthCheckUrl": null,
+ "vipAddress": "api-listen-order",
+ "secureVipAddress": "api-listen-order",
+ "countryId": 1,
+ "dataCenterInfo": {
+ "@class": "com.netflix.appinfo.InstanceInfo$DefaultDataCenterInfo",
+ "name": "MyOwn"
+ },
+ "hostName": "127.0.0.1",
+ "status": "UP",
+ "overriddenStatus": "UNKNOWN",
+ "leaseInfo": {
+ "renewalIntervalInSecs": 1,
+ "durationInSecs": 1,
+ "registrationTimestamp": 1579489514655,
+ "lastRenewalTimestamp": 1579489524146,
+ "evictionTimestamp": 0,
+ "serviceUpTimestamp": 1579489514147
+ },
+ "isCoordinatingDiscoveryServer": false,
+ "metadata": {
+ "yueyi": "2019",
+ "user.password": "root",
+ "management.port": "8084",
+ "jmx.port": "61378",
+ "user.name": "root"
+ },
+ "lastUpdatedTimestamp": 1579489514655,
+ "lastDirtyTimestamp": 1579489514111,
+ "actionType": "ADDED",
+ "asgName": null
+ },
+ "scheme": null
+ }
+ ```
+
+ 或者使用**spring.cloud.inetutils**配置网卡选择
+
+## Eureka 健康检查
+
+由于server和client通过心跳保持 服务状态,而只有状态为UP的服务才能被访问。看eureka界面中的status。
+
+比如心跳一直正常,服务一直UP,但是此服务DB连不上了,无法正常提供服务。
+
+此时,我们需要将 微服务的健康状态也同步到server。只需要启动eureka的健康检查就行。这样微服务就会将自己的健康状态同步到eureka。配置如下即可。
+
+### 开启手动控制
+
+在client端配置:将自己真正的健康状态传播到server。
+
+```yaml
+eureka:
+ client:
+ healthcheck:
+ enabled: true
+```
+
+### Client端配置Actuator
+
+```xml
+
+ org.springframework.boot
+ spring-boot-starter-actuator
+
+```
+
+
+
+### 改变健康状态的Service
+
+```java
+@Service
+public class HealthStatusService implements HealthIndicator{
+
+ private Boolean status = true;
+
+ public void setStatus(Boolean status) {
+ this.status = status;
+ }
+
+ @Override
+ public Health health() {
+ // TODO Auto-generated method stub
+ if(status)
+ return new Health.Builder().up().build();
+ return new Health.Builder().down().build();
+ }
+
+ public String getStatus() {
+ // TODO Auto-generated method stub
+ return this.status.toString();
+ }
+```
+
+### 测试用的Controller
+
+```java
+ @GetMapping("/health")
+ public String health(@RequestParam("status") Boolean status) {
+
+ healthStatusSrv.setStatus(status);
+ return healthStatusSrv.getStatus();
+ }
+```
+
+
+
+## 安全配置
+
+### 开启Eureka安全连接
+
+```
+spring.security.user.name=yiming
+spring.security.user.password=123
+```
+
+
+
+
+
+
+
+### 如果服务注册报错
+
+```
+Root name 'timestamp' does not match expected ('instance') for type [simple
+```
+
+是默认开启了防止跨域攻击
+
+
+
+#### 手动关闭
+
+在服务端增加配置类
+
+```
+@Configuration
+@EnableWebSecurity
+public class WebSecurityConfig extends WebSecurityConfigurerAdapter{
+
+ @Override
+ protected void configure(HttpSecurity http) throws Exception {
+ // TODO Auto-generated method stub
+ http.csrf().disable();
+ super.configure(http);
+ }
+
+}
+
+```
+
+## 服务间调用
+
+ 微服务中,很多服务系统都在独立的进程中运行,通过各个服务系统之间的协作来实现一个大项目的所有业务功能。服务系统间 使用多种跨进程的方式进行通信协作,而RESTful风格的网络请求是最为常见的交互方式之一。
+
+http。
+
+ 思考:如果让我们写服务调用如何写。
+
+1. 硬编码。不好。ip域名写在代码中。目的:找到服务。
+
+2. 根据服务名,找相应的ip。目的:这样ip切换或者随便变化,对调用方没有影响。
+
+ Map<服务名,服务列表> map;
+
+3. 加上负载均衡。目的:高可用。
+
+
+
+spring cloud提供的方式:
+
+1. RestTemplate
+2. Feign
+
+我个人习惯用RestTemplate,因为自由,方便调用别的第三方的http服务。feign也可以,更面向对象一些,更优雅一些,就是需要配置。
+
+### Rest
+
+##
+
+```sh
+RESTful网络请求是指RESTful风格的网络请求,其中REST是Resource Representational State Transfer的缩写,直接翻译即“资源表现层状态转移”。
+Resource代表互联网资源。所谓“资源”是网络上的一个实体,或者说网上的一个具体信息。它可以是一段文本、一首歌曲、一种服务,可以使用一个URI指向它,每种“资源”对应一个URI。
+Representational是“表现层”意思。“资源”是一种消息实体,它可以有多种外在的表现形式,我们把“资源”具体呈现出来的形式叫作它的“表现层”。比如说文本可以用TXT格式进行表现,也可以使用XML格式、JSON格式和二进制格式;视频可以用MP4格式表现,也可以用AVI格式表现。URI只代表资源的实体,不代表它的形式。它的具体表现形式,应该由HTTP请求的头信息Accept和Content-Type字段指定,这两个字段是对“表现层”的描述。
+State Transfer是指“状态转移”。客户端访问服务的过程中必然涉及数据和状态的转化。如果客户端想要操作服务端资源,必须通过某种手段,让服务器端资源发生“状态转移”。而这种转化是建立在表现层之上的,所以被称为“表现层状态转移”。客户端通过使用HTTP协议中的四个动词来实现上述操作,它们分别是:获取资源的GET、新建或更新资源的POST、更新资源的PUT和删除资源的DELETE。
+```
+
+RestTemplate是Spring提供的同步HTTP网络客户端接口,它可以简化客户端与HTTP服务器之间的交互,并且它强制使用RESTful风格。它会处理HTTP连接和关闭,只需要使用者提供服务器的地址(URL)和模板参数。
+
+```
+第一个层次(Level 0)的 Web 服务只是使用 HTTP 作为传输方式,实际上只是远程方法调用(RPC)的一种具体形式。SOAP 和 XML-RPC 都属于此类。
+第二个层次(Level 1)的 Web 服务引入了资源的概念。每个资源有对应的标识符和表达。
+第三个层次(Level 2)的 Web 服务使用不同的 HTTP 方法来进行不同的操作,并且使用 HTTP 状态码来表示不同的结果。如 HTTP GET 方法来获取资源,HTTP DELETE 方法来删除资源。
+第四个层次(Level 3)的 Web 服务使用 HATEOAS。在资源的表达中包含了链接信息。客户端可以根据链接来发现可以执行的动作。
+```
+
+**git的restful api**
+
+https://developer.github.com/v3/
+
+
+
+
+
+## 作业:
+
+- 使用ribbon完成负载均衡的调用
+- 高可用集群搭起来
\ No newline at end of file
diff --git "a/20 \346\236\266\346\236\204\345\270\210\344\270\211\346\234\237 SpringCloud\345\276\256\346\234\215\345\212\241\346\236\266\346\236\204/SpringCloud04.md" "b/20 \346\236\266\346\236\204\345\270\210\344\270\211\346\234\237 SpringCloud\345\276\256\346\234\215\345\212\241\346\236\266\346\236\204/SpringCloud04.md"
new file mode 100644
index 0000000..a372a82
--- /dev/null
+++ "b/20 \346\236\266\346\236\204\345\270\210\344\270\211\346\234\237 SpringCloud\345\276\256\346\234\215\345\212\241\346\236\266\346\236\204/SpringCloud04.md"
@@ -0,0 +1,362 @@
+# SpringCloud 04
+
+## RestTemplate
+
+### 依赖注入
+
+```
+ @Bean
+ // 开启负载均衡
+ @LoadBalanced
+ RestTemplate restTemplate() {
+ return new RestTemplate();
+ }
+```
+
+接下来便可以使用资源地址调用服务
+
+```
+String url ="http://provider/getHi";
+String respStr = restTemplate.getForObject(url, String.class);
+
+```
+
+
+
+### get 请求处理
+
+#### getForEntity
+
+getForEntity方法的返回值是一个ResponseEntity,ResponseEntity是Spring对HTTP请求响应的封装,包括了几个重要的元素,如响应码、contentType、contentLength、响应消息体等。
+
+```
+<200,Hi,[Content-Type:"text/plain;charset=UTF-8", Content-Length:"8", Date:"Fri, 10 Apr 2020 09:58:44 GMT", Keep-Alive:"timeout=60", Connection:"keep-alive"]>
+```
+
+
+
+#### 返回一个Map
+
+**调用方**
+
+```
+ String url ="http://provider/getMap";
+
+ ResponseEntity