From d2f55e89351c027f4a8735beeb7cafe9a542d1f7 Mon Sep 17 00:00:00 2001 From: dunwu Date: Sat, 27 Jan 2024 23:26:45 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=95=B4=E7=90=86=E5=9B=BE=E7=89=87?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 2 +- docs/.vuepress/config.js | 2 +- ...\344\271\213Filter\345\222\214Listener.md" | 2 +- ...53\351\200\237\345\205\245\351\227\250.md" | 42 +++++++++---------- ...at\350\277\236\346\216\245\345\231\250.md" | 14 +++---- .../03.Tomcat\345\256\271\345\231\250.md" | 2 +- .../02.Jetty.md" | 6 +-- ...53\351\200\237\345\205\245\351\227\250.md" | 22 +++++----- ...00\344\275\263\345\256\236\350\267\265.md" | 8 ++-- ...55\345\244\256\344\273\223\345\272\223.md" | 8 ++-- ...45\345\205\267\345\257\271\346\257\224.md" | 6 +-- .../02.CAT.md" | 4 +- .../03.Zipkin.md" | 6 +-- .../04.Skywalking.md" | 6 +-- .../01.Freemark.md" | 2 +- .../04.\346\265\213\350\257\225/01.Junit.md" | 2 +- .../04.\346\265\213\350\257\225/03.Jmeter.md" | 24 +++++------ .../01.Java\346\227\245\345\277\227.md" | 10 ++--- ...53\351\200\237\345\205\245\351\227\250.md" | 4 +- .../02.Mybatis\345\216\237\347\220\206.md" | 22 +++++----- .../11.ORM/README.md" | 2 +- .../12.\345\256\211\345\205\250/01.Shiro.md" | 10 ++--- .../02.SpringSecurity.md" | 2 +- .../01.Dubbo.md" | 16 +++---- ...72\346\234\254\345\216\237\347\220\206.md" | 22 +++++----- .../01.MQ/03.RocketMQ.md" | 6 +-- .../01.MQ/04.ActiveMQ.md" | 6 +-- ...30\344\270\255\351\227\264\344\273\266.md" | 2 +- .../04.Ehcache.md" | 2 +- .../02.\347\274\223\345\255\230/README.md" | 2 +- .../01.Hystrix.md" | 10 ++--- 31 files changed, 137 insertions(+), 137 deletions(-) diff --git a/README.md b/README.md index 11f3a7d..7d3dbdd 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@

- logo + logo

