Skip to content

Commit c6aba1a

Browse files
committed
文章中知识和问题章节补充
数据密集型应用系统设计 从零开始学架构 读书笔记合入
1 parent 96b876d commit c6aba1a

61 files changed

Lines changed: 3218 additions & 208 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

md/about/me/about-content-style.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,4 +104,7 @@ docs/.vuepress/templates/dev.html: 用于开发环境的 HTML 模板文件。
104104
docs/.vuepress/templates/ssr.html: 构建时基于 Vue SSR 的 HTML 模板文件。
105105
docs/.vuepress/config.js: 配置文件的入口文件,也可以是 YML 或 toml。
106106
docs/.vuepress/enhanceApp.js: 客户端应用的增强。
107-
```
107+
```
108+
109+
110+
collapsable: true 设置折叠属性

md/about/scenery/about-scenery-record.md

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
1-
# 并发 - 各类锁的应用场景
1+
# 风景 - 记录
22

3-
> 本节主要介绍互斥锁、自旋锁、读写锁、悲观锁、乐观锁的应用场景。
43

54
[[toc]]
65

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
# 知识 - 服务网格
2+
3+
> Service Mesh 是微服务时代的 TCP/IP 协议。
4+
5+
[[toc]]
6+
7+
# 参考资料
8+
9+
* [同源策略(SOP](https://en.wikipedia.org/wiki/Same-origin_policy)
10+
* [跨源资源共享](https://en.wikipedia.org/wiki/Cross-origin_resource_sharing)
11+
12+
## 同源策略
13+
14+
在计算领域,**同源策略(SOP,Same origin policy)**是网络应用程序安全模型中的一个重要概念。根据该政策,Web 浏览器允许第一个网页中包含的脚本访问第二个网页中的数据,但前提是两个网页具有相同的来源。源被定义为**URI 协议、主机名和端口号**的组合。此策略**可防止一个页面上的恶意脚本通过该页面的文档对象模型**获取对另一个网页上敏感数据的访问权限。
15+
16+
这种机制对于广泛依赖HTTP cookie 来维护经过身份验证的用户会话的现代 Web 应用程序具有特殊意义,因为服务器基于 HTTP cookie 信息来显示敏感信息或采取状态更改操作。必须在客户端维护不相关站点提供的内容之间的严格分离,以防止数据机密性或完整性丢失。
17+
18+
记住同源策略只适用于脚本是非常重要的。这意味着可以通过相应的 HTML 标签跨源访问图像、CSS 和动态加载的脚本等资源(字体是一个明显的例外)。攻击利用了同源策略不适用于 HTML 标记这一事实。
19+
20+
* 放宽同源政策
21+
* 数据污染
22+
* 文档.域属性
23+
* 跨源资源共享
24+
* 跨文档消息传递
25+
* JSONP
26+
* WebSockets
27+
28+
## 跨源资源共享
29+
30+
CORS(Cross origin resource sharing)是一种机制,允许从提供第一个资源的域之外的另一个域请求网页上的受限资源。
31+
32+
网页可以自由嵌入跨源图像、样式表、脚本、iframe和视频。同源安全策略默认禁止某些“跨域”请求,尤其是Ajax请求。CORS 定义了一种方式,浏览器和服务器可以通过这种方式进行交互以确定允许跨源请求是否安全。它允许比纯粹的同源请求更多的自由和功能,但比简单地允许所有跨源请求更安全。(一般只服务端(后端)设置Access-Control-Allow-Origin即可,前端无须设置,若要带cookie请求:前后端都需要设置。)
33+
34+
例如:在spring boot中提供了 @CrossOrigin 注解用于解决跨域问题。
35+
36+
```java
37+
//origin="*"代表所有域名都可访问
38+
//maxAge飞行前响应的缓存持续时间的最大年龄,简单来说就是Cookie的有效期 单位为秒若maxAge是负数,则代表为临时Cookie,不会被持久化,Cookie信息保存在浏览器内存中,浏览器关闭Cookie就消失
39+
@CrossOrigin(origins = "*",maxAge = 3600)
40+
```
41+
42+
与 CORS 相关的 HTTP 标头是:
43+
44+
* 请求标头
45+
* Origin 源
46+
* Access-Control-Request-Method 请求的方法
47+
* Access-Control-Request-Headers 请求的头
48+
49+
* 响应头
50+
* Access-Control-Allow-Origin 允许请求的域
51+
* Access-Control-Allow-Credentials 表示是否允许发送cookie
52+
* Access-Control-Expose-Headers 暴露的头
53+
* Access-Control-Max-Age 本次预检的有效期
54+
* Access-Control-Allow-Methods 允许请求的方法
55+
* Access-Control-Allow-Headers 允许请求的头
56+
57+
58+
预检示例:
59+
60+
在执行某些类型的跨域 Ajax 请求时,支持 CORS 的现代浏览器会发起一个额外的“预检”请求,以确定它们是否有权执行该操作。跨源请求以这种方式进行预检,因为它们可能会对用户数据产生影响。
61+
62+
以百度搜索,关键词"haha"为例,可以看到存在两次请求:
63+
64+
![](/_images/article/knowledge/百度搜索预检.png)
65+
66+
“预检”请求和响应结果:
67+
68+
![](/_images/article/knowledge/百度搜索预检请求与响应.png)
69+
70+
正式请求和响应结果:
71+
72+
![](/_images/article/knowledge/百度搜索正式请求与响应.png)
73+
74+
可以看出预检请求方法为OPTIONS,正式请求方法为POST;且预检请求响应结果为Content-Type为 text/plain,正式请求响应结果为Content-Type为 application/json。
75+
76+
Lines changed: 264 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,264 @@
1+
# 知识 - 看门狗和喂狗机制
2+
3+
> Watchdog机制原理和喂狗机制。
4+
5+
[[toc]]
6+
7+
# 参考资料
8+
9+
* [Watchdog机制原理](https://blog.csdn.net/qq_43369592/article/details/123521848)
10+
* [Watchdog工作原理](https://blog.csdn.net/SHK242673/article/details/122364714)
11+
12+
# 看门狗
13+
14+
守护脚本的功能是,当检测到某进程不存在是,立即重启该进程,**对应着服务器检测到某个进程不喂狗时立即杀死该进程。**
15+
16+
两者想结合完成对客户端及服务器端的保护。守护进程中用shell语言编写了protect函数,输入参数为$1,即进程名。启动守护脚本后,将分先后运行服务器和客户端可执行文件并运行在后台,再在主循环中轮询守护对应的进程。
17+
18+
<<< @/md/article/knowledge/src/swd.sh
19+
20+
## 安卓系统中WatchDog工作原理
21+
22+
Softwere Watchdog Timeout,顾名思义就是软件超时监控狗。
23+
24+
原理框架示意图:
25+
26+
![](/_images/article/knowledge/watchdog.png)
27+
28+
System Server 进程是Android的一个核心进程,里面为App运行提供了很多核心服务,如AMS、WMS、PKMS等等,如果这些核心的服务和重要的线程卡住,就会导致相应的功能异常。如果没有一种机制让这些服务复位的话,就会严重影响用户的体验,所以Google引入了System Server Watchdog 机制,用来**监控这些核心服务和重要线程是否被卡住**
29+
30+
### Watchdog的初始化
31+
32+
Watchdog的初始化是在SystemServer init的后期,如果SystemServer在init的过程中卡死了,那么就意味着Watchdog不会生效。
33+
34+
Watchdog是一个单例线程,在SystemServer启动时就会获取它并初始化和启动(init/start).
35+
36+
```c++
37+
private void startOtherServices() {
38+
...
39+
traceBeginAndSlog("InitWatchdog");
40+
final Watchdog watchdog = Watchdog.getInstance();
41+
watchdog.init(context, mActivityManagerService);
42+
traceEnd();
43+
...
44+
traceBeginAndSlog("StartWatchdog");
45+
Watchdog.getInstance().start();
46+
traceEnd();
47+
...
48+
}
49+
```
50+
51+
Watchdog继承于Thread,创建的线程名为”watchdog”。mHandlerCheckers队列包括、 主线程,fg, ui, io, display线程的HandlerChecker对象。
52+
53+
```c++
54+
private Watchdog() {
55+
super("watchdog");
56+
mMonitorChecker = new HandlerChecker(FgThread.getHandler(),
57+
"foreground thread", DEFAULT_TIMEOUT);
58+
mHandlerCheckers.add(mMonitorChecker);
59+
// Add checker for main thread. We only do a quick check since there
60+
// can be UI running on the thread.
61+
mHandlerCheckers.add(new HandlerChecker(new Handler(Looper.getMainLooper()),
62+
"main thread", DEFAULT_TIMEOUT));
63+
// Add checker for shared UI thread.
64+
mHandlerCheckers.add(new HandlerChecker(UiThread.getHandler(),"ui thread", DEFAULT_TIMEOUT));
65+
// And also check IO thread.
66+
mHandlerCheckers.add(new HandlerChecker(IoThread.getHandler(),"i/o thread", DEFAULT_TIMEOUT));
67+
// And the display thread.
68+
mHandlerCheckers.add(new HandlerChecker(DisplayThread.getHandler(),
69+
"display thread", DEFAULT_TIMEOUT));
70+
// And the animation thread.
71+
mHandlerCheckers.add(new HandlerChecker(AnimationThread.getHandler(),
72+
"animation thread", DEFAULT_TIMEOUT));
73+
// And the surface animation thread.
74+
mHandlerCheckers.add(new HandlerChecker(SurfaceAnimationThread.getHandler(),
75+
"surface animation thread", DEFAULT_TIMEOUT));
76+
......
77+
}
78+
```
79+
80+
## HandlerChecker分类
81+
82+
大致可以分为两类
83+
84+
* Looper Checker: 用于检查线程的消息队列是否长时间处于非空闲状态,Watchdog自身的消息队列,Ui, Io, Display这些全局的消息队列都是被检查的对象。 如果被监测的消息队列一直闲不下来,则说明可能已经阻塞等待了很长时间。
85+
86+
* Monitor Checker: 用于检查Monitor对象是否发生死锁,AMP、PKMS、WMS等核心系统服务都是Monitor对象。通过调用实现类的monitor方法,例如AMS.monitor()方法, 获取当前类的对象锁,如果当前对象锁已经被持有,则monitor()会一直处于wait状态,直到超时,这种情况下,很可能是线程发生了死锁。
87+
88+
## Watchdog的运作
89+
90+
```cpp
91+
@Override
92+
public void run() {
93+
boolean waitedHalf = false; //标识第一个30s超时
94+
boolean mSFHang = false; //标识surfaceflinger是否hang
95+
while (true) {
96+
...
97+
synchronized (this) {
98+
...
99+
// 1. 调度所有的HandlerChecker
100+
for (int i=0; i<mHandlerCheckers.size(); i++) {
101+
HandlerChecker hc = mHandlerCheckers.get(i);
102+
//shceduleCheckLocked()所做的事情可以想象成给所有的目标thread发放任务。
103+
hc.scheduleCheckLocked();
104+
}
105+
...
106+
// 2. 开始定期检查
107+
long start = SystemClock.uptimeMillis();
108+
while (timeout > 0) {
109+
...
110+
try {
111+
wait(timeout);
112+
} catch (InterruptedException e) {
113+
Log.wtf(TAG, e);
114+
}
115+
...
116+
timeout = CHECK_INTERVAL - (SystemClock.uptimeMillis() - start);
117+
}
118+
119+
// 3. 检查HandlerChecker的完成状态
120+
final int waitState = evaluateCheckerCompletionLocked();
121+
if (waitState == COMPLETED) {
122+
...
123+
continue;
124+
} else if (waitState == WAITING) {
125+
...
126+
continue;
127+
} else if (waitState == WAITED_HALF) {
128+
...
129+
continue;
130+
}
131+
132+
// 4. 存在超时的HandlerChecker
133+
blockedCheckers = getBlockedCheckersLocked();
134+
//超了60秒,此时便出问题了,收集超时的HandlerChecker
135+
subject = describeCheckersLocked(blockedCheckers);
136+
allowRestart = mAllowRestart;
137+
}
138+
...
139+
// 5. 保存日志,判断是否需要杀掉系统进程
140+
Slog.w(TAG, "*** GOODBYE!");
141+
Process.killProcess(Process.myPid());
142+
System.exit(10);
143+
} // end of while (true)
144+
......
145+
}
146+
147+
```
148+
149+
以上代码片段主要的运行逻辑如下:
150+
151+
1. Watchdog运行后,便开始无限循环,依次调用每一个HandlerChecker的scheduleCheckLocked()方法
152+
2. 调度完HandlerChecker之后,便开始定期检查是否超时,每一次检查的间隔时间由CHECK_INTERVAL常量设定,为30秒
153+
3. 每一次检查都会调用evaluateCheckerCompletionLocked()方法来评估一下HandlerChecker的完成状态:
154+
* COMPLETED表示已经完成
155+
* WAITING和WAITED_HALF表示还在等待,但未超时
156+
* OVERDUE表示已经超时。默认情况下,timeout是1分钟,但监测对象可以通过传参自行设定,譬如PKMS的Handler Checker的超时是10分钟
157+
4. 如果超时时间到了,还有HandlerChecker处于未完成的状态(OVERDUE),则**通过getBlockedCheckersLocked()方法,获取阻塞的HandlerChecker,生成一些描述信息**
158+
5. 保存日志,包括一些运行时的堆栈信息,这些日志是我们解决Watchdog问题的重要依据。如果判断需要杀掉system_server进程,则给当前进程(system_server)发送signal 9。
159+
160+
只要Watchdog没有发现超时任务,HandlerChecker就会被不停的调度。
161+
162+
## HandlerChecker的运作
163+
164+
```cpp
165+
public final class HandlerChecker implements Runnable {
166+
167+
public void scheduleCheckLocked() {
168+
// Looper Checker中是不包含monitor对象的,判断消息队列是否处于空闲
169+
if (mMonitors.size() == 0 && mHandler.getLooper().isIdling()) {
170+
mCompleted = true;
171+
return;
172+
}
173+
...
174+
// 将Monitor Checker的对象置于消息队列之前,优先运行
175+
mHandler.postAtFrontOfQueue(this);
176+
}
177+
178+
@Override
179+
public void run() {
180+
// 依次调用Monitor对象的monitor()方法
181+
for (int i = 0 ; i < size ; i++) {
182+
synchronized (Watchdog.this) {
183+
mCurrentMonitor = mMonitors.get(i);
184+
}
185+
mCurrentMonitor.monitor();
186+
}
187+
...
188+
}
189+
}
190+
191+
```
192+
193+
## 总结
194+
195+
**总体流程:**
196+
197+
Watchdog是一个运行在system_server进程的名为”watchdog”的线程::
198+
199+
* Watchdog运作过程,当阻塞时间超过1分钟则触发一次watchdog,会杀死system_server,触发上层重启;
200+
201+
* mHandlerCheckers记录所有的HandlerChecker对象的列表,包括foreground, main, ui, i/o, display线程的handler;
202+
203+
* mHandlerChecker.mMonitors记录所有Watchdog目前正在监控Monitor,所有的这些monitors都运行在foreground线程。
204+
205+
* 有两种方式加入Watchdog的监控:
206+
* addThread():用于监测Handler对象,默认超时时长为60s.这种超时往往是所对应的handler线程消息处理得慢;
207+
* addMonitor(): 用于监控实现了Watchdog.Monitor接口的服务.这种超时可能是”android.fg”线程消息处理得慢,也可能是monitor迟迟拿不到锁;
208+
209+
以下情况,即使触发了Watchdog,也不会杀掉system_server进程:
210+
* monkey: 设置IActivityController,拦截systemNotResponding事件, 比如monkey.
211+
* hang: 执行am hang命令,不重启;
212+
* debugger: 连接debugger的情况, 不重启;
213+
214+
**输出信息**
215+
216+
watchdog在check过程中出现阻塞1分钟的情况,则会输出:
217+
218+
1. AMS.dumpStackTraces:输出system_server和3个native进程的traces
219+
* 该方法会输出两次,第一次在超时30s的地方;第二次在超时1min;
220+
221+
2. WD.dumpKernelStackTraces,**输出system_server进程中所有线程的kernel stack;**
222+
* **节点/proc/%d/task获取进程内所有的线程列表**
223+
* **节点/proc/%d/stack获取kernel的栈**
224+
225+
3. doSysRq, 触发kernel来dump所有阻塞线程,输出所有CPU的backtrace到kernel log;
226+
* 节点/proc/sysrq-trigger
227+
4. dropBox,输出文件到/data/system/dropbox,内容是trace + blocked信息
228+
229+
5. 杀掉system_server,进而触发zygote进程自杀,从而重启上层framework。
230+
231+
**Handler方式**
232+
233+
Watchdog监控的线程有:默认地DEFAULT_TIMEOUT=60s,调试时才为10s方便找出潜在的ANR问题。
234+
235+
atchdog监控的线程有:默认地DEFAULT_TIMEOUT=60s,调试时才为10s方便找出潜在的ANR问题。
236+
237+
| 线程名| 对应handler | 说明|
238+
| ------------- |:-------------:| -----:|
239+
| system_server | new Handler(Looper.getMainLooper()) | 当前主线程|
240+
| android.fg | FgThread.getHandler | 前台线程|
241+
| android.ui | UiThread.getHandler | UI线程|
242+
| android.io | IoThread.getHandler | I/O线程|
243+
| android.display | DisplayThread.getHandler | display线程|
244+
| ActivityManager | AMS.MainHandler | AMS构造函数中使用|
245+
| PowerManagerService | PMS.PowerManagerHandler | PMS.onStart()中使用|
246+
247+
目前watchdog会监控system_server进程中的以上7个线程,必须保证这些线程的Looper消息处理时间不得超过1分钟。
248+
249+
**Monitor方式**
250+
251+
能够被Watchdog监控的系统服务都实现了Watchdog.Monitor接口,并实现其中的monitor()方法。运行在android.fg线程, 系统中实现该接口类主要有:
252+
253+
* ActivityManagerService
254+
* WindowManagerService
255+
* InputManagerService
256+
* PowerManagerService
257+
* NetworkManagementService
258+
* MountService
259+
* NativeDaemonConnector
260+
* BinderThreadMonitor
261+
* MediaProjectionManagerService
262+
* MediaRouterService
263+
* MediaSessionService
264+
* BinderThreadMonitor

0 commit comments

Comments
 (0)