diff --git a/docs/.vuepress/config.js b/docs/.vuepress/config.js index f706971..f254fa1 100644 --- a/docs/.vuepress/config.js +++ b/docs/.vuepress/config.js @@ -64,7 +64,7 @@ module.exports = { } ], sidebarDepth: 2, // 侧边栏显示深度,默认1,最大2(显示到h3标题) - logo: 'https://raw.githubusercontent.com/dunwu/images/dev/common/dunwu-logo.png', // 导航栏logo + logo: 'https://raw.githubusercontent.com/dunwu/images/master/common/dunwu-logo.png', // 导航栏logo repo: 'dunwu/java-tutorial', // 导航栏右侧生成Github链接 searchMaxSuggestions: 10, // 搜索结果显示最大数 lastUpdated: '上次更新', // 更新的时间,及前缀文字 string | boolean (取值为git提交时间) diff --git "a/docs/02.JavaEE/01.JavaWeb/03.JavaWeb\344\271\213Filter\345\222\214Listener.md" "b/docs/02.JavaEE/01.JavaWeb/03.JavaWeb\344\271\213Filter\345\222\214Listener.md" index f13e99b..8cd8ebd 100644 --- "a/docs/02.JavaEE/01.JavaWeb/03.JavaWeb\344\271\213Filter\345\222\214Listener.md" +++ "b/docs/02.JavaEE/01.JavaWeb/03.JavaWeb\344\271\213Filter\345\222\214Listener.md" @@ -24,7 +24,7 @@ permalink: /pages/5ecb29/ Filter 提供了过滤链(Filter Chain)的概念,一个过滤链包括多个 Filter。客户端请求 request 在抵达 Servlet 之前会经过过滤链的所有 Filter,服务器响应 response 从 Servlet 抵达客户端浏览器之前也会经过过滤链的所有 FIlter。 -![img](https://raw.githubusercontent.com/dunwu/images/dev/snap/1559054413341.png) +![img](https://raw.githubusercontent.com/dunwu/images/master/snap/1559054413341.png) ### 过滤器方法 diff --git "a/docs/02.JavaEE/02.\346\234\215\345\212\241\345\231\250/01.Tomcat/01.Tomcat\345\277\253\351\200\237\345\205\245\351\227\250.md" "b/docs/02.JavaEE/02.\346\234\215\345\212\241\345\231\250/01.Tomcat/01.Tomcat\345\277\253\351\200\237\345\205\245\351\227\250.md" index 77264e0..269f5fb 100644 --- "a/docs/02.JavaEE/02.\346\234\215\345\212\241\345\231\250/01.Tomcat/01.Tomcat\345\277\253\351\200\237\345\205\245\351\227\250.md" +++ "b/docs/02.JavaEE/02.\346\234\215\345\212\241\345\231\250/01.Tomcat/01.Tomcat\345\277\253\351\200\237\345\205\245\351\227\250.md" @@ -111,7 +111,7 @@ tar -zxf apache-tomcat-8.5.24.tar.gz 启动后,访问 `http://localhost:8080` ,可以看到 Tomcat 安装成功的测试页面。 -![img](https://raw.githubusercontent.com/dunwu/images/dev/cs/java/javaweb/tools/tomcat/tomcat.png) +![img](https://raw.githubusercontent.com/dunwu/images/master/cs/java/javaweb/tools/tomcat/tomcat.png) ### 2.2. 配置 @@ -364,7 +364,7 @@ public class SimpleTomcatServer { - 设置启动应用的端口、JVM 参数、启动浏览器等。 - 成功后,可以访问 `http://localhost:8080/`(当然,你也可以在 url 中设置上下文名称)。 -![img](https://raw.githubusercontent.com/dunwu/images/dev/cs/java/javaweb/tools/tomcat/tomcat-intellij-run-config.png) +![img](https://raw.githubusercontent.com/dunwu/images/master/cs/java/javaweb/tools/tomcat/tomcat-intellij-run-config.png) > **说明** > @@ -374,7 +374,7 @@ public class SimpleTomcatServer { ## 3. Tomcat 架构 -![img](https://raw.githubusercontent.com/dunwu/images/dev/snap/20201113193431.png) +![img](https://raw.githubusercontent.com/dunwu/images/master/snap/20201113193431.png) Tomcat 要实现 2 个核心功能: @@ -402,7 +402,7 @@ Tomcat 支持的应用层协议有: Tomcat 支持多种 I/O 模型和应用层协议。为了实现这点,一个容器可能对接多个连接器。但是,单独的连接器或容器都不能对外提供服务,需要把它们组装起来才能工作,组装后这个整体叫作 Service 组件。Tomcat 内可能有多个 Service,通过在 Tomcat 中配置多个 Service,可以实现通过不同的端口号来访问同一台机器上部署的不同应用。 -![img](https://raw.githubusercontent.com/dunwu/images/dev/snap/20201111093124.png) +![img](https://raw.githubusercontent.com/dunwu/images/master/snap/20201111093124.png) **一个 Tomcat 实例有一个或多个 Service;一个 Service 有多个 Connector 和 Container**。Connector 和 Container 之间通过标准的 ServletRequest 和 ServletResponse 通信。 @@ -418,13 +418,13 @@ Tomcat 支持多种 I/O 模型和应用层协议。为了实现这点,一个 Tomcat 设计了 3 个组件来实现这 3 个功能,分别是 **`EndPoint`**、**`Processor`** 和 **`Adapter`**。 -![img](https://raw.githubusercontent.com/dunwu/images/dev/snap/20201111101440.png) +![img](https://raw.githubusercontent.com/dunwu/images/master/snap/20201111101440.png) 组件间通过抽象接口交互。这样做还有一个好处是**封装变化。**这是面向对象设计的精髓,将系统中经常变化的部分和稳定的部分隔离,有助于增加复用性,并降低系统耦合度。网络通信的 I/O 模型是变化的,可能是非阻塞 I/O、异步 I/O 或者 APR。应用层协议也是变化的,可能是 HTTP、HTTPS、AJP。浏览器端发送的请求信息也是变化的。但是整体的处理逻辑是不变的,EndPoint 负责提供字节流给 Processor,Processor 负责提供 Tomcat Request 对象给 Adapter,Adapter 负责提供 ServletRequest 对象给容器。 如果要支持新的 I/O 方案、新的应用层协议,只需要实现相关的具体子类,上层通用的处理逻辑是不变的。由于 I/O 模型和应用层协议可以自由组合,比如 NIO + HTTP 或者 NIO2 + AJP。Tomcat 的设计者将网络通信和应用层协议解析放在一起考虑,设计了一个叫 ProtocolHandler 的接口来封装这两种变化点。各种协议和通信模型的组合有相应的具体实现类。比如:Http11NioProtocol 和 AjpNioProtocol。 -![img](https://raw.githubusercontent.com/dunwu/images/dev/snap/20201027091819.png) +![img](https://raw.githubusercontent.com/dunwu/images/master/snap/20201027091819.png) #### 3.2.1. ProtocolHandler 组件 @@ -444,7 +444,7 @@ EndPoint 是一个接口,对应的抽象实现类是 AbstractEndpoint,而 Ab Processor 是一个接口,定义了请求的处理等方法。它的抽象实现类 AbstractProcessor 对一些协议共有的属性进行封装,没有对方法进行实现。具体的实现有 AJPProcessor、HTTP11Processor 等,这些具体实现类实现了特定协议的解析方法和请求处理方式。 -![img](https://raw.githubusercontent.com/dunwu/images/dev/snap/20201113185929.png) +![img](https://raw.githubusercontent.com/dunwu/images/master/snap/20201113185929.png) 从图中我们看到,EndPoint 接收到 Socket 连接后,生成一个 SocketProcessor 任务提交到线程池去处理,SocketProcessor 的 Run 方法会调用 Processor 组件去解析应用层协议,Processor 通过解析生成 Request 对象后,会调用 Adapter 的 Service 方法。 @@ -471,7 +471,7 @@ Tomcat 是怎么确定请求是由哪个 Wrapper 容器里的 Servlet 来处理 举例来说,假如有一个网购系统,有面向网站管理人员的后台管理系统,还有面向终端客户的在线购物系统。这两个系统跑在同一个 Tomcat 上,为了隔离它们的访问域名,配置了两个虚拟域名:`manage.shopping.com`和`user.shopping.com`,网站管理人员通过`manage.shopping.com`域名访问 Tomcat 去管理用户和商品,而用户管理和商品管理是两个单独的 Web 应用。终端客户通过`user.shopping.com`域名去搜索商品和下订单,搜索功能和订单管理也是两个独立的 Web 应用。如下所示,演示了 url 应声 Servlet 的处理流程。 -![img](https://raw.githubusercontent.com/dunwu/images/dev/snap/20201113192022.jpg) +![img](https://raw.githubusercontent.com/dunwu/images/master/snap/20201113192022.jpg) 假如有用户访问一个 URL,比如图中的`http://user.shopping.com:8080/order/buy`,Tomcat 如何将这个 URL 定位到一个 Servlet 呢? @@ -490,7 +490,7 @@ Pipeline-Valve 是责任链模式,责任链模式是指在一个请求处理 先来了解一下 Valve 和 Pipeline 接口的设计: -![img](https://raw.githubusercontent.com/dunwu/images/dev/cs/java/javaweb/tools/tomcat/Pipeline与Valve.png) +![img](https://raw.githubusercontent.com/dunwu/images/master/cs/java/javaweb/tools/tomcat/Pipeline与Valve.png) - 每一个容器都有一个 Pipeline 对象,只要触发这个 Pipeline 的第一个 Valve,这个容器里 Pipeline 中的 Valve 就都会被调用到。但是,不同容器的 Pipeline 是怎么链式触发的呢,比如 Engine 中 Pipeline 需要调用下层容器 Host 中的 Pipeline。 - 这是因为 Pipeline 中还有个 getBasic 方法。这个 BasicValve 处于 Valve 链表的末端,它是 Pipeline 中必不可少的一个 Valve,负责调用下层容器的 Pipeline 里的第一个 Valve。 @@ -499,7 +499,7 @@ Pipeline-Valve 是责任链模式,责任链模式是指在一个请求处理 - 各层容器对应的 basic valve 分别是 `StandardEngineValve`、`StandardHostValve`、 `StandardContextValve`、`StandardWrapperValve`。 - 由于 Valve 是一个处理点,因此 invoke 方法就是来处理请求的。注意到 Valve 中有 getNext 和 setNext 方法,因此我们大概可以猜到有一个链表将 Valve 链起来了。 -![img](https://raw.githubusercontent.com/dunwu/images/dev/cs/java/javaweb/tools/tomcat/请求处理过程.png) +![img](https://raw.githubusercontent.com/dunwu/images/master/cs/java/javaweb/tools/tomcat/请求处理过程.png) 整个调用过程由连接器中的 Adapter 触发的,它会调用 Engine 的第一个 Valve: @@ -511,7 +511,7 @@ connector.getService().getContainer().getPipeline().getFirst().invoke(request, r ### 4.1. Tomcat 的启动过程 -![img](https://raw.githubusercontent.com/dunwu/images/dev/snap/20201118145455.png) +![img](https://raw.githubusercontent.com/dunwu/images/master/snap/20201118145455.png) 1. Tomcat 是一个 Java 程序,它的运行从执行 `startup.sh` 脚本开始。`startup.sh` 会启动一个 JVM 来运行 Tomcat 的启动类 `Bootstrap`。 2. `Bootstrap` 会初始化 Tomcat 的类加载器并实例化 `Catalina`。 @@ -731,12 +731,12 @@ ContextConfig 解析 web.xml 顺序: ### 4.3. LifeCycle -![img](https://raw.githubusercontent.com/dunwu/images/dev/snap/20201118105012.png) +![img](https://raw.githubusercontent.com/dunwu/images/master/snap/20201118105012.png) #### 4.3.1. 请求处理过程
- +
1. 根据 server.xml 配置的指定的 connector 以及端口监听 http、或者 ajp 请求 @@ -747,25 +747,25 @@ ContextConfig 解析 web.xml 顺序: ### 4.4. Connector 流程
- +
#### 4.4.1. 阻塞 IO
- +
#### 4.4.2. 非阻塞 IO
- +
#### 4.4.3. IO 多路复用
- +
阻塞与非阻塞的区别在于进行读操作和写操作的系统调用时,如果此时内核态没有数据可读或者没有缓冲空间可写时,是否阻塞。 @@ -775,7 +775,7 @@ IO 多路复用的好处在于可同时监听多个 socket 的可读和可写事 #### 4.4.4. Tomcat 各类 Connector 对比
- +
- JIO:用 java.io 编写的 TCP 模块,阻塞 IO @@ -796,7 +796,7 @@ Apache Portable Runtime 是一个高度可移植的库,它是 Apache HTTP Serv **NIO 处理相关类**
- +
Poller 线程从 EventQueue 获取 PollerEvent,并执行 PollerEvent 的 run 方法,调用 Selector 的 select 方法,如果有可读的 Socket 则创建 Http11NioProcessor,放入到线程池中执行; @@ -829,7 +829,7 @@ Note: ### 4.6. 异步 Servlet
- +
传统流程: @@ -839,7 +839,7 @@ Note: - 最后,根据处理的结果提交响应,Servlet 线程结束
- +
异步处理流程: diff --git "a/docs/02.JavaEE/02.\346\234\215\345\212\241\345\231\250/01.Tomcat/02.Tomcat\350\277\236\346\216\245\345\231\250.md" "b/docs/02.JavaEE/02.\346\234\215\345\212\241\345\231\250/01.Tomcat/02.Tomcat\350\277\236\346\216\245\345\231\250.md" index d76dc06..9f35bd7 100644 --- "a/docs/02.JavaEE/02.\346\234\215\345\212\241\345\231\250/01.Tomcat/02.Tomcat\350\277\236\346\216\245\345\231\250.md" +++ "b/docs/02.JavaEE/02.\346\234\215\345\212\241\345\231\250/01.Tomcat/02.Tomcat\350\277\236\346\216\245\345\231\250.md" @@ -20,7 +20,7 @@ permalink: /pages/3c954b/ Tomcat 的 NioEndPoint 组件利用 Java NIO 实现了 I/O 多路复用模型。 -![img](https://raw.githubusercontent.com/dunwu/images/dev/snap/20201127094302.jpg) +![img](https://raw.githubusercontent.com/dunwu/images/master/snap/20201127094302.jpg) NioEndPoint 子组件功能简介: @@ -123,7 +123,7 @@ private final SynchronizedQueue events = new SynchronizedQueue<>(); Nio2Endpoint 工作流程跟 NioEndpoint 较为相似。 -![img](https://raw.githubusercontent.com/dunwu/images/dev/snap/20201127143839.jpg) +![img](https://raw.githubusercontent.com/dunwu/images/master/snap/20201127143839.jpg) Nio2Endpoint 子组件功能说明: @@ -218,7 +218,7 @@ Tomcat 本身是 Java 编写的,为了调用 C 语言编写的 APR,需要通 ### 3.1. AprEndpoint 工作流程 -![img](https://raw.githubusercontent.com/dunwu/images/dev/snap/20201127145740.jpg) +![img](https://raw.githubusercontent.com/dunwu/images/master/snap/20201127145740.jpg) #### 3.1.1. Acceptor @@ -282,7 +282,7 @@ java my.class 这个命令行中的`java`其实是**一个可执行程序,这个程序会创建 JVM 来加载和运行你的 Java 类**。操作系统会创建一个进程来执行这个`java`可执行程序,而每个进程都有自己的虚拟地址空间,JVM 用到的内存(包括堆、栈和方法区)就是从进程的虚拟地址空间上分配的。请你注意的是,JVM 内存只是进程空间的一部分,除此之外进程空间内还有代码段、数据段、内存映射区、内核空间等。从 JVM 的角度看,JVM 内存之外的部分叫作本地内存,C 程序代码在运行过程中用到的内存就是本地内存中分配的。下面我们通过一张图来理解一下。 -![img](https://raw.githubusercontent.com/dunwu/images/dev/snap/20201127150729.jpg) +![img](https://raw.githubusercontent.com/dunwu/images/master/snap/20201127150729.jpg) Tomcat 的 Endpoint 组件在接收网络数据时需要预先分配好一块 Buffer,所谓的 Buffer 就是字节数组`byte[]`,Java 通过 JNI 调用把这块 Buffer 的地址传给 C 代码,C 代码通过操作系统 API 读取 Socket 并把数据填充到这块 Buffer。Java NIO API 提供了两种 Buffer 来接收数据:HeapByteBuffer 和 DirectByteBuffer,下面的代码演示了如何创建两种 Buffer。 @@ -323,7 +323,7 @@ Tomcat 中的 AprEndpoint 就是通过 DirectByteBuffer 来接收数据的,而 从下面的图你会发现这个过程有 6 次内存拷贝,并且 read 和 write 等系统调用将导致进程从用户态到内核态的切换,会耗费大量的 CPU 和内存资源。 -![img](https://raw.githubusercontent.com/dunwu/images/dev/snap/20201127151041.jpg) +![img](https://raw.githubusercontent.com/dunwu/images/master/snap/20201127151041.jpg) 而 Tomcat 的 AprEndpoint 通过操作系统层面的 sendfile 特性解决了这个问题,sendfile 系统调用方式非常简洁。 @@ -337,7 +337,7 @@ sendfile(socket, file, len); 第二步:数据并没有从内核缓冲区复制到 Socket 关联的缓冲区,只有记录数据位置和长度的描述符被添加到 Socket 缓冲区中;接着把数据直接从内核缓冲区传递给网卡。这个过程你可以看下面的图。 -![img](https://raw.githubusercontent.com/dunwu/images/dev/snap/20201127151155.jpg) +![img](https://raw.githubusercontent.com/dunwu/images/master/snap/20201127151155.jpg) ## 4. Executor 组件 @@ -508,7 +508,7 @@ Tomcat 用 ProtocolHandler 组件屏蔽应用层协议的差异,其中 Protoco WebSocket 是通过 HTTP 协议来进行握手的,因此当 WebSocket 的握手请求到来时,HttpProtocolHandler 首先接收到这个请求,在处理这个 HTTP 请求时,Tomcat 通过一个特殊的 Filter 判断该当前 HTTP 请求是否是一个 WebSocket Upgrade 请求(即包含`Upgrade: websocket`的 HTTP 头信息),如果是,则在 HTTP 响应里添加 WebSocket 相关的响应头信息,并进行协议升级。具体来说就是用 UpgradeProtocolHandler 替换当前的 HttpProtocolHandler,相应的,把当前 Socket 的 Processor 替换成 UpgradeProcessor,同时 Tomcat 会创建 WebSocket Session 实例和 Endpoint 实例,并跟当前的 WebSocket 连接一一对应起来。这个 WebSocket 连接不会立即关闭,并且在请求处理中,不再使用原有的 HttpProcessor,而是用专门的 UpgradeProcessor,UpgradeProcessor 最终会调用相应的 Endpoint 实例来处理请求。 -![img](https://raw.githubusercontent.com/dunwu/images/dev/snap/20201127153521.jpg) +![img](https://raw.githubusercontent.com/dunwu/images/master/snap/20201127153521.jpg) 你可以看到,Tomcat 对 WebSocket 请求的处理没有经过 Servlet 容器,而是通过 UpgradeProcessor 组件直接把请求发到 ServerEndpoint 实例,并且 Tomcat 的 WebSocket 实现不需要关注具体 I/O 模型的细节,从而实现了与具体 I/O 方式的解耦。 diff --git "a/docs/02.JavaEE/02.\346\234\215\345\212\241\345\231\250/01.Tomcat/03.Tomcat\345\256\271\345\231\250.md" "b/docs/02.JavaEE/02.\346\234\215\345\212\241\345\231\250/01.Tomcat/03.Tomcat\345\256\271\345\231\250.md" index d72a1c6..0cf551d 100644 --- "a/docs/02.JavaEE/02.\346\234\215\345\212\241\345\231\250/01.Tomcat/03.Tomcat\345\256\271\345\231\250.md" +++ "b/docs/02.JavaEE/02.\346\234\215\345\212\241\345\231\250/01.Tomcat/03.Tomcat\345\256\271\345\231\250.md" @@ -335,7 +335,7 @@ Tomcat 作为 Web 容器,需要解决以下问题: 2. 两个 Web 应用都依赖同一个第三方的 JAR 包,比如 Spring,那 Spring 的 JAR 包被加载到内存后,Tomcat 要保证这两个 Web 应用能够共享,也就是说 Spring 的 JAR 包只被加载一次,否则随着依赖的第三方 JAR 包增多,JVM 的内存会膨胀。 3. 需要隔离 Tomcat 本身的类和 Web 应用的类。 -![img](https://raw.githubusercontent.com/dunwu/images/dev/snap/20201130141536.png) +![img](https://raw.githubusercontent.com/dunwu/images/master/snap/20201130141536.png) #### WebAppClassLoader diff --git "a/docs/02.JavaEE/02.\346\234\215\345\212\241\345\231\250/02.Jetty.md" "b/docs/02.JavaEE/02.\346\234\215\345\212\241\345\231\250/02.Jetty.md" index 369b740..d1c00d2 100644 --- "a/docs/02.JavaEE/02.\346\234\215\345\212\241\345\231\250/02.Jetty.md" +++ "b/docs/02.JavaEE/02.\346\234\215\345\212\241\345\231\250/02.Jetty.md" @@ -254,7 +254,7 @@ mvn jetty:run ### Jetty 架构简介 -![img](https://raw.githubusercontent.com/dunwu/images/dev/snap/20201127154145.jpg) +![img](https://raw.githubusercontent.com/dunwu/images/master/snap/20201127154145.jpg) Jetty Server 就是由多个 Connector(连接器)、多个 Handler(处理器),以及一个线程池组成。 @@ -379,7 +379,7 @@ getEndPoint().fillInterested(_readCallback); 到此你应该了解了 Connector 的工作原理,下面我画张图再来回顾一下 Connector 的工作流程。 -![img](https://raw.githubusercontent.com/dunwu/images/dev/snap/20201118175805.jpg) +![img](https://raw.githubusercontent.com/dunwu/images/master/snap/20201118175805.jpg) 1. Acceptor 监听连接请求,当有连接请求到达时就接受连接,一个连接对应一个 Channel,Acceptor 将 Channel 交给 ManagedSelector 来处理。 @@ -427,7 +427,7 @@ public interface Handler extends LifeCycle, Destroyable Handler 只是一个接口,完成具体功能的还是它的子类。那么 Handler 有哪些子类呢?它们的继承关系又是怎样的?这些子类是如何实现 Servlet 容器功能的呢? -![img](https://raw.githubusercontent.com/dunwu/images/dev/snap/20201118181025.png) +![img](https://raw.githubusercontent.com/dunwu/images/master/snap/20201118181025.png) 在 AbstractHandler 之下有 AbstractHandlerContainer,为什么需要这个类呢?这其实是个过渡,为了实现链式调用,一个 Handler 内部必然要有其他 Handler 的引用,所以这个类的名字里才有 Container,意思就是这样的 Handler 里包含了其他 Handler 的引用。 diff --git "a/docs/11.\350\275\257\344\273\266/01.\346\236\204\345\273\272/01.Maven/01.Maven\345\277\253\351\200\237\345\205\245\351\227\250.md" "b/docs/11.\350\275\257\344\273\266/01.\346\236\204\345\273\272/01.Maven/01.Maven\345\277\253\351\200\237\345\205\245\351\227\250.md" index 265088c..7c3f469 100644 --- "a/docs/11.\350\275\257\344\273\266/01.\346\236\204\345\273\272/01.Maven/01.Maven\345\277\253\351\200\237\345\205\245\351\227\250.md" +++ "b/docs/11.\350\275\257\344\273\266/01.\346\236\204\345\273\272/01.Maven/01.Maven\345\277\253\351\200\237\345\205\245\351\227\250.md" @@ -135,9 +135,9 @@ export PATH=$MAVEN_HOME/bin:$PATH 右键 "计算机",选择 "属性",之后点击 "高级系统设置",点击"环境变量",来设置环境变量,有以下系统变量需要配置: -![img](https://raw.githubusercontent.com/dunwu/images/dev/snap/20200108143017.png) +![img](https://raw.githubusercontent.com/dunwu/images/master/snap/20200108143017.png) -![img](https://raw.githubusercontent.com/dunwu/images/dev/snap/20200108143038.png) +![img](https://raw.githubusercontent.com/dunwu/images/master/snap/20200108143038.png) ### 检测安装成功 @@ -265,15 +265,15 @@ java -cp target/my-app-1.0-SNAPSHOT.jar com.mycompany.app.App 依次点击 File -> New -> Project 打开创建工程对话框,选择 Maven 工程。 -![img](https://raw.githubusercontent.com/dunwu/images/dev/snap/1555414103572.png) +![img](https://raw.githubusercontent.com/dunwu/images/master/snap/1555414103572.png) (2)输入项目信息 -![img](https://raw.githubusercontent.com/dunwu/images/dev/snap/1555415549748.png) +![img](https://raw.githubusercontent.com/dunwu/images/master/snap/1555415549748.png) (3)点击 Intellij 侧边栏中的 Maven 工具界面,有几个可以直接使用的 maven 命令,可以帮助你进行构建。 -![img](https://raw.githubusercontent.com/dunwu/images/dev/snap/1555415806237.png) +![img](https://raw.githubusercontent.com/dunwu/images/master/snap/1555415806237.png) ### 在 Eclipse 中创建 Maven 工程 @@ -285,7 +285,7 @@ java -cp target/my-app-1.0-SNAPSHOT.jar com.mycompany.app.App 点击 Help -> Eclipse Marketplace,搜索 maven 关键字,选择安装红框对应的 Maven 插件。 -![img](https://raw.githubusercontent.com/dunwu/images/dev/snap/20181127195117.png) +![img](https://raw.githubusercontent.com/dunwu/images/master/snap/20181127195117.png) (2)Maven 环境配置 @@ -293,7 +293,7 @@ java -cp target/my-app-1.0-SNAPSHOT.jar com.mycompany.app.App 如下图所示,配置 settings.xml 文件的位置 -![img](https://raw.githubusercontent.com/dunwu/images/dev/snap/20181127195128.png) +![img](https://raw.githubusercontent.com/dunwu/images/master/snap/20181127195128.png) (3)创建 Maven 工程 @@ -301,7 +301,7 @@ File -> New -> Maven Project -> Next,在接下来的窗口中会看到一大 接下来设置项目的参数,如下: -![img](https://raw.githubusercontent.com/dunwu/images/dev/snap/20181127195151.png) +![img](https://raw.githubusercontent.com/dunwu/images/master/snap/20181127195151.png) **groupId**是项目组织唯一的标识符,实际对应 JAVA 的包的结构,是 main 目录里 java 的目录结构。 @@ -315,11 +315,11 @@ Eclipse 中构建方式: 在 Elipse 项目上右击 -> Run As 就能看到很多 Maven 操作。这些操作和 maven 命令是等效的。例如 Maven clean,等同于 mvn clean 命令。 -![img](https://raw.githubusercontent.com/dunwu/images/dev/snap/20181127195208.png) +![img](https://raw.githubusercontent.com/dunwu/images/master/snap/20181127195208.png) 你也可以点击 Maven build,输入组合命令,并保存下来。如下图: -![img](https://raw.githubusercontent.com/dunwu/images/dev/snap/20181127195219.png) +![img](https://raw.githubusercontent.com/dunwu/images/master/snap/20181127195219.png) Maven 命令构建方式: @@ -327,7 +327,7 @@ Maven 命令构建方式: 进入工程所在目录,输入 maven 命令就可以了。 -![img](https://raw.githubusercontent.com/dunwu/images/dev/snap/20181127195243.png) +![img](https://raw.githubusercontent.com/dunwu/images/master/snap/20181127195243.png) ## 使用说明 diff --git "a/docs/11.\350\275\257\344\273\266/01.\346\236\204\345\273\272/01.Maven/04.Maven\345\256\236\346\210\230\351\227\256\351\242\230\345\222\214\346\234\200\344\275\263\345\256\236\350\267\265.md" "b/docs/11.\350\275\257\344\273\266/01.\346\236\204\345\273\272/01.Maven/04.Maven\345\256\236\346\210\230\351\227\256\351\242\230\345\222\214\346\234\200\344\275\263\345\256\236\350\267\265.md" index ee3b4ef..d6936df 100644 --- "a/docs/11.\350\275\257\344\273\266/01.\346\236\204\345\273\272/01.Maven/04.Maven\345\256\236\346\210\230\351\227\256\351\242\230\345\222\214\346\234\200\344\275\263\345\256\236\350\267\265.md" +++ "b/docs/11.\350\275\257\344\273\266/01.\346\236\204\345\273\272/01.Maven/04.Maven\345\256\236\346\210\230\351\227\256\351\242\230\345\222\214\346\234\200\344\275\263\345\256\236\350\267\265.md" @@ -48,21 +48,21 @@ maven 的 JDK 源与指定的 JDK 编译版本不符。 Project SDK 是否正确 -![img](https://raw.githubusercontent.com/dunwu/images/dev/snap/20181127203324.png) +![img](https://raw.githubusercontent.com/dunwu/images/master/snap/20181127203324.png) SDK 路径是否正确 -![img](https://raw.githubusercontent.com/dunwu/images/dev/snap/20181127203427.png) +![img](https://raw.githubusercontent.com/dunwu/images/master/snap/20181127203427.png) - **查看 Settings > Maven 的配置** JDK for importer 是否正确 -![img](https://raw.githubusercontent.com/dunwu/images/dev/snap/20181127203408.png) +![img](https://raw.githubusercontent.com/dunwu/images/master/snap/20181127203408.png) Runner 是否正确 -![img](https://raw.githubusercontent.com/dunwu/images/dev/snap/20181127203439.png) +![img](https://raw.githubusercontent.com/dunwu/images/master/snap/20181127203439.png) ### 重复引入依赖 diff --git "a/docs/11.\350\275\257\344\273\266/01.\346\236\204\345\273\272/01.Maven/05.Maven\346\225\231\347\250\213\344\271\213\345\217\221\345\270\203jar\345\210\260\347\247\201\346\234\215\346\210\226\344\270\255\345\244\256\344\273\223\345\272\223.md" "b/docs/11.\350\275\257\344\273\266/01.\346\236\204\345\273\272/01.Maven/05.Maven\346\225\231\347\250\213\344\271\213\345\217\221\345\270\203jar\345\210\260\347\247\201\346\234\215\346\210\226\344\270\255\345\244\256\344\273\223\345\272\223.md" index 32416c4..0c236c3 100644 --- "a/docs/11.\350\275\257\344\273\266/01.\346\236\204\345\273\272/01.Maven/05.Maven\346\225\231\347\250\213\344\271\213\345\217\221\345\270\203jar\345\210\260\347\247\201\346\234\215\346\210\226\344\270\255\345\244\256\344\273\223\345\272\223.md" +++ "b/docs/11.\350\275\257\344\273\266/01.\346\236\204\345\273\272/01.Maven/05.Maven\346\225\231\347\250\213\344\271\213\345\217\221\345\270\203jar\345\210\260\347\247\201\346\234\215\346\210\226\344\270\255\345\244\256\344\273\223\345\272\223.md" @@ -32,7 +32,7 @@ permalink: /pages/2ddf04/ 注册账号成功后,根据你 Java 包的功能分别写上`Summary`、`Description`、`Group Id`、`SCM url`以及`Project URL`等必要信息,可以参见我之前创建的 Issue:[OSSRH-36187](https://issues.sonatype.org/browse/OSSRH-36187)。 -![img](https://raw.githubusercontent.com/dunwu/images/dev/snap/20181106143734.png) +![img](https://raw.githubusercontent.com/dunwu/images/master/snap/20181106143734.png) 创建完之后需要等待 Sonatype 的工作人员审核处理,审核时间还是很快的,我的审核差不多等待了两小时。当 Issue 的 Status 变为`RESOLVED`后,就可以进行下一步操作了。 @@ -308,7 +308,7 @@ gpg: unchanged: 1 进入[官方下载地址](https://www.sonatype.com/download-oss-sonatype),选择合适版本下载。 -![img](https://raw.githubusercontent.com/dunwu/images/dev/snap/20181127203029.png) +![img](https://raw.githubusercontent.com/dunwu/images/master/snap/20181127203029.png) 本人希望将 Nexus 部署在 Linux 机器,所以选用的是 Unix 版本。 @@ -340,13 +340,13 @@ Usage: ./nexus {start|stop|run|run-redirect|status|restart|force-reload} 启动成功后,在浏览器中访问 `http://:8081`,欢迎页面如下图所示: -![img](https://raw.githubusercontent.com/dunwu/images/dev/snap/20181127203131.png) +![img](https://raw.githubusercontent.com/dunwu/images/master/snap/20181127203131.png) 点击右上角 Sign in 登录,默认用户名/密码为:admin/admin123。 有必要提一下的是,在 Nexus 的 Repositories 管理页面,展示了可用的 maven 仓库,如下图所示: -![img](https://raw.githubusercontent.com/dunwu/images/dev/snap/20181127203156.png) +![img](https://raw.githubusercontent.com/dunwu/images/master/snap/20181127203156.png) > 说明: > diff --git "a/docs/11.\350\275\257\344\273\266/03.\347\233\221\346\216\247\350\257\212\346\226\255/01.\347\233\221\346\216\247\345\267\245\345\205\267\345\257\271\346\257\224.md" "b/docs/11.\350\275\257\344\273\266/03.\347\233\221\346\216\247\350\257\212\346\226\255/01.\347\233\221\346\216\247\345\267\245\345\205\267\345\257\271\346\257\224.md" index 2c1d9e9..d460dcc 100644 --- "a/docs/11.\350\275\257\344\273\266/03.\347\233\221\346\216\247\350\257\212\346\226\255/01.\347\233\221\346\216\247\345\267\245\345\205\267\345\257\271\346\257\224.md" +++ "b/docs/11.\350\275\257\344\273\266/03.\347\233\221\346\216\247\350\257\212\346\226\255/01.\347\233\221\346\216\247\345\267\245\345\205\267\345\257\271\346\257\224.md" @@ -17,17 +17,17 @@ permalink: /pages/c7c5ec/ ## 监控工具发展史 -![img](https://raw.githubusercontent.com/dunwu/images/dev/snap/20200211165813.png) +![img](https://raw.githubusercontent.com/dunwu/images/master/snap/20200211165813.png) ## 监控工具比对 ### 特性对比 -![img](https://raw.githubusercontent.com/dunwu/images/dev/snap/20200211171551.png) +![img](https://raw.githubusercontent.com/dunwu/images/master/snap/20200211171551.png) ### 生态对比 -![img](https://raw.githubusercontent.com/dunwu/images/dev/snap/20200211172631.png) +![img](https://raw.githubusercontent.com/dunwu/images/master/snap/20200211172631.png) ## 技术选型 diff --git "a/docs/11.\350\275\257\344\273\266/03.\347\233\221\346\216\247\350\257\212\346\226\255/02.CAT.md" "b/docs/11.\350\275\257\344\273\266/03.\347\233\221\346\216\247\350\257\212\346\226\255/02.CAT.md" index 639d3a9..f3e36d6 100644 --- "a/docs/11.\350\275\257\344\273\266/03.\347\233\221\346\216\247\350\257\212\346\226\255/02.CAT.md" +++ "b/docs/11.\350\275\257\344\273\266/03.\347\233\221\346\216\247\350\257\212\346\226\255/02.CAT.md" @@ -38,7 +38,7 @@ CAT 监控系统将每次 URL、Service 的请求内部执行情况都封装为 - **Heartbeat** 表示程序内定期产生的统计信息, 如 CPU 利用率, 内存利用率, 连接池状态, 系统负载等 - **Metric** 用于记录业务指标、指标可能包含对一个指标记录次数、记录平均值、记录总和,业务指标最低统计粒度为 1 分钟 -![img](https://raw.githubusercontent.com/dunwu/images/dev/snap/20200211174235.png) +![img](https://raw.githubusercontent.com/dunwu/images/master/snap/20200211174235.png) ## CAT 部署 @@ -73,7 +73,7 @@ CAT 主要分为三个模块: 在实际开发和部署中,cat-consumer 和 cat-home 是部署在一个 jvm 内部,每个 CAT 服务端都可以作为 consumer 也可以作为 home,这样既能减少整个 CAT 层级结构,也可以增加整个系统稳定性。 -![img](https://raw.githubusercontent.com/dunwu/images/dev/snap/20200211174001.png) +![img](https://raw.githubusercontent.com/dunwu/images/master/snap/20200211174001.png) 上图是 CAT 目前多机房的整体结构图: diff --git "a/docs/11.\350\275\257\344\273\266/03.\347\233\221\346\216\247\350\257\212\346\226\255/03.Zipkin.md" "b/docs/11.\350\275\257\344\273\266/03.\347\233\221\346\216\247\350\257\212\346\226\255/03.Zipkin.md" index a36e4d1..e3951c8 100644 --- "a/docs/11.\350\275\257\344\273\266/03.\347\233\221\346\216\247\350\257\212\346\226\255/03.Zipkin.md" +++ "b/docs/11.\350\275\257\344\273\266/03.\347\233\221\346\216\247\350\257\212\346\226\255/03.Zipkin.md" @@ -30,7 +30,7 @@ Zipkin 基于 Google Dapper 的论文设计而来,由 Twitter 公司开发贡 Zipkin UI 还提供了一个依赖关系图,该关系图显示了每个应用程序中跟踪了多少个请求。这对于识别聚合行为(包括错误路径或对不赞成使用的服务的调用)很有帮助。 -![Zipkin UI](https://raw.githubusercontent.com/dunwu/images/dev/snap/20200211161706.png) +![Zipkin UI](https://raw.githubusercontent.com/dunwu/images/master/snap/20200211161706.png) ### 多平台 @@ -48,7 +48,7 @@ Zipkin 服务器捆绑了用于采集和存储数据的扩展。 数据以 json 形式存储,可以参考:[Zipkin 官方的 Swagger API](https://zipkin.io/zipkin-api/#/default/post_spans) -![Zipkin Swagger API](https://raw.githubusercontent.com/dunwu/images/dev/snap/20200211162055.png) +![Zipkin Swagger API](https://raw.githubusercontent.com/dunwu/images/master/snap/20200211162055.png) ## 二、Zipkin 安装 @@ -94,7 +94,7 @@ ZipKin 可以分为两部分, 架构如下: -![Zipkin 架构](https://raw.githubusercontent.com/dunwu/images/dev/snap/20200211155836.png) +![Zipkin 架构](https://raw.githubusercontent.com/dunwu/images/master/snap/20200211155836.png) ### Zipkin Server diff --git "a/docs/11.\350\275\257\344\273\266/03.\347\233\221\346\216\247\350\257\212\346\226\255/04.Skywalking.md" "b/docs/11.\350\275\257\344\273\266/03.\347\233\221\346\216\247\350\257\212\346\226\255/04.Skywalking.md" index e0c84c3..be925e6 100644 --- "a/docs/11.\350\275\257\344\273\266/03.\347\233\221\346\216\247\350\257\212\346\226\255/04.Skywalking.md" +++ "b/docs/11.\350\275\257\344\273\266/03.\347\233\221\346\216\247\350\257\212\346\226\255/04.Skywalking.md" @@ -24,7 +24,7 @@ SkyWalking 是观察性分析平台和应用性能管理系统。 提供分布式追踪、服务网格遥测分析、度量聚合和可视化一体化解决方案。 -![img](https://raw.githubusercontent.com/dunwu/images/dev/snap/20200211152235.png) +![img](https://raw.githubusercontent.com/dunwu/images/master/snap/20200211152235.png) ### SkyWalking 特性 @@ -45,7 +45,7 @@ SkyWalking 是观察性分析平台和应用性能管理系统。 从逻辑上讲,SkyWalking 分为四个部分:探针(Probes),平台后端,存储和 UI。 -![SkyWalking 架构](https://raw.githubusercontent.com/dunwu/images/dev/snap/20200211153516.png) +![SkyWalking 架构](https://raw.githubusercontent.com/dunwu/images/master/snap/20200211153516.png) - **探针(Probes)** - 探针是指集成到目标系统中的代理或 SDK 库。它们负责收集数据(包括跟踪数据和统计数据)并将其按照 SkyWalking 的要求重新格式化为。 - **平台后端** - 平台后端是一个提供后端服务的集群。它用于聚合、分析和驱动从探针到 UI 的流程。它还为传入格式(如 Zipkin 的格式),存储实现程序和集群管理提供可插入功能。 您甚至可以使用 Observability Analysis Language 自定义聚合和分析。 @@ -56,7 +56,7 @@ SkyWalking 是观察性分析平台和应用性能管理系统。 进入 [Apache SkyWalking 官方下载页面](http://skywalking.apache.org/downloads/),选择安装版本,下载解压到本地。 -![SkyWalking 组件](https://raw.githubusercontent.com/dunwu/images/dev/snap/20200211154612.png) +![SkyWalking 组件](https://raw.githubusercontent.com/dunwu/images/master/snap/20200211154612.png) 安装分为三个部分: diff --git "a/docs/12.\345\267\245\345\205\267/03.\346\250\241\346\235\277\345\274\225\346\223\216/01.Freemark.md" "b/docs/12.\345\267\245\345\205\267/03.\346\250\241\346\235\277\345\274\225\346\223\216/01.Freemark.md" index a36c702..ed73fcc 100644 --- "a/docs/12.\345\267\245\345\205\267/03.\346\250\241\346\235\277\345\274\225\346\223\216/01.Freemark.md" +++ "b/docs/12.\345\267\245\345\205\267/03.\346\250\241\346\235\277\345\274\225\346\223\216/01.Freemark.md" @@ -35,7 +35,7 @@ Freemark 模板一句话概括就是:**_`模板 + 数据模型 = 输出`_** - **FTL 标签**:FTL 标签和 HTML 标签很相似,但是它们却是给 FreeMarker 的指示, 而且不会打印在输出内容中。 - **注释**:注释和 HTML 的注释也很相似,但它们是由 `<#--` 和 `-->`来分隔的。注释会被 FreeMarker 直接忽略, 更不会在输出内容中显示。 -![img](https://raw.githubusercontent.com/dunwu/images/dev/snap/ftl-template.png) +![img](https://raw.githubusercontent.com/dunwu/images/master/snap/ftl-template.png) > 🔔 注意: > diff --git "a/docs/12.\345\267\245\345\205\267/04.\346\265\213\350\257\225/01.Junit.md" "b/docs/12.\345\267\245\345\205\267/04.\346\265\213\350\257\225/01.Junit.md" index defa29a..55d6bf3 100644 --- "a/docs/12.\345\267\245\345\205\267/04.\346\265\213\350\257\225/01.Junit.md" +++ "b/docs/12.\345\267\245\345\205\267/04.\346\265\213\350\257\225/01.Junit.md" @@ -51,7 +51,7 @@ permalink: /pages/06533c/ 组件间依赖关系: -![img](https://raw.githubusercontent.com/dunwu/images/dev/cs/java/javalib/test/junit/junit5-components.png) +![img](https://raw.githubusercontent.com/dunwu/images/master/cs/java/javalib/test/junit/junit5-components.png) ## JUnit 注解 diff --git "a/docs/12.\345\267\245\345\205\267/04.\346\265\213\350\257\225/03.Jmeter.md" "b/docs/12.\345\267\245\345\205\267/04.\346\265\213\350\257\225/03.Jmeter.md" index e1649bf..c4841c4 100644 --- "a/docs/12.\345\267\245\345\205\267/04.\346\265\213\350\257\225/03.Jmeter.md" +++ "b/docs/12.\345\267\245\345\205\267/04.\346\265\213\350\257\225/03.Jmeter.md" @@ -45,7 +45,7 @@ Jmeter 的工作原理是仿真用户向服务器发送请求,并收集服务 Jmeter 的工作流如下图所示: -![img](https://raw.githubusercontent.com/dunwu/images/dev/cs/java/javaweb/technology/test/jmeter-workflow.png) +![img](https://raw.githubusercontent.com/dunwu/images/master/cs/java/javaweb/technology/test/jmeter-workflow.png) ### 主要元素 @@ -65,7 +65,7 @@ Jmeter 的主要元素如下: - **`预处理器元素(Pre-Processor Elements)`** - 预处理器元素在采样器发出请求之前执行,如果预处理器附加到采样器元素,那么它将在该采样器元素运行之前执行。预处理器元素用于在运行之前准备环境及参数。 - **`后处理器元素(Post-Processor Elements)`** - 后处理器元素是在发送采样器请求之后执行的元素,常用于处理响应数据。 -![img](https://raw.githubusercontent.com/dunwu/images/dev/cs/java/javaweb/technology/test/jmeter-elements.png) +![img](https://raw.githubusercontent.com/dunwu/images/master/cs/java/javaweb/technology/test/jmeter-elements.png) > 📌 提示: > @@ -99,7 +99,7 @@ Jmeter 的主要元素如下: Unix 类系统运行 `jmeter` ;Windows 系统运行 `jmeter.bat` -![image-20191024104517721](https://raw.githubusercontent.com/dunwu/images/dev/snap/jmeter/image-20191024104517721.png) +![image-20191024104517721](https://raw.githubusercontent.com/dunwu/images/master/snap/jmeter/image-20191024104517721.png) ## 使用 @@ -117,7 +117,7 @@ Unix 类系统运行 `jmeter` ;Windows 系统运行 `jmeter.bat` - 设置线程数和循环次数 -![image-20191024105545736](https://raw.githubusercontent.com/dunwu/images/dev/snap/jmeter/image-20191024105545736.png) +![image-20191024105545736](https://raw.githubusercontent.com/dunwu/images/master/snap/jmeter/image-20191024105545736.png) #### 配置原件 @@ -125,7 +125,7 @@ Unix 类系统运行 `jmeter` ;Windows 系统运行 `jmeter.bat` - 填写协议、服务器名称或 IP、端口号 -![image-20191024110016264](https://raw.githubusercontent.com/dunwu/images/dev/snap/jmeter/image-20191024110016264.png) +![image-20191024110016264](https://raw.githubusercontent.com/dunwu/images/master/snap/jmeter/image-20191024110016264.png) #### 构造 HTTP 请求 @@ -135,35 +135,35 @@ Unix 类系统运行 `jmeter` ;Windows 系统运行 `jmeter.bat` - 填写方法、路径 - 填写参数、消息体数据、文件上传 -![image-20191024110953063](https://raw.githubusercontent.com/dunwu/images/dev/snap/jmeter/image-20191024110953063.png) +![image-20191024110953063](https://raw.githubusercontent.com/dunwu/images/master/snap/jmeter/image-20191024110953063.png) #### 添加 HTTP 请求头 - 在“线程组”上右键 【添加】=>【配置元件】=>【HTTP 信息头管理器】 - 由于我的测试例中传输的数据为 json 形式,所以设置键值对 `Content-Type`:`application/json` -![image-20191024111825226](https://raw.githubusercontent.com/dunwu/images/dev/snap/jmeter/image-20191024111825226.png) +![image-20191024111825226](https://raw.githubusercontent.com/dunwu/images/master/snap/jmeter/image-20191024111825226.png) #### 添加断言 - 在“线程组”上右键 【添加】=>【断言】=>【 响应断言 】 - 在我的案例中,以 HTTP 应答状态码为 200 来判断请求是否成功 -![image-20191024112335130](https://raw.githubusercontent.com/dunwu/images/dev/snap/jmeter/image-20191024112335130.png) +![image-20191024112335130](https://raw.githubusercontent.com/dunwu/images/master/snap/jmeter/image-20191024112335130.png) #### 添加察看结果树 - 在“线程组”上右键 【添加】=>【监听器】=>【察看结果树】 - 直接点击运行,就可以查看测试结果 -![image-20191024113849270](https://raw.githubusercontent.com/dunwu/images/dev/snap/jmeter/image-20191024113849270.png) +![image-20191024113849270](https://raw.githubusercontent.com/dunwu/images/master/snap/jmeter/image-20191024113849270.png) #### 添加汇总报告 - 在“线程组”上右键 【添加】=>【监听器】=>【汇总报告】 - 直接点击运行,就可以查看测试结果 -![image-20191024114016424](https://raw.githubusercontent.com/dunwu/images/dev/snap/jmeter/image-20191024114016424.png) +![image-20191024114016424](https://raw.githubusercontent.com/dunwu/images/master/snap/jmeter/image-20191024114016424.png) #### 保存测试计划 @@ -181,7 +181,7 @@ jmeter -n -t [jmx file] -l [results file] -e -o [Path to web report folder] 执行测试计划后,在 `-e -o` 参数后指定的 web 报告目录下,可以找到测试报告内容。在浏览器中打开 `index.html` 文件,可以看到如下报告: -![image-20191024120233058](https://raw.githubusercontent.com/dunwu/images/dev/snap/jmeter/image-20191024120233058.png) +![image-20191024120233058](https://raw.githubusercontent.com/dunwu/images/master/snap/jmeter/image-20191024120233058.png) ## 问题 @@ -193,7 +193,7 @@ jmeter -n -t [jmx file] -l [results file] -e -o [Path to web report folder] 配置如下所示: -![image-20191127175820747](https://raw.githubusercontent.com/dunwu/images/dev/snap/image-20191127175820747.png) +![image-20191127175820747](https://raw.githubusercontent.com/dunwu/images/master/snap/image-20191127175820747.png) 重要配置说明(其他配置根据实际情况填): diff --git "a/docs/12.\345\267\245\345\205\267/99.\345\205\266\344\273\226/01.Java\346\227\245\345\277\227.md" "b/docs/12.\345\267\245\345\205\267/99.\345\205\266\344\273\226/01.Java\346\227\245\345\277\227.md" index c37498e..f507823 100644 --- "a/docs/12.\345\267\245\345\205\267/99.\345\205\266\344\273\226/01.Java\346\227\245\345\277\227.md" +++ "b/docs/12.\345\267\245\345\205\267/99.\345\205\266\344\273\226/01.Java\346\227\245\345\277\227.md" @@ -64,7 +64,7 @@ logback 当前分成三个模块:`logback-core`、`logback-classic` 和 `logba Log4j2 架构: -![img](https://raw.githubusercontent.com/dunwu/images/dev/cs/java/javalib/log/log4j2-architecture.jpg) +![img](https://raw.githubusercontent.com/dunwu/images/master/cs/java/javalib/log/log4j2-architecture.jpg) ### Log4j vs Logback vs Log4j2 @@ -108,7 +108,7 @@ common-logging 的功能是提供日志功能的 API 接口,本身并不提供 [官网地址](http://www.slf4j.org/) -![img](https://raw.githubusercontent.com/dunwu/images/dev/cs/java/javalib/log/slf4j-to-other-log.png) +![img](https://raw.githubusercontent.com/dunwu/images/master/cs/java/javalib/log/slf4j-to-other-log.png) ### common-logging vs slf4j @@ -202,7 +202,7 @@ _slf4j-jdk14-1.7.21.jar_ 会自动将 _slf4j-api-1.7.21.jar_ 也添加到你的 假如你正在开发应用程序所调用的组件当中已经使用了 common-logging,这时你需要 jcl-over-slf4j.jar 把日志信息输出重定向到 slf4j-api,slf4j-api 再去调用 slf4j 实际依赖的日志组件。这个过程称为桥接。下图是官方的 slf4j 桥接策略图: -![img](https://raw.githubusercontent.com/dunwu/images/dev/cs/java/javalib/log/slf4j-bind-strategy.png) +![img](https://raw.githubusercontent.com/dunwu/images/master/cs/java/javalib/log/slf4j-bind-strategy.png) 从图中应该可以看出,无论你的老项目中使用的是 common-logging 或是直接使用 log4j、java.util.logging,都可以使用对应的桥接 jar 包来解决兼容问题。 @@ -418,7 +418,7 @@ log4j2 基本配置形式如下: - 要点 - 它有 ``、``、`` 三个子元素。 -![img](https://raw.githubusercontent.com/dunwu/images/dev/cs/java/javalib/log/logback-configuration.png) +![img](https://raw.githubusercontent.com/dunwu/images/master/cs/java/javalib/log/logback-configuration.png) ### `` @@ -456,7 +456,7 @@ log4j2 基本配置形式如下: - 属性 - class:设置具体的实例化类。 -![img](https://raw.githubusercontent.com/dunwu/images/dev/cs/java/javalib/log/logback-appender.png) +![img](https://raw.githubusercontent.com/dunwu/images/master/cs/java/javalib/log/logback-appender.png) ### `` diff --git "a/docs/13.\346\241\206\346\236\266/11.ORM/01.Mybatis\345\277\253\351\200\237\345\205\245\351\227\250.md" "b/docs/13.\346\241\206\346\236\266/11.ORM/01.Mybatis\345\277\253\351\200\237\345\205\245\351\227\250.md" index 704af1b..f61fe42 100644 --- "a/docs/13.\346\241\206\346\236\266/11.ORM/01.Mybatis\345\277\253\351\200\237\345\205\245\351\227\250.md" +++ "b/docs/13.\346\241\206\346\236\266/11.ORM/01.Mybatis\345\277\253\351\200\237\345\205\245\351\227\250.md" @@ -19,11 +19,11 @@ permalink: /pages/538358/ > MyBatis 的前身就是 iBatis ,是一个作用在数据持久层的对象关系映射(Object Relational Mapping,简称 ORM)框架。 -![img](https://raw.githubusercontent.com/dunwu/images/dev/snap/20200716162305.png) +![img](https://raw.githubusercontent.com/dunwu/images/master/snap/20200716162305.png) ## Mybatis 简介 -![img](https://raw.githubusercontent.com/dunwu/images/dev/snap/20210510164925.png) +![img](https://raw.githubusercontent.com/dunwu/images/master/snap/20210510164925.png) ### 什么是 MyBatis diff --git "a/docs/13.\346\241\206\346\236\266/11.ORM/02.Mybatis\345\216\237\347\220\206.md" "b/docs/13.\346\241\206\346\236\266/11.ORM/02.Mybatis\345\216\237\347\220\206.md" index d36c074..326a601 100644 --- "a/docs/13.\346\241\206\346\236\266/11.ORM/02.Mybatis\345\216\237\347\220\206.md" +++ "b/docs/13.\346\241\206\346\236\266/11.ORM/02.Mybatis\345\216\237\347\220\206.md" @@ -229,7 +229,7 @@ public class MybatisDemo { ## Mybatis 生命周期 -![img](https://raw.githubusercontent.com/dunwu/images/dev/snap/20210510113446.png) +![img](https://raw.githubusercontent.com/dunwu/images/master/snap/20210510113446.png) ### SqlSessionFactoryBuilder @@ -239,7 +239,7 @@ public class MybatisDemo { `Configuration` 类包含了对一个 `SqlSessionFactory` 实例你可能关心的所有内容。 -![img](https://raw.githubusercontent.com/dunwu/images/dev/snap/20210508173040.png) +![img](https://raw.githubusercontent.com/dunwu/images/master/snap/20210508173040.png) `SqlSessionFactoryBuilder` 应用了建造者设计模式,它有五个 `build` 方法,允许你通过不同的资源创建 `SqlSessionFactory` 实例。 @@ -261,7 +261,7 @@ SqlSessionFactory build(Configuration config) **`SqlSessionFactory` 负责创建 `SqlSession` 实例。** -![img](https://raw.githubusercontent.com/dunwu/images/dev/snap/20210510105641.png) +![img](https://raw.githubusercontent.com/dunwu/images/master/snap/20210510105641.png) `SqlSessionFactory` 应用了工厂设计模式,它提供了一组方法,用于创建 SqlSession 实例。 @@ -304,7 +304,7 @@ Configuration getConfiguration(); SqlSession 类的方法可以按照下图进行大致分类: -![img](https://raw.githubusercontent.com/dunwu/images/dev/snap/20210510110638.png) +![img](https://raw.githubusercontent.com/dunwu/images/master/snap/20210510110638.png) #### SqlSession 生命周期 @@ -338,7 +338,7 @@ Mybatis 会根据相应的接口声明的方法信息,通过动态代理机制 下面的示例展示了一些方法签名以及它们是如何映射到 `SqlSession` 上的。 -![img](https://raw.githubusercontent.com/dunwu/images/dev/snap/20210512111723.png) +![img](https://raw.githubusercontent.com/dunwu/images/master/snap/20210512111723.png) > **注意** > @@ -383,7 +383,7 @@ Mybatis 支持诸如 `@Insert`、`@Update`、`@Delete`、`@Select`、`@Result` 这些组件的架构层次如下: -![img](https://raw.githubusercontent.com/dunwu/images/dev/snap/20210512114852.png) +![img](https://raw.githubusercontent.com/dunwu/images/master/snap/20210512114852.png) ### 配置层 @@ -437,13 +437,13 @@ Mybatis 和数据库的交互有两种方式: - 如果开启了二级缓存,`SqlSession` 会先使用 `CachingExecutor` 对象来处理查询请求。`CachingExecutor` 会在二级缓存中查看是否有匹配的数据,如果匹配,则直接返回缓存结果;如果缓存中没有,再交给真正的 `Executor` 对象来完成查询,之后 `CachingExecutor` 会将真正 `Executor` 返回的查询结果放置到缓存中,然后在返回给用户。 - 二级缓存的生命周期是应用级别的。 -![img](https://raw.githubusercontent.com/dunwu/images/dev/snap/20210512185709.png) +![img](https://raw.githubusercontent.com/dunwu/images/master/snap/20210512185709.png) ## SqlSession 内部工作机制 从前文,我们已经了解了,Mybatis 封装了对数据库的访问,把对数据库的会话和事务控制放到了 SqlSession 对象中。那么具体是如何工作的呢?接下来,我们通过源码解读来进行分析。 -![img](https://raw.githubusercontent.com/dunwu/images/dev/snap/20210512173437.png) +![img](https://raw.githubusercontent.com/dunwu/images/master/snap/20210512173437.png) `SqlSession` 对于 insert、update、delete、select 的内部处理机制基本上大同小异。所以,接下来,我会以一次完整的 select 查询流程为例讲解 `SqlSession` 内部的工作机制。相信读者如果理解了 select 的处理流程,对于其他 CRUD 操作也能做到一通百通。 @@ -459,7 +459,7 @@ Mybatis 和数据库的交互有两种方式: Executor 即执行器,它负责生成动态 SQL 以及管理缓存。 -![img](https://raw.githubusercontent.com/dunwu/images/dev/snap/20210512150000.png) +![img](https://raw.githubusercontent.com/dunwu/images/master/snap/20210512150000.png) - `Executor` 即执行器接口。 - `BaseExecutor` 是 `Executor` 的抽象类,它采用了模板方法设计模式,内置了一些共性方法,而将定制化方法留给子类去实现。 @@ -474,7 +474,7 @@ Executor 即执行器,它负责生成动态 SQL 以及管理缓存。 `StatementHandler` 的家族成员: -![img](https://raw.githubusercontent.com/dunwu/images/dev/snap/20210512160243.png) +![img](https://raw.githubusercontent.com/dunwu/images/master/snap/20210512160243.png) - `StatementHandler` 是接口; - `BaseStatementHandler` 是实现 `StatementHandler` 的抽象类,内置一些共性方法; @@ -572,7 +572,7 @@ Mybatis 所有的配置信息都维持在 `Configuration` 对象之中。中维 `MappedStatement` 维护了一个 Mapper 方法的元数据信息,其数据组织可以参考下面的 debug 截图: -![img](https://raw.githubusercontent.com/dunwu/images/dev/snap/20210511150650.png) +![img](https://raw.githubusercontent.com/dunwu/images/master/snap/20210511150650.png) > 小结: > diff --git "a/docs/13.\346\241\206\346\236\266/11.ORM/README.md" "b/docs/13.\346\241\206\346\236\266/11.ORM/README.md" index fe20c39..3184ca6 100644 --- "a/docs/13.\346\241\206\346\236\266/11.ORM/README.md" +++ "b/docs/13.\346\241\206\346\236\266/11.ORM/README.md" @@ -21,7 +21,7 @@ permalink: /pages/e873e1/ > Mybatis 的前身就是 iBatis ,是一款优秀的持久层框架,它支持自定义 SQL、存储过程以及高级映射。本文以一个 Mybatis 完整示例为切入点,结合 Mybatis 底层源码分析,图文并茂的讲解 Mybatis 的核心工作机制。 -![img](https://raw.githubusercontent.com/dunwu/images/dev/snap/20210522101005.png) +![img](https://raw.githubusercontent.com/dunwu/images/master/snap/20210522101005.png) ### [Mybatis 快速入门](01.Mybatis快速入门.md) diff --git "a/docs/13.\346\241\206\346\236\266/12.\345\256\211\345\205\250/01.Shiro.md" "b/docs/13.\346\241\206\346\236\266/12.\345\256\211\345\205\250/01.Shiro.md" index e2b4f31..02308e3 100644 --- "a/docs/13.\346\241\206\346\236\266/12.\345\256\211\345\205\250/01.Shiro.md" +++ "b/docs/13.\346\241\206\346\236\266/12.\345\256\211\345\205\250/01.Shiro.md" @@ -24,7 +24,7 @@ permalink: /pages/cd25bf/ ### Shiro 特性

- +

核心功能: @@ -48,7 +48,7 @@ permalink: /pages/cd25bf/ ### Shiro 架构概述

- +

- **Subject** - **主题**。它代表当前用户,`Subject` 可以是一个人,但也可以是第三方服务、守护进程帐户、时钟守护任务或者其它——当前和软件交互的任何事件。`Subject` 是 Shiro 的入口。 @@ -63,7 +63,7 @@ permalink: /pages/cd25bf/ `SecurityManager` 是 Shiro 框架核心中的核心,它相当于 Shiro 的总指挥,负责调度所有行为,包括:认证、授权、获取安全数据(调用 `Realm`)、会话管理等。 -![img](https://raw.githubusercontent.com/dunwu/images/dev/cs/java/javaweb/standalone/security/shiro/ShiroArchitecture.png) +![img](https://raw.githubusercontent.com/dunwu/images/master/cs/java/javaweb/standalone/security/shiro/ShiroArchitecture.png) `SecurityManager` 聚合了以下组件: @@ -128,7 +128,7 @@ currentUser.logout(); ### 认证流程 -![img](https://raw.githubusercontent.com/dunwu/images/dev/snap/20200317092427.png) +![img](https://raw.githubusercontent.com/dunwu/images/master/snap/20200317092427.png) 1. 应用程序代码调用 `Subject.login` 方法,传入构造的 `AuthenticationToken` 实例,该实例代表最终用户的 `Principals` 和 `Credentials`。 @@ -282,7 +282,7 @@ public void updateAccount(Account userAccount) { ### 授权流程 -![img](https://raw.githubusercontent.com/dunwu/images/dev/snap/20200317092618.png) +![img](https://raw.githubusercontent.com/dunwu/images/master/snap/20200317092618.png) 1. 应用程序或框架代码调用任何 `Subject` 的 `hasRole*`,`checkRole*`,`isPermitted*` 或 `checkPermission*` 方法,并传入所需的权限或角色。 diff --git "a/docs/13.\346\241\206\346\236\266/12.\345\256\211\345\205\250/02.SpringSecurity.md" "b/docs/13.\346\241\206\346\236\266/12.\345\256\211\345\205\250/02.SpringSecurity.md" index 4c136eb..cf605a3 100644 --- "a/docs/13.\346\241\206\346\236\266/12.\345\256\211\345\205\250/02.SpringSecurity.md" +++ "b/docs/13.\346\241\206\346\236\266/12.\345\256\211\345\205\250/02.SpringSecurity.md" @@ -70,7 +70,7 @@ try { Spring Security 框架中的认证数据模型如下: -![img](https://raw.githubusercontent.com/dunwu/images/dev/snap/20200331115710.png) +![img](https://raw.githubusercontent.com/dunwu/images/master/snap/20200331115710.png) - `Authentication` - 认证信息实体。 - `principal` - 用户标识。如:用户名、账户名等。通常是 `UserDetails` 的实例(后面详细讲解)。 diff --git "a/docs/13.\346\241\206\346\236\266/14.\345\276\256\346\234\215\345\212\241/01.Dubbo.md" "b/docs/13.\346\241\206\346\236\266/14.\345\276\256\346\234\215\345\212\241/01.Dubbo.md" index ec3281f..1c95b13 100644 --- "a/docs/13.\346\241\206\346\236\266/14.\345\276\256\346\234\215\345\212\241/01.Dubbo.md" +++ "b/docs/13.\346\241\206\346\236\266/14.\345\276\256\346\234\215\345\212\241/01.Dubbo.md" @@ -37,7 +37,7 @@ RPC(Remote Procedure Call),即远程过程调用,它是一种通过网 #### RPC 工作流程 -![img](https://raw.githubusercontent.com/dunwu/images/dev/snap/20200305121252.jpg) +![img](https://raw.githubusercontent.com/dunwu/images/master/snap/20200305121252.jpg) 1. 服务消费方(client)调用以本地调用方式调用服务; 2. client stub 接收到调用后负责将方法、参数等组装成能够进行网络传输的消息体; @@ -188,7 +188,7 @@ Dubbo 支持多种配置方式: - Properties 最后,相当于缺省值,只有 XML 没有配置时,dubbo.properties 的相应配置项才会生效,通常用于共享公共配置,比如应用名。
- +
#### xml 配置 @@ -264,7 +264,7 @@ dubbo.registry.address=10.20.153.10:9090 #### 配置之间的关系
- +
#### 配置覆盖关系 @@ -277,7 +277,7 @@ dubbo.registry.address=10.20.153.10:9090 其中,服务提供方配置,通过 URL 经由注册中心传递给消费方。
- +
### 动态配置中心 @@ -310,7 +310,7 @@ configCenter.setAddress("zookeeper://127.0.0.1:2181"); ### Dubbo 核心组件
- +
节点角色: @@ -350,7 +350,7 @@ configCenter.setAddress("zookeeper://127.0.0.1:2181"); ### Dubbo 架构层次
- +
图例说明: @@ -487,7 +487,7 @@ Dubbo 的 Hessian 协议可以和原生 Hessian 服务互操作,即: 在集群调用失败时,Dubbo 提供了多种容错方案,缺省为 failover 重试。
- +
- **Failover** - **失败自动切换**,当出现失败,重试其它服务器。通常用于读操作,但重试会带来更长延迟。可通过 retries="2" 来设置重试次数(不含第一次)。 @@ -702,7 +702,7 @@ public class HelloServiceMock implements HelloService { 在开发及测试环境下,经常需要绕过注册中心,只测试指定服务提供者,这时候可能需要点对点直连,点对点直联方式,将以服务接口为单位,忽略注册中心的提供者列表,A 接口配置点对点,不影响 B 接口从注册中心获取列表。
- +
配置方式: diff --git "a/docs/14.\344\270\255\351\227\264\344\273\266/01.MQ/02.\346\266\210\346\201\257\351\230\237\345\210\227\345\237\272\346\234\254\345\216\237\347\220\206.md" "b/docs/14.\344\270\255\351\227\264\344\273\266/01.MQ/02.\346\266\210\346\201\257\351\230\237\345\210\227\345\237\272\346\234\254\345\216\237\347\220\206.md" index fa5d6f9..8c73bd4 100644 --- "a/docs/14.\344\270\255\351\227\264\344\273\266/01.MQ/02.\346\266\210\346\201\257\351\230\237\345\210\227\345\237\272\346\234\254\345\216\237\347\220\206.md" +++ "b/docs/14.\344\270\255\351\227\264\344\273\266/01.MQ/02.\346\266\210\346\201\257\351\230\237\345\210\227\345\237\272\346\234\254\345\216\237\347\220\206.md" @@ -57,11 +57,11 @@ MQ 通信模型大致有以下类型: 假设这样一个场景,用户向系统 A 发起请求,系统 A 处理计算只需要 10 ms,然后通知系统 BCD 写库,系统 BCD 写库耗时分别为:100ms、200ms、300ms。最终总耗时为: 10+100ms+200ms+300ms=610ms。此外,加上请求和响应的网络传输时间,从用户角度看,可能要等待将近 1s 才能得到结果。 -![img](https://raw.githubusercontent.com/dunwu/images/dev/cs/design/theory/mq/mq_3.png) +![img](https://raw.githubusercontent.com/dunwu/images/master/cs/design/theory/mq/mq_3.png) 如果使用 MQ,系统 A 接到请求后,耗时 10ms 处理计算,然后向系统 BCD 连续发送消息,假设耗时 5ms。那么 这一过程的总耗时为 3ms + 5ms = 8ms,这相比于 610 ms,大大缩短了响应时间。至于系统 BCD 的写库操作,只要自行消费 MQ 后处理即可,用户无需关注。 -![img](https://raw.githubusercontent.com/dunwu/images/dev/cs/design/theory/mq/mq_4.png) +![img](https://raw.githubusercontent.com/dunwu/images/master/cs/design/theory/mq/mq_4.png) ### 系统解耦 @@ -76,11 +76,11 @@ MQ 通信模型大致有以下类型: 如果需要和新的系统建立通信或删除已建立的通信,都需要修改代码,这种方案显然耦合度很高。 -![img](https://raw.githubusercontent.com/dunwu/images/dev/cs/design/theory/mq/mq_1.png) +![img](https://raw.githubusercontent.com/dunwu/images/master/cs/design/theory/mq/mq_1.png) 如果使用 MQ,系统间的通信只需要通过发布/订阅(Pub/Sub)模型即可,彼此没有直接联系,也就不需要相互感知,从而达到 **解耦**。 -![img](https://raw.githubusercontent.com/dunwu/images/dev/cs/design/theory/mq/mq_2.png) +![img](https://raw.githubusercontent.com/dunwu/images/master/cs/design/theory/mq/mq_2.png) ### 流量削峰 @@ -92,11 +92,11 @@ MQ 通信模型大致有以下类型: 假设某个系统读写数据库的稳定性能为每秒处理 1000 条数据。平常情况下,远远达不到这么大的处理量。假设,因为因为做活动,系统的瞬时请求量剧增,达到每秒 10000 个并发请求,数据库根本承受不了,可能直接就把数据库给整崩溃了,这样系统服务就不可用了。 -![img](https://raw.githubusercontent.com/dunwu/images/dev/cs/design/theory/mq/mq_5.png) +![img](https://raw.githubusercontent.com/dunwu/images/master/cs/design/theory/mq/mq_5.png) 如果使用 MQ,每秒写入 10000 条请求,但是系统 A 每秒只从 MQ 中消费 1000 条请求,然后写入数据库。这样,就不会超过数据库的承受能力,而是把请求积压在 MQ 中。只要高峰期一过,系统 A 就会很快把积压的消息给处理掉。 -![img](https://raw.githubusercontent.com/dunwu/images/dev/cs/design/theory/mq/mq_6.png) +![img](https://raw.githubusercontent.com/dunwu/images/master/cs/design/theory/mq/mq_6.png) ### 传输缓冲 @@ -104,7 +104,7 @@ MQ 通信模型大致有以下类型: 例如,Kafka 常被用于做为各种日志数据、采集数据的数据中转。然后,Kafka 将数据转发给 Logstash、Elasticsearch 中,然后基于 Elasticsearch 来做日志中心,提供检索、聚合、分析日志的能力。开发者可以通过 Kibana 集成 Elasticsearch 数据进行可视化展示,或自行进行定制化开发。 -![img](https://raw.githubusercontent.com/dunwu/images/dev/snap/20200930164342.png) +![img](https://raw.githubusercontent.com/dunwu/images/master/snap/20200930164342.png) (2)MQ 也可以被用于流式处理。 @@ -155,7 +155,7 @@ MQ 主要引入了以下问题: Kafka 的客户端和 Broker 都会保存 Offset。客户端消费消息后,每隔一段时间,就把已消费的 Offset 提交给 Kafka Broker,表示已消费。 -![img](https://raw.githubusercontent.com/dunwu/images/dev/snap/20210427194009.png) +![img](https://raw.githubusercontent.com/dunwu/images/master/snap/20210427194009.png) 在这个过程中,如果客户端应用消费消息后,因为宕机、重启等情况而没有提交已消费的 Offset 。当系统恢复后,会继续消费消息,由于 Offset 未提交,就会出现重复消费的问题。 @@ -217,7 +217,7 @@ MQ 重复消费不可怕,可怕的是没有应对机制,可以借鉴的思 - 消费方维护 N 个缓存队列,具有相同 ID 的数据都写入同一个队列中; - 创建 N 个线程,每个线程只负责从指定的一个队列中取数据。 -![img](https://raw.githubusercontent.com/dunwu/images/dev/snap/20210427194215.png) +![img](https://raw.githubusercontent.com/dunwu/images/master/snap/20210427194215.png) ### 消息积压 @@ -249,7 +249,7 @@ MQ 重复消费不可怕,可怕的是没有应对机制,可以借鉴的思 - Kafka 日志的分区(Partition)分布在 Kafka 集群的节点上。每个节点在处理数据和请求时,共享这些分区。每一个分区都会在已配置的节点上进行备份,确保容错性。 -![img](https://raw.githubusercontent.com/dunwu/images/dev/cs/java/javaweb/distributed/mq/kafka/kafka-cluster-roles.png) +![img](https://raw.githubusercontent.com/dunwu/images/master/cs/java/javaweb/distributed/mq/kafka/kafka-cluster-roles.png) #### Kafka 的副本机制 @@ -268,7 +268,7 @@ Kafka 在 0.8 以前的版本中,如果一个 Broker 宕机了,其上面的 **同一个 Topic 的不同 Partition 会分布在多个 Broker 上,而且一个 Partition 还会在其他的 Broker 上面进行备份**,Producer 在发布消息到某个 Partition 时,先找到该 Partition 的 Leader,然后向这个 Leader 推送消息;每个 Follower 都从 Leader 拉取消息,拉取消息成功之后,向 Leader 发送一个 ACK 确认。 -![img](https://raw.githubusercontent.com/dunwu/images/dev/cs/java/javaweb/distributed/mq/kafka/kafka-replication.png) +![img](https://raw.githubusercontent.com/dunwu/images/master/cs/java/javaweb/distributed/mq/kafka/kafka-replication.png) > FAQ > diff --git "a/docs/14.\344\270\255\351\227\264\344\273\266/01.MQ/03.RocketMQ.md" "b/docs/14.\344\270\255\351\227\264\344\273\266/01.MQ/03.RocketMQ.md" index c1cf228..65853a6 100644 --- "a/docs/14.\344\270\255\351\227\264\344\273\266/01.MQ/03.RocketMQ.md" +++ "b/docs/14.\344\270\255\351\227\264\344\273\266/01.MQ/03.RocketMQ.md" @@ -23,7 +23,7 @@ RocketMQ 是一款开源的分布式消息队列,基于高可用分布式集 RocketMQ 被阿里巴巴捐赠给 Apache,成为 Apache 的孵化项目。 -![img](https://raw.githubusercontent.com/dunwu/images/dev/cs/java/javaweb/distributed/mq/rocketmq/rmq-model.png) +![img](https://raw.githubusercontent.com/dunwu/images/master/cs/java/javaweb/distributed/mq/rocketmq/rmq-model.png) RocketMQ 有以下核心概念: @@ -310,7 +310,7 @@ nohup sh bin/mqbroker -n localhost:9876 -c conf/broker.conf & ## 架构 -![img](https://raw.githubusercontent.com/dunwu/images/dev/cs/java/javaweb/distributed/mq/rocketmq/rmq-basic-arc.png) +![img](https://raw.githubusercontent.com/dunwu/images/master/cs/java/javaweb/distributed/mq/rocketmq/rmq-basic-arc.png) RocketMQ 由四部分组成:NameServer、Broker、Producer、Consumer。其中任意一个组成都可以水平扩展为集群模式,以避免单点故障问题。 @@ -359,7 +359,7 @@ Broker 有几个重要的子模块: - **HA Service**:高可用服务,提供 Master Broker 和 Slave Broker 之间的数据同步功能。 - **Index Service**:根据特定的 Message key 对投递到 Broker 的消息进行索引服务,以提供消息的快速查询。 -![img](https://raw.githubusercontent.com/dunwu/images/dev/cs/java/javaweb/distributed/mq/rocketmq/rmq-basic-component.png) +![img](https://raw.githubusercontent.com/dunwu/images/master/cs/java/javaweb/distributed/mq/rocketmq/rmq-basic-component.png) ## 原理 diff --git "a/docs/14.\344\270\255\351\227\264\344\273\266/01.MQ/04.ActiveMQ.md" "b/docs/14.\344\270\255\351\227\264\344\273\266/01.MQ/04.ActiveMQ.md" index 0489048..c97bd4c 100644 --- "a/docs/14.\344\270\255\351\227\264\344\273\266/01.MQ/04.ActiveMQ.md" +++ "b/docs/14.\344\270\255\351\227\264\344\273\266/01.MQ/04.ActiveMQ.md" @@ -30,7 +30,7 @@ JMS 有两种消息模型: #### P2P 的特点 -![img](https://raw.githubusercontent.com/dunwu/images/dev/cs/java/javalib/jms/jms-pointToPoint.gif) +![img](https://raw.githubusercontent.com/dunwu/images/master/cs/java/javalib/jms/jms-pointToPoint.gif) 在点对点的消息系统中,消息分发给一个单独的使用者。点对点消息往往与队列 `javax.jms.Queue` 相关联。 @@ -44,7 +44,7 @@ JMS 有两种消息模型: #### Pub/Sub 的特点 -![img](https://raw.githubusercontent.com/dunwu/images/dev/cs/java/javalib/jms/jms-publishSubscribe.gif) +![img](https://raw.githubusercontent.com/dunwu/images/master/cs/java/javalib/jms/jms-publishSubscribe.gif) 发布/订阅消息系统支持一个事件驱动模型,消息生产者和消费者都参与消息的传递。生产者发布事件,而使用者订阅感兴趣的事件,并使用事件。该类型消息一般与特定的主题 `javax.jms.Topic` 关联。 @@ -58,7 +58,7 @@ JMS 有两种消息模型: ### JMS 编程模型 -![img](https://raw.githubusercontent.com/dunwu/images/dev/cs/java/javalib/jms/jms-publishSubscribe.gif) +![img](https://raw.githubusercontent.com/dunwu/images/master/cs/java/javalib/jms/jms-publishSubscribe.gif) #### ConnectionFactory diff --git "a/docs/14.\344\270\255\351\227\264\344\273\266/02.\347\274\223\345\255\230/02.Java\347\274\223\345\255\230\344\270\255\351\227\264\344\273\266.md" "b/docs/14.\344\270\255\351\227\264\344\273\266/02.\347\274\223\345\255\230/02.Java\347\274\223\345\255\230\344\270\255\351\227\264\344\273\266.md" index 84a962c..8fb0a61 100644 --- "a/docs/14.\344\270\255\351\227\264\344\273\266/02.\347\274\223\345\255\230/02.Java\347\274\223\345\255\230\344\270\255\351\227\264\344\273\266.md" +++ "b/docs/14.\344\270\255\351\227\264\344\273\266/02.\347\274\223\345\255\230/02.Java\347\274\223\345\255\230\344\270\255\351\227\264\344\273\266.md" @@ -24,7 +24,7 @@ permalink: /pages/970fa6/ 因此,在很多缓存框架、缓存库中,其 API 都参考了 JSR 107 规范。 -![img](https://raw.githubusercontent.com/dunwu/images/dev/snap/20200709174139.png) +![img](https://raw.githubusercontent.com/dunwu/images/master/snap/20200709174139.png) Java Caching 定义了 5 个核心接口 diff --git "a/docs/14.\344\270\255\351\227\264\344\273\266/02.\347\274\223\345\255\230/04.Ehcache.md" "b/docs/14.\344\270\255\351\227\264\344\273\266/02.\347\274\223\345\255\230/04.Ehcache.md" index 5ffa73c..acf5e4a 100644 --- "a/docs/14.\344\270\255\351\227\264\344\273\266/02.\347\274\223\345\255\230/04.Ehcache.md" +++ "b/docs/14.\344\270\255\351\227\264\344\273\266/02.\347\274\223\345\255\230/04.Ehcache.md" @@ -19,7 +19,7 @@ permalink: /pages/c4647d/ > EhCache 是一个纯 Java 的进程内缓存框架,具有快速、精干等特点,是 Hibernate 中默认的 CacheProvider。 -![img](https://raw.githubusercontent.com/dunwu/images/dev/cs/java/javaweb/technology/cache/ehcache-architecture.png) +![img](https://raw.githubusercontent.com/dunwu/images/master/cs/java/javaweb/technology/cache/ehcache-architecture.png) ## 一、简介 diff --git "a/docs/14.\344\270\255\351\227\264\344\273\266/02.\347\274\223\345\255\230/README.md" "b/docs/14.\344\270\255\351\227\264\344\273\266/02.\347\274\223\345\255\230/README.md" index 758a8e1..144db19 100644 --- "a/docs/14.\344\270\255\351\227\264\344\273\266/02.\347\274\223\345\255\230/README.md" +++ "b/docs/14.\344\270\255\351\227\264\344\273\266/02.\347\274\223\345\255\230/README.md" @@ -21,7 +21,7 @@ permalink: /pages/71104f/ > > 如果想深入学习缓存,建议先了解一下 [缓存基本原理](https://dunwu.github.io/design/distributed/分布式缓存.html),有助于理解缓存的特性、原理,使用缓存常见的问题及解决方案。 -![img](https://raw.githubusercontent.com/dunwu/images/dev/snap/20200710163555.png) +![img](https://raw.githubusercontent.com/dunwu/images/master/snap/20200710163555.png) ## 📖 内容 diff --git "a/docs/14.\344\270\255\351\227\264\344\273\266/03.\346\265\201\351\207\217\346\216\247\345\210\266/01.Hystrix.md" "b/docs/14.\344\270\255\351\227\264\344\273\266/03.\346\265\201\351\207\217\346\216\247\345\210\266/01.Hystrix.md" index 6d7d8e2..2812554 100644 --- "a/docs/14.\344\270\255\351\227\264\344\273\266/03.\346\265\201\351\207\217\346\216\247\345\210\266/01.Hystrix.md" +++ "b/docs/14.\344\270\255\351\227\264\344\273\266/03.\346\265\201\351\207\217\346\216\247\345\210\266/01.Hystrix.md" @@ -45,15 +45,15 @@ Hystrix 官方宣布**不再发布新版本**。 当一切正常时,整体系统如下所示: -![img](https://raw.githubusercontent.com/dunwu/images/dev/snap/20200717141615.png) +![img](https://raw.githubusercontent.com/dunwu/images/master/snap/20200717141615.png) 在高并发场景,这些依赖的稳定性与否对系统的影响非常大,但是依赖有很多不可控问题:如网络连接、资源繁忙、服务宕机等。例如:下图中有一个 QPS 为 50 的依赖 I 出现不可用,但是其他依赖服务是可用的。 -![img](https://raw.githubusercontent.com/dunwu/images/dev/snap/20200717141749.png) +![img](https://raw.githubusercontent.com/dunwu/images/master/snap/20200717141749.png) 但是,在高并发场景下,当依赖 I 阻塞时,大多数服务器的线程池就出现阻塞(BLOCK)。当这种级联故障愈演愈烈,就可能造成整个线上服务不可用的雪崩效应,如下图: -![img](https://raw.githubusercontent.com/dunwu/images/dev/snap/20200717141859.png) +![img](https://raw.githubusercontent.com/dunwu/images/master/snap/20200717141859.png) Hystrix 就是为了解决这类问题而应运而生。 @@ -71,7 +71,7 @@ Hystrix 具有以下功能: 如果使用 Hystrix 对每个基础依赖服务进行过载保护,则整个系统架构将会类似下图所示,每个依赖项彼此隔离,受到延迟时发生饱和的资源的被限制访问,并包含 fallback 逻辑(用于降级处理),该逻辑决定了在依赖项中发生任何类型的故障时做出对应的处理。 -![img](https://raw.githubusercontent.com/dunwu/images/dev/snap/20200717142842.png) +![img](https://raw.githubusercontent.com/dunwu/images/master/snap/20200717142842.png) ## Hystrix 核心概念 @@ -79,7 +79,7 @@ Hystrix 具有以下功能: 如下图所示,Hystrix 的工作流程大致可以分为 9 个步骤。 -![img](https://raw.githubusercontent.com/dunwu/images/dev/snap/20200717143247.png) +![img](https://raw.githubusercontent.com/dunwu/images/master/snap/20200717143247.png) ### (一)包装命令