diff --git a/.gitattributes b/.gitattributes
index e2e421c..2125666 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -1 +1 @@
-*.* linguist-language=php
\ No newline at end of file
+* text=auto
\ No newline at end of file
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..723ef36
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1 @@
+.idea
\ No newline at end of file
diff --git a/CONTENT.md b/CONTENT.md
new file mode 100644
index 0000000..31c86ef
--- /dev/null
+++ b/CONTENT.md
@@ -0,0 +1,41 @@
+# PHP面试指南
+
+> 忘掉你的经验,试试我的方法。
+
+## 市场前景
+
+### php份额
+
+### 技术成熟度曲线
+
+## 薪资水平
+
+### 程序员
+
+### php
+
+## 作者介绍
+
+### 从业经验
+
+### 为什么要写这个
+
+## 使用指南
+
+### 应聘者
+
+### 面试官
+
+## 我理解的面试
+
+### 岗位的来由
+
+### 面试流程
+
+### 工作能力证明
+
+## 问答列表
+
+## 参考资料
+
+## 版权声明
\ No newline at end of file
diff --git a/README.md b/README.md
index a0e09ef..413e778 100644
--- a/README.md
+++ b/README.md
@@ -1,4 +1,64 @@
-# PHP面试问答
+# PHP 面试问答
+
+> PHP 很没前途,请把工作留给我,谢谢!
+
+## 一、PHP 篇
+
+- [【试读】编程语言基础](./docs/php/编程语言简介.md)
+- 【试读】PHP 与编程范式
+- [【试读】当下最流行的 PHP 本地环境搭建方式](./docs/php/当下最流行的PHP本地环境搭建方式.md)
+- 【试读】代码风格指南
+- 【试读】代码注释
+- [【试读】将变量打印出来,你知道哪些方式](./docs/php/将变量打印出来你知道哪些方式.md)
+- 【试读】使用 xdebug 调试你的代码
+- 【试读】基础知识
+- [【试读】单引号和双引号的区别](./docs/php/单引号和双引号的区别.md)
+- [【试读】isset 和 empty 的区别之如何判空](./docs/php/isset和empty的区别之如何判空.md)
+- 【试读】面向对象编程
+- 【试读】PHP 与函数式编程
+- 【试读】PHP 与元编程
+- 【试读】命名空间
+- 【试读】PHP 标准库(SPL)
+- 【试读】日期和时间
+- 【试读】请使用 UTF-8 编码
+- 【试读】本地化与国际化
+- 【试读】2025 年有哪些流行的框架
+- 【试读】如何进行依赖管理
+- 【试读】依赖注入
+- 【试读】错误与异常
+- [【试读】composer 包升级](./docs/php/composer包升级.md)
+- 【试读】MySQL 扩展
+- 【试读】PDO 扩展
+- 【试读】单元测试
+- 【试读】Postman
+
+## 二、数据结构与算法篇
+
+## 三、网络篇
+
+## 四、设计模式篇
+
+- 【试读】如何解决复杂问题
+
+## 五、数据基础设施篇
+
+## 六、架构篇
+
+-【试读】领域驱动设计(DDD)
+
+## 七、服务器篇
+
+## 八、安全篇
+
+- 【试读】密码学简介
+- 【试读】加密与编码
+
+## 九、客户端篇
+
+## 十、番外篇
+
+- [【试读】你的编码热情是如何消退的?](./docs/番外/你的编码热情是如何消退的.md)
+
结合实际PHP面试,汇总自己遇到的问题,以及网上其他人遇到的问题,尝试提供简洁准确的答案
@@ -14,58 +74,45 @@
- 本仓库需要什么内容:`实际经典面试题` + `靠谱简答` + `详细深入文章(必要的话)`
-## 面试流程
+## 一、面试准备
-
+
-## 微信群
+> 简历 -> 笔试 -> 技术一面 -> 技术二面 -> 技术三面 -> HR面 -> offer
-扫码加微信,备注:`PIQA`,有时候可能在忙,稍等片刻
+- [技术岗面试潜规则](./docs/面试/技术岗面试潜规则.md)
+- [设计一份吸引面试官的简历](./docs/面试/设计一份吸引面试官的简历.md)
+- [读懂岗位精准投递](./docs/面试/读懂岗位精准投递.md)
+- [做好充分的准备去面试](./docs/面试/做好充分的准备去面试.md)
+- [把握面试时的关键点](./docs/面试/把握面试时的关键点.md)
+- [捕捉面试官微表情,做出应对策略](./docs/面试/捕捉面试官微表情,做出应对策略.md)
+- [巧妙推销自己的3个技巧](./docs/面试/巧妙推销自己的3个技巧.md)
+- [判断公司背景,做出合理选择](./docs/面试/判断公司背景,做出合理选择.md)
+- [了解行业薪资,清晰找准定位](./docs/面试/了解行业薪资,清晰找准定位.md)
+- [目标明确,阐明沟通](./docs/面试/目标明确,阐明沟通.md)
+- [工作交接流程福利衔接](./docs/面试/工作交接流程福利衔接.md)
+- [如何让工作年限变成优势](./docs/面试/如何让工作年限变成优势.md)
-

+## 二、问答列表
-## 问题列表
+问题和内容分级
-### 网络篇
+|星标|难度|岗位|关键字|
+|---|---|---|---|
+|*|一星|助理工程师|基础知识|
+|**|二星|工程师|灵活使用|
+|***|三星|高级工程师|深入原理|
+|****|四星|资深工程师|疑难杂症|
+|****|五星|架构师/专家|领域话语|
-- [计算机网络体系结构](./docs/01.网络.md#1-计算机网络体系结构)
-- [UDP 的主要特点](./docs/01.网络.md#2-udp-的主要特点)
-- [TCP 的主要特点](./docs/01.网络.md#3-tcp-的主要特点)
-- [简述三报文握手建立 TCP 连接](./docs/01.网络.md#4-简述三报文握手建立-tcp-连接)
-- [建立 TCP 连接为什么最后还要发送确认](./docs/01.网络.md#5-建立-tcp-连接为什么最后还要发送确认)
-- [简述 TCP 连接的释放](./docs/01.网络.md#6-简述-tcp-连接的释放)
-- [TIME-WAIT 是什么,为什么必须等待 2MLS](./docs/01.网络.md#7-time-wait-是什么为什么必须等待-2mls)
-- [TCP 粘包问题](./docs/01.网络.md#8-tcp-粘包问题)
-- [UDP、TCP 区别,适用场景](./docs/01.网络.md#9-udptcp-区别适用场景)
-- [建立 socket 需要哪些步骤](./docs/01.网络.md#10-建立-socket-需要哪些步骤)
-- [DNS 主要作用是什么](./docs/01.网络.md#11-dns-主要作用是什么)
-- [HTTP 报文组成](./docs/01.网络.md#12-http-报文组成)
-- [HTTP 状态码](./docs/01.网络.md#13-http-状态码)
-- [常见的 HTTP 方法](./docs/01.网络.md#14-常见的-http-方法)
-- [GET 与 POST 请求方式区别](./docs/01.网络.md#15-get-与-post-请求方式区别)
-- [HTTP 优缺点](./docs/01.网络.md#16-http-优缺点)
-- [HTTPS 通信原理](./docs/01.网络.md#17-https-通信原理)
-- [HTTP 2.0](./docs/01.网络.md#18-http-20)
-- [WebSocket](./docs/01.网络.md#19-websocket)
-- [IPv6 与 IPv4 有什么变化](./docs/01.网络.md#20-ipv6-与-ipv4-有什么变化)
-- [什么是心跳机制](./docs/01.网络.md#21-什么是心跳机制)
-- [什么是长连接](./docs/01.网络.md#22-什么是长连接)
+问答模版:
-### 数据结构与算法篇
+1、工作内容->实际问题->用到知识->设置问题->期望回答->评分表->面试评价
-- [衡量、比较算法优劣的指标](./docs/02.数据结构与算法/QA.md#衡量比较算法优劣的指标)
-- [链表有哪些](./docs/02.数据结构与算法/QA.md#链表有哪些)
-- [线性结构](./docs/02.数据结构与算法/QA.md#线性结构)
-- [树](./docs/02.数据结构与算法/QA.md#树)
-- [散列查找](./docs/02.数据结构与算法/QA.md#散列查找)
-- [排序](./docs/02.数据结构与算法/QA.md#排序)
-- [其他](./docs/02.数据结构与算法/QA.md#其他)
+2、被安排充当面试官->网上找题库->题库(自己熟悉的)->八股文->筛选
-### PHP 篇
+### 1、PHP篇
-- [echo、print、print_r、var_dump 区别](./docs/03.PHP/QA.md#echoprintprint_rvar_dump-区别)
-- [单引号和双引号的区别](./docs/03.PHP/QA.md#单引号和双引号的区别)
-- [isset 和 empty 的区别](./docs/03.PHP/QA.md#isset-和-empty-的区别)
- [static、self、$this 的区别](./docs/03.PHP/QA.md#staticselfthis-的区别)
- [include、require、include_once、require_once 的区别](./docs/03.PHP/QA.md#includerequireinclude_oncerequire_once-的区别)
- [数组处理函数](./docs/03.PHP/QA.md#常见数组函数)
@@ -77,6 +124,7 @@
- [public、protected、private、final 区别](./docs/03.PHP/QA.md#publicprotectedprivatefinal-区别)
- [客户端/服务端 IP 获取,了解代理透传 实际IP 的概念](./docs/03.PHP/QA.md#客户端服务端-ip-获取了解代理透传-实际ip-的概念)
- [类的静态调用和实例化调用](./docs/03.PHP/QA.md#类的静态调用和实例化调用)
+- [接口类和抽象类的区别](./docs/03.PHP/QA.md#接口类和抽象类的区别)
- [PHP 不实例化调用方法](./docs/03.PHP/QA.md#php-不实例化调用方法)
- [php.ini 配置选项](./docs/03.PHP/QA.md#phpini-配置选项)
- [php-fpm.conf 配置](./docs/03.PHP/QA.md#php-fpmconf-配置)
@@ -91,48 +139,15 @@
- [MVC 的理解](./docs/03.PHP/QA.md#mvc-的理解)
- [主流 PHP 框架特点](./docs/03.PHP/QA.md#主流-php-框架特点)
- [对象关系映射/ORM](./docs/03.PHP/QA.md#对象关系映射orm)
+- [串行、并行、并发的区别](./docs/03.PHP/QA.md#串行、并行、并发的区别)
+- [同步与异步的理解](./docs/03.PHP/QA.md#同步与异步的理解)
+- [阻塞与非阻塞的理解](./docs/03.PHP/QA.md#阻塞与非阻塞的理解)
+- [同步阻塞与非同步阻塞的理解](./docs/03.PHP/QA.md#同步阻塞与非同步阻塞的理解)
+- [一条echo输出语句是如何执行的](./docs/php/一条echo输出语句是如何执行的.md)
+- [FastCGI Process Manager](./docs/php/FastCGI-Process-Manager.md)
+- [php支持哪些注释风格](./docs/php/php支持哪些注释风格.md)
-### Web 篇
-
-- [SEO 有哪些需要注意的](./docs/04.Web/QA.md#seo-有哪些需要注意的)
-- [img 标签的 title 和 alt 有什么区别](./docs/04.Web/QA.md#img-标签的-title-和-alt-有什么区别)
-- [CSS 选择器的分类](./docs/04.Web/QA.md#css-选择器的分类)
-- [CSS sprite 是什么,有什么优缺点](./docs/04.Web/QA.md#css-sprite-是什么有什么优缺点)
-- [display: none 与 visibility: hidden 的区别](./docs/04.Web/QA.md#display-none-与-visibility-hidden-的区别)
-- [display: block 和 display: inline 的区别](./docs/04.Web/QA.md#display-block-和-display-inline-的区别)
-- [CSS 文件、style 标签、行内 style 属性优先级](./docs/04.Web/QA.md#css-文件style-标签行内-style-属性优先级)
-- [link 与 @import 的区别](./docs/04.Web/QA.md#link-与-import-的区别)
-- [盒子模型](./docs/04.Web/QA.md#盒子模型)
-- [容器包含若干浮动元素时如何清理(包含)浮动](./docs/04.Web/QA.md#容器包含若干浮动元素时如何清理包含浮动)
-- [如何水平居中一个元素](./docs/04.Web/QA.md#如何水平居中一个元素)
-- [如何竖直居中一个元素](./docs/04.Web/QA.md#如何竖直居中一个元素)
-- [flex 与 CSS 盒子模型有什么区别](./docs/04.Web/QA.md#flex-与-css-盒子模型有什么区别)
-- [Position 属性](./docs/04.Web/QA.md#position-属性)
-- [PNG,GIF,JPG 的区别及如何选](./docs/04.Web/QA.md#pnggifjpg-的区别及如何选)
-- [为什么把 JavaScript 文件放在 Html 底部](./docs/04.Web/QA.md#为什么把-javascript-文件放在-html-底部)
-- [JavaScript 数据类型](./docs/04.Web/QA.md#javascript-数据类型)
-- [JavaScript 操作 DOM 的方法有哪些](./docs/04.Web/QA.md#javascript-操作-dom-的方法有哪些)
-- [JavaScript 字符串方法有哪些](./docs/04.Web/QA.md#javascript-字符串方法有哪些)
-- [JavaScript 字符串截取方法有哪些?有什么区别](./docs/04.Web/QA.md#javascript-字符串截取方法有哪些有什么区别)
-- [setTimeout 和 setInterval 的区别](./docs/04.Web/QA.md#settimeout-和-setinterval-的区别)
-- [使用 new 操作符实例化一个对象的具体步骤](./docs/04.Web/QA.md#使用-new-操作符实例化一个对象的具体步骤)
-- [如何实现 ajax 请求](./docs/04.Web/QA.md#如何实现-ajax-请求)
-- [同源策略是什么](./docs/04.Web/QA.md#同源策略是什么)
-- [如何解决跨域问题](./docs/04.Web/QA.md#如何解决跨域问题)
-- [引起内存泄漏的操作有哪些](./docs/04.Web/QA.md#引起内存泄漏的操作有哪些)
-- [闭包理解及应用](./docs/04.Web/QA.md#闭包理解及应用)
-- [对 JavaScript 原型的理解](./docs/04.Web/QA.md#对-javascript-原型的理解)
-- [对 JavaScript 模块化的理解](./docs/04.Web/QA.md#对-javascript-模块化的理解)
-- [如何判断网页中图片加载成功或者失败](./docs/04.Web/QA.md#如何判断网页中图片加载成功或者失败)
-- [如何实现懒加载](./docs/04.Web/QA.md#如何实现懒加载)
-- [JSONP 原理](./docs/04.Web/QA.md#jsonp-原理)
-- [Cookie 读写](./docs/04.Web/QA.md#cookie-读写)
-- 从浏览器地址栏输入 URL 到显示页面的步骤
-- [Vue.js 双向绑定原理](./docs/04.Web/QA.md#vuejs-双向绑定原理)
-- 如何进行网站性能优化
-- [渐进增强](./docs/04.Web/QA.md#渐进增强)
-
-### MySQL 篇
+### 2、存储篇
- [体系结构](./docs/05.MySQL/QA.md#体系结构)
- [基础操作](./docs/05.MySQL/QA.md#基础操作)
@@ -152,9 +167,34 @@
- [EXPLAIN 输出格式](./docs/05.MySQL/QA.md#explain-输出格式)
- my.cnf 配置
- 慢查询
-
-### Redis 篇
-
+- [一条SQL查询语句是如何执行的](./docs/存储/一条SQL查询语句是如何执行的.md)
+- [一条SQL更新语句是如何执行的](./docs/存储/一条SQL更新语句是如何执行的.md)
+- [事务隔离:为什么你改了我还看不见?](./docs/存储/事务隔离-为什么你改了我还看不见.md)
+- [深入浅出索引(上)](./docs/存储/深入浅出索引-上.md)
+- [深入浅出索引(下)](./docs/存储/深入浅出索引-下.md)
+- [全局锁和表锁:给表加个字段怎么有这么多阻碍](./docs/存储/全局锁和表锁-给表加个字段怎么有这么多阻碍.md)
+- [行锁功过:怎么减少行锁对性能的影响](./docs/存储/行锁功过-怎么减少行锁对性能的影响.md)
+- [事务到底是隔离的还是不隔离的](./docs/存储/事务到底是隔离的还是不隔离的.md)
+- [普通索引和唯一索引,应该怎么选择](./docs/存储/普通索引和唯一索引,应该怎么选择.md)
+- [MySQL为什么有时候会选错索引](./docs/存储/MySQL为什么有时候会选错索引.md)
+- [怎么给字符串字段加索引](./docs/存储/怎么给字符串字段加索引.md)
+- [为什么我的MySQL会抖一下](./docs/存储/为什么我的MySQL会抖一下.md)
+- [为什么表数据删掉一半,表文件大小不变](./docs/存储/为什么表数据删掉一半,表文件大小不变.md)
+- [count()这么慢,我该怎么办](./docs/存储/count()这么慢,我该怎么办.md)
+- [order by是怎么工作的](./docs/存储/order-by是怎么工作的.md)
+- [如何正确地显示随机消息](./docs/存储/如何正确地显示随机消息.md)
+- [为什么这些SQL语句逻辑相同,性能却差异巨大](./docs/存储/为什么这些SQL语句逻辑相同,性能却差异巨大.md)
+- [为什么我只查一行的语句,也执行这么慢](./docs/存储/为什么我只查一行的语句,也执行这么慢.md)
+- [幻读是什么,幻读有什么问题](./docs/存储/幻读是什么,幻读有什么问题.md)
+- [为什么我只改一行的语句,锁这么多](./docs/存储/为什么我只改一行的语句,锁这么多.md)
+- [MySQL有哪些饮鸩止渴提高性能的方法](./docs/存储/MySQL有哪些饮鸩止渴提高性能的方法.md)
+- [MySQL是怎么保证数据不丢的](./docs/存储/MySQL是怎么保证数据不丢的.md)
+- [MySQL是怎么保证主备一致的](./docs/存储/MySQL是怎么保证主备一致的.md)
+- [MySQL是怎么保证高可用的](./docs/存储/MySQL是怎么保证高可用的.md)
+- [备库为什么会延迟好几个小时](./docs/存储/备库为什么会延迟好几个小时.md)
+- [主库出问题了,从库怎么办](./docs/存储/主库出问题了,从库怎么办.md)
+- [读写分离有哪些坑](./docs/存储/读写分离有哪些坑.md)
+- [如何判断一个数据库是不是出问题了](./docs/存储/如何判断一个数据库是不是出问题了.md)
- [Redis 介绍](./docs/06.Redis/QA.md#redis-介绍)
- [Redis 特点](./docs/06.Redis/QA.md#redis-特点)
- [Redis 支持哪些数据结构](./docs/06.Redis/QA.md#redis-支持哪些数据结构)
@@ -171,31 +211,44 @@
- redis.conf 配置
- 慢查询
-### Linux 篇
+### 3、网络篇
-- [Linux 目录结构](./docs/07.Linux/QA.md#linux-目录结构)
-- [Linux 基础](./docs/07.Linux/QA.md#linux-基础)
-- [命令与文件查找](./docs/07.Linux/QA.md#命令与文件查找)
-- [数据流重定向](./docs/07.Linux/QA.md#数据流重定向)
-- [sed](./docs/07.Linux/QA.md#sed)
-- [awk](./docs/07.Linux/QA.md#awk)
-- [计划任务](./docs/07.Linux/QA.md#计划任务)
-- [Vim](./docs/07.Linux/QA.md#vim)
-- [负载查看](./docs/07.Linux/QA.md#负载查看)
-- Linux 内存管理
-- [进程、线程、协程区别](./docs/07.Linux/QA.md#进程线程协程区别)
-- 进程间通信与信号机制
+- [计算机网络体系结构](./docs/01.网络.md#1-计算机网络体系结构)
+- [UDP 的主要特点](./docs/01.网络.md#2-udp-的主要特点)
+- [TCP 的主要特点](./docs/01.网络.md#3-tcp-的主要特点)
+- [简述三报文握手建立 TCP 连接](./docs/01.网络.md#4-简述三报文握手建立-tcp-连接)
+- [建立 TCP 连接为什么最后还要发送确认](./docs/01.网络.md#5-建立-tcp-连接为什么最后还要发送确认)
+- [简述 TCP 连接的释放](./docs/01.网络.md#6-简述-tcp-连接的释放)
+- [TIME-WAIT 是什么,为什么必须等待 2MLS](./docs/01.网络.md#7-time-wait-是什么为什么必须等待-2mls)
+- [TCP 粘包问题](./docs/01.网络.md#8-tcp-粘包问题)
+- [UDP、TCP 区别,适用场景](./docs/01.网络.md#9-udptcp-区别适用场景)
+- [建立 socket 需要哪些步骤](./docs/01.网络.md#10-建立-socket-需要哪些步骤)
+- [DNS 主要作用是什么](./docs/01.网络.md#11-dns-主要作用是什么)
+- [HTTP 报文组成](./docs/01.网络.md#12-http-报文组成)
+- [HTTP 状态码](./docs/01.网络.md#13-http-状态码)
+- [常见的 HTTP 方法](./docs/01.网络.md#14-常见的-http-方法)
+- [GET 与 POST 请求方式区别](./docs/01.网络.md#15-get-与-post-请求方式区别)
+- [HTTP 优缺点](./docs/01.网络.md#16-http-优缺点)
+- [HTTPS 通信原理](./docs/01.网络.md#17-https-通信原理)
+- [HTTP 2.0](./docs/01.网络.md#18-http-20)
+- [WebSocket](./docs/01.网络.md#19-websocket)
+- [IPv6 与 IPv4 有什么变化](./docs/01.网络.md#20-ipv6-与-ipv4-有什么变化)
+- [什么是心跳机制](./docs/01.网络.md#21-什么是心跳机制)
+- [什么是长连接](./docs/01.网络.md#22-什么是长连接)
-### 安全篇
+### 4、数据结构与算法篇
-- [跨站脚本攻击(XSS)](./docs/08.安全/QA.md#跨站脚本攻击xss)
-- [跨站点请求伪造(CSRF)](./docs/08.安全/QA.md#跨站点请求伪造csrf)
-- [SQL 注入](./docs/08.安全/QA.md#sql-注入)
-- [应用层拒绝服务攻击](./docs/08.安全/QA.md#应用层拒绝服务攻击)
-- [PHP 安全](./docs/08.安全/QA.md#php-安全)
-- [伪随机数和真随机数](./docs/08.安全/QA.md#伪随机数和真随机数)
+- [概述](./docs/02.数据结构与算法.md#1-概述)
+- [实现基础](./docs/02.数据结构与算法.md#2-实现基础)
+- [线性结构](./docs/02.数据结构与算法.md#3-线性结构)
+- [树](./docs/02.数据结构与算法.md#4-树)
+- [散列查找](./docs/02.数据结构与算法.md#5-散列查找)
+- [图](./docs/02.数据结构与算法.md#6-图)
+- [排序](./docs/02.数据结构与算法.md#7-排序)
+- [补充](./docs/02.数据结构与算法.md#8-补充)
+- [经典算法题](./docs/02.数据结构与算法.md#9-经典算法题)
-### 设计模式篇
+### 5、设计模式篇
- [什么是设计模式](./docs/09.设计模式/QA.md#什么是设计模式)
- [如何理解框架](./docs/09.设计模式/QA.md#如何理解框架)
@@ -212,7 +265,22 @@
- [控制反转](./docs/09.设计模式/QA.md#控制反转)
- [依赖注入](./docs/09.设计模式/QA.md#依赖注入)
-### 架构篇
+### 6、服务器篇
+
+- [Linux 目录结构](./docs/07.Linux/QA.md#linux-目录结构)
+- [Linux 基础](./docs/07.Linux/QA.md#linux-基础)
+- [命令与文件查找](./docs/07.Linux/QA.md#命令与文件查找)
+- [数据流重定向](./docs/07.Linux/QA.md#数据流重定向)
+- [sed](./docs/07.Linux/QA.md#sed)
+- [awk](./docs/07.Linux/QA.md#awk)
+- [计划任务](./docs/07.Linux/QA.md#计划任务)
+- [Vim](./docs/07.Linux/QA.md#vim)
+- [负载查看](./docs/07.Linux/QA.md#负载查看)
+- Linux 内存管理
+- [进程、线程、协程区别](./docs/07.Linux/QA.md#进程线程协程区别)
+- 进程间通信与信号机制
+
+### 7、架构篇
- [OAuth 2.0](./docs/10.架构/QA.md#oauth-20)
- [单点登录](./docs/10.架构/QA.md#单点登录)
@@ -237,6 +305,58 @@
- 服务降级
- 语言对比
+### 8、安全篇
+
+- [跨站脚本攻击(XSS)](./docs/08.安全/QA.md#跨站脚本攻击xss)
+- [跨站点请求伪造(CSRF)](./docs/08.安全/QA.md#跨站点请求伪造csrf)
+- [SQL 注入](./docs/08.安全/QA.md#sql-注入)
+- [应用层拒绝服务攻击](./docs/08.安全/QA.md#应用层拒绝服务攻击)
+- [PHP 安全](./docs/08.安全/QA.md#php-安全)
+- [伪随机数和真随机数](./docs/08.安全/QA.md#伪随机数和真随机数)
+
+### 9、面试篇
+
+### 10、web篇
+
+
+- [SEO 有哪些需要注意的](./docs/04.Web/QA.md#seo-有哪些需要注意的)
+- [img 标签的 title 和 alt 有什么区别](./docs/04.Web/QA.md#img-标签的-title-和-alt-有什么区别)
+- [CSS 选择器的分类](./docs/04.Web/QA.md#css-选择器的分类)
+- [CSS sprite 是什么,有什么优缺点](./docs/04.Web/QA.md#css-sprite-是什么有什么优缺点)
+- [display: none 与 visibility: hidden 的区别](./docs/04.Web/QA.md#display-none-与-visibility-hidden-的区别)
+- [display: block 和 display: inline 的区别](./docs/04.Web/QA.md#display-block-和-display-inline-的区别)
+- [CSS 文件、style 标签、行内 style 属性优先级](./docs/04.Web/QA.md#css-文件style-标签行内-style-属性优先级)
+- [link 与 @import 的区别](./docs/04.Web/QA.md#link-与-import-的区别)
+- [盒子模型](./docs/04.Web/QA.md#盒子模型)
+- [容器包含若干浮动元素时如何清理(包含)浮动](./docs/04.Web/QA.md#容器包含若干浮动元素时如何清理包含浮动)
+- [如何水平居中一个元素](./docs/04.Web/QA.md#如何水平居中一个元素)
+- [如何竖直居中一个元素](./docs/04.Web/QA.md#如何竖直居中一个元素)
+- [flex 与 CSS 盒子模型有什么区别](./docs/04.Web/QA.md#flex-与-css-盒子模型有什么区别)
+- [Position 属性](./docs/04.Web/QA.md#position-属性)
+- [PNG,GIF,JPG 的区别及如何选](./docs/04.Web/QA.md#pnggifjpg-的区别及如何选)
+- [为什么把 JavaScript 文件放在 Html 底部](./docs/04.Web/QA.md#为什么把-javascript-文件放在-html-底部)
+- [JavaScript 数据类型](./docs/04.Web/QA.md#javascript-数据类型)
+- [JavaScript 操作 DOM 的方法有哪些](./docs/04.Web/QA.md#javascript-操作-dom-的方法有哪些)
+- [JavaScript 字符串方法有哪些](./docs/04.Web/QA.md#javascript-字符串方法有哪些)
+- [JavaScript 字符串截取方法有哪些?有什么区别](./docs/04.Web/QA.md#javascript-字符串截取方法有哪些有什么区别)
+- [setTimeout 和 setInterval 的区别](./docs/04.Web/QA.md#settimeout-和-setinterval-的区别)
+- [使用 new 操作符实例化一个对象的具体步骤](./docs/04.Web/QA.md#使用-new-操作符实例化一个对象的具体步骤)
+- [如何实现 ajax 请求](./docs/04.Web/QA.md#如何实现-ajax-请求)
+- [同源策略是什么](./docs/04.Web/QA.md#同源策略是什么)
+- [如何解决跨域问题](./docs/04.Web/QA.md#如何解决跨域问题)
+- [引起内存泄漏的操作有哪些](./docs/04.Web/QA.md#引起内存泄漏的操作有哪些)
+- [闭包理解及应用](./docs/04.Web/QA.md#闭包理解及应用)
+- [对 JavaScript 原型的理解](./docs/04.Web/QA.md#对-javascript-原型的理解)
+- [对 JavaScript 模块化的理解](./docs/04.Web/QA.md#对-javascript-模块化的理解)
+- [如何判断网页中图片加载成功或者失败](./docs/04.Web/QA.md#如何判断网页中图片加载成功或者失败)
+- [如何实现懒加载](./docs/04.Web/QA.md#如何实现懒加载)
+- [JSONP 原理](./docs/04.Web/QA.md#jsonp-原理)
+- [Cookie 读写](./docs/04.Web/QA.md#cookie-读写)
+- 从浏览器地址栏输入 URL 到显示页面的步骤
+- [Vue.js 双向绑定原理](./docs/04.Web/QA.md#vuejs-双向绑定原理)
+- 如何进行网站性能优化
+- [渐进增强](./docs/04.Web/QA.md#渐进增强)
+
## 为何要写这个
从事软件开发,已经接近五个年头了,去年面试中,发现自己依然处于尴尬的位置。简单重复,缺乏挑战的工作,已经没有多大吸引力了,优秀的平台,面试缺屡次碰壁。人上年纪之后,思维敏感度、记忆力都明显有所下滑。
diff --git "a/docs/01.\347\275\221\347\273\234.md" "b/docs/01.\347\275\221\347\273\234.md"
index bd3d6b0..1240a51 100644
--- "a/docs/01.\347\275\221\347\273\234.md"
+++ "b/docs/01.\347\275\221\347\273\234.md"
@@ -14,7 +14,7 @@
- 数据链路层:将网络层交下来的 IP 数据报组装成帧,并在两个相邻结点间的链路上传送
- 物理层:利用物理媒体以`比特`形式传送数据
-拓展阅读 [《计算机网络体系结构》](https://blog.maplemark.cn/2019/04/计算机网络体系结构.html)
+拓展阅读 [《计算机网络体系结构》](./01.网络/01.计算机网络体系结构.md)
### 2. UDP 的主要特点
@@ -25,7 +25,7 @@
- UDP 支持一对一、一对多、多对一和多对多的交互通信
- UDP 的`首部开销小`,只有8个字节,比 TCP 的20个字节的首部要短
-拓展阅读 [《用户数据报协议 UDP》](https://blog.maplemark.cn/2019/04/用户数据报协议udp.html)
+拓展阅读 [《用户数据报协议 UDP》](./01.网络/02.用户数据报协议UDP.md)
### 3. TCP 的主要特点
@@ -35,21 +35,22 @@
- TCP 提供`全双工通信`。TCP 允许通信双方的应用进程在任何时候都能发送数据。TCP 连接的两端都设有发送缓存和接受缓存,用来临时存放双向通信的数据
- `面向字节流`。TCP 中的“流”指的是`流入到进程或从进程流出的字节序列`
-拓展阅读 [《传输控制协议 TCP》](https://blog.maplemark.cn/2019/04/tcp协议详解.html)
+拓展阅读 [《传输控制协议 TCP》](./01.网络/03.传输控制协议TCP.md)
### 4. 简述三报文握手建立 TCP 连接
-- 服务器进程先创建传输控制块 TCB,并处于监听状态,等待客户端的连接请求
-- 客户端创建传输控制块 TCB,并向服务器发出连接请求报文段
-- 服务器收到连接请求报文段后,如同意建立连接,则发送确认报文段
-- 客户端进程收到服务器的确认报文段后,立即回复确认报文段,并进入已建立连接状态
-- 服务器收到确认报文段之后,也进入已建立连接状态
+- 服务器进程先创建传输控制块 TCB,并处于监听状态,等待客户端的连接请求;此时状态为LISTEN
+- 客户端创建传输控制块 TCB,并向服务器发出连接请求报文段SYN,此时状态为SYN-SEND
+- 服务器收到连接请求报文段后,如同意建立连接,则发送确认报文段ACK,此时状态为SYN-RECV,并且客户端链接进入半链接队列,系统参数/proc/sys/net/ipv4/tcp_max_syn_backlog
+- 客户端进程收到服务器的确认报文段后,立即回复确认报文段ACK,并进入已建立连接状态,此时状态为ESTABLISHED
+- 服务器收到确认报文段之后,也进入已建立连接状态,此时状态为ESTABLISHED,并且客户端链接进入全连接队列,系统参数/proc/sys/net/core/somaxconn
> 传输控制块 TCB(Transmission Control Block)存储了每一个连接中的一些重要信息
### 5. 建立 TCP 连接为什么最后还要发送确认
这主要是为了防止已失效的连接请求报文段突然又传到了 TCP 服务器,避免产生错误
+简述为了保证数据的正确性和顺序
### 6. 简述 TCP 连接的释放
@@ -77,7 +78,7 @@ TIME-WAIT 是一种 TCP 状态。等待 2MLS 可以保证客户端最后一个
- 在每条消息的头部加一个长度字段,这恐怕是最常见的做法
- 利用消息本身的格式来分包,例如 XML 格式的消息中 ``...`` 的配对,或者 JSON 格式中的 { ... } 的配对。解析这种消息格式通常会用到状态机(state machine)
-拓展阅读 [《TCP粘包拆包》](https://blog.maplemark.cn/2019/04/tcp粘包拆包.html)
+拓展阅读 [《TCP粘包拆包》](./01.网络/04.TCP粘包拆包.md)
### 9. UDP、TCP 区别,适用场景
@@ -100,9 +101,9 @@ TIME-WAIT 是一种 TCP 状态。等待 2MLS 可以保证客户端最后一个
#### TCP 适用场景
-文件传输(FTP HTTP 对数据准确性要求较高,速度可以相对慢)
-发送或接收邮件(POP IMAP SMTP 对数据准确性要求高,非紧急应用)
-远程登录(telnet SSH 对数据准确性有要求,有连接的概念)
+- 文件传输(FTP HTTP 对数据准确性要求较高,速度可以相对慢)
+- 发送或接收邮件(POP IMAP SMTP 对数据准确性要求高,非紧急应用)
+- 远程登录(telnet SSH 对数据准确性有要求,有连接的概念)
### 10. 建立 socket 需要哪些步骤
@@ -167,7 +168,7 @@ HTTP 报文组成部分
|503|Service Unavailable|无法为请求提供服务|***|
|504|Gateway Timeout|代理或网关超时(等待另一服务器响应超时)|***|
-拓展阅读 [《HTTP状态码》](https://blog.maplemark.cn/2019/04/http状态码.html)
+拓展阅读 [《HTTP状态码》](./01.网络/05.HTTP状态码.md)
拓展阅读 [《5xx系列错误》](../03.PHP/QA.md#502504-错误产生原因及解决方式)
@@ -175,17 +176,18 @@ HTTP 报文组成部分

-拓展阅读 [《HTTP方法详解》](https://blog.maplemark.cn/2019/04/http方法详解.html)
+拓展阅读 [《HTTP方法详解》](./01.网络/06.HTTP方法详解.md)
### 15. GET 与 POST 请求方式区别
|GET|POST|
|-|-|
|后退按钮/刷新无害|数据会被重新提交|
-|数据长度限制/URL长度2048字符|长度无限制|
+|数据长度限制/URL长度2048字符|长度无限制(协议不限制;实际上受nginx和PHP的限制,php还会限制post报文变量的个数)|
|数据可见/安全性差|不可见/更安全|
|可以被缓存|不可以被缓存|
|书签可收藏|书签不可收藏|
+|产生一个TCP数据包| 产生两个TCP数据包 |
### 16. HTTP 优缺点
@@ -197,7 +199,7 @@ HTTP 报文组成部分

-拓展阅读 [《HTTPS细节介绍》](https://blog.maplemark.cn/2019/04/https细节介绍.html)
+拓展阅读 [《HTTPS细节介绍》](./01.网络/07.HTTPS细节介绍.md)
### 18. HTTP 2.0
@@ -224,4 +226,4 @@ WebSocket 是一种通信协议,定义了一个全双工通信信道,仅通
### 22. 什么是长连接
-长连接,指在一个连接上可以连续发送多个数据包,在连接保持期间,如果没有数据包发送,需要双方发链路检测包
\ No newline at end of file
+长连接,指在一个连接上可以连续发送多个数据包,在连接保持期间,如果没有数据包发送,需要双方发链路检测包
diff --git "a/docs/01.\347\275\221\347\273\234/01.\350\256\241\347\256\227\346\234\272\347\275\221\347\273\234\344\275\223\347\263\273\347\273\223\346\236\204.md" "b/docs/01.\347\275\221\347\273\234/01.\350\256\241\347\256\227\346\234\272\347\275\221\347\273\234\344\275\223\347\263\273\347\273\223\346\236\204.md"
new file mode 100755
index 0000000..1f18b11
--- /dev/null
+++ "b/docs/01.\347\275\221\347\273\234/01.\350\256\241\347\256\227\346\234\272\347\275\221\347\273\234\344\275\223\347\263\273\347\273\223\346\236\204.md"
@@ -0,0 +1,125 @@
+# 计算机网络体系结构
+
+在计算机网络的基本概念中,分层次的体系结构是最基本的
+
+## 计算机网络体系结构的形成
+
+### 分层
+
+相互通信的两个计算机系统必须高度协调工作才行,而这种“协调”是相当复杂的。为了设计这样复杂的计算机网络,最初提出了分层的方法。“`分层`”可将庞大而复杂的问题,转化为若干较小的局部问题,而这些较小的局部问题比较易于研究和处理
+
+### 国际标准
+
+全球经济的发展使得不同网络体系结构的用户迫切要求能够互相交换信息,国际标准化组织 ISO 提出了 OSI。只要遵循 OSI 标准,一个系统就可以和位于世界上任何地方的、也遵循这同一标准的其他任何系统进行通信
+
+现今规则最大的、覆盖全球的、基于 TCP/IP 的互联网并未使用 OSI 标准。在20世纪90年代初期,虽然整套的 OSI 国际标准已制定出来,但基于 TCP/IP 的互联网已抢先在全球相当大的范围成功地运行了,而同时却几乎找不到有厂家生产出符合 OSI 标准的商业产品。OSI 只获得了一些理论研究的成果,市场化方面则彻底失败了
+
+TCP/IP 常被称为是`事实上的国际标准`
+
+## 协议与划分层次
+
+### 网络协议
+
+在计算机网络中要做到有条不紊地交换数据,就必须准守一些事先约定好的规则。这些规则明确了所交换的数据的格式以及有关的同步问题
+
+为进行网络中的数据交换而建立的规则、标准或约定称为`网络协议`。网络协议也可简称为`协议`
+
+**协议组成要素**
+
+- `语法`,即数据与控制信息的结构或格式
+- `语义`,即需要发出何种控制信息,完成何种动作以及做出何种响应
+- `同步`,即事件实现顺序的详细说明
+
+协议通常有两种不同的形式。一种是使用便于人来阅读和理解的文字描述。另一种是使用让计算机能够理解的程序代码。这两种不同形式的协议都必须能够对网络上的信息交换过程做出精确的解释
+
+### 划分层次
+
+对于非常复杂的计算机网络协议,其结构应该是层次式的
+
+
+
+**分层可以带来很多好处**
+
+- `各层之间是独立的`。某一层并不需要知道它的下一层是如何实现的,而仅仅需要知道该层通过层间接口(即界面)所提供的服务
+- `灵活性好`。当任何一层发送变化时(例如由于技术的变化),只要层间接口关系保持不变,则在这层以上或以下各层均不受影响
+- `结构上可分割开`。各层都可以采用最合适的技术来实现
+- `易于实现和维护`。这种结构使得实现和调试一个庞大而又复杂的系统变得易于处理,因为整个的系统已被分解为若干个相对独立的子系统
+- `能促进标准化工作`。因为每一层的功能及其所提供的服务都已有了精确的说明
+
+**各层所要完成的功能**
+
+- `差错控制` 使相应层次对等方的通信更加可靠
+- `流量控制` 发送端的发送速率必须使接收端来得及接收,不要太快
+- `分段和重装` 发送端将要发送的数据块划分为更小的单位,在接收端将其还原
+- `复用和分用` 发送端几个高层会话复用一条逻辑连接,数据传送结束后释放连接
+- `连接建立和释放` 交换数据前先建立一条逻辑连接,数据传送结束后释放连接
+
+**分层缺点**
+
+有些功能会在不同的层次中重复出现,因而产生了额外开销
+
+**体系结构**
+
+计算机网络的各层及其协议的集合就是网络的`体系结构`。计算机网络的体系结构就是这个计算机网络及其构件所应完成的功能的精确定义
+
+体系结构是抽象的,而实现则是具体的,是真正在运行的计算机硬件和软件
+
+## 具有五层协议的体系结构
+
+### 五层协议
+
+OSI 的七层协议体系结构的概念清楚,理论也较完整,但它既复杂又不实用。TCP/IP 体系结构则不同,但它现在却得到了非常广泛的应用。TCP/IP 是一个四层的体系结构。在学习计算机网络的原理时往往采用折中的办法,即综合 OSI 和 TCP/IP 的优点,采用一种只有五层协议的体系结构,这样既简洁又能将概念阐述清楚
+
+
+
+### 各层作用
+
+- 应用层:应用层协议定义的是应用进程间通信和交互的规则
+- 运输层:运输层的任务就是负责向`两台主机中进程之间的通信`提供`通用的数据传输`服务
+- 网络层:把运输层产生的报文段或用户数据报封装成`分组`或`包`进行传送
+- 数据链路层:将网络层交下来的 IP 数据报组装成帧,并在两个相邻结点间的链路上传送
+- 物理层:利用物理媒体以`比特`形式传送数据
+
+### 小结
+
+- 把应用层交互的数据单元称为`报文`
+- 运输层主要协议:传输控制协议 TCP、用户数据报协议 UDP
+- 在 TCP/IP 体系中,由于网络层使用 IP 协议,因此分组也叫 `IP 数据报`,或简称为数据报
+
+
+
+## 实体、协议、服务和服务访问点
+
+当研究开放系统中的信息交换时,往往使用`实体`(entity)这一较为抽象的名词表示`任何可发送或接受信息的硬件或软件进程`
+
+协议是控制两个对等实体(或多个实体)进行通信的规则的集合
+
+在协议的控制下,两个对等实体间的通信使得本层能够向上一层提供服务。要实现本层协议,还需要使用下面一层所提供的服务
+
+协议是“水平的”,即协议是控制对等实体之间通信的规则。但服务是“垂直的”,即服务是由下层向上层通过层间接口提供的
+
+
+
+### 计算机网络协议特点
+
+协议必须把所有不利的条件事先都估计到,而不能假定一切都是正常的和非常理想的
+
+非常仔细地检查这个协议能否应付各种异常情况
+
+## TCP/IP 的体系结构
+
+TCP/IP 的体系结构比较简单,只有四层
+
+
+
+应当指出,技术的发展并不是遵循严格的 OSI 分层概念。实际上现在的互联网使用的 TCP/IP 体系结构有时已经演变成为下图所示的那样,即某些应用程序可以直接使用 IP 层,或甚至直接使用最下面的网络接口层
+
+
+
+还有一种方法,就是分层次画出具体的协议表示 TCP/IP 协议族,它的特点是上下两头大而中间小:应用层和网络接口层都有多种协议,而中间的 IP 层很小,上层的各种协议都向下汇聚到一个 IP 协议中
+
+TCP/IP 协议可以为各式各样的应用提供服务,同时 TCP/IP 协议也允许 IP 协议在各式各样的网络构成的互联网上运行。IP 协议在互联网中充当着核心的作用
+
+
+
+**《计算机网络体系结构》 原文链接:[https://blog.maplemark.cn/2019/04/计算机网络体系结构.html](https://blog.maplemark.cn/2019/04/计算机网络体系结构.html)**
\ No newline at end of file
diff --git "a/docs/01.\347\275\221\347\273\234/02.\347\224\250\346\210\267\346\225\260\346\215\256\346\212\245\345\215\217\350\256\256UDP.md" "b/docs/01.\347\275\221\347\273\234/02.\347\224\250\346\210\267\346\225\260\346\215\256\346\212\245\345\215\217\350\256\256UDP.md"
new file mode 100755
index 0000000..77d8e6f
--- /dev/null
+++ "b/docs/01.\347\275\221\347\273\234/02.\347\224\250\346\210\267\346\225\260\346\215\256\346\212\245\345\215\217\350\256\256UDP.md"
@@ -0,0 +1,49 @@
+# 用户数据报协议 UDP
+
+## UDP 概述
+
+用户数据报协议 UDP 只在 IP 的数据报服务之上增加了很少一点的功能,这就是复用和分用的功能以及查错检测的功能
+
+### UDP 的主要特点
+
+1. UDP 是`无连接的`,即发送数据之前不需要建立连接(发送数据结束时也没有连接可释放),减少了开销和发送数据之前的时延
+2. UDP 使用`尽最大努力交付`,即不保证可靠交付,主机不需要维持复杂的连接状态表
+3. UDP 是`面向报文`的,发送方的 UDP 对应用程序交下来的报文,在添加首部后就向下交付 IP 层。UDP 对应用层交下来的报文,既不合并,也不拆分,而是`保留这些报文的边界`
+
+
+
+4. UDP `没有拥塞控制`,网络出现的拥塞不会使源主机的发送速率降低。这对某些实时应用是很重要的
+5. UDP 支持一对一、一对多、多对一和多对多的交互通信
+6. UDP 的`首部开销小`,只有8个字节,比 TCP 的20个字节的首部要短
+
+### 存在问题
+
+1. 某些实时应用需要使用没有拥塞控制的 UDP,但很多的源主机同时都向网络发送高速率的实时视频流时,网络就有可能发生拥塞,导致大家都无法正常接收。
+2. 还有一些使用 UDP 的实时应用,需要对 UDP 的不可靠传输进行适当的改进,以减少数据的丢失。应用进程可以在不影响应用的实时性的前提下,增加一些提高可靠性的措施,如采用前向纠错或重传已丢失的报文
+
+## UDP 的首部格式
+
+用户数据报 UDP 有两个字段:`数据字段`和`首部字段`。首部字段很简单,只有8个字节,由四个字段组成,每个字段都是两个字节
+
+### 首部字段
+
+- `源端口` 源端口号。在需要对方回信时。不需要时可用全0
+- `目的端口` 目的端口号。这在终点交付报文时必须使用
+- `长度` UDP 用户数据报的长度,其最小值是8(仅有首部)
+- `检验和` 检测 UDP 用户数据报在传输中是否有错。有错就丢弃
+
+
+
+### 端口分用
+
+当运输层从 IP 层收到 UDP 数据报时,就根据首部中的目的端口,把 UDP 数据报通过相应的端口,上交最后的终点——应用进程
+
+
+
+如果接受方 UDP 发现收到的报文中的目的端口号不正确(即不存在对应于该端口号的应用程序),就丢弃该报文,并由网际控制报文协议 ICMP 发送“端口不可达”差错报文给发送方
+
+### 伪首部
+
+UDP 用户数据报首部中检验和的计算方法有些特殊。在计算检验和时,要在 UDP 用户数据报之前增加 12 个字节的`伪首部`。所谓“伪首部”是因为这种伪首部并不是 UDP 用户数据报真正的首部。只是在计算检验和时,临时添加在 UDP 用户数据报前面,得到一个临时的 UDP 用户数据报。检验和就是按照这个临时用户数据报来计算的。伪首部既不向下传也不向上递交,而仅仅是为了计算检验和
+
+**《用户数据报协议UDP》 原文链接:[https://blog.maplemark.cn/2019/04/用户数据报协议udp.html](https://blog.maplemark.cn/2019/04/用户数据报协议udp.html)**
\ No newline at end of file
diff --git "a/docs/01.\347\275\221\347\273\234/03.\344\274\240\350\276\223\346\216\247\345\210\266\345\215\217\350\256\256TCP.md" "b/docs/01.\347\275\221\347\273\234/03.\344\274\240\350\276\223\346\216\247\345\210\266\345\215\217\350\256\256TCP.md"
new file mode 100755
index 0000000..8d828c9
--- /dev/null
+++ "b/docs/01.\347\275\221\347\273\234/03.\344\274\240\350\276\223\346\216\247\345\210\266\345\215\217\350\256\256TCP.md"
@@ -0,0 +1,381 @@
+# 传输控制协议 TCP
+
+## 传输控制协议 TCP 概述
+
+### TCP 最主要的特点
+
+- TCP 是`面向连接的运输层协议`。应用程序在使用 TCP 协议之前,必须先建立 TCP 连接。在传送数据完毕后,必须释放已经建立的 TCP 连接
+- 每一条 TCP 连接只能有两个`端点`,每一条 TCP 连接只能是`点对点`的(一对一)
+- TCP 提供`可靠交付`的服务。通过 TCP 连接传送的数据,无差错、不丢失、不重复,并且按序到达
+- TCP 提供`全双工通信`。TCP 允许通信双方的应用进程在任何时候都能发送数据。TCP 连接的两端都设有发送缓存和接受缓存,用来临时存放双向通信的数据
+- `面向字节流`。TCP 中的“流”指的是`流入到进程或从进程流出的字节序列`
+
+### 面向字节流
+
+“面向字节流”的含义是:虽然应用程序和 TCP 的交互式一次一个数据块(大小不等),但 TCP 把应用程序交下来的数据仅仅看成是一连串的`无结构的字节流`。TCP 并不知道所传送的字节流的含义
+
+TCP 不保证接收方应用程序所收到的数据块和发送方应用程序所发出的数据块具有对应大小的关系
+
+> 例如,发送方应用程序交给发送方的 TCP 共10个数据块,但接收方的 TCP 可能只用了4个数据块就把收到的字节流交付上层的应用程序
+
+接收方应用程序收到的字节流必须和发送方应用程序发出的字节流完全一样。接收方的应用程序必须有能力识别收到的字节流,把它还原成有意义的应用层数据
+
+
+
+TCP 和 UDP 在发送报文时采用的方式完全不同。TCP 并不关心应用进程一次把多长的报文发送到 TCP 的缓存中,而是根据对方给出的窗口值和当前网络拥塞的程度来决定一个报文段应包含多少个字节(UDP 发送的报文长度是应用进程给出的)。如果应用进程传送到 TCP 缓存的数据块太长,TCP 就可以把它划分短一些再传送。如果应用进程一次只发来一个字节,TCP 也可以等待积累有足够多的字节后再构成报文段发送出去
+
+### TCP 的连接
+
+TCP 把`连接`作为`最基本的抽象`。TCP 的许多特性都与 TCP 是面向连接的这个基本特性有关
+
+TCP 连接的端点叫做`套接字(socket)或插口`,根据 RFC 793 的定义:端口号拼接到(concatenated with) IP 地址即构成了套接字
+
+> 套接字 socket = (IP 地址:端口号)
+
+`每一条 TCP 连接唯一地被通信两端的两个端点(即两个套接字)所确定`
+
+> TCP 连接 ::= {socket1, socket2} = {(IP1: port1), (IP2: port2)}
+
+TCP 连接就是由协议软件所提供的一种抽象。`TCP 连接的端口是个很抽象的套接字`,即( `IP地址`: `端口号`)。同一个 IP 地址可以有多个不同的 TCP 连接,而同一个端口号也可以出现在多个不同的 TCP 连接中
+
+### 易混淆的 socket
+
+同一个名词 socket 却可表示多种不同的意思,以下 socket 的意思跟本文中所引用的 RFC 793 定义的 socket(指端口号拼接到 IP 地址)不同
+
+- 允许应用程序访问连网协议的`应用编程接口 API(Application Programming Interface)`,即运输层和应用层之间的接口,称为 socket API,并简称为 socket
+- 在 socket API 中使用的一个`函数名`也叫做 socket
+- 调用 socket 函数的`端点`称为 socket,如“创建一个数据报 socket”
+- 调用 socket 函数时,其`返回值`称为 socket 描述符,可简称为 socket
+- 在操作系统内核中连网协议的 Berkeley 实现,称为 socket `实现`
+
+## 可靠传输的工作原理
+
+### 理想的传输条件
+
+理想的传输条件有以下两个特点
+
+- 传输信道不产生差错
+- 不管发送方以多快的速度发送数据,接收方总是来得及处理收到的数据
+
+实际的网络不具备以上两个理想条件。需要使用一些可靠的传输协议,当出现差错时让发送方重传出现差错的数据,同时在接收方来不及处理收到的数据时,及时告诉发送方适当减低发送数据的速度。这样,不可靠的传输信道就能够实现可靠传输了
+
+### 停止等待协议
+
+全双工通信的双方既是发送方也是接收方。把传送的数据单元都称为分组。“停止等待”就是每发完一个分组就停止发送,等待对方的确认。在收到确认后再发送下一个分组
+
+#### 无差错情况
+
+
+
+#### 出现差错
+
+只要超过一段时间没有收到确认,就认为刚才发送的分组丢失了,因而重传前面发送过的分组。这就叫做`超时重传`。要实现超时重传,就要在每发送完一个分组时设置一个`超时计时器`
+
+- 发送完一个分组后,`必须暂时保留已发送的分组的副本`(在发生超时重传时使用)。只有在收到相应的确认后才能清除暂时保留的分组副本
+- 分组和确认分组都必须进行`编号`。这样才能明确是哪一个发送出去的分组收到了确认,而哪一个分组还没有收到确认
+- 超时计时器的重传时间`应当比数据在分组传输的平均往返时间更长一些`
+
+#### 确认丢失和确认迟到
+
+
+
+使用上述的确认和重传机制,我们就可以`在不可靠的传输网络上实现可靠的通信`
+
+像上述的这种可靠传输协议常称为`自动重传请求 ARQ(Automatic Repeat reQuest)`。重传的请求是自动进行的。接收方不需要请求发送方重传某个出错的分组
+
+#### 信道利用率
+
+停止等待协议的优点是简单,但缺点是信道利用率太低
+
+
+
+为了提高传输效率,发送方可以不使用低效率的停止等待协议,而是采用`流水线传输`。流水线传输就是发送方可连续发送多个分组,不必每发完一个分组就停顿下来等待对方的确认。这样可使信道上一直有数据不间断地在传送。这种传输方式可以获得很高的信道利用率
+
+
+
+### 连续 ARQ 协议
+
+位于发送窗口内的5个分组都可以连续发送出去,而不需要等待对方的确认。可以提高信道利用率
+
+
+
+接收方一般都是采用`累积确认`的方式。接收方不需要对收到的分组逐个发送确认,而是在收到几个分组后,`对按序到达的最后一个分组发送确认`
+
+积累确认有优点也有缺点。优点是:容易实现,即使确认丢失也不必重传。缺点是不能向发送方反映出接收方已经正确收到的所有分组的信息
+
+## TCP 报文段的首部格式
+
+TCP 虽然是面向字节流的,但 TCP 传送的数据单元却是报文段。一个 TCP 报文段分为首部和数据两部分。TCP 报文段首部的前20个字节是固定的,后面有4n字节是根据需要而增加的选项(n是整数)。因此 TCP 首部的最小长度是20字节
+
+
+
+### 首部字段
+
+- `源端口`和`目的端口` 各占2个字节,分别写入源端口号和目的端口号
+- `序号` 占4字节。序号范围是[0, 232-1],共232(即4 294 967 296)个序号。序号增加到232-1后,下一个序号就又回到0。在一个 TCP 连接中传送的字节流中的`每一个字节都按顺序编号`
+- `确认号` 占4字节,是`期望收到对方下一个报文段的第一个数据字节的序号`
+- `数据偏移` 占4字节,它指出 TCP 报文段的数据起始处距离 TCP 报文段的起始处有多远。这个字段实际上是指出 TCP 报文段的首部长度
+- `保留` 占6位,保留为今后使用,但目前应置为0
+
+下面有6个`控制位`,用来说明本报文段的性质
+
+- `紧急 URG(URGent)` 当 URG=1 时,表明紧急指针字段有效。它告诉系统此报文段中有紧急数据,应尽快传送(相当于高优先级的数据),而不是按原先的排队顺序来传送
+- `确认 ACK(ACKnowledgment)` 仅当 ACK=1 时确认号字段才有效。当 ACK=0 时,确认号无效。TCP 规定,在连接建立后所有传送的报文段都必须把 ACK 置1
+- `推送 PSH(Push)` 当两个应用进程进行交互式的通信时,有时在一端的应用进程希望在键入一个命令后立即就能够收到对方的响应
+- `复位 RST(ReSeT)` 当 RST=1 时,表明 TCP 连接中出现严重差错(如由于主机崩溃或其他原因),必须释放连接,然后再重新建立运输连接
+- `同步 SYN(SYNnchronization)` 在连接建立时用来同步序号。当 SYN=1 而 ACK=0 时,表明这是一个连接请求报文段。对方若同意建立连接,则应在响应的报文段中使 SYN=1 和 ACK=1
+- `终止 FIN(FINis)` 用来释放一个连接。当 FIN=1 时,表明此报文段的发送发的数据已发送完毕,并要求释放运输连接
+
+- `窗口` 占2字节。窗口值是[0, 216-1]之间的整数。窗口值作为接收方让发送方设置其发送窗口的依旧
+- `检验和` 占2字节。检验和字段检验的范围包括首部和数据这两部分
+- `紧急指针` 占2字节。紧急指针仅在 URG=1 时才有意义,它指出本报文段中的紧急数据的字节数
+- `选项` 长度可变,最长可达40字节
+
+## TCP 可靠传输的实现
+
+### 以字节为单位的滑动窗口
+
+#### 发送窗口构造
+
+TCP 的滑动窗口是以字节为单位的。假定 A 收到了 B `发来`的确认报文段,其中窗口是20字节,而确认号是31(这表明 B 期望收到的下一个序号是31,而序号30为止的数据已经收到了)。根据这两个数据,A 就构造出自己的发送窗口
+
+
+
+发送窗口标识:在没有收到 B 的确认的情况下,A 可以连续把窗口内的数据都发送出去。凡是已经发送出去的数据,在未收到确认之前都必须暂时保留,以便在超时重传时使用
+
+#### 发送窗口变化
+
+发送窗口的位置由窗口前沿和后沿的位置共同确定。发送窗口后沿的变化情况有两种,即不动(没有收到新的确认)和前移(收到了新的确认)。发送窗口后沿不可能向后移动,因为不能撤销已收到的确认
+
+发送窗口前沿通常是不断向前移动,但也有可能不动。这对应于两种情况:
+
+- 一是没有收到新的确认,对应通知的窗口大小也不变
+- 二是收到了新的窗口单对方通知的窗口缩小了,使得发送窗口前沿正好不动
+
+发送窗口前沿也有可能`向后收缩`。这发生在对方通知的窗口缩小了。但 TCP 的标准`强烈不赞成这样做`。因为很可能发送方在收到这个通知以前已经发送了窗口中的许多数据,现在又要收缩窗口,不让发送这些数据,这样就会产生一些错误
+
+
+
+要描述一个发送窗口的状态需要三个指针:P1,P2,P3。指针都指向字节的序号。这三个指针指向的几个部分的意义如下:
+
+- 小于 P1 的是已发送并已收到确认的部分,而大于 P3 的是不允许发送的部分
+- P3 - P1 = `A 的发送窗口`
+- P2 - P1 已发送但尚未收到确认的字节数
+- P3 - P2 允许发送但当前尚未发送的字节数(又称为`可用窗口`或`有效窗口`)
+
+B 的接收窗口大小是20。在接收窗口外面,到30号为止的数据是已经发送过确认,并且已经交付主机了。因此在 B 可以不再保留这些数据。接收窗口内的序号(31\~50)是允许接收的。在上图中,B 收到了序号为32和33的数据。这些数据没有按序到达,因为序号为31的数据没有收到(也许丢失了,也许滞留在网络中的某处)。请注意,B 只能对按序收到的数据中的最高序号给出确认,因此 B 发送的确认报文段中的确认号仍然是31(即期望收到的序号),而不是32或33
+
+现在假定 B 收到了序号为31的数据,并把序号为31\~33的数据交付主机,然后 B 删除这些数据。接着把接收窗口向前移动3个序号,同时给 A 发送确认,其中窗口值仍为20,但确认号是34。这表明 B 已经收到了到序号33为止的数据。B 还收到了序号为37,38和40的数据,但这些都没有按序到达,只能先暂存在接收窗口中。A 收到 B 的确认后,就可以把发送窗口向前滑动3个序号,但指针 P2 不动。现在 A 的可用窗口增大了,可发送的序号范围是42\~53
+
+
+
+A 在继续发送完序号42\~53的数据后,指针 P2 向前移动和 P3 重合。发送窗口内的序号都已用完,但还没有再收到确认。由于 A 的发送窗口已满,可用窗口已减小到零,因此必须停止发送。发送窗口内所有的数据都已正确到达 B,B 也早已发出了确认。但所有这些确认都滞留在网络中。在没有收到 B 的确认时,A 不能猜测:”或许 B 收到了吧!“为了保证可靠传输,A 只能认为 B 还没有收到这些数据。于是,A 在经过一段时间后(由超时计时器控制)就重传这部分数据,重新设置超时计时器,直到收到 B 的确认为止。如果 A 收到确认号落在发送窗口内,那么 A 就可以发送窗口继续向前滑动,并发送新的数据
+
+
+
+#### 缓存和窗口
+
+发送方维持的发送缓存和发送窗口,以及接收方维持的接收缓存和接收窗口
+
+
+
+发送缓存用来暂时存放:
+
+- 发送应用程序传送给对方 TCP 准备发送的数据
+- TCP 已发送出但尚未收到确认的数据
+
+已被确认的数据应当从发送缓存中删除,因此发送缓存和发送窗口的后沿是重合的。发送应用程序必须控制写入缓存的速率,不能太快,否则发送缓存就会没有存放数据的空间
+
+接收缓存用来暂时存放:
+
+- 按序到达的、但尚未被接收应用程序读取的数据
+- 未按序到达的数据
+
+收到的分组被检测出有差错,则丢弃。接收应用程序来不及读取收到的数据,接收缓存最终就会被填满,使接收窗口减小到零。接收应用程序能够及时从接收缓存中读取收到的数据,接收窗口就可以增大,最大亦不能超过接收缓存的大小
+
+要点小结:
+
+- 虽然 A 的发送窗口是根据 B 的接收窗口设置的,但在同一时刻,A 的发送窗口并不总是和 B 的接收窗口一样大。通过网络传送窗口值需要经历一定的时间滞后,该时间并不确定的
+- 对于不按序到达的数据,TCP 通常是先临时存放在接收窗口,等字节流中所缺少的字节收到后,在`按序交付上层的应用进程`
+- TCP 要求接收方必须有累积确认的功能,这样可以减少传输开销
+
+### 超时重传时间的选择
+
+TCP 的发送方在规定的时间内没有收到确认就要重传已发送的报文段。这种重传的概念是很简单的,但重传时间的选择却是 TCP 最复杂的问题之一
+
+由于 TCP 的下层是互联网环境,发送的报文段可能只经过一个高速率的局域网,也可能经过多个低速率的网络,并且每个 IP 数据报所选择的路由还可能不同。如果把超时重传时间设置得太短,就会引起很多报文段的不必要的重传,使网络负荷增大。但若把超时重传时间设置的过长,则又使网络的空闲时间增大,降低了传输效率
+
+TCP 采用了一种自适应算法,它记录一个报文段发出的时间,以及收到相应的确认的时间。这两个时间之差就是`报文段的往返时间 RTT`
+
+> 新的 RTTs = (1 - α) x (旧的 RTTs) + α x (新的 RTT 样本)
+
+RTT:报文段往返时间
+RTTs:加权平均往返时间
+α: 0 ≤ α < 1,RFC 6298 推荐的 α 值为 1/8,即 0.125
+
+> RTO = RTTs + 4 x RTTD
+
+RTO:超时重传时间
+RTTD:RTT 的偏差的加权平均值
+
+> 新的 RTTD = (1 - β) x (旧的 RTTD) + β x |RTTs - 新的 RTT 样本|
+
+β:小于1的系数,推荐值是 1/4,即 0.25
+
+## TCP 流量控制
+
+### 利用滑动窗口实现流量控制
+
+流量控制(flow control):让发送方的发送速率不要太快,要让接收方来得及接收
+
+利用滑动窗口机制可以很方便地在 TCP 连接上实现对发送方的流量控制
+
+
+
+`发送方的发送窗口不能超过接收方给出的接收窗口的数值`。TCP 的`窗口单位是字节,不是报文段`
+
+避免死锁:TCP 为每一个连接设有一个`持续计时器(persistence timer)`。只要 TCP 连接的一方收到对方的零窗口通知,就启动持续计时器。若持续计时器设置的时间到期,就发送一个零窗口`探测报文段`(仅携带1字节的数据),而对方就在确认这个探测报文段时给出了现在的窗口值。如果窗口仍是零,那么收到这个报文段的一方就重新设置持续计时器。如果窗口不是零,那么死锁的僵局就可以打破了
+
+### TCP 的传输效率
+
+#### 发送机制
+
+- TCP 维持一个变量,它等于`最大报文段长度 MSS`。只要缓存中存放的数据达到 MSS 字节时,就组装成一个 TCP 报文段发送出去
+- 由发送方的应用进程指明要求发送报文段,即 TCP 支持的`推送(push)`操作
+- 发送方的一个计时器期限到了,这时把当前已有的缓存数据装入报文段(但长度不能超过 MSS)发送出去
+
+#### Nagle 算法
+
+> 在 TCP 的实现中广泛使用 Nagle 算法
+
+若发送应用进程把要发送的数据逐个字节地送到 TCP 的发送缓存,则发送方就把第一个数据字节先发送出去,把后面到达的数据字节都缓存起来。当发送方收到对第一个数据字符的确认后,再把发送缓存中的所有数据组装成一个报文段发送出去,同时继续对随后到达的数据进行缓存。只有在收到对前一个报文段的确认后才继续发送下一个报文段。当数据达到较快而网络速率较慢时,用这样的方法可明显地减少所用的网络宽带。Nagle 算法还规定,当到达的数据已达到发送窗口大小的一半或已达到报文段的最大长度时,就立即发送一个报文段。这样可以有效提高网络的吞吐量
+
+#### 糊涂窗口综合征
+
+> TCP 接收方的缓存已满,仅剩一个字节,并还将保持这种状态持续一段时间。导致发送方只能发送一个字节。导致网络的效率很低
+
+为了解决这个问题,可以`让接收方等待一段时间`,使得或者接受缓存已有足够空间容纳一个最长的报文段,或者`等到接受缓存已有一半空闲的空间`。只要出现这两种情况之一,接收方就发出确认报文,并向发送方通知当前的窗口大小。发送方也不要发送大小的报文段,而是把数据积累成足够大的报文段,或达到接收方缓存的空间的一半大小
+
+## TCP 的拥塞控制
+
+### 拥塞控制的一般原理
+
+在计算机网络中的链路容量(即宽带)、交换结点中的缓存和处理机等,都是网络资源。在某段时间,若对网络中某一资源的需求超过了该资源所能提供的可用部分,网络的性能就要变坏。这种情况就叫做`拥塞`(congestion)
+
+`拥塞控制`就是`防止过多的数据注入到网络中,这样可以使网络中的路由器或链路不致过载`。拥塞控制所要做的都是一个前提,就是`网络能够承受现有的网络负荷`
+
+
+
+### TCP 的拥塞控制方法
+
+TCP 进行拥塞控制的算法有四种,即`慢开始`(slow-start)、`拥塞避免`(congestion avoidance)、`快重传`(fast retransmit)和`快恢复`(fast recovery)
+
+#### 慢开始
+
+当主机开始发送数据时,由于并不清楚网络的负荷情况,如果立即把大量数据字节注入到网络,就有可能引起网络发生拥塞。经验证明,较好的方法是先探测一下,即`由小到大逐渐增大发送窗口`,也就是说,`由小到大逐渐增大拥塞窗口数值`
+
+cwnd:发送方的拥塞窗口,开始发送方设置 cwnd = 1
+
+#### 拥塞避免
+
+让拥塞窗口 cwnd 缓慢地增大,即每经过一个往返时间 RTT 就把发送方的拥塞窗口 cwnd 加1,而不是像慢开始阶段那样加倍增加。因此在拥塞避免阶段就有“`加法增大`” AI(Additive Increase)的特点。这表明在拥塞避免阶段,拥塞窗口 cwnd `按线性规律缓慢增长`,比慢开始算法的拥塞窗口增长速率缓慢得多
+
+“拥塞避免”并非完全能够避免拥塞,而是把拥塞窗口控制为按线性规律增长,`使网络比较不容易出现拥塞`
+
+在执行慢开始算法时,发送方每收到一个对新报文段的确认 ACK,就把拥塞窗口值加1,然后开始下一轮的传输。因此拥塞窗口 cwnd 随着传输轮次按指数规律增长。当拥塞窗口 cwnd 增长到慢开始门限值 ssthresh 时,就改成执行拥塞避免算法,拥塞窗口按线性规律增长
+
+ssthresh:慢开始门限,一般的,会有一个初始值,下图中为16个报文段
+
+
+
+当拥塞窗口 cwnd = 24 时,网络出现了超时,发送方判断为网络拥塞。于是调整门限值 ssthresh = cwnd / 2 = 12,同时设置拥塞窗口 cwnd = 1,进入慢开始阶段
+
+#### 快重传
+
+采用快重传算法可以让发送方`尽早知道发生了个别报文段的丢失`。快重传算法首先要求接收方不要等待自己发送数据时才进行捎带确认,而是要`立即发送确认`,即使收到了`失序的报文段`也要立即发出对已收到的报文段的重复确认
+
+
+
+#### 快恢复
+
+发送方知道当前只是丢失了个别的报文段。于是不启动慢开始,而是执行`快恢复`算法。这时,发送方调整门限值 ssthresh = cwnd / 2 = 8,同时设置拥塞窗口 cwnd = ssthresh = 8,并开始执行拥塞避免算法
+
+TCP Reno 版本:区别于老的 TCP Tahao 版本
+
+## TCP 的运输连接管理
+
+TCP 是面向连接的协议。运输连接是用来传送 TCP 报文的。TCP 运输连接的建立和释放是每一次面向连接的通信中必不可少的过程。运输连接有三个阶段,`连接建立`、`数据传送`和`连接释放`。运输的连接管理就是使运输连接的建立和释放都能够正常地进行
+
+在 TCP 连接建立过程中要解决以下三个问题:
+
+- 要使每一方能够确知对方的存在
+- 要允许双方协商一些参数(最大窗口值、是否使用窗口扩大选项和时间戳选项以及服务质量等)
+- 能够对运输实体资源(缓存大小、连接表中的项目等)进行分配
+
+### TCP 的连接建立
+
+TCP 建立连接的过程叫做握手,握手需要在客户和服务器之间交换三个 TCP 报文段
+
+
+
+#### 连接建立过程
+
+1. 最初客户/服务器的 TCP 进程都处于 `CLOSED(关闭)`状态。在本实例中,A `主动打开连接`,而 B `被动打开连接`
+2. B 的 TCP 服务器进程先创建`传输控制块` TCB,并处于 `LISTEN(收听)` 状态,等待客户的连接请求
+3. A 的 TCP 客户进程创建`传输控制模块` TCB。并向 B 发出连接请求报文段,首部中的同部位 SYN = 1,选择一个初始序号 seq = x。TCP 客户端进程进入 `SYN-SENT(同步已发送)` 状态。TCP 规定,SYN 报文段(即 SYN = 1 的报文段)不能携带数据,但要`消耗一个序号`
+4. B 收到连接请求报文段后,如同意建立连接,则向 A 发送确认。在确认报文段中应把 SYN 位和 ACK 位都置1,确认号是 ack = x + 1,同时也为自己选择一个初始序号 seq = y。这时 TCP 服务器进程进入 `SYN-RCVD(同步收到)` 状态。这个报文段也不能携带数据,但同样`要消耗掉一个序号`
+5. TCP 客户进程收到 B 的确认后,还要向 B 给出确认。确认报文段的 ACK 置1,确认号 ack = y + 1,而自己的序号 seq = x + 1。TCP 的标准规定,ACK 报文段可以携带数据。但`如果不携带数据则不消耗序号`,在这种情况下,下一个数据报文段的序号仍是 seq = x + 1。这时,TCP 连接已经建立,A 进入 `ESTABLISHED(已建立连接)` 状态
+6. 当 B 收到 A 的确认后,也进入 `ESTABLISHED` 状态
+
+> `传输控制块` TCB(Transmission Control Block)存储了每一个连接中的一些重要信息,如:TCP 连接表,指向发送和接收缓存的指针,指向重传队列的指针,当前的发送和接收序号等等
+
+#### 四报文握手
+
+B 发送给 A 的报文段,可拆成两个报文段。先发送一个确认报文段(ACK = 1,ack = x + 1),然后再发送一个同步报文段(SYN = 1,seq = y)。这样的过程就变成了`四报文握手`,与三报文握手效果一致
+
+#### 异常情况
+
+为什么 A 最后还要发送一次确认呢?这主要是为了防止已失效的连接请求报文段突然又传到了 B,因而产生错误
+
+正常情况:A 发出连接请求,但因连接请求报文丢失而未收到确认。于是 A 再重传一次连接请求。后来收到了确认,建立了连接。数据传输完毕后,就释放了连接。A 共发送了两个连接请求报文段,其中第一个丢失,第二个到达了 B,没有“已失效的连接请求报文段”
+
+异常情况:A 发出的第一个连接请求报文段并没有丢失,而是在某些网络结点长时间滞留了,以致延误到连接释放以后的某个时间才到达 B。本来这是一个早已失效的报文段。但 B 收到此失效的连接请求报文段后,就误认为是 A 又发出一次新的连接请求。于是就向 A 发出确认报文段,同意建立连接。假定不采用报文握手,那么只要 B 发出确认,新的连接就建立了。
+
+> 现在 A 并没有发出建立连接的请求,因此不会理睬 B 的确认,也不会向 B 发送数据。但 B 却以为新的运输连接已经建立了,并一直等待 A 发来数据。B 的`许多资源就这样被浪费了`。
+
+> 采用三报文握手的办法,可以防止上述现象的发生
+
+### TCP 的连接释放
+
+
+
+#### 连接释放过程
+
+1. A 的应用进程先向其 TCP 发出连接释放报文段,并停止再发送数据,主动关闭 TCP 连接。A 把连接释放报文段首部的终止控制位 FIN 置1,其序号 seq = u,它等于前面已传送过的数据的最后一个字节的序号加1。这时 A 进入 `FIN-WAIT-1(终止等待1)` 状态,等待 B 的确认。TCP 规定,FIN 报文段即使不携带数据,也消耗一个序号
+2. B 收到连接释放报文段后即发出确认,确认号是 ack = u + 1,而这个报文段自己的序号是 v,等于 B 前面已传送过的数据的最后一个字节的序号加1。B随即进入 `CLOSE-WAIT(关闭等待)` 状态。TCP 服务器进程这时应通知高层应用进程,因而从 A 到 B 这个方向的连接就释放了,这时的 TCP 连接处于 `半关闭(half-close)` 状态,即 A 已经没有数据要发送了,但 B 若发送数据,A 仍要接收。也就是说,从 B 到 A 这个方向的连接并未关闭,这个状态可能会持续一段时间
+3. A 收到来自 B 的确认后,就进入 `FIN-WAIT-2(终止等待2)` 状态,等待 B 发出的连接释放报文段
+4. 若 B 已经没有要向 A 发送的数据,其应用进程就通知 TCP 释放连接。这时 B 发出的连接释放报文段必须使 FIN = 1。现假定 B 的序号为 w(在半关闭状态 B 可能又发送了一些数据)。B 还必须重复上次已发送过的确认号 ack = u + 1。这时 B 就进入 `LAST-ACK(最后确认)`状态,等待 A 的确认
+5. A 在收到 B 的连接释放报文段后,必须对此发出确认。在确认报文段中把 ACK 置1,确认号 ack = w + 1,而自己的序号是 seq = u + 1(根据 TCP 标准,前面发送过的 FIN 报文段要消耗一个序号)。然后进入到 `TIME-WAIT(时间等待)`状态。此时 TCP 连接还没有释放掉。必须经过`时间等待计时器(TIME-WAIT timer)`设置的时间2MSL后,A 才进入到 `CLOSED` 状态
+6. 当 A 撤销相应的传输控制块 TCB 后,就结束了这次的 TCP 连接
+
+> 时间 MSL 叫做`最长报文段寿命`(Maximum Segment Lifetime),RFC 793建议设为2分钟。但这完全是从工程上来考虑的,对于现在的网络,MSL = 2分钟可能太长了一些
+
+#### TIME-WAIT 等待时间
+
+为什么 A 在 TIME-WAIT 状态必须等待 2MSL 的时间呢?
+
+为了保证 A 发送的最后一个 ACK 报文段能够到达 B。这个 ACK 报文段有可能丢失,因而使处在 LAST-ACK 状态的 B 收不到对已发送的 FIN + ACK 报文段的确认。B 会超时 重传这个 FIN + ACK 报文段,而 A 就能在 2MSL 时间内收到这个重传的 FIN + ACK 报文段。接着 A 重传一次确认,重新启动 2MSL 计时器。最后,A 和 B 都正常进入到 CLOSED 状态。如果 A 在 TIME-WAIT 状态不等待一段时间,而是在发完 ACK 报文段后立即释放连接,那么就无法收到 B 重传的 FIN + ACK 报文段,因而也不会再发送一次确认报文段。这样,B 就无法安装正常步骤进入 CLOSED 状态
+
+防止前面提到的“已失效的连接请求报文段”出现在本连接中。A 在发送完最后一个 ACK 报文段后,再经过时间 2MSL,就可以使本连接持续的时间内所产生的所有报文段都从网络中消失。这样就可以使下一个新的连接中不会出现这种旧的连接请求报文段
+
+B 只要收到 A 发出的确认,就进入 CLOSED 状态。同样,B 在撤销相应的传输控制 TCB 后,就结束了这次的 TCP 连接。B 结束 TCP 连接的时间要比 A 早一些
+
+`保活计时器(keepalive timer)`:服务器每收到一次客户的数据,就重新设置保活计时器,时间的设置通常是两小时。若两小时没有收到客户的数据,服务器就发送一个探测报文段,以后则每隔75秒发送一次。若一连发送10个探测报文段后仍无客户的响应,服务器就认为客户端出了故障,接着就关闭这个连接
+
+### TCP 的有限状态机
+
+为了更清晰地看出 TCP 连接的各种状态之间的关系,下图为 TCP 的有限状态机。图中每一个方框即 TCP 可能具有的状态。每个方框中的大写英文字符串是 TCP 标准所使用的 TCP 连接状态名。状态之间的箭头表示可能发生的状态变迁。箭头旁边的字,表明引起这种变迁的原因,或表明发生状态变迁后又出现什么动作。请注意图中有三种不同的箭头。`粗实线箭头`表示对`客户进程的正常变迁`。`粗虚线箭头`表示对`服务器进程的正常变迁`。另一种`细线箭头`表示`异常变迁`
+
+
+
+**《TCP协议详解》原文链接:[https://blog.maplemark.cn/2019/04/tcp协议详解.html](https://blog.maplemark.cn/2019/04/tcp协议详解.html)**
\ No newline at end of file
diff --git "a/docs/01.\347\275\221\347\273\234/04.TCP\347\262\230\345\214\205\346\213\206\345\214\205.md" "b/docs/01.\347\275\221\347\273\234/04.TCP\347\262\230\345\214\205\346\213\206\345\214\205.md"
new file mode 100755
index 0000000..5272992
--- /dev/null
+++ "b/docs/01.\347\275\221\347\273\234/04.TCP\347\262\230\345\214\205\346\213\206\345\214\205.md"
@@ -0,0 +1,50 @@
+# TCP 粘包拆包
+
+## 粘包问题
+
+在 TCP 这种字节流协议上做`应用层分包`是网络编程的基本需求。分包指的是在发生一个消息(message)或一帧(frame)数据时,通过一定的处理,让接收方能从字节流中识别并截取(还原)出一个个消息。因此,`“粘包问题”是个伪命题`
+
+## 短连接分包
+
+对于短连接的 TCP 服务,分包不是一个问题,只要发送方主动关闭连接,就表示一个消息发送完毕,接收方 read() 返回0,从而知道消息的结尾
+
+## TCP 发送机制
+
+为了提高 TCP 的传输效率,TCP 有一套自己的发送机制
+
+- TCP 维持一个变量,它等于`最大报文段长度 MSS`。只要缓存中存放的数据达到 MSS 字节时,就组装成一个 TCP 报文段发送出去
+- 由发送方的应用进程指明要求发送报文段,即 TCP 支持的`推送(push)`操作
+- 发送方的一个计时器期限到了,这时把当前已有的缓存数据装入报文段(但长度不能超过 MSS)发送出去
+
+## 长连接分包
+
+对于长连接的 TCP 服务,分包有四种方法
+
+- 消息长度固定
+- 使用特殊的字符或字符串作为消息的边界,例如 HTTP 协议的 headers 以“\r\n”为字段的分隔符
+- 在每条消息的头部加一个长度字段,这恐怕是最常见的做法
+- 利用消息本身的格式来分包,例如 XML 格式的消息中 ``...`` 的配对,或者 JSON 格式中的 { ... } 的配对。解析这种消息格式通常会用到状态机(state machine)
+
+## 复杂的分包
+
+假如消息格式非常简单,“消息”本身是一个字符串,每条消息有一个4字节的头部,以网络序存放字符串的长度。消息直接没有间隙,字符串也不要求以 '\0' 结尾
+
+发送两条消息“hello”和“smartboy”,打包后的字节流共有21字节
+
+```text
+0x00, 0x00, 0x00, 0x05, 'h', 'e', 'l', 'l', 'o',
+0x00, 0x00, 0x00, 0x08, 's', 'm', 'a', 'r', 't', 'b', 'o', 'y'
+```
+
+假设数据最终都全部到达,数据解析逻辑至少能正确处理以下各种数据到达的次序
+
+- 一个字节一个字节到达
+- 数据分两次到达,第一次收到2个字节,不足消息的长度字段
+- 数据分两次到达,第一次收到4个字节,刚好够长度字段,但是没有 body
+- 数据分两次到达,第一次收到8个字节,长度完整,但 body 不完整
+- 数据分两次到达,第一次收到9个字节,长度完整,但 body 也完整
+- 数据分两次到达,第一次收到10个字节,第一条消息的长度完整、body 也完整,第二条消息长度不完整
+- 请自行移动和增加分割点,一共有超过 100 万种可能(221-1)
+- 数据一次就全部到达
+
+**《TCP粘包拆包》 原文链接:[https://blog.maplemark.cn/2019/04/tcp粘包拆包.html](https://blog.maplemark.cn/2019/04/tcp粘包拆包.html)**
\ No newline at end of file
diff --git "a/docs/01.\347\275\221\347\273\234/05.HTTP\347\212\266\346\200\201\347\240\201.md" "b/docs/01.\347\275\221\347\273\234/05.HTTP\347\212\266\346\200\201\347\240\201.md"
new file mode 100755
index 0000000..a8f666d
--- /dev/null
+++ "b/docs/01.\347\275\221\347\273\234/05.HTTP\347\212\266\346\200\201\347\240\201.md"
@@ -0,0 +1,168 @@
+# HTTP 状态码
+
+## 状态码
+
+状态码是来告诉客户端,发生了什么事情。状态码为客户端提供了一种`理解事务处理结果`的`便捷方式`。状态码位于响应的起始行中
+
+> 比如,在行 HTTP/1.0 200 OK 中,状态码就是200
+
+客户端向一个 HTTP 服务器发送请求报文时,会遇到很多意想不到的情况,请求不一定能够成功完成。服务器可能会告诉你无法找到所请求的资源,你没有访问资源的权限,或者资源被移到了其他地方
+
+状态码是在每条响应报文的起始行中返回的。会返回一个数字状态和一个可读的状态。`数字码`便于程序进行差错处理,而`原因短语`则便于人们理解
+
+## 原因短语
+
+原因短语是响应起始行中的最后一个组件。它为状态码提供了`文本形式`的解释
+
+> 比如,在行 HTTP/1.0 200 OK 中,OK 就是原因短语
+
+原因短语和状态码是成对出现的。原因短语是状态码的`可读`版本,应用程序开发者将其传送给用户,用于说明在请求间发生了什么情况。HTTP 规范并没有提供任何硬性规定,要求原因短语以何种形式出现
+
+## 状态码分类
+
+### 五大类
+
+可以通过三位数字代码对不同状态码进行分类
+
+- 200 到 299 之间的状态码表示成功
+- 300 到 399 之间的代码表示资源已经被移走了
+- 400 到 499 之间的代码表示客户端的请求出错了
+- 500 到 599 之间的代码表示服务器出错了
+
+|状态码|整体范围|已定义范围|分类|
+|-|-|-|-|
+|1XX|100~199|100~101|信息提示|
+|2XX|200~299|200~206|成功|
+|3XX|300~399|300~305|重定向|
+|4XX|400~499|400~415|客户端错误|
+|5XX|500~599|500~505|服务器错误|
+
+当前的 HTTP 版本只为每类状态定义了几个代码。随着协议的发展,HTTP 规范中会正式地定义更多的状态码。若收到了不认识的状态码,可能是有人将其作为当前协议的`扩展定义`的。可以根据其所处的范围,将它作为那个类别中一个普通的成员来处理
+
+> 例如,若收到了状态码 515(在 5XX 代码的已定义范围之外),就应该认为这条响应指出了服务器的错误,这是 5XX 报文的通用类别
+
+### 100 ~ 199,信息状态码
+
+HTTP/1.1 向协议中引入了信息性状态码。这些状态码相对较新,关于其复杂性和感
+知价值存在一些争论,而受到限制
+
+|状态码|原因短语|含义|
+|-|-|-|
+|100|Continue|说明收到了请求的初始部分,请客户端继续。发送了这个状态码之后,服务器在收到请求之后必须进行响应|
+|101|Switching Protocols|说明服务器正在根据客户端的指定,将协议切换成 Update 首部所列的协议|
+
+100 Continue 状态码的目的是对这样的情况进行优化:HTTP 客户端应用程序有一个实体的主体部分要发送给服务器,但希望在发送之前查看一下服务器是否会接受这个实体。客户端应用程序只有在避免向服务器发送一个服务器`无法处理或使用的大实体`,才应该使用 100 Continue
+
+### 200 ~ 299,成功状态码
+
+客户端发起请求时,这些请求通常都是成功的。服务器有一组用来表示成功的状态码,分别对应于不同类型的请求
+
+|状态码|原因短语|含义|
+|-|-|-|
+|200|OK|请求没问题,实体的主体部分包含了所请求的资源|
+|201|Created|用于创建服务器对象的请求(比如:PUT)。响应的实体主体部分中应该包含引用了已创建的资源的URL,Location首部包含的则是最具体的引擎。服务器必须在发送这个状态码之前创建好对象|
+|202|Accepted|请求已被接受,服务器还未对其执行任何动作。不能保证服务器会完成这个请求;接受请求时,它看起来是有效的。服务器应在实体的主体部分包含对请求状态的描述,或附加请求预计处理时间、信息获取指针|
+|203|Non-Authoritative Information|实体首部包含的信息不是来自于源端服务器,而是来自资源的副本。如果中间节点上有一份副本,但无法或没有对元数据进行验证,就会出现这种情况|
+|204|No Content|响应报文中包含若干首部和一个状态行,但没有实体的主体部分。主要用于在浏览器不转为显示新文档的情况下,对其进行更新(比如刷新一个表单页面)|
+|205|Reset Content|另一个主要用于浏览器的代码。负责告知浏览器清除当前页面中的所有 HTML 表单元素|
+|206|Partial Content|成功执行了一个部分或 Range(范围)请求。客户端可以通过一些特殊的首部来获取部分或某个范围内的文档|
+
+### 300 ~ 399,重定向状态码
+
+重定向状态码要么告知客户端使用替代位置来访问他们所感兴趣的资源,要么就提供一个替代的响应而不是资源的内容。如果资源已被移动,可发送一个重定向状态码和一个可选的 Location 首部来告知客户端资源已被移走,以及现在可以在哪里找到它。这样,浏览器就可以在不打扰使用者的情况下,透明地转入新的位置了
+
+请求报文
+
+```text
+GET /index.php HTTP/1.1
+Host: blog.maplemark.cn
+Accept: *
+```
+
+响应报文
+
+```text
+HTTP/1.1 301 Moved Permanently
+Server: nginx/1.12.2
+Date: Fri, 19 Apr 2019 03:58:59 GMT
+Content-Type: text/html; charset=UTF-8
+X-Powered-By: PHP/7.2.16
+Location: https://blog.maplemark.cn/
+```
+
+请求报文
+
+```text
+GET / HTTP/1.1
+Host: blog.maplemark.cn
+Accept: *
+```
+
+响应报文
+
+```text
+HTTP/1.1 200 OK
+Server: nginx/1.12.2
+Date: Fri, 19 Apr 2019 03:59:34 GMT
+Content-Type: text/html; charset=UTF-8
+Transfer-Encoding: chunked
+Connection: keep-alive
+...
+```
+
+|状态码|原因短语|含义|
+|-|-|-|
+|300|Multiple Choices|客户端请求一个实际指向多个资源的URL时会返回这个状态码,比如服务器上有某个HTML文档有多个语言版本。返回时会带有一个选项列表,用户可以选择期望使用的那项|
+|301|Moved Permanently|在请求的 URL 已被移除时使用。响应的 Location 首部中应该包含资源现在所处的 URL|
+|302|Found|与 301 状态码类似;但是,客户端应该使用 Location 首部给出的URL 来临时定位资源。将来的请求仍应使用老的 URL|
+|303|See Other|告知客户端应该用另一个 URL 来获取资源。新的 URL 位于响应报文的 Location 首部。其主要目的是允许 POST 请求的响应将客户端定向到某个资源上去|
+|304|Not Modified|客户端可以通过所包含的请求首部,使其请求变成有条件的。若用户发起了一个条件 GET 请求,而资源近期未被修改,可以通过该状态码表明。带有这个状态码的响应不应该包含实体的主体部分|
+|305|Use Proxy|用来说明必须通过一个代理来访问资源;代理的位置由 Location首部给出。客户端是相对某个特定资源来解析这条响应的,不能假定所有请求,甚至所有对持有所请求资源的服务器的请求都通过这个代理进行。如果客户端错误地让代理介入了某条请求,可能会引发破坏性的行为,而且会造成安全漏洞|
+|306|(未使用)|当前未使用|
+|307|Temporary Redirect|与 301 状态码类似;但客户端应该使用 Location 首部给出的 URL来临时定位资源。将来的请求应该使用老的 URL|
+
+> 302、303 和 307 状态码之间存在一些交叉。这些状态码的用法有着细微的差别,大部分差别都源于 HTTP/1.0 和 HTTP/1.1 应用程序对这些状态码`处理方式`的不同,为兼容 HTTP/1.0 而保留了一些状态码(例如 302 状态码)
+
+### 400 ~ 499,客户端错误状态码
+
+有时客户端会发送一些服务器`无法处理`的东西,比如格式错误的请求报文,或者最常见的是,请求一个不存在的 URL
+
+很多客户端错误都是由浏览器来处理的,甚至不会打扰到你。只有少量错误,比如404,还是会穿过浏览器来到用户面前
+
+|状态码|原因短语|含义|
+|-|-|-|
+|400|Bad Request|用于告知客户端它发送了一个错误的请求|
+|401|Unauthorized|与适当的首部一同返回,在这些首部中请求客户端在获取对资源的访问权之前,对自己进行认证|
+|402|Payment Required|现在这个状态码还未使用,但已经被保留,以作未来之用|
+|403|Forbidden|用于说明请求被服务器拒绝了。如果服务器想说明为什么拒绝请求,可以包含实体的主体部分来对原因进行描述。但这个状态码通常是在服务器不想说明拒绝原因的时候使用的|
+|404|Not Found|用于说明服务器无法找到所请求的 URL。通常会包含一个实体,以便客户端应用程序显示给用户看|
+|405|Method Not Allowed|发起的请求中带有所请求的 URL 不支持的方法时,使用此状态码。应该在响应中包含 Allow 首部,以告知客户端对所请求的资源可以使用哪些方法|
+|406|Not Acceptable|客户端可以指定参数来说明它们愿意接收什么类型的实体。服务器没有与客户端可接受的 URL 相匹配的资源时,使用此代码。通常,服务器会包含一些首部,以便客户端弄清楚为什么请求无法满足|
+|407|Proxy Authentication Required|与 401 状态码类似,但用于要求对资源进行认证的代理服务器|
+|408|Request Timeout|如果客户端完成请求所花的时间太长,服务器可以回送此状态码,并关闭连接。超时时长随服务器的不同有所不同,但通常对所有的合法请求来说,都是够长的|
+|409|Conflict|用于说明请求可能在资源上引发的一些冲突。服务器担心请求会引发冲突时,可以发送此状态码。响应中应该包含描述冲突的主体|
+|410|Gone|与 404 类似,只是服务器曾经拥有过此资源。主要用于 Web 站点的维护,这样服务器的管理者就可以在资源被移除的情况下通知客户端了|
+|411|Length Required|服务器要求在请求报文中包含 Content-Length 首部时使用|
+|412|Precondition Failed|客户端发起了条件请求,且其中一个条件失败了的时候使用。客户端包含了 Expect 首部时发起的就是条件请求|
+|413|Request Entity Too Large|客户端发送的实体主体部分比服务器能够或者希望处理的要大时,使用此状态码|
+|414|Request URI Too Long|客户端所发请求中的请求 URL 比服务器能够或者希望处理的要长时,使用此状态码|
+|415|Unsupported Media Type|服务器无法理解或无法支持客户端所发实体的内容类型时,使用此状态码|
+|416|Requested Range Not Satisfiable|请求报文所请求的是指定资源的某个范围,而此范围无效或无法满足时,使用此状态码|
+|417|Expectation Failed|请求的 Expect 请求首部包含了一个期望,但服务器无法满足此期望时,使用此状态码。如果代理或其他中间应用程序有确切证据说明源端服务器会为某请求产生一个失败的期望,就可以发送这个响应状态码|
+
+### 500 ~ 599,服务器错误状态码
+
+有时客户端发送了一条有效请求,服务器自身却出错了。这可能是客户端碰上了服务器的缺陷,或者服务器上的子元素,比如某个网关资源,出了错
+
+代理尝试着代表客户端与服务器进行交流时,经常会出现问题。代理会发布 5XX 服务器错误状态码来描述所遇到的问题
+
+|状态码|原因短语|含义|
+|-|-|-|
+|500|Internal Server Error|服务器遇到一个妨碍它为请求提供服务的错误时,使用此状态码|
+|501|Not Implemented|客户端发起的请求超出服务器的能力范围(比如,使用了服务器不支持的请求方法)时,使用此状态码|
+|502|Bad Gateway|作为代理或网关使用的服务器从请求响应链的下一条链路上收到了一条伪响应(比如,它无法连接到其父网关)时,使用此状态码|
+|503|Service Unavailable|用来说明服务器现在无法为请求提供服务,但将来可以。如果服务器知道什么时候资源会变为可用的,可以在响应中包含一个 RetryAfter 首部|
+|504|Gateway Timeout|与状态码 408 类似,只是这里的响应来自一个网关或代理,它们在等待另一服务器对其请求进行响应时超时了|
+|505|HTTP Version Not Supported|服务器收到的请求使用了它无法或不愿支持的协议版本时,使用此状态码。有些服务器应用程序会选择不支持协议的早期版本|
+
+**《HTTP状态码》 原文链接:[https://blog.maplemark.cn/2019/04/http状态码.html](https://blog.maplemark.cn/2019/04/http状态码.html)**
\ No newline at end of file
diff --git "a/docs/01.\347\275\221\347\273\234/06.HTTP\346\226\271\346\263\225\350\257\246\350\247\243.md" "b/docs/01.\347\275\221\347\273\234/06.HTTP\346\226\271\346\263\225\350\257\246\350\247\243.md"
new file mode 100755
index 0000000..1a4ef84
--- /dev/null
+++ "b/docs/01.\347\275\221\347\273\234/06.HTTP\346\226\271\346\263\225\350\257\246\350\247\243.md"
@@ -0,0 +1,95 @@
+# HTTP方法详解
+
+## 常见的 HTTP 方法
+
+HTTP 请求方法用于告诉服务器要做什么。HTTP 规范中定义了一组常用的请求方法。
+
+> 例如:GET 方法负责从服务器获取文档,POST 方法会向服务器发送需要处理的数据,OPTIONS 方法用于确定服务器的一般功能,或者服务器处理特定资源的能力
+
+下图描述了7种 HTTP 方法,并不是所有服务器都实现了所有7种方法。有些方法的请求报文中有主体,有些则无主体的请求
+
+
+
+由于 HTTP 设计易于扩展,除这些方法,其他服务器可能还会实现一些自己的请求方法。这些附加的方法是对 HTTP 规范的扩展,被称为`扩展方法`
+
+## 安全方法
+
+HTTP 定义了一组被称为`安全方法`的方法。GET 方法和 HEAD 方法都被认为是安全的,这就意味着使用 GET 或 HEAD 方法的 HTTP 请求都不会产生什么动作
+
+不产生动作,在这里意味着 HTTP 请求不会在服务器上产生什么结果。例如,你在 Colin 的五金商店购物时,点击了“提交购买”按钮。点击按钮时会提交一个带有信用卡信息的 POST 请求,那么在服务器上,就会为你执行一个动作。在这种情况下,为购买行为支付信用卡就是所执行的动作
+
+安全方法并不一定是什么动作都不执行的(实际上,这是由 Web 开发者决定的)。使用安全方法的目的就是当使用可能引发某一动作的不安全方法时,`允许 HTTP 应用程序开发者通知用户`。在 Colin 的五金商店的例子中,你的 Web 浏览器可能会弹出一条警告消息,说明你正在用不安全的方法发起请求,这样可能会在服务器上引发一些事件(比如用你的信用卡支付费用)
+
+## 方法详解
+
+### GET 方法
+
+GET 是最常用的方法。通常用于请求服务器发送某个资源。HTTP/1.1 要求服务器实现此方法
+
+
+
+### HEAD 方法
+
+HEAD 方法与 GET 方法的行为很类似,但服务器在响应中只返回首部。不会返回实体的主体部分。这就允许客户端在未获取实际资源的情况下,对资源的首部进行检查。使用 HEAD,可以:
+
+- 在不获取资源的情况下了解资源的情况(比如,判断其类型)
+- 通过查看响应中的状态码,看看某个对象是否存在
+- 通过查看首部,测试资源是否被修改了
+
+服务器开发者必须确保返回的首部与 GET 请求所返回的首部完全相同。遵循 HTTP/1.1 规范,就必须实现 HEAD 方法
+
+
+
+### PUT 方法
+
+与 GET 从服务器读取文档相反,PUT 方法会向服务器写入文档。有些发布系统允许用户创建 Web 页面,并用 PUT 直接将其安装到 Web 服务器上去
+
+
+
+PUT 方法的语义就是让服务器用请求的主体部分来创建一个由所请求的 URL 命名的新文档,或者,如果那个 URL 已经存在的话,就用这个主体来替代它。
+
+因为 PUT 允许用户对内容进行修改,所以很多 Web 服务器都要求在执行 PUT 之前,用密码登录
+
+### POST 方法
+
+POST 方法起初是用来向服务器输入数据的。实际上,通常会用它来支持 HTML 的表单。表单中填好的数据通常会被送给服务器,然后由服务器将其发送到它要去的地方(比如,送到一个服务器网关程序中,然后由这个程序对其进行处理)
+
+
+
+### TRACE 方法
+
+客户端发起一个请求时,这个请求可能要穿过防火墙、代理、网关或其他一些应用程序。每个中间节点都可能会`修改原始的 HTTP 请求`。TRACE 方法允许客户端在最终将请求发送给服务器时,看看它变成了什么样子
+
+TRACE 请求会在目的服务器端发起一个“环回”诊断。行程最后一站的服务器会弹回一条 TRACE 响应,并在响应主体中携带它收到的原始请求报文。这样客户端就可以查看在所有中间 HTTP 应用程序组成的请求/响应链上,原始报文是否,以及如何被毁坏或修改过 TRACE 方法主要用于诊断;也就是说,用于验证请求是否如愿穿过了请求/响应链。它也是一种很好的工具,可以用来查看代理和其他应用程序对用户请求所产生效果
+
+尽管 TRACE 可以很方便地用于诊断,但它确实也有缺点,它假定中间应用程序对各种不同类型请求(不同的方法——GET、HEAD、POST 等)的处理是相同的。很多 HTTP 应用程序会根据方法的不同做出不同的事情——比如,代理可能会将 POST 请求直接发送给服务器,而将 GET 请求发送给另一个 HTTP 应用程序(比如Web 缓存)。TRACE 并不提供区分这些方法的机制。通常,中间应用程序会自行决定对 TRACE 请求的处理方式
+
+TRACE 请求中不能带有实体的主体部分。TRACE 响应的实体主体部分包含了响应服务器收到的请求的精确副本
+
+
+
+### OPTIONS
+
+OPTIONS 方法请求 Web 服务器告知其支持的各种功能。可以询问服务器通常支持哪些方法,或者对某些特殊资源支持哪些方法。(有些服务器可能只支持对一些特殊类型的对象使用特定的操作)
+
+这为客户端应用程序提供了一种手段,使其不用实际访问那些资源就能判定访问各种资源的最优方式
+
+
+
+### DELETE
+
+DELETE 方法所做的事情就是请服务器删除请求 URL 所指定的资源。但是,客户端应用程序无法保证删除操作一定会被执行。因为 HTTP 规范允许服务器在不通知客户端的情况下撤销请求
+
+
+
+### 扩展方法
+
+HTTP 被设计成字段可扩展的,这样新的特性就不会使老的软件失效了。扩展方法指的就是没有在 HTTP/1.1 规范中定义的方法。服务器会为它所管理的资源实现一些 HTTP 服务,这些方法为开发者提供了一种扩展这些 HTTP 服务能力的手段。下图列出了一些常见的扩展方法实例。这些方法就是 WebDAV HTTP 扩展包含的所有方法,这些方法有助于通过 HTTP 将 Web 内容发布到 Web 服务器上去
+
+
+
+并不是所有的扩展方法都是在正式规范中定义的,认识到这一点很重要。如果你定义了一个扩展方法,很可能大部分 HTTP 应用程序都无法理解。同样,你的 HTTP应用程序也可能会遇到一些其他应用程序在用的,而它并不理解的扩展方法
+
+在这些情况下,最好对扩展方法宽容一些。如果能够在不破坏端到端行为的情况下将带有未知方法的报文传递给下游服务器,代理应尝试传递这些报文。如果可能破坏端到端行为则应以 501 Not Implemented(无法实现)状态码进行响应。最好按惯例“对所发送的内容要求严一点,对所接收的内容宽容一些”来处理扩展方法(以及一般的 HTTP 扩展)
+
+**《HTTP方法详解》 原文链接:[https://blog.maplemark.cn/2019/04/http方法详解.html](https://blog.maplemark.cn/2019/04/http方法详解.html)**
\ No newline at end of file
diff --git "a/docs/01.\347\275\221\347\273\234/07.HTTPS\347\273\206\350\212\202\344\273\213\347\273\215.md" "b/docs/01.\347\275\221\347\273\234/07.HTTPS\347\273\206\350\212\202\344\273\213\347\273\215.md"
new file mode 100755
index 0000000..07a6573
--- /dev/null
+++ "b/docs/01.\347\275\221\347\273\234/07.HTTPS\347\273\206\350\212\202\344\273\213\347\273\215.md"
@@ -0,0 +1,93 @@
+# HTTPS 细节介绍
+
+HTTPS 是最常见的 HTTP `安全版本`。它得到了很广泛的应用,所有主要的商业浏览器和服务器上都提供 HTTPS。HTTPS 将 HTTP 协议与一组强大的对称、非对称和基于证书的加密技术结合在一起,使得 HTTPS 不仅很安全,而且很灵活,很容易在处于无序状态的、分散的全球互联网上进行管理
+
+HTTPS 加速了因特网应用程序的成长,已经成为基于 Web 的电子商务快速成长的主要推动力。在广域网中对分布式 Web 应用程序的安全管理方面,HTTPS 也是非常重要的
+
+## HTTPS 概述
+
+HTTPS 就是在安全的传输层上发送的 HTTP。HTTPS 没有将未加密的 HTTP 报文发送给 TCP,并通过世界范围内的因特网进行传输,它在将 HTTP 报文发送给 TCP 之前,先将其发送给了一个安全层,对其进行加密
+
+
+
+现在,HTTP 安全层是通过 SSL 及其现代替代协议 TLS 来实现的。我们遵循常见的用法,用术语 SSL 来表示 SSL 或者 TLS
+
+## HTTPS 方案
+
+现在,安全 HTTP 是可选的。因此,对 Web 服务器发起请求时,我们需要有一种方式来告知 Web 服务器去执行 HTTP 的安全协议版本。这是在 URL 的方案中实现的。通常情况下,非安全 HTTP 的 URL 方案前缀为 http,如下所示:
+
+> http://blog.maplemark.cn
+
+在安全 HTTPS 协议中,URL 的方案前缀为 https,如下所示:
+
+> https://blog.maplemark.cn
+
+请求一个客户端(比如 Web 浏览器)对某 Web 资源执行某事务时,它会去检查 URL 的方案
+
+- 如果 URL 的方案为 http,客户端就会打开一条到服务器端口 80(默认情况下)
+的连接,并向其发送老的 HTTP 命令
+- 如果 URL 的方案为 https,客户端就会打开一条到服务器端口 443(默认情况下)
+的连接,然后与服务器“握手”,以二进制格式与服务器交换一些 SSL 安全参数,
+附上加密的 HTTP 命令
+
+SSL 是个二进制协议,与 HTTP 完全不同,其流量是承载在另一个端口上的(SSL 通常是由端口 443 承载的)。如果 SSL 和 HTTP 流量都从端口 80 到达,大部分 Web 服务器会将二进制 SSL 流量理解为错误的 HTTP 并关闭连接。将安全服务进一步整合到 HTTP 层中去就无需使用多个目的端口了,在实际中这样不会引发严重的问题
+
+
+
+## 建立安全传输
+
+在未加密 HTTP 中,客户端会打开一条到 Web 服务器端口 80 的 TCP 连接,发送一条请求报文,接收一条响应报文,关闭连接
+
+由于 SSL 安全层的存在,HTTPS 中这个过程会略微复杂一些。在 HTTPS 中,客户端首先打开一条到 Web 服务器端口 443(安全 HTTP 的默认端口)的连接。一旦建立了 TCP 连接,客户端和服务器就会初始化 SSL 层,对加密参数进行沟通,并交换密钥。握手完成之后,SSL 初始化就完成了,客户端就可以将请求报文发送给安全层了。在将这些报文发送给 TCP 之前,要先对其进行加密
+
+## SSL 握手
+
+在发送已加密的 HTTP 报文之前,客户端和服务器要进行一次 SSL 握手,在这个握手过程中,它们要完成以下工作
+
+- 交换协议版本号
+- 选择一个两端都了解的密码
+- 对两端的身份进行认证
+- 生成临时的会话密钥,以便加密信道
+
+
+
+在通过网络传输任何已加密的 HTTP 数据之前,SSL 已经发送了一组握手数据来建立通信连接了
+
+
+
+这是 SSL 握手的简化版本。根据 SSL 的使用方式,握手过程可能会复杂一些,但总
+的思想就是这样
+
+## 服务器证书
+
+SSL 支持双向认证,将服务器证书承载回客户端,再将客户端的证书回送给服务器。而现在,浏览时并不经常使用客户端证书。大部分用户甚至都没有自己的客户端证书。服务器可以要求使用客户端证书,但实际中很少出现这种情况。
+
+另一方面,安全 HTTPS 事务总是要求使用服务器证书的。在一个 Web 服务器上执行安全事务,比如提交信用卡信息时,你总是希望是在与你所认为的那个组织对话。由知名权威机构签发的服务器证书可以帮助你在发送信用卡或私人信息之前评估你对服务器的信任度。
+
+服务器证书是一个显示了组织的名称、地址、服务器 DNS 域名以及其他信息的 X.509 v3 派生证书。你和你所用的客户端软件可以检查证书,以确保所有的信息都是可信的
+
+
+
+## 站点证书的有效性
+
+SSL 自身不要求用户检查 Web 服务器证书,但大部分现代浏览器都会对证书进行简单的完整性检查,并为用户提供进行进一步彻查的手段。网景公司提出的一种 Web 服务器证书有效性算法是大部分浏览器有效性验证技术的基础。
+
+- 日期检测
+
+首先,浏览器检查证书的起始日期和结束日期,以确保证书仍然有效。如果证书过期了,或者还未被激活,则证书有效性验证失败,浏览器显示一条错误信息
+
+- 签名颁发者可信度检测
+
+每个证书都是由某些证书颁发机构(CA)签发的,它们负责为服务器担保。证书有不同的等级,每种证书都要求不同级别的背景验证。比如,如果申请某个电子商务服务器证书,通常需要提供一个营业的合法证明
+
+任何人都可以生成证书,但有些 CA 是非常著名的组织,它们通过非常清晰的流程来验证证书申请人的身份及商业行为的合法性。因此,浏览器会附带一个签名颁发机构的受信列表。如果浏览器收到了某未知(可能是恶意的)颁发机构签发的证书,那它通常会显示一条警告信息。有些证书会携带到受信 CA 的有效签名路径,浏览器可能会选择接受所有此类证书。换句话说,如果某受信 CA 为“Sam 的签名商店”签发了一个证书,而 Sam 的签名商店也签发了一个站点证书,浏览器可能会将其作为从有效 CA 路径导出的证书接受
+
+- 签名检测
+
+一旦判定签名授权是可信的,浏览器就要对签名使用签名颁发机构的公开密钥,并将其与校验码进行比较,以查看证书的完整性
+
+- 站点身份检测
+
+为防止服务器复制其他人的证书,或拦截其他人的流量,大部分浏览器都会试着去验证证书中的域名与它们所对话的服务器的域名是否匹配。服务器证书中通常都包含一个域名,但有些 CA 会为一组或一群服务器创建一些包含了服务器名称列表或通配域名的证书。如果主机名与证书中的标识符不匹配,面向用户的客户端要么就去通知用户,要么就以表示证书不正确的差错报文来终止连接
+
+**《HTTPS细节介绍》 原文链接:[http://blog.maplemark.cn/2019/05/https细节介绍.html](http://blog.maplemark.cn/2019/05/https细节介绍.html)**
\ No newline at end of file
diff --git "a/docs/01.\347\275\221\347\273\234/08.SSL-TLS\345\215\217\350\256\256\350\277\220\350\241\214\346\234\272\345\210\266\347\232\204\346\246\202\350\277\260.md" "b/docs/01.\347\275\221\347\273\234/08.SSL-TLS\345\215\217\350\256\256\350\277\220\350\241\214\346\234\272\345\210\266\347\232\204\346\246\202\350\277\260.md"
new file mode 100755
index 0000000..c268ba7
--- /dev/null
+++ "b/docs/01.\347\275\221\347\273\234/08.SSL-TLS\345\215\217\350\256\256\350\277\220\350\241\214\346\234\272\345\210\266\347\232\204\346\246\202\350\277\260.md"
@@ -0,0 +1,142 @@
+# SSL/TLS协议运行机制的概述
+
+互联网的通信安全,建立在SSL/TLS协议之上。
+
+本文简要介绍SSL/TLS协议的运行机制。文章的重点是设计思想和运行过程,不涉及具体的实现细节。如果想了解这方面的内容,请参阅[RFC文档](http://tools.ietf.org/html/rfc5246)。
+
+## 一、作用
+
+不使用SSL/TLS的HTTP通信,就是不加密的通信。所有信息明文传播,带来了三大风险。
+
+- `窃听风险`(eavesdropping):第三方可以获知通信内容。
+- `篡改风险`(tampering):第三方可以修改通信内容。
+- `冒充风险`(pretending):第三方可以冒充他人身份参与通信。
+
+SSL/TLS协议是为了解决这三大风险而设计的,希望达到:
+
+- 所有信息都是`加密传播`,第三方无法窃听。
+- 具有`校验机制`,一旦被篡改,通信双方会立刻发现。
+- 配备`身份证书`,防止身份被冒充。
+
+互联网是开放环境,通信双方都是未知身份,这为协议的设计带来了很大的难度。而且,协议还必须能够经受所有匪夷所思的攻击,这使得SSL/TLS协议变得异常复杂。
+
+## 二、历史
+
+互联网加密通信协议的历史,几乎与互联网一样长。
+
+```text
+1994年,NetScape公司设计了SSL协议(Secure Sockets Layer)的1.0版,但是未发布。
+1995年,NetScape公司发布SSL 2.0版,很快发现有严重漏洞。
+1996年,SSL 3.0版问世,得到大规模应用。
+1999年,互联网标准化组织ISOC接替NetScape公司,发布了SSL的升级版TLS 1.0版。
+2006年和2008年,TLS进行了两次升级,分别为TLS 1.1版和TLS 1.2版。最新的变动是2011年TLS 1.2的修订版。
+```
+
+目前,应用最广泛的是TLS 1.0,接下来是SSL 3.0。但是,主流浏览器都已经实现了TLS 1.2的支持。
+
+TLS 1.0通常被标示为SSL 3.1,TLS 1.1为SSL 3.2,TLS 1.2为SSL 3.3。
+
+## 三、基本的运行过程
+
+SSL/TLS协议的基本思路是采用公钥加密法,也就是说,客户端先向服务器端索要公钥,然后用公钥加密信息,服务器收到密文后,用自己的私钥解密。
+
+但是,这里有两个问题。
+
+- 如何保证公钥不被篡改?
+
+> 解决方法:将公钥放在数字证书中。只要证书是可信的,公钥就是可信的。
+
+- 公钥加密计算量太大,如何减少耗用的时间?
+
+> 解决方法:每一次对话(session),客户端和服务器端都生成一个"对话密钥"(session key),用它来加密信息。由于"对话密钥"是对称加密,所以运算速度非常快,而服务器公钥只用于加密"对话密钥"本身,这样就减少了加密运算的消耗时间。
+
+因此,SSL/TLS协议的基本过程是这样的:
+
+> 客户端向服务器端索要并验证公钥。
+
+> 双方协商生成"对话密钥"。
+
+> 双方采用"对话密钥"进行加密通信。
+
+上面过程的前两步,又称为"握手阶段"(handshake)。
+
+## 四、握手阶段的详细过程
+
+"握手阶段"涉及四次通信,我们一个个来看。需要注意的是,"握手阶段"的所有通信都是明文的。
+
+### 4.1 客户端发出请求(ClientHello)
+
+首先,客户端(通常是浏览器)先向服务器发出加密通信的请求,这被叫做ClientHello请求。
+
+在这一步,客户端主要向服务器提供以下信息。
+
+> 支持的协议版本,比如TLS 1.0版。
+
+> 一个客户端生成的随机数,稍后用于生成"对话密钥"。
+
+> 支持的加密方法,比如RSA公钥加密。
+
+> 支持的压缩方法。
+
+这里需要注意的是,客户端发送的信息之中不包括服务器的域名。也就是说,理论上服务器只能包含一个网站,否则会分不清应该向客户端提供哪一个网站的数字证书。这就是为什么通常一台服务器只能有一张数字证书的原因。
+
+对于虚拟主机的用户来说,这当然很不方便。2006年,TLS协议加入了一个Server Name Indication扩展,允许客户端向服务器提供它所请求的域名。
+
+### 4.2 服务器回应(SeverHello)
+
+服务器收到客户端请求后,向客户端发出回应,这叫做SeverHello。服务器的回应包含以下内容。
+
+> 确认使用的加密通信协议版本,比如TLS 1.0版本。如果浏览器与服务器支持的版本不一致,服务器关闭加密通信。
+
+> 一个服务器生成的随机数,稍后用于生成"对话密钥"。
+
+> 确认使用的加密方法,比如RSA公钥加密。
+
+> 服务器证书。
+
+除了上面这些信息,如果服务器需要确认客户端的身份,就会再包含一项请求,要求客户端提供"客户端证书"。比如,金融机构往往只允许认证客户连入自己的网络,就会向正式客户提供USB密钥,里面就包含了一张客户端证书。
+
+### 4.3 客户端回应
+
+客户端收到服务器回应以后,首先验证服务器证书。如果证书不是可信机构颁布、或者证书中的域名与实际域名不一致、或者证书已经过期,就会向访问者显示一个警告,由其选择是否还要继续通信。
+
+如果证书没有问题,客户端就会从证书中取出服务器的公钥。然后,向服务器发送下面三项信息。
+
+> 一个随机数。该随机数用服务器公钥加密,防止被窃听。
+
+> 编码改变通知,表示随后的信息都将用双方商定的加密方法和密钥发送。
+
+> 客户端握手结束通知,表示客户端的握手阶段已经结束。这一项同时也是前面发送的所有内容的hash值,用来供服务器校验。
+
+上面第一项的随机数,是整个握手阶段出现的第三个随机数,又称"pre-master key"。有了它以后,客户端和服务器就同时有了三个随机数,接着双方就用事先商定的加密方法,各自生成本次会话所用的同一把"会话密钥"。
+
+至于为什么一定要用三个随机数,来生成"会话密钥",dog250解释得很好:
+
+> "不管是客户端还是服务器,都需要随机数,这样生成的密钥才不会每次都一样。由于SSL协议中证书是静态的,因此十分有必要引入一种随机因素来保证协商出来的密钥的随机性。
+
+> 对于RSA密钥交换算法来说,pre-master-key本身就是一个随机数,再加上hello消息中的随机,三个随机数通过一个密钥导出器最终导出一个对称密钥。
+
+> pre master的存在在于SSL协议不信任每个主机都能产生完全随机的随机数,如果随机数不随机,那么pre master secret就有可能被猜出来,那么仅适用pre master secret作为密钥就不合适了,因此必须引入新的随机因素,那么客户端和服务器加上pre master secret三个随机数一同生成的密钥就不容易被猜出了,一个伪随机可能完全不随机,可是是三个伪随机就十分接近随机了,每增加一个自由度,随机性增加的可不是一。"
+
+此外,如果前一步,服务器要求客户端证书,客户端会在这一步发送证书及相关信息。
+
+### 4.4 服务器的最后回应
+
+服务器收到客户端的第三个随机数pre-master key之后,计算生成本次会话所用的"会话密钥"。然后,向客户端最后发送下面信息。
+
+> 编码改变通知,表示随后的信息都将用双方商定的加密方法和密钥发送。
+
+> 服务器握手结束通知,表示服务器的握手阶段已经结束。这一项同时也是前面发送的所有内容的hash值,用来供客户端校验。
+
+至此,整个握手阶段全部结束。接下来,客户端与服务器进入加密通信,就完全是使用普通的HTTP协议,只不过用"会话密钥"加密内容。
+
+## 五、参考链接
+
+- MicroSoft TechNet, [SSL/TLS in Detail](http://technet.microsoft.com/en-us/library/cc785811(v=ws.10).aspx)
+- Jeff Moser, [The First Few Milliseconds of an HTTPS Connection](http://www.moserware.com/2009/06/first-few-milliseconds-of-https.html)
+- Wikipedia, [Transport Layer Security](http://en.wikipedia.org/wiki/Transport_Layer_Security)
+- StackExchange, [How does SSL work?](http://security.stackexchange.com/questions/20803/how-does-ssl-work)
+
+(完)
+
+**《SSL/TLS协议运行机制的概述》 [原文链接](http://www.ruanyifeng.com/blog/2014/02/ssl_tls.html)**
\ No newline at end of file
diff --git "a/docs/01.\347\275\221\347\273\234/assets/network-architecture-01.png" "b/docs/01.\347\275\221\347\273\234/assets/network-architecture-01.png"
new file mode 100755
index 0000000..33d0563
Binary files /dev/null and "b/docs/01.\347\275\221\347\273\234/assets/network-architecture-01.png" differ
diff --git "a/docs/01.\347\275\221\347\273\234/assets/network-architecture-02.png" "b/docs/01.\347\275\221\347\273\234/assets/network-architecture-02.png"
new file mode 100755
index 0000000..bd52da9
Binary files /dev/null and "b/docs/01.\347\275\221\347\273\234/assets/network-architecture-02.png" differ
diff --git "a/docs/01.\347\275\221\347\273\234/assets/network-architecture-03.png" "b/docs/01.\347\275\221\347\273\234/assets/network-architecture-03.png"
new file mode 100755
index 0000000..1de6110
Binary files /dev/null and "b/docs/01.\347\275\221\347\273\234/assets/network-architecture-03.png" differ
diff --git "a/docs/01.\347\275\221\347\273\234/assets/network-architecture-04.png" "b/docs/01.\347\275\221\347\273\234/assets/network-architecture-04.png"
new file mode 100755
index 0000000..7ff884b
Binary files /dev/null and "b/docs/01.\347\275\221\347\273\234/assets/network-architecture-04.png" differ
diff --git "a/docs/01.\347\275\221\347\273\234/assets/network-architecture-05.png" "b/docs/01.\347\275\221\347\273\234/assets/network-architecture-05.png"
new file mode 100755
index 0000000..5283b9a
Binary files /dev/null and "b/docs/01.\347\275\221\347\273\234/assets/network-architecture-05.png" differ
diff --git "a/docs/01.\347\275\221\347\273\234/assets/network-architecture-06.png" "b/docs/01.\347\275\221\347\273\234/assets/network-architecture-06.png"
new file mode 100755
index 0000000..2c6158d
Binary files /dev/null and "b/docs/01.\347\275\221\347\273\234/assets/network-architecture-06.png" differ
diff --git "a/docs/01.\347\275\221\347\273\234/assets/network-architecture-07.png" "b/docs/01.\347\275\221\347\273\234/assets/network-architecture-07.png"
new file mode 100755
index 0000000..4886f6b
Binary files /dev/null and "b/docs/01.\347\275\221\347\273\234/assets/network-architecture-07.png" differ
diff --git "a/docs/01.\347\275\221\347\273\234/assets/network-http-message.png" "b/docs/01.\347\275\221\347\273\234/assets/network-http-message.png"
new file mode 100755
index 0000000..e1d813c
Binary files /dev/null and "b/docs/01.\347\275\221\347\273\234/assets/network-http-message.png" differ
diff --git "a/docs/01.\347\275\221\347\273\234/assets/network-http-method-01.png" "b/docs/01.\347\275\221\347\273\234/assets/network-http-method-01.png"
new file mode 100755
index 0000000..391c22d
Binary files /dev/null and "b/docs/01.\347\275\221\347\273\234/assets/network-http-method-01.png" differ
diff --git "a/docs/01.\347\275\221\347\273\234/assets/network-http-method-02.png" "b/docs/01.\347\275\221\347\273\234/assets/network-http-method-02.png"
new file mode 100755
index 0000000..9364178
Binary files /dev/null and "b/docs/01.\347\275\221\347\273\234/assets/network-http-method-02.png" differ
diff --git "a/docs/01.\347\275\221\347\273\234/assets/network-http-method-03.png" "b/docs/01.\347\275\221\347\273\234/assets/network-http-method-03.png"
new file mode 100755
index 0000000..c3296b3
Binary files /dev/null and "b/docs/01.\347\275\221\347\273\234/assets/network-http-method-03.png" differ
diff --git "a/docs/01.\347\275\221\347\273\234/assets/network-http-method-04.png" "b/docs/01.\347\275\221\347\273\234/assets/network-http-method-04.png"
new file mode 100755
index 0000000..0f22dee
Binary files /dev/null and "b/docs/01.\347\275\221\347\273\234/assets/network-http-method-04.png" differ
diff --git "a/docs/01.\347\275\221\347\273\234/assets/network-http-method-05.png" "b/docs/01.\347\275\221\347\273\234/assets/network-http-method-05.png"
new file mode 100755
index 0000000..837e0f8
Binary files /dev/null and "b/docs/01.\347\275\221\347\273\234/assets/network-http-method-05.png" differ
diff --git "a/docs/01.\347\275\221\347\273\234/assets/network-http-method-06.png" "b/docs/01.\347\275\221\347\273\234/assets/network-http-method-06.png"
new file mode 100755
index 0000000..5f57bb8
Binary files /dev/null and "b/docs/01.\347\275\221\347\273\234/assets/network-http-method-06.png" differ
diff --git "a/docs/01.\347\275\221\347\273\234/assets/network-http-method-07.png" "b/docs/01.\347\275\221\347\273\234/assets/network-http-method-07.png"
new file mode 100755
index 0000000..fbf741c
Binary files /dev/null and "b/docs/01.\347\275\221\347\273\234/assets/network-http-method-07.png" differ
diff --git "a/docs/01.\347\275\221\347\273\234/assets/network-http-method-08.png" "b/docs/01.\347\275\221\347\273\234/assets/network-http-method-08.png"
new file mode 100755
index 0000000..efda61d
Binary files /dev/null and "b/docs/01.\347\275\221\347\273\234/assets/network-http-method-08.png" differ
diff --git "a/docs/01.\347\275\221\347\273\234/assets/network-http-method.png" "b/docs/01.\347\275\221\347\273\234/assets/network-http-method.png"
new file mode 100755
index 0000000..220bfa4
Binary files /dev/null and "b/docs/01.\347\275\221\347\273\234/assets/network-http-method.png" differ
diff --git "a/docs/01.\347\275\221\347\273\234/assets/network-https-01.png" "b/docs/01.\347\275\221\347\273\234/assets/network-https-01.png"
new file mode 100755
index 0000000..b7a9c5a
Binary files /dev/null and "b/docs/01.\347\275\221\347\273\234/assets/network-https-01.png" differ
diff --git "a/docs/01.\347\275\221\347\273\234/assets/network-https-02.png" "b/docs/01.\347\275\221\347\273\234/assets/network-https-02.png"
new file mode 100755
index 0000000..15cf671
Binary files /dev/null and "b/docs/01.\347\275\221\347\273\234/assets/network-https-02.png" differ
diff --git "a/docs/01.\347\275\221\347\273\234/assets/network-https-03.png" "b/docs/01.\347\275\221\347\273\234/assets/network-https-03.png"
new file mode 100755
index 0000000..ef0a714
Binary files /dev/null and "b/docs/01.\347\275\221\347\273\234/assets/network-https-03.png" differ
diff --git "a/docs/01.\347\275\221\347\273\234/assets/network-https-04.png" "b/docs/01.\347\275\221\347\273\234/assets/network-https-04.png"
new file mode 100755
index 0000000..293eb11
Binary files /dev/null and "b/docs/01.\347\275\221\347\273\234/assets/network-https-04.png" differ
diff --git "a/docs/01.\347\275\221\347\273\234/assets/network-https-05.png" "b/docs/01.\347\275\221\347\273\234/assets/network-https-05.png"
new file mode 100755
index 0000000..83c1b01
Binary files /dev/null and "b/docs/01.\347\275\221\347\273\234/assets/network-https-05.png" differ
diff --git "a/docs/01.\347\275\221\347\273\234/assets/network-https.png" "b/docs/01.\347\275\221\347\273\234/assets/network-https.png"
new file mode 100755
index 0000000..4e1112b
Binary files /dev/null and "b/docs/01.\347\275\221\347\273\234/assets/network-https.png" differ
diff --git "a/docs/01.\347\275\221\347\273\234/assets/network-tcp-01.png" "b/docs/01.\347\275\221\347\273\234/assets/network-tcp-01.png"
new file mode 100755
index 0000000..d0f490d
Binary files /dev/null and "b/docs/01.\347\275\221\347\273\234/assets/network-tcp-01.png" differ
diff --git "a/docs/01.\347\275\221\347\273\234/assets/network-tcp-02.png" "b/docs/01.\347\275\221\347\273\234/assets/network-tcp-02.png"
new file mode 100755
index 0000000..cc7f634
Binary files /dev/null and "b/docs/01.\347\275\221\347\273\234/assets/network-tcp-02.png" differ
diff --git "a/docs/01.\347\275\221\347\273\234/assets/network-tcp-03.png" "b/docs/01.\347\275\221\347\273\234/assets/network-tcp-03.png"
new file mode 100755
index 0000000..54a72b6
Binary files /dev/null and "b/docs/01.\347\275\221\347\273\234/assets/network-tcp-03.png" differ
diff --git "a/docs/01.\347\275\221\347\273\234/assets/network-tcp-04.png" "b/docs/01.\347\275\221\347\273\234/assets/network-tcp-04.png"
new file mode 100755
index 0000000..4a9a4b9
Binary files /dev/null and "b/docs/01.\347\275\221\347\273\234/assets/network-tcp-04.png" differ
diff --git "a/docs/01.\347\275\221\347\273\234/assets/network-tcp-05.png" "b/docs/01.\347\275\221\347\273\234/assets/network-tcp-05.png"
new file mode 100755
index 0000000..da2dbaa
Binary files /dev/null and "b/docs/01.\347\275\221\347\273\234/assets/network-tcp-05.png" differ
diff --git "a/docs/01.\347\275\221\347\273\234/assets/network-tcp-06.png" "b/docs/01.\347\275\221\347\273\234/assets/network-tcp-06.png"
new file mode 100755
index 0000000..de18485
Binary files /dev/null and "b/docs/01.\347\275\221\347\273\234/assets/network-tcp-06.png" differ
diff --git "a/docs/01.\347\275\221\347\273\234/assets/network-tcp-07.png" "b/docs/01.\347\275\221\347\273\234/assets/network-tcp-07.png"
new file mode 100755
index 0000000..ebfbe7a
Binary files /dev/null and "b/docs/01.\347\275\221\347\273\234/assets/network-tcp-07.png" differ
diff --git "a/docs/01.\347\275\221\347\273\234/assets/network-tcp-08.png" "b/docs/01.\347\275\221\347\273\234/assets/network-tcp-08.png"
new file mode 100755
index 0000000..52254e8
Binary files /dev/null and "b/docs/01.\347\275\221\347\273\234/assets/network-tcp-08.png" differ
diff --git "a/docs/01.\347\275\221\347\273\234/assets/network-tcp-09.png" "b/docs/01.\347\275\221\347\273\234/assets/network-tcp-09.png"
new file mode 100755
index 0000000..1e774e5
Binary files /dev/null and "b/docs/01.\347\275\221\347\273\234/assets/network-tcp-09.png" differ
diff --git "a/docs/01.\347\275\221\347\273\234/assets/network-tcp-10.png" "b/docs/01.\347\275\221\347\273\234/assets/network-tcp-10.png"
new file mode 100755
index 0000000..acfab03
Binary files /dev/null and "b/docs/01.\347\275\221\347\273\234/assets/network-tcp-10.png" differ
diff --git "a/docs/01.\347\275\221\347\273\234/assets/network-tcp-11.png" "b/docs/01.\347\275\221\347\273\234/assets/network-tcp-11.png"
new file mode 100755
index 0000000..12b8842
Binary files /dev/null and "b/docs/01.\347\275\221\347\273\234/assets/network-tcp-11.png" differ
diff --git "a/docs/01.\347\275\221\347\273\234/assets/network-tcp-12.png" "b/docs/01.\347\275\221\347\273\234/assets/network-tcp-12.png"
new file mode 100755
index 0000000..20fe73d
Binary files /dev/null and "b/docs/01.\347\275\221\347\273\234/assets/network-tcp-12.png" differ
diff --git "a/docs/01.\347\275\221\347\273\234/assets/network-tcp-13.png" "b/docs/01.\347\275\221\347\273\234/assets/network-tcp-13.png"
new file mode 100755
index 0000000..3ffca77
Binary files /dev/null and "b/docs/01.\347\275\221\347\273\234/assets/network-tcp-13.png" differ
diff --git "a/docs/01.\347\275\221\347\273\234/assets/network-tcp-14.png" "b/docs/01.\347\275\221\347\273\234/assets/network-tcp-14.png"
new file mode 100755
index 0000000..88ed98b
Binary files /dev/null and "b/docs/01.\347\275\221\347\273\234/assets/network-tcp-14.png" differ
diff --git "a/docs/01.\347\275\221\347\273\234/assets/network-tcp-15.png" "b/docs/01.\347\275\221\347\273\234/assets/network-tcp-15.png"
new file mode 100755
index 0000000..3f32e40
Binary files /dev/null and "b/docs/01.\347\275\221\347\273\234/assets/network-tcp-15.png" differ
diff --git "a/docs/01.\347\275\221\347\273\234/assets/network-tcp-16.png" "b/docs/01.\347\275\221\347\273\234/assets/network-tcp-16.png"
new file mode 100755
index 0000000..a8e3267
Binary files /dev/null and "b/docs/01.\347\275\221\347\273\234/assets/network-tcp-16.png" differ
diff --git "a/docs/01.\347\275\221\347\273\234/assets/network-tcp-17.png" "b/docs/01.\347\275\221\347\273\234/assets/network-tcp-17.png"
new file mode 100755
index 0000000..2e9f46a
Binary files /dev/null and "b/docs/01.\347\275\221\347\273\234/assets/network-tcp-17.png" differ
diff --git "a/docs/01.\347\275\221\347\273\234/assets/network-tcp-18.png" "b/docs/01.\347\275\221\347\273\234/assets/network-tcp-18.png"
new file mode 100755
index 0000000..30d7b8c
Binary files /dev/null and "b/docs/01.\347\275\221\347\273\234/assets/network-tcp-18.png" differ
diff --git "a/docs/01.\347\275\221\347\273\234/assets/network-tcp-19.png" "b/docs/01.\347\275\221\347\273\234/assets/network-tcp-19.png"
new file mode 100755
index 0000000..4585fc1
Binary files /dev/null and "b/docs/01.\347\275\221\347\273\234/assets/network-tcp-19.png" differ
diff --git "a/docs/01.\347\275\221\347\273\234/assets/network-udp-01.png" "b/docs/01.\347\275\221\347\273\234/assets/network-udp-01.png"
new file mode 100755
index 0000000..bce3af7
Binary files /dev/null and "b/docs/01.\347\275\221\347\273\234/assets/network-udp-01.png" differ
diff --git "a/docs/01.\347\275\221\347\273\234/assets/network-udp-02.png" "b/docs/01.\347\275\221\347\273\234/assets/network-udp-02.png"
new file mode 100755
index 0000000..2d0e8bc
Binary files /dev/null and "b/docs/01.\347\275\221\347\273\234/assets/network-udp-02.png" differ
diff --git "a/docs/01.\347\275\221\347\273\234/assets/network-udp-03.png" "b/docs/01.\347\275\221\347\273\234/assets/network-udp-03.png"
new file mode 100755
index 0000000..6215e34
Binary files /dev/null and "b/docs/01.\347\275\221\347\273\234/assets/network-udp-03.png" differ
diff --git "a/docs/01.\347\275\221\347\273\234/assets/network-websocket.png" "b/docs/01.\347\275\221\347\273\234/assets/network-websocket.png"
new file mode 100755
index 0000000..51f1a5a
Binary files /dev/null and "b/docs/01.\347\275\221\347\273\234/assets/network-websocket.png" differ
diff --git "a/docs/02.\346\225\260\346\215\256\347\273\223\346\236\204\344\270\216\347\256\227\346\263\225.md" "b/docs/02.\346\225\260\346\215\256\347\273\223\346\236\204\344\270\216\347\256\227\346\263\225.md"
new file mode 100644
index 0000000..6a3523e
--- /dev/null
+++ "b/docs/02.\346\225\260\346\215\256\347\273\223\346\236\204\344\270\216\347\256\227\346\263\225.md"
@@ -0,0 +1,241 @@
+# 问题与简答
+
+## 数据结构与算法篇
+
+### 1. 概述
+
+#### 解决问题的效率
+
+解决问题方法的效率,跟`数据的组织方式`有关,跟`空间的利用效率`有关,也跟`算法的巧妙程度`有关
+
+#### 抽象数据类型
+
+`抽象数据类型`(Abstract Data Type,ADT)是一种对"数据类型"的描述,这种描述是"抽象"的
+
+数据类型描述内容:一是`数据对象集`,二是`与数据集合相关联的操作集`
+
+#### 算法定义
+
+算法是一个`有限指令集`,它接受一些输入,产生输出,并在一定的有限步骤之后终止
+
+#### 算法复杂度
+
+- 空间复杂度 S(n):根据算法写成的程序在执行时占用存储单元的长度
+- 时间复杂度 T(n):根据算法写成的程序在执行时耗时时间的长度
+
+#### 分析算法效率
+
+- 最坏情况的复杂度 Tworst(n)
+- 平均复杂度 Tavg(n)
+
+拓展阅读 [《数据结构与算法概述》](./02.数据结构与算法/01.数据结构与算法概述.md)
+
+### 2. 实现基础
+
+数据结构的处理方法是从这些具体应用中`抽象`出共性的数据组织与操作方式,进而采用某种具体的程序设计语言`实现`相应的数据存储与操作
+
+#### 数据存储基础
+
+- 数组
+
+数组是最基本的构造类型,它是一组相同类型数据的有序集合
+
+- 结构
+
+结构类型是一种允许把一些数据分量聚合成一个整体的数据类型,它能够把有内在联系的不同类型的数据统一成一个整体,使它们相互关联
+
+- 链表
+
+链表是一种常见而重要的基础数据结构,也是实现复杂数据结构的重要手段
+
+#### 流程控制基础
+
+程序设计语言除了能够表达各种各样的数据外,还必须提供一种手段来表达数据处理的过程,即`程序的控制过程`
+
+按照结构化程序设计的观点,任何程序都可以将程序模块通过三种基本的控制结构进行组合来实现。这三种基本的控制结构是`顺序`、`分支`和`循环`
+
+拓展阅读 [《数据结构实现基础》](./02.数据结构与算法/02.数据结构实现基础.md)
+
+### 3. 线性结构
+
+#### 线性表
+
+线性表(Linear List)是由同一类型的数据元素构成的有序序列的线性结构
+
+操作集:初始化、指定查找、查找、插入、删除、求表长
+
+实现方式:顺序存储、链式存储
+
+#### 堆栈
+
+堆栈(Stack)可以认为是具有一定约束的线性表,插入和删除操作都作用在一个称为栈顶(Top)的端点位置
+
+操作集:生成栈、判断是否满、压栈、判断是否空、出栈
+
+实现方式:顺序存储、链式存储
+
+#### 队列
+
+队列(Queue)是一个有序线性表,队列的插入和删除操作分别是在线性表的两个不同的端点进行
+
+操作集:生成队列、判断是否满、压入队列、判断是否为空,移除队列
+
+实现方式:顺序存储、链式存储
+
+### 4. 树
+
+树(Tree)是一种十分重要且广泛应用的非线性数据结构
+
+#### 二叉树
+
+五种基本形态:空二叉树、只有根节点的二叉树、只有根节点和左子树TL的二叉树、只有根节点和右子树TR的二叉树、具有根节点、左子树TL和右子树TR的二叉树
+
+其它二叉树:斜二叉树、满二叉树、完美二叉树
+
+实现方式:顺序存储、链式存储
+
+操作集:创建二叉树、判断是否为空、遍历(先序遍历、中序遍历、后序遍历、层序遍历)
+
+#### 二叉搜索树
+
+二叉搜索树(Binary Search Tree)是一种对排序和查找都很有用的特殊二叉树
+
+定义:左子树 < 根节点 < 右子树
+
+实现方式:一般用链表实现
+
+操作集:创建二叉树、判断是否为空、遍历、查找、查找最小元素、查找最大元素、插入、删除
+
+时间复杂度:最好 O(logN) 最差 O(N)
+
+#### 平衡二叉树
+
+平衡二叉树(Balanced Binary Tree)又称为 AVL 树,AVL 树的插入、删除、查找操作均可在O(logN)时间内完成
+
+定义:任一结点的左、右子树均为 AVL 树;根节点左、右子树高度差的绝对值不超过1
+
+平衡二叉树的调整:单旋调整、双旋调整
+
+#### 树的应用
+
+堆及其操作、哈夫曼树、集合及其运算
+
+### 5. 散列查找
+
+符号表(SymbolTable)是名字(Name)-属性(Attribute)对的集合,符号表最核心的操作是查找、插入和删除
+
+操作集:创建符号表、查找指定名字是否存在、获取指定名字对应属性、更改指定名字对应属性、插入新名字及其属性、删除名字及其属性
+
+使用散列技术实现符号表的操作集,符号表也叫做`散列表`(Hash Table,即哈希表),散列(Hashing)是一种重要的查找方法
+
+散列函数(哈希函数):在查找数据时,由函数 h 对给定值 key 计算出地址,将 key 与该地址单元中数据对象关键字进行比较,确定查找是否成功。散列法又称为"关键字-地址转换法"
+
+关键字分类:一般把关键字分为`数字型关键字`和`字符串型关键字`
+
+#### 数字型关键字的散列构造
+
+- 直接定址法
+
+h(key) = a x key + b (a、b为常数)
+
+- 除留余数法
+
+h(key) = key mod p
+
+- 数字分析法
+
+h(key) = atoi(key + 7)
+
+#### 字符串型关键字的散列构造
+
+- ASCII 码加和法
+
+h(key) = (Σkey[i]) mode TableSize
+
+#### 冲突处理
+
+- 开放地址法
+
+开放地址法就是一旦产生了冲突,即该地址已经存放了其它数据元素,就去寻找另一个空的散列地址
+
+- 链地址法
+
+链地址法是将所有关键词为同义词的数据对象通过结点链接存储在同一个单链表中
+
+- 影响冲突的因素
+
+散列函数是否均匀、处理冲突的方法、散列表的装填因子 α
+
+### 6. 图
+
+图的结构是任意两个数据对象之前都可能存在某种特定关系的数据结构
+
+### 7. 排序
+
+没有一种排序算法在任何情况下都是最优的,必须根据实际情况选择最优的算法来解决问题
+
+算法稳定性:在一组待排序记录中,如果存在任意两个相等的记录 R 和 S,且在待排序记录中 R 在 S 前,如果在排序后 R 依然在 S 前,即它们的前后位置在排序前后不发生改变,则称为排序算法为稳定的
+
+#### 选择排序
+
+- 简单选择排序
+
+简单选择排序(Simple Selection Sort)是一种直观的排序算法,在未排序的序列中,选出最小的元素和序列的首位元素交换,接下来在剩下的未排序序列中再选出最小元素与序列的第二位元素交换,依次类推,最后形成从小到大的已排序序列
+
+时间复杂度:O(N2)
+
+- 堆排序
+
+将无序的序列生成一个最大堆,将堆顶元素与最后一个元素对换位置,将剩下元素生成最大堆,依次进行元素交换并生成最大堆
+
+时间复杂度:O(NlogN)
+空间复杂度:O(1)
+
+#### 插入排序
+
+- 简单插入排序
+
+将待排序的一组序列分为已排好序和未排序的两个部分,初始状态时,已排序序列仅包含第一个元素,未排序序列中的元素为除了第一个以外N-1个元素;此后将未排序序列中的元素逐一插入到已排序的序列中。如此往复,经过N-1次插入后,未排序序列中元素个数为0,则排序完成
+
+时间复杂度:O(N2) 稳定排序
+
+- 希尔排序
+
+将待排序的一组元素按一定间隔分为若干个序列,分别进行插入排序。开始时设置的"间隔"较大,在每轮排序中将间隔逐步减小,直到"间隔"为1,也就是最后一步是进行简单插入排序
+
+时间复杂度:和增量序列的选取有关 非稳定排序
+
+#### 交换排序
+
+- 冒泡排序
+
+对元素个数为 N 的待排序序列进行排序时,共进行N-1次循环。在第 k 次循环中,对从第1到第N-k个元素从前往后进行比较,每次比较相邻的两个元素,若前一个元素大于后一个元素,则两者互换位置,否则保持位置不变
+
+时间复杂度:O(N2)
+
+- 快速排序
+
+将未排序元素根据一个作为基准的"主元"分为两个子序列,其中一个子序列的记录均大于主元,而另一个子序列均小于主元,然后递归地对这两个子序列用类似的方法进行排序
+
+时间复杂度:O(Nlog2N)
+
+#### 归并排序
+
+将大小为 N 的序列看成 N 个长度为1的子序列,接下来将相邻子序列两两进行归并操作,形成N/2(+1)个长度为2(或1)的有序子序列;然后再继续进行相邻子序列两两归并操作,如果一直循环,直到剩下1个长度为 N 的序列,则该序列为原序列完成排序后的结果
+
+时间复杂度:O(Nlog2N)
+空间复杂度:O(N)
+
+#### 基数排序
+
+- 桶排序
+
+如果已知 N 个关键字的取值范围是在 0 到 M-1 之间,而 M 比 N 小的多,则桶排序算法将关键字的每个取值建立一个"桶",即建立 M 个桶,在扫描 N 个关键字时,将每个关键字放入相应的桶中,然后按桶的顺序收集一遍就自然有序了
+
+- 基数排序
+
+基数排序是桶排序的一种推广,它所考虑的待排记录包含不止一个关键字
+
+### 8. 补充
+
+### 9. 经典算法题
\ No newline at end of file
diff --git "a/docs/02.\346\225\260\346\215\256\347\273\223\346\236\204\344\270\216\347\256\227\346\263\225/01.\346\225\260\346\215\256\347\273\223\346\236\204\344\270\216\347\256\227\346\263\225\346\246\202\350\277\260.md" "b/docs/02.\346\225\260\346\215\256\347\273\223\346\236\204\344\270\216\347\256\227\346\263\225/01.\346\225\260\346\215\256\347\273\223\346\236\204\344\270\216\347\256\227\346\263\225\346\246\202\350\277\260.md"
new file mode 100644
index 0000000..34c072f
--- /dev/null
+++ "b/docs/02.\346\225\260\346\215\256\347\273\223\346\236\204\344\270\216\347\256\227\346\263\225/01.\346\225\260\346\215\256\347\273\223\346\236\204\344\270\216\347\256\227\346\263\225\346\246\202\350\277\260.md"
@@ -0,0 +1,132 @@
+# 数据结构与算法概述
+
+## 引子
+
+什么是数据结构?如果翻阅不同的教材,可以看到五花八门的描述。事实上,这个问题在计算机科学界至今没有标准的定义。
+
+```text
+在计算机科学中,数据结构(英语:data structure)是计算机中存储、组织数据的方式(维基百科)
+```
+
+### 思考问题
+
+#### 书籍摆放
+
+问题:如果你是书店的主人,该如何摆放你的书籍,才能让顾客最快捷的找到想要的书籍?
+
+- 方法1:随便放
+
+> 放书非常方便,有新书直接插到空位。但是查找很不方便,如果没有这本书,需要翻遍整个书架
+
+- 方法2:按照书名的拼音字母顺序排放
+
+> 新书插入需要给新书腾出空间,造成图书需要向后移动
+
+- 方法3:把书架分成几块区域,每块区域指定摆放某种类别的图书;在每种类别内,按照书名的拼音字母顺序排放
+
+> 查找和插入工作量都减少很多,但是无法预估每种类别的图书会有多少,容易造成空间的浪费
+
+#### 数字打印
+
+问题:写程序实现一个函数 PrintN,使得传入一个正整数为 N 的参数,能顺序打印从 1 到 N 的全部正整数
+
+```php
+//版本一
+function PrintN($n)
+{
+ for ($i=1; $i <= $n; $i++) {
+ echo "{$i}\n";
+ }
+}
+//版本二
+function PrintN($n)
+{
+ if ($n > 0) {
+ PrintN($n-1);
+ echo "{$n}\n";
+ }
+}
+```
+
+> 当输入 N 为 100、1000、10000...,N 变的越来越大时候,实现版本一和版本二有什么区别?(debug_backtrace)
+
+#### 一元多项式计算
+
+问题:一元多项式的标准表达式可以写成:f(x) = $a_0$ + $a_1$x + ... + $a_{n-1}$$x^{n-1}$ + $a_n$$x^n$。现给定一个多项式的阶数 n,并将全体系数 $\{a_i\}^n_{i=0}$ 存放在数组 a[] 里。请写程序计算这个多项式在给定点 x 处的值
+
+```php
+function f($n, $a, $x)
+{
+ $p = $a[0];
+ for ($i=1; $i <= $n; $i++) {
+ $p += $a[$i] * pow($x, $i);
+ }
+ return $p;
+}
+$x = 2; $n = 1;
+$a = [];
+for ($i=0; $i <= $n; $i++) {
+ $a[$i] = $i+1;
+}
+$fn = f($n, $a, $x);
+echo $fn . "\n";
+```
+
+通过提公因式 x 减少乘法的运算次数,把多项式改写为:
+
+> f(x) = $a_0$ + x($a_1$ + x(...($a_{n-1}$ + x($a_n$))...))
+
+```php
+function f2($n, $a, $x)
+{
+ $p = $a[$n];
+ for ($i=$n; $i > 0 ; $i--) {
+ $p = $a[$i-1] + $x * $p;
+ }
+ return $p;
+}
+```
+
+### 解决问题的效率
+
+解决一个非常简单的问题,往往也有多种方法,且不同方法之间的效率可能相差甚远。解决问题方法的效率,跟`数据的组织方式`有关,跟`空间的利用效率`有关,也跟`算法的巧妙程度`有关。
+
+## 数据结构
+
+### 定义
+
+- 数据结构的定义,首先应该包含数据对象在计算机中的组织方式——这类似于图书的摆放方法。并且,数据对象必定与一系列加在数据对象上的操作相关联,就如我们在书架上摆放图书是为了能找得到想要的书,或者是插入一本新买的书。
+
+- 在讨论数据结构的时候,关心的是`数据对象`本身以及它们在计算机中的`组织方式`,还要关心与它们相关联的`操作集`,以及实现这些操作的最高效的算法。
+
+- 关于数据对象在计算机中的组织方式,包含两个概念:数据对象集的逻辑结构、数据对象集在计算机中的物理存储结构
+
+### 抽象数据类型
+
+- 抽象数据类型(Abstract Data Type)是一种对"数据结构"的描述,这种描述是"抽象"的。数据类型描述内容:数据对象集、与数据集合相关联的操作集。
+
+- 抽象:描述数据类型的方法不依赖于具体实现,即数据对象集合操作集的描述与存放数据的机器无关、与数据存储的物理结构无关、与实现操作的算法和编程语言均无关。抽象是计算机求解问题的基本方式和重要手段,使得一种设计可以应用于多种场景。
+
+## 算法
+
+### 定义
+
+> 算法(algorithm)自于9世纪波斯数学家,在数学上提出了算法这个概念。
+
+算法是一个`有限指令集`,它接受一些输入(非必须),产生输出,并一定在有限步骤之后终止。
+
+> 算法不是程序,算法比程序更抽象,强调表现做什么,忽略细节性怎么做。这样的好处是使整体思路清晰易懂,形成模块化的风格。
+
+### 算法复杂度
+
+衡量、比较算法的指标主要有以下两个:
+
+- 空间复杂度 S(n):根据算法写成的程序在执行时占用存储单元的长度
+- 时间复杂度 T(n):根据算法写成的程序在执行时耗时时间的长度
+
+分析一般算法效率:
+
+- 最坏情况复杂度 $T_{worst}$(n)
+- 平均复杂度 $T_{avg}$(n)
+
+**《数据结构与算法概述》 原文链接:[https://blog.maplemark.cn/2019/07/数据结构与算法概述.html](https://blog.maplemark.cn/2019/07/数据结构与算法概述.html)**
\ No newline at end of file
diff --git "a/docs/02.\346\225\260\346\215\256\347\273\223\346\236\204\344\270\216\347\256\227\346\263\225/02.\346\225\260\346\215\256\347\273\223\346\236\204\345\256\236\347\216\260\345\237\272\347\241\200.md" "b/docs/02.\346\225\260\346\215\256\347\273\223\346\236\204\344\270\216\347\256\227\346\263\225/02.\346\225\260\346\215\256\347\273\223\346\236\204\345\256\236\347\216\260\345\237\272\347\241\200.md"
new file mode 100644
index 0000000..e5f6451
--- /dev/null
+++ "b/docs/02.\346\225\260\346\215\256\347\273\223\346\236\204\344\270\216\347\256\227\346\263\225/02.\346\225\260\346\215\256\347\273\223\346\236\204\345\256\236\347\216\260\345\237\272\347\241\200.md"
@@ -0,0 +1,170 @@
+# 数据结构实现基础
+
+## 引子
+
+### 数据统计
+
+例子:在日常数据处理中,经常碰到需要对一组数据进行基本的统计分析,包含这些操作:平均数、最大值、最小值、中位数、标准差、方差等。这类统计可能发生在各种情况,比如学生成绩统计、家庭开支情况、GDP 统计等等,都会涉及到这类数据统计。
+
+为每个具体应用都编写一个程序不会是一个好方法,程序都具有很大的相似性。数据结构的处理方法是从这些具体应用中`抽象出共性的数据组织与操作方法`,进而采用某种具体的程序设计语言`实现相应的数据存储与操作`
+
+数据抽象
+
+- 类型名称:统计数据集
+- 数据对象集:N 个元素 {x1, x2, ... , xN} 的集合 S
+- 操作集:
+1. ElementType Average(S, N):求 S 中 N 个元素的平均值
+2. ElementType Max(S, N):求 S 中 N 个元素的最大值
+3. ElementType Min(S, N):求 S 中 N 个元素的最小值
+4. ElementType Median(S, N):求 S 中 N 个元素的中位数
+
+### 数据存储
+
+数据组织的基本存储方式主要是利用数组和链表方式来实现的,包括很复杂的数据结构,如图、树,也都不外乎应用数组和链表来实现
+
+- 若要实现的操作不是基本统计,而是集合运算,需要判断元素是否属于集合、对集合进行并和交运算、元素插入集合等。这些操作虽然在简单数组也可以实现,但是效率不高,使用树的组织方式可以更方便的实现集合的上述运算。
+- 若除了基本的统计操作外,还需要动态的维护一个集合,即经常往集合里加入/删除元素,那应该设计多大的数组来保存这些元素呢,太大浪费空间,太小不够用。使用链表来保存数据或许更适合,但是链表也有缺点,链表需要记录后续节点地址,跟数组存储相比,链表需要更多的存储空间,同时程序实现也比数组更加复杂。
+
+数据结构的存储实现跟所需要的操作密切相关,`没有最好的存储方式,只有最合适的存储方式`。
+
+### 操作实现
+
+- 在确定数据的存储方式后,数据结构涉及的另一个问题是相关的操作如何实现。这些操作的实现需要利用程序设计语言提供的另一个功能,即`流程设计功能`。
+
+- 在任何高级程序设计语言都提供了一种的基本流程控制语句,即分支控制语句和循环控制语句。分支控制结构、循环控制结构加上程序自然的语句顺序执行结构,是实现任何算法流程的基本结构。
+
+- 在程序中,我们可以将程序的某个基本功能设计为函数,这一方面降低了程序设计的复杂性,另一方面也提高了程序设计的重用性。递归是数据结构算法设计的很重要的手段。
+
+## 数据结构存储基础
+
+变量是数据存储的基本单位,而变量是有类型的,例如:整型、浮点型、字符型、布尔型
+
+### 数组
+
+数组是最基本的构造类型,它是一组相同类型数据的有序集合
+
+### 指针
+
+指针变量用于存放变量的地址,通过指针就能间接访问那个变量
+
+### 结构体
+
+结构类型是一种允许把一些数据分量聚合成一个整体的数据类型,它能够把有内在联系的不同类型的数据统一成一个整体,使它们相互关联。同时,结构又是一个变量的集合,可以按照与成员类型变量相同的操作方法单独使用其变量成员。结构与数组的区别在于,数组的所有元素必须是相同类型的,而结构的成员可以是不同的数据类型。
+
+```text
+struct 结构名 {
+ 类型名 结构成员名 1;
+ 类型名 结构成员名 2;
+ ......
+ 类型名 结构成员名 n;
+};
+```
+
+### 链表
+
+链表使一种常见而重要的基础数据结构,也是实现复杂数据结构的重要手段。它不按照线性的顺序存储数据,而是由若干个同一结构类型的"结点"依次串联而成的,即每一个结点里保存着下一个结点的地址。使用链表结构可以克服数据需要预先知道数据大小的缺点,可以充分利用计算机内存空间,实现灵活的内存动态管理。但链表失去了数组方便随机存储的优点,同时链表由于增加了结点的指针域,空间开销比较大。
+
+### 单向链表
+
+#### 单向链表的结构
+
+
+
+```php
+//单向链表结点
+class node
+{
+ public $data;
+ public $next;
+
+ /**
+ * @param $p1 结点数据
+ * @param $p2 下一个结点
+ */
+ public function __construct($p1, $p2)
+ {
+ $this->data = $p1;
+ $this->next = $p2;
+ }
+}
+```
+
+#### 单向链表的常见操作
+
+- 链表的建立
+
+应用链表进行程序设计时,往往需要先建立一个链表,建立链表的过程实际上就是不断在链表中插入结点的过程
+
+```php
+class singleLinkList
+{
+ /**
+ * @param $n int 结点数目
+ * @return $head obj 头结点
+ */
+ public function create($n)
+ {
+ $head = new node(0, null);
+ for ($i=$n; $i > 0; $i--) {
+ $newNode = new node($i, null);
+ $newNode->next = $head->next;
+ $head->next = $newNode;
+ }
+ return $head;
+ }
+}
+```
+
+- 插入结点
+
+在单向链表 head 的某个结点 p 之后插入一新结点:找到正确位置 p,申请新结点 t 并对 t 的结点信息赋值,最后将 t 插入在 p 之后
+
+- 删除结点
+
+从单向链表 head 中删除一个结点:找到被删除结点的前面一个结点 p,删除 p 之后的结点
+
+- 单向链表的遍历
+
+对单向链表最常见的处理方式:逐个查看链表中每个结点的数据并进行处理
+
+### 双向链表
+
+
+
+在单向链表基础上增加指向前驱单元指针的链表叫做`双向链表`。结点增加指向其前驱结点的指针,将牺牲一部分空间代价,前驱单元查找可以不必从链头开始查找
+
+```php
+//双向链表结点
+class node
+{
+ public $data;
+ public $next;
+ public $previous;
+
+ /**
+ * @param $p1 结点数据
+ * @param $p2 下一个结点
+ * @param $p3 前一个结点
+ */
+ public function __construct($p1, $p2, $p3)
+ {
+ $this->data = $p1;
+ $this->next = $p2;
+ $this->previous = $p3;
+ }
+}
+```
+
+### 双向循环链表
+
+
+
+将双向链表最后一个单元的 Next 指针指向链表的第一个单元,而第一个单元的 Previous 指针指向链表的最后一个单元,这样构成的链表称为`双向循环链表`
+
+## 流程控制基础
+
+程序设计语言除了能表达各种各样的数据外,还必须提供一种手段来表达数据处理的过程,即`程序的控制过程`。程序的控制过程通过程序中的一系列语句来实现。
+
+按照结构化程序设计的观点,任何程序都可以将程序模块通过三种基本的控制结构进行组合来实现。这三种基本的控制结构是`顺序`、`分支`、`循环`。
+
+**《数据结构实现基础》 原文链接:[https://blog.maplemark.cn/2019/07/数据结构实现基础.html](https://blog.maplemark.cn/2019/07/数据结构实现基础.html)**
\ No newline at end of file
diff --git "a/docs/02.\346\225\260\346\215\256\347\273\223\346\236\204\344\270\216\347\256\227\346\263\225/03.\347\272\277\346\200\247\347\273\223\346\236\204.md" "b/docs/02.\346\225\260\346\215\256\347\273\223\346\236\204\344\270\216\347\256\227\346\263\225/03.\347\272\277\346\200\247\347\273\223\346\236\204.md"
new file mode 100644
index 0000000..2d8e6aa
--- /dev/null
+++ "b/docs/02.\346\225\260\346\215\256\347\273\223\346\236\204\344\270\216\347\256\227\346\263\225/03.\347\272\277\346\200\247\347\273\223\346\236\204.md"
@@ -0,0 +1,156 @@
+# 线性结构
+
+在数据的逻辑结构中,有种常见而且简单的结构是`线性结构`,即数据元素之间构成一个`有序`的序列。
+
+## 线性表的定义与实现
+
+### 线性表的定义
+
+线性表(Linear List)是由同一类型的数据元素构成的有序序列的线性结构。线性表中的元素的个数称为线性表的长度;当线性表中没有元素时,称为空表;表的起始位置称为表头;表的结束位置称为表尾。
+
+类型名称:线性表(List)
+
+操作集:
+- 1.MakeEmpty:初始化新的空线性表
+- 2.FindKth:根据指定的位序,返回相应元素
+- 3.Find:查找特定元素
+- 4.Insert:指定位序,插入元素
+- 5.Delete:删除指定位序的元素
+- 6.Length:返回线性表的长度
+
+### 线性表的顺序存储实现
+
+线性表的顺序存储是指在内存中用地址连续的一块存储空间顺序存放线性表的各元素。考虑到线性表的运算有插入、删除等,即表的长度是动态可变的,因此,数组的容量需要设计得足够大。
+
+
+
+> MAXSIZE:根据实际问题定义的足够大的整数
+
+> Last:记录当前线性表中最后一个元素在数组中的位置
+
+#### 初始化
+
+顺序表的初始化即构造一个空表。首先动态分配表结构所需要的存储空间,然后将表中的指针置为空,表示表中没有数据元素。
+
+#### 查找
+
+顺序存储的线性表中,查找主要是指在线性表中查找给定值相同的数据元素。由于线性表的元素都存储在数组中,所以这个查找过程实际上就是在数组的顺序查找。查找的平均时间复杂度为O(n)。
+
+#### 插入
+
+顺序表的插入是指在表的第 i 个位序上插入一个值为 X 的新元素。首先将位序之后的元素向后移动,为新元素让出位置;将新元素置入;修改表长度。
+
+#### 删除
+
+顺序表的删除是指将表中指定位序的元素从线性表中去掉,删除后并改变表长度。将指定位序的元素删除,并将位序之后的元素向前移动;修改表长度。
+
+> 由于顺序表的存储特点是用物理上的相邻实现了逻辑上的相邻,它要求用连续的存储单元顺序存储线性表中的各元素,因此,对顺序表插入、删除时需要通过移动数据元素来实现,运行效率影响较大。
+
+### 线性表的链式存储实现
+
+使用链表结构可以克服数组表示线性表的缺陷。下图为单向链表的图示表示形式,它有 n 个数据单元,每个数据单元由数据域和链接域两部分组成。数据域用来存放数值,链接域是线性表数据单元的结构指针。
+
+
+
+```php
+//结点的结构定义
+class node
+{
+ public $data;
+ public $next;
+
+ /**
+ * @param $p1 结点数据
+ * @param $p2 下一个结点
+ */
+ public function __construct($p1, $p2)
+ {
+ $this->data = $p1;
+ $this->next = $p2;
+ }
+}
+```
+
+#### 求表长
+
+从链表的第一个元素起,从头到尾遍历一遍。
+
+#### 查找
+
+线性表的查找有两种:按序号查找、按值查找
+
+- 按序号查找
+
+从链表的第一个元素起,判断结点序号是否相同,相同则返回结点值,不同则继续,没有则返回错误信息。
+
+- 按值查找
+
+从头到尾遍历,知道找到为止;从链表的第一个元素结点起,判断当前结点的值是否相等;若是,则返回结点位置,否则继续,知道表结束为止;找不到则返回错误信息。
+
+#### 插入
+
+线性表的插入是在指定位序前插入一个新元素。在插入位序为1是,代表插入到链表的头;当位序为表尾时,代表插入到链表最后。新增节点,节点值为新元素值,节点指向指针地址根据位序赋予,链表保持。
+
+#### 删除
+
+单向链表中删除指定位序元素,首先需要找到被删除结点的前一个元素,然后再删除结点并释放空间。
+
+## 堆栈
+
+`堆栈`(Stack)是具有一定约束的线性表,插入和删除操作都作用在一个称为栈顶(Top)的端点位置。
+
+
+
+### 表达式求值
+
+表达式求值是程序设计语言编译中的一个基本问题,即编译程序要将源程序中描述的表达式转换为正确的机器指令序列或直接求出常量表达式的值。要实现表达式求值,首先需要理解一个表达式,主要是运算的先后顺序。
+
+### 抽象数据类型
+
+类型名称:堆栈(Stack)
+数据对象集:一个有0个或多个元素的有穷线性表
+操作集:
+- 1.CreateStack:生成空堆栈
+- 2.IsFull:判断堆栈是否已满
+- 3.Push:将元素压入堆栈
+- 4.IsEmpty:判断堆栈是否为空
+- 5.Pop:删除并返回栈顶元素
+
+### 堆栈的实现
+
+由于栈是线性表,因而栈的存储结构可采用顺序和链式两种形式。顺序存储的栈称为顺序栈,链式存储的栈称为链栈。
+
+#### 栈的顺序存储实现
+
+栈的顺序存储结构通常由一个一维数组和一个记录栈顶元素位置的变量组成,另外我们还可以用一个变量来存储堆栈的最大容量,这样方便判断什么时候堆栈是满的。
+
+#### 栈的链式存储实现
+
+栈的链式存储结构(链栈)与单链表类似,但其操作受限制,插入和删除操作只能在链栈的栈顶进行。栈顶指针就是链表的头指针。
+
+### 堆栈应用:表达式求值
+
+## 队列
+
+`队列`(Queue)是一个有序线性表,队列的插入和删除操作分别在线性表的两个不同端点进行的。先进先出特点。
+
+### 队列的定义
+
+类型名称:队列(Queue)
+数据对象集:一个有0个或多个元素的又穷线性表
+操作集:
+- 1.CreateQueue:生成空队列
+- 2.IsFull:判断队列是否已满
+- 3.AddQ:将新元素压入队列
+- 4.IsEmpty:判断队列是否为空
+- 5.DeleteQ:删除并返回队列头元素
+
+### 队列的实现
+
+#### 队列的顺序存储实现
+
+队列最简单的表示方法是用数组。用数组存储队列有许多种具体的方法。一般可以选择将队列头放数组下标小的位置,而将队列尾放在数组下标大的位置,并用两个变量分别指示队列的头和尾。
+
+#### 队列的链式存储实现
+
+队列与堆栈一样,也可以采用链式存储结构,但队列的头必须指向链表的头结点,队列的尾指向链表的尾结点
\ No newline at end of file
diff --git "a/docs/02.\346\225\260\346\215\256\347\273\223\346\236\204\344\270\216\347\256\227\346\263\225/04.\346\240\221.md" "b/docs/02.\346\225\260\346\215\256\347\273\223\346\236\204\344\270\216\347\256\227\346\263\225/04.\346\240\221.md"
new file mode 100644
index 0000000..2a3ec10
--- /dev/null
+++ "b/docs/02.\346\225\260\346\215\256\347\273\223\346\236\204\344\270\216\347\256\227\346\263\225/04.\346\240\221.md"
@@ -0,0 +1,49 @@
+# 树
+
+在计算机科学中,`树`(Tree)是一种抽象数据类型(ADT)或是实现这种抽象数据类型的数据结构,用来模拟具有树状结构性质的数据集合。树是一种十分重要的`非线性数据结构`。
+
+## 树的定义、表示和术语
+
+树是 n(n≥0)个结点构成的有限集合。当 n=0 时,称为空树。对于任意非空树(n>0),具备如下特点。
+
+- 每个节点都只有有限个子节点或无子节点
+- 没有父节点的节点称为根节点
+- 每一个非根节点有且只有一个父节点
+- 除了根节点外,每个子节点可以分为多个不相交的子树
+- 树里面没有环路(cycle)
+
+## 二叉树
+
+### 二叉树的定义
+
+在计算机科学中,`二叉树`(Binary tree)是每个节点最多只有两个分支的树结构。通常分支被称作"左子树"或"右子树"。二叉树的分支具有左右次序,不能随意颠倒。
+
+![二叉树五种基本形态]()
+
+### 二叉树的性质
+
+### 二叉树的存储结构
+
+### 二叉树的操作
+
+## 二叉搜索树
+
+### 二叉搜索树的定义
+
+### 二叉搜索树的动态查找
+
+### 二叉搜索树的插入
+
+### 二叉搜索树的删除
+
+## 平衡二叉树
+
+### 平衡二叉树的定义
+
+### 平衡二叉树的调整
+
+## 树的应用
+
+### 堆及其操作
+
+### 哈夫曼树
\ No newline at end of file
diff --git "a/docs/02.\346\225\260\346\215\256\347\273\223\346\236\204\344\270\216\347\256\227\346\263\225/05.\346\225\243\345\210\227\346\237\245\346\211\276.md" "b/docs/02.\346\225\260\346\215\256\347\273\223\346\236\204\344\270\216\347\256\227\346\263\225/05.\346\225\243\345\210\227\346\237\245\346\211\276.md"
new file mode 100644
index 0000000..e69de29
diff --git "a/docs/02.\346\225\260\346\215\256\347\273\223\346\236\204\344\270\216\347\256\227\346\263\225/06.\345\233\276.md" "b/docs/02.\346\225\260\346\215\256\347\273\223\346\236\204\344\270\216\347\256\227\346\263\225/06.\345\233\276.md"
new file mode 100644
index 0000000..e69de29
diff --git "a/docs/02.\346\225\260\346\215\256\347\273\223\346\236\204\344\270\216\347\256\227\346\263\225/07.\346\216\222\345\272\217.md" "b/docs/02.\346\225\260\346\215\256\347\273\223\346\236\204\344\270\216\347\256\227\346\263\225/07.\346\216\222\345\272\217.md"
new file mode 100644
index 0000000..e69de29
diff --git "a/docs/02.\346\225\260\346\215\256\347\273\223\346\236\204\344\270\216\347\256\227\346\263\225/08.\347\256\227\346\263\225\350\241\245\345\205\205.md" "b/docs/02.\346\225\260\346\215\256\347\273\223\346\236\204\344\270\216\347\256\227\346\263\225/08.\347\256\227\346\263\225\350\241\245\345\205\205.md"
new file mode 100644
index 0000000..e69de29
diff --git "a/docs/02.\346\225\260\346\215\256\347\273\223\346\236\204\344\270\216\347\256\227\346\263\225/09.\347\273\217\345\205\270\347\256\227\346\263\225\351\242\230.md" "b/docs/02.\346\225\260\346\215\256\347\273\223\346\236\204\344\270\216\347\256\227\346\263\225/09.\347\273\217\345\205\270\347\256\227\346\263\225\351\242\230.md"
new file mode 100644
index 0000000..d75ea41
--- /dev/null
+++ "b/docs/02.\346\225\260\346\215\256\347\273\223\346\236\204\344\270\216\347\256\227\346\263\225/09.\347\273\217\345\205\270\347\256\227\346\263\225\351\242\230.md"
@@ -0,0 +1,3 @@
+# 经典算法题
+
+## 1
\ No newline at end of file
diff --git "a/docs/02.\346\225\260\346\215\256\347\273\223\346\236\204\344\270\216\347\256\227\346\263\225/QA.md" "b/docs/02.\346\225\260\346\215\256\347\273\223\346\236\204\344\270\216\347\256\227\346\263\225/QA.md"
deleted file mode 100644
index 89dfd26..0000000
--- "a/docs/02.\346\225\260\346\215\256\347\273\223\346\236\204\344\270\216\347\256\227\346\263\225/QA.md"
+++ /dev/null
@@ -1,93 +0,0 @@
-# 问题与简答
-
-## 数据结构与算法篇
-
-### 衡量、比较算法优劣的指标
-
-> 空间复杂度S(n)、时间复杂度T(n)
-
-### 链表有哪些
-
-> 单向链表、双向链表、循环链表
-
-### 线性结构
-
-- 线性表
-
-> 线性表是由同一类型的数据元素构成的有序序列的线性结构
-
-> 实现方式: 线性存储、链式存储
-
-- 堆栈
-
-> 堆栈可以认为是具有一定约束的线性表,插入和删除操作都作用在一个称为栈顶的端点位置
-
-- 队列
-
-> 队列是一个有序线性表,但队列的插入和删除是分别在线性表的两个不同端点进行的
-
-### 树
-
-- 查找
-
-> 顺序查找、二分查找
-
-- 二叉树
-
-- 二叉搜索树
-
-- 平衡二叉树
-
-### 散列查找
-
-- 散列表
-
-- 散列函数的构造方法
-
-> 数字型关键字、字符串关键字
-
-- 处理冲突的方法
-
-> 开放地址法、链地址法
-
-### 排序
-
-- 选择排序
-
-> 简单选择排序、堆排序
-
-- 插入排序
-
-> 简单插入排序、希尔排序
-
-- 交换排序
-
-> 冒泡排序、快速排序
-
-- 归并排序
-
-- 基数排序
-
-> 桶排序、基数排序
-
-### 跳跃表
-
-### 其他
-
-- KPM
-
-- 布隆过滤器
-
-- 贪心算法
-
-- 回溯算法
-
-- 动态规划
-
-- 最小生成树
-
-- 最短路径
-
-- 推荐算法
-
-- 深度优先、广度优先
\ No newline at end of file
diff --git "a/docs/02.\346\225\260\346\215\256\347\273\223\346\236\204\344\270\216\347\256\227\346\263\225/assets/DSA-double-link.png" "b/docs/02.\346\225\260\346\215\256\347\273\223\346\236\204\344\270\216\347\256\227\346\263\225/assets/DSA-double-link.png"
new file mode 100644
index 0000000..38297d7
Binary files /dev/null and "b/docs/02.\346\225\260\346\215\256\347\273\223\346\236\204\344\270\216\347\256\227\346\263\225/assets/DSA-double-link.png" differ
diff --git "a/docs/02.\346\225\260\346\215\256\347\273\223\346\236\204\344\270\216\347\256\227\346\263\225/assets/DSA-double-link2.png" "b/docs/02.\346\225\260\346\215\256\347\273\223\346\236\204\344\270\216\347\256\227\346\263\225/assets/DSA-double-link2.png"
new file mode 100644
index 0000000..95e7480
Binary files /dev/null and "b/docs/02.\346\225\260\346\215\256\347\273\223\346\236\204\344\270\216\347\256\227\346\263\225/assets/DSA-double-link2.png" differ
diff --git "a/docs/02.\346\225\260\346\215\256\347\273\223\346\236\204\344\270\216\347\256\227\346\263\225/assets/DSA-single-link.png" "b/docs/02.\346\225\260\346\215\256\347\273\223\346\236\204\344\270\216\347\256\227\346\263\225/assets/DSA-single-link.png"
new file mode 100644
index 0000000..74e09c0
Binary files /dev/null and "b/docs/02.\346\225\260\346\215\256\347\273\223\346\236\204\344\270\216\347\256\227\346\263\225/assets/DSA-single-link.png" differ
diff --git "a/docs/02.\346\225\260\346\215\256\347\273\223\346\236\204\344\270\216\347\256\227\346\263\225/assets/DSA-stack.png" "b/docs/02.\346\225\260\346\215\256\347\273\223\346\236\204\344\270\216\347\256\227\346\263\225/assets/DSA-stack.png"
new file mode 100644
index 0000000..cb89c11
Binary files /dev/null and "b/docs/02.\346\225\260\346\215\256\347\273\223\346\236\204\344\270\216\347\256\227\346\263\225/assets/DSA-stack.png" differ
diff --git "a/docs/02.\346\225\260\346\215\256\347\273\223\346\236\204\344\270\216\347\256\227\346\263\225/assets/DSA-\347\272\277\346\200\247\350\241\250\347\232\204\351\223\276\350\241\250\350\241\250\347\244\272.png" "b/docs/02.\346\225\260\346\215\256\347\273\223\346\236\204\344\270\216\347\256\227\346\263\225/assets/DSA-\347\272\277\346\200\247\350\241\250\347\232\204\351\223\276\350\241\250\350\241\250\347\244\272.png"
new file mode 100644
index 0000000..2490f47
Binary files /dev/null and "b/docs/02.\346\225\260\346\215\256\347\273\223\346\236\204\344\270\216\347\256\227\346\263\225/assets/DSA-\347\272\277\346\200\247\350\241\250\347\232\204\351\223\276\350\241\250\350\241\250\347\244\272.png" differ
diff --git "a/docs/02.\346\225\260\346\215\256\347\273\223\346\236\204\344\270\216\347\256\227\346\263\225/assets/DSA-\347\272\277\346\200\247\350\241\250\347\232\204\351\241\272\345\272\217\345\255\230\345\202\250\347\244\272\346\204\217.png" "b/docs/02.\346\225\260\346\215\256\347\273\223\346\236\204\344\270\216\347\256\227\346\263\225/assets/DSA-\347\272\277\346\200\247\350\241\250\347\232\204\351\241\272\345\272\217\345\255\230\345\202\250\347\244\272\346\204\217.png"
new file mode 100644
index 0000000..cec5bb6
Binary files /dev/null and "b/docs/02.\346\225\260\346\215\256\347\273\223\346\236\204\344\270\216\347\256\227\346\263\225/assets/DSA-\347\272\277\346\200\247\350\241\250\347\232\204\351\241\272\345\272\217\345\255\230\345\202\250\347\244\272\346\204\217.png" differ
diff --git "a/docs/02.\346\225\260\346\215\256\347\273\223\346\236\204\344\270\216\347\256\227\346\263\225/assets/\346\225\260\346\215\256\347\273\223\346\236\204.sketch" "b/docs/02.\346\225\260\346\215\256\347\273\223\346\236\204\344\270\216\347\256\227\346\263\225/assets/\346\225\260\346\215\256\347\273\223\346\236\204.sketch"
new file mode 100644
index 0000000..436eb1e
Binary files /dev/null and "b/docs/02.\346\225\260\346\215\256\347\273\223\346\236\204\344\270\216\347\256\227\346\263\225/assets/\346\225\260\346\215\256\347\273\223\346\236\204.sketch" differ
diff --git "a/docs/03.PHP/01.PHP\346\225\260\347\273\204.md" "b/docs/03.PHP/01.PHP\346\225\260\347\273\204.md"
index 2c07df1..a3b88dd 100644
--- "a/docs/03.PHP/01.PHP\346\225\260\347\273\204.md"
+++ "b/docs/03.PHP/01.PHP\346\225\260\347\273\204.md"
@@ -1,178 +1,258 @@
-# PHP 数组
-
-## 简介
-
-这些函数允许你通过不同的方式来使用和操作数组。数组是存储、管理和操作变量组的必不可少的工具。
-
-PHP 支持简单数组和多维数组,数组可由用户自己创建也可以由其它函数创建。有很多特殊的数据库处理函数可以从数据库查询中返回数组以及一些返回数组的函数。
-
-## 预定义常量
-
-下列常量作为 PHP 核心的一部分总是可用的。
-
-CASE_LOWER (integer)
-
-> CASE_LOWER 用在 array_change_key_case() 中将数组的键名转换成小写字母。这也是 array_change_key_case() 的默认值。
-
-CASE_UPPER (integer)
-
-> CASE_UPPER 用在 array_change_key_case() 中将数组的键名转换成大写字母。
-排序顺序标识:
-
-SORT_ASC (integer)
-
-> SORT_ASC 用在 array_multisort() 函数中,使其升序排列。
-
-SORT_DESC (integer)
-
-> SORT_DESC 用在 array_multisort() 函数中,使其降序排列。
-
-- 排序类型标识:用于各种排序函数
-
-SORT_REGULAR (integer)
-
-> SORT_REGULAR 用于对对象进行通常比较。
-
-SORT_NUMERIC (integer)
-
-> SORT_NUMERIC 用于对对象进行数值比较。
-
-SORT_STRING (integer)
-
-> SORT_STRING 用于对对象进行字符串比较。
-
-SORT_LOCALE_STRING (integer)
-
-> SORT_LOCALE_STRING 基于当前区域来对对象进行字符串比较。PHP 4.4.0 和 5.0.2 新加。
-
-COUNT_NORMAL (integer)
-
-COUNT_RECURSIVE (integer)
-
-EXTR_OVERWRITE (integer)
-
-EXTR_SKIP (integer)
-
-EXTR_PREFIX_SAME (integer)
-
-EXTR_PREFIX_ALL (integer)
-
-EXTR_PREFIX_INVALID (integer)
-
-EXTR_PREFIX_IF_EXISTS (integer)
-
-EXTR_IF_EXISTS (integer)
-
-EXTR_REFS (integer)
-
-## 对数组进行排序
-
-PHP 有一些用来排序数组的函数
-
-主要区别有:
-
-- 有些函数基于 array 的键来排序, 而其他的基于值来排序的:$array['key'] = 'value';。
-- 排序之后键和值之间的关联关系是否能够保持, 是指排序之后数组的键可能 会被重置为数字型的(0,1,2 ...)。
-- 排序的顺序有:字母表顺序, 由低到高(升序), 由高到低(降序),数字排序,自然排序,随机顺序或者用户自定义排序。
-- 注意:下列的所有排序函数都是直接作用于数组本身, 而不是返回一个新的有序的数组。
-- 以下函数对于数组中相等的元素,它们在排序后的顺序是未定义的。 (也即相等元素之间的顺序是不稳定的)。
-
-|函数名称|排序依据|数组索引健保持|排序的顺序|相关函数|
-|-|-|-|-|-|
-|array_multisort()|值|键值关联的保持,数字类型的不保持|第一个数组或者由选项指定|array_walk()|
-|asort()|值|是|由低到高|arsort()|
-|arsort()|值|是|由高到低|asort()|
-|krsort()|键|是|由高到低|ksort()|
-|ksort()|键|是|由低到高|asort()|
-|natcasesort()|值|是|自然排序,大小写不敏感|natsort()|
-|natsort()|值|是|自然排序|natcasesort()|
-|rsort()|值|否|由高到低|sort()|
-|shuffle()|值|否|随机|array_rand()|
-|sort()|值|否|由低到高|rsort()|
-|uasort()|值|是|由用户定义|uksort()|
-|uksort()|键|是|由用户定义|uasort()|
-|usort()|值|否|由用户定义|uasort()|
-
-## 数组函数
-
-array_change_key_case — 将数组中的所有键名修改为全大写或小写
-array_chunk — 将一个数组分割成多个
-array_column — 返回数组中指定的一列
-array_combine — 创建一个数组,用一个数组的值作为其键名,另一个数组的值作为其值
-array_count_values — 统计数组中所有的值
-array_diff_assoc — 带索引检查计算数组的差集
-array_diff_key — 使用键名比较计算数组的差集
-array_diff_uassoc — 用用户提供的回调函数做索引检查来计算数组的差集
-array_diff_ukey — 用回调函数对键名比较计算数组的差集
-array_diff — 计算数组的差集
-array_fill_keys — 使用指定的键和值填充数组
-array_fill — 用给定的值填充数组
-array_filter — 用回调函数过滤数组中的单元
-array_flip — 交换数组中的键和值
-array_intersect_assoc — 带索引检查计算数组的交集
-array_intersect_key — 使用键名比较计算数组的交集
-array_intersect_uassoc — 带索引检查计算数组的交集,用回调函数比较索引
-array_intersect_ukey — 用回调函数比较键名来计算数组的交集
-array_intersect — 计算数组的交集
-array_key_exists — 检查数组里是否有指定的键名或索引
-array_key_first — Gets the first key of an array
-array_key_last — Gets the last key of an array
-array_keys — 返回数组中部分的或所有的键名
-array_map — 为数组的每个元素应用回调函数
-array_merge_recursive — 递归地合并一个或多个数组
-array_merge — 合并一个或多个数组
-array_multisort — 对多个数组或多维数组进行排序
-array_pad — 以指定长度将一个值填充进数组
-array_pop — 弹出数组最后一个单元(出栈)
-array_product — 计算数组中所有值的乘积
-array_push — 将一个或多个单元压入数组的末尾(入栈)
-array_rand — 从数组中随机取出一个或多个单元
-array_reduce — 用回调函数迭代地将数组简化为单一的值
-array_replace_recursive — 使用传递的数组递归替换第一个数组的元素
-array_replace — 使用传递的数组替换第一个数组的元素
-array_reverse — 返回单元顺序相反的数组
-array_search — 在数组中搜索给定的值,如果成功则返回首个相应的键名
-array_shift — 将数组开头的单元移出数组
-array_slice — 从数组中取出一段
-array_splice — 去掉数组中的某一部分并用其它值取代
-array_sum — 对数组中所有值求和
-array_udiff_assoc — 带索引检查计算数组的差集,用回调函数比较数据
-array_udiff_uassoc — 带索引检查计算数组的差集,用回调函数比较数据和索引
-array_udiff — 用回调函数比较数据来计算数组的差集
-array_uintersect_assoc — 带索引检查计算数组的交集,用回调函数比较数据
-array_uintersect_uassoc — 带索引检查计算数组的交集,用单独的回调函数比较数据和索引
-array_uintersect — 计算数组的交集,用回调函数比较数据
-array_unique — 移除数组中重复的值
-array_unshift — 在数组开头插入一个或多个单元
-array_values — 返回数组中所有的值
-array_walk_recursive — 对数组中的每个成员递归地应用用户函数
-array_walk — 使用用户自定义函数对数组中的每个元素做回调处理
-array — 新建一个数组
-arsort — 对数组进行逆向排序并保持索引关系
-asort — 对数组进行排序并保持索引关系
-compact — 建立一个数组,包括变量名和它们的值
-count — 计算数组中的单元数目,或对象中的属性个数
-current — 返回数组中的当前单元
-each — 返回数组中当前的键/值对并将数组指针向前移动一步
-end — 将数组的内部指针指向最后一个单元
-extract — 从数组中将变量导入到当前的符号表
-in_array — 检查数组中是否存在某个值
-key_exists — 别名 array_key_exists
-key — 从关联数组中取得键名
-krsort — 对数组按照键名逆向排序
-ksort — 对数组按照键名排序
-list — 把数组中的值赋给一组变量
-natcasesort — 用“自然排序”算法对数组进行不区分大小写字母的排序
-natsort — 用“自然排序”算法对数组排序
-next — 将数组中的内部指针向前移动一位
-pos — current 的别名
-prev — 将数组的内部指针倒回一位
-range — 根据范围创建数组,包含指定的元素
-reset — 将数组的内部指针指向第一个单元
-rsort — 对数组逆向排序
-shuffle — 打乱数组
-sizeof — count 的别名
-sort — 对数组排序
-uasort — 使用用户自定义的比较函数对数组中的值进行排序并保持索引关联
-uksort — 使用用户自定义的比较函数对数组中的键名进行排序
-usort — 使用用户自定义的比较函数对数组中的值进行排序
\ No newline at end of file
+# PHP 数组
+
+## 简介
+
+这些函数允许你通过不同的方式来使用和操作数组。数组是存储、管理和操作变量组的必不可少的工具。
+
+PHP 支持简单数组和多维数组,数组可由用户自己创建也可以由其它函数创建。有很多特殊的数据库处理函数可以从数据库查询中返回数组以及一些返回数组的函数。
+
+## 预定义常量
+
+下列常量作为 PHP 核心的一部分总是可用的。
+
+CASE_LOWER (integer)
+
+> CASE_LOWER 用在 array_change_key_case() 中将数组的键名转换成小写字母。这也是 array_change_key_case() 的默认值。
+
+CASE_UPPER (integer)
+
+> CASE_UPPER 用在 array_change_key_case() 中将数组的键名转换成大写字母。
+排序顺序标识:
+
+SORT_ASC (integer)
+
+> SORT_ASC 用在 array_multisort() 函数中,使其升序排列。
+
+SORT_DESC (integer)
+
+> SORT_DESC 用在 array_multisort() 函数中,使其降序排列。
+
+- 排序类型标识:用于各种排序函数
+
+SORT_REGULAR (integer)
+
+> SORT_REGULAR 用于对对象进行通常比较。
+
+SORT_NUMERIC (integer)
+
+> SORT_NUMERIC 用于对对象进行数值比较。
+
+SORT_STRING (integer)
+
+> SORT_STRING 用于对对象进行字符串比较。
+
+SORT_LOCALE_STRING (integer)
+
+> SORT_LOCALE_STRING 基于当前区域来对对象进行字符串比较。PHP 4.4.0 和 5.0.2 新加。
+
+COUNT_NORMAL (integer)
+
+COUNT_RECURSIVE (integer)
+
+EXTR_OVERWRITE (integer)
+
+EXTR_SKIP (integer)
+
+EXTR_PREFIX_SAME (integer)
+
+EXTR_PREFIX_ALL (integer)
+
+EXTR_PREFIX_INVALID (integer)
+
+EXTR_PREFIX_IF_EXISTS (integer)
+
+EXTR_IF_EXISTS (integer)
+
+EXTR_REFS (integer)
+
+## 对数组进行排序
+
+PHP 有一些用来排序数组的函数
+
+主要区别有:
+
+- 有些函数基于 array 的键来排序, 而其他的基于值来排序的:$array['key'] = 'value';。
+- 排序之后键和值之间的关联关系是否能够保持, 是指排序之后数组的键可能 会被重置为数字型的(0,1,2 ...)。
+- 排序的顺序有:字母表顺序, 由低到高(升序), 由高到低(降序),数字排序,自然排序,随机顺序或者用户自定义排序。
+- 注意:下列的所有排序函数都是直接作用于数组本身, 而不是返回一个新的有序的数组。
+- 以下函数对于数组中相等的元素,它们在排序后的顺序是未定义的。 (也即相等元素之间的顺序是不稳定的)。
+
+|函数名称|排序依据|数组索引健保持|排序的顺序|相关函数|
+|-|-|-|-|-|
+|array_multisort()|值|键值关联的保持,数字类型的不保持|第一个数组或者由选项指定|array_walk()|
+|asort()|值|是|由低到高|arsort()|
+|arsort()|值|是|由高到低|asort()|
+|krsort()|键|是|由高到低|ksort()|
+|ksort()|键|是|由低到高|asort()|
+|natcasesort()|值|是|自然排序,大小写不敏感|natsort()|
+|natsort()|值|是|自然排序|natcasesort()|
+|rsort()|值|否|由高到低|sort()|
+|shuffle()|值|否|随机|array_rand()|
+|sort()|值|否|由低到高|rsort()|
+|uasort()|值|是|由用户定义|uksort()|
+|uksort()|键|是|由用户定义|uasort()|
+|usort()|值|否|由用户定义|uasort()|
+
+## 数组函数
+
+array_change_key_case — 将数组中的所有键名修改为全大写或小写
+
+array_chunk — 将一个数组分割成多个
+
+array_column — 返回数组中指定的一列
+
+array_combine — 创建一个数组,用一个数组的值作为其键名,另一个数组的值作为其值
+
+array_count_values — 统计数组中所有的值
+
+array_diff_assoc — 带索引检查计算数组的差集
+
+array_diff_key — 使用键名比较计算数组的差集
+
+array_diff_uassoc — 用用户提供的回调函数做索引检查来计算数组的差集
+
+array_diff_ukey — 用回调函数对键名比较计算数组的差集
+
+array_diff — 计算数组的差集
+
+array_fill_keys — 使用指定的键和值填充数组
+
+array_fill — 用给定的值填充数组
+
+array_filter — 用回调函数过滤数组中的单元
+
+array_flip — 交换数组中的键和值
+
+array_intersect_assoc — 带索引检查计算数组的交集
+
+array_intersect_key — 使用键名比较计算数组的交集
+
+array_intersect_uassoc — 带索引检查计算数组的交集,用回调函数比较索引
+
+array_intersect_ukey — 用回调函数比较键名来计算数组的交集
+
+array_intersect — 计算数组的交集
+
+array_key_exists — 检查数组里是否有指定的键名或索引
+
+array_key_first — Gets the first key of an array
+
+array_key_last — Gets the last key of an array
+
+array_keys — 返回数组中部分的或所有的键名
+
+array_map — 为数组的每个元素应用回调函数
+
+array_merge_recursive — 递归地合并一个或多个数组
+
+array_merge — 合并一个或多个数组
+
+array_multisort — 对多个数组或多维数组进行排序
+
+array_pad — 以指定长度将一个值填充进数组
+
+array_pop — 弹出数组最后一个单元(出栈)
+
+array_product — 计算数组中所有值的乘积
+
+array_push — 将一个或多个单元压入数组的末尾(入栈)
+
+array_rand — 从数组中随机取出一个或多个单元
+
+array_reduce — 用回调函数迭代地将数组简化为单一的值
+
+array_replace_recursive — 使用传递的数组递归替换第一个数组的元素
+
+array_replace — 使用传递的数组替换第一个数组的元素
+
+array_reverse — 返回单元顺序相反的数组
+
+array_search — 在数组中搜索给定的值,如果成功则返回首个相应的键名
+
+array_shift — 将数组开头的单元移出数组
+
+array_slice — 从数组中取出一段
+
+array_splice — 去掉数组中的某一部分并用其它值取代
+
+array_sum — 对数组中所有值求和
+
+array_udiff_assoc — 带索引检查计算数组的差集,用回调函数比较数据
+
+array_udiff_uassoc — 带索引检查计算数组的差集,用回调函数比较数据和索引
+
+array_udiff — 用回调函数比较数据来计算数组的差集
+
+array_uintersect_assoc — 带索引检查计算数组的交集,用回调函数比较数据
+
+array_uintersect_uassoc — 带索引检查计算数组的交集,用单独的回调函数比较数据和索引
+
+array_uintersect — 计算数组的交集,用回调函数比较数据
+
+array_unique — 移除数组中重复的值
+
+array_unshift — 在数组开头插入一个或多个单元
+
+array_values — 返回数组中所有的值
+
+array_walk_recursive — 对数组中的每个成员递归地应用用户函数
+
+array_walk — 使用用户自定义函数对数组中的每个元素做回调处理
+
+array — 新建一个数组
+
+arsort — 对数组进行逆向排序并保持索引关系
+
+asort — 对数组进行排序并保持索引关系
+
+compact — 建立一个数组,包括变量名和它们的值
+
+count — 计算数组中的单元数目,或对象中的属性个数
+
+current — 返回数组中的当前单元
+
+each — 返回数组中当前的键/值对并将数组指针向前移动一步
+
+end — 将数组的内部指针指向最后一个单元
+
+extract — 从数组中将变量导入到当前的符号表
+
+in_array — 检查数组中是否存在某个值
+
+key_exists — 别名 array_key_exists
+
+key — 从关联数组中取得键名
+
+krsort — 对数组按照键名逆向排序
+
+ksort — 对数组按照键名排序
+
+list — 把数组中的值赋给一组变量
+
+natcasesort — 用“自然排序”算法对数组进行不区分大小写字母的排序
+
+natsort — 用“自然排序”算法对数组排序
+
+next — 将数组中的内部指针向前移动一位
+
+pos — current 的别名
+
+prev — 将数组的内部指针倒回一位
+
+range — 根据范围创建数组,包含指定的元素
+
+reset — 将数组的内部指针指向第一个单元
+
+rsort — 对数组逆向排序
+
+shuffle — 打乱数组
+
+sizeof — count 的别名
+
+sort — 对数组排序
+
+uasort — 使用用户自定义的比较函数对数组中的值进行排序并保持索引关联
+
+uksort — 使用用户自定义的比较函数对数组中的键名进行排序
+
+usort — 使用用户自定义的比较函数对数组中的值进行排序
diff --git "a/docs/03.PHP/03.echo\343\200\201print\343\200\201print_r\343\200\201var_dump\345\214\272\345\210\253.md" "b/docs/03.PHP/03.echo\343\200\201print\343\200\201print_r\343\200\201var_dump\345\214\272\345\210\253.md"
deleted file mode 100644
index f5bd059..0000000
--- "a/docs/03.PHP/03.echo\343\200\201print\343\200\201print_r\343\200\201var_dump\345\214\272\345\210\253.md"
+++ /dev/null
@@ -1,51 +0,0 @@
-# echo、print、print_r、var_dump 区别
-
-## echo
-
-- 输出单个或多个字符,多个使用逗号分隔
-- 无返回值
-
-```php
-echo "String 1", "String 2";
-```
-
-## print
-
-- 只可以输出单个字符
-- 返回`1`,因此可用于表达式
-
-```php
-print "Hello";
-if ($expr && print "foo") {}
-```
-
-## print_r
-
-- 输出关于变量的易于理解的信息
-- 支持多种数据类型,包括字符、数组、对象,格式化成易读格式
-- 在调试时非常有用
-- 若设置第二个参数,可将输出值返回(而不直接输出)
-
-```php
-$b = [
- 'm' => 'monkey',
- 'foo' => 'bar',
- 'x' => ['x', 'y', 'z'],
-];
-$results = print_r($b, true); //$results 包含了 print_r 的输出
-```
-
-## var_dump
-
-- 输出关于变量的易于理解的信息,多个可用分号分隔
-- 支持多种数据类型,包括字符、数组、对象,格式化成易读格式
-- 输出格式与`print_r`不同,`var_dump`的输出包含`数据类型`
-- 在调试时非常有用
-- 无返回值
-
-## 注意
-
-- 即使`print`可用于表达式,但这种用法,常常不利于代码可读性,与其他操作符混用容易让人误解
-- `echo`和`print`都是语言结构,`print_r`和`var_dump`是普通函数。`echo`或`print`使用时,不需要使用括号将变量括起来
-
-**《echo、print、print_r、var_dump区别》 原文链接:[https://blog.maplemark.cn/2019/04/echo-print-print_r-var_dump区别.html](https://blog.maplemark.cn/2019/04/echo-print-print_r-var_dump区别.html)**
\ No newline at end of file
diff --git a/docs/03.PHP/QA.md b/docs/03.PHP/QA.md
index 7acd48d..780114a 100644
--- a/docs/03.PHP/QA.md
+++ b/docs/03.PHP/QA.md
@@ -1,532 +1,580 @@
-# 问题与简答
-
-## PHP 篇
-
-### echo、print、print_r、var_dump 区别
-
-> `echo`和`print`是语言结构、`print_r`和`var_dump`是普通函数
-
-- echo:输出一个或多个字符串
-
-- print:输出字符串
-
-- print_r:打印关于变量的易于理解的信息
-
-- var_dump:打印关于变量的易于理解的信息(带类型)
-
-拓展阅读 [《echo、print、print_r、var_dump区别》](./03.echo、print、print_r、var_dump区别.md)
-
-### 单引号和双引号的区别
-
-双引号可以被分析器解析,单引号则不行
-
-### isset 和 empty 的区别
-
-isset:检测变量是否已设置并且非 NULL
-
-empty:判断变量是否为空,变量为 0/false 也会被认为是空;变量不存在,不会产生警告
-
-### static、self、$this 的区别
-
-static:static 可以用于静态或非静态方法中,也可以访问类的静态属性、静态方法、常量和非静态方法,但不能访问非静态属性
-
-self:可以用于访问类的静态属性、静态方法和常量,但 self 指向的是当前定义所在的类,这是 self 的限制
-
-$this:指向的是实际调用时的对象,也就是说,实际运行过程中,谁调用了类的属性或方法,$this 指向的就是哪个对象。但 $this 不能访问类的静态属性和常量,且 $this 不能存在于静态方法中
-
-### include、require、include_once、require_once 的区别
-
-require 和 include 几乎完全一样,除了处理失败的方式不同之外。require 在出错时产生 E_COMPILE_ERROR 级别的错误。换句话说将导致脚本中止而 include 只产生警告(E_WARNING),脚本会继续运行
-
-include_once 语句在脚本执行期间包含并运行指定文件。此行为和 include 语句类似,唯一区别是如果该文件中已经被包含过,则不会再次包含。如同此语句名字暗示的那样,只会包含一次
-
-### 常见数组函数
-
-array_count_values — 统计数组中所有的值
-
-array_flip — 交换数组中的键和值
-
-array_merge — 合并一个或多个数组
-
-array_multisort — 对多个数组或多维数组进行排序
-
-array_pad — 以指定长度将一个值填充进数组
-
-array_pop — 弹出数组最后一个单元(出栈)
-
-array_push — 将一个或多个单元压入数组的末尾(入栈)
-
-array_rand — 从数组中随机(伪随机)取出一个或多个单元
-
-array_keys — 返回数组中部分的或所有的键名
-
-array_values — 返回数组中所有的值
-
-count — 计算数组中的单元数目,或对象中的属性个数
-
-sort — 对数组排序
-
-### Cookie 和 Session
-
-Cookie:PHP 透明的支持 HTTP cookie 。cookie 是一种远程浏览器端存储数据并以此来跟踪和识别用户的机制
-
-Session:会话机制(Session)在 PHP 中用于保持用户连续访问Web应用时的相关数据
-
-### 预定义变量
-
-对于全部脚本而言,PHP 提供了大量的预定义变量
-
-超全局变量 — 超全局变量是在全部作用域中始终可用的内置变量
-
-```text
-$GLOBALS — 引用全局作用域中可用的全部变量
-$_SERVER — 服务器和执行环境信息
-$_GET — HTTP GET 变量
-$_POST — HTTP POST 变量
-$_FILES — HTTP 文件上传变量
-$_REQUEST — HTTP Request 变量
-$_SESSION — Session 变量
-$_ENV — 环境变量
-$_COOKIE — HTTP Cookies
-$php_errormsg — 前一个错误信息
-$HTTP_RAW_POST_DATA — 原生POST数据
-$http_response_header — HTTP 响应头
-$argc — 传递给脚本的参数数目
-$argv — 传递给脚本的参数数组
-```
-
-- 超全局变量
-
-PHP 中的许多预定义变量都是“超全局的”,这意味着它们在一个脚本的全部作用域中都可用。在函数或方法中无需执行 global $variable; 就可以访问它们
-
-超全局变量:$GLOBALS、$\_SERVER、$\_GET、$\_POST、$\_FILES、$\_COOKIE、$\_SESSION、$\_REQUEST、$\_ENV
-
-### 传值和传引用的区别
-
-传值导致对象生成了一个拷贝,传引用则可以用两个变量指向同一个内容
-
-### 构造函数和析构函数
-
-构造函数:PHP 5 允行开发者在一个类中定义一个方法作为构造函数。具有构造函数的类会在每次创建新对象时先调用此方法,所以非常适合在使用对象之前做一些初始化工作
-
-析构函数:PHP 5 引入了析构函数的概念,这类似于其它面向对象的语言,如 C++。析构函数会在到某个对象的所有引用都被删除或者当对象被显式销毁时执行
-
-### 魔术方法
-
-\_\_construct(), \_\_destruct(), \_\_call(), \_\_callStatic(), \_\_get(), \_\_set(), \_\_isset(), \_\_unset(), \_\_sleep(), \_\_wakeup(), \_\_toString(), \_\_invoke() 等方法在 PHP 中被称为"魔术方法"(Magic methods)
-
-### public、protected、private、final 区别
-
-对属性或方法的访问控制,是通过在前面添加关键字 public(公有),protected(受保护)或 private(私有)来实现的。被定义为公有的类成员可以在任何地方被访问
-
-PHP 5 新增了一个 final 关键字。如果父类中的方法被声明为 final,则子类无法覆盖该方法。如果一个类被声明为 final,则不能被继承
-
-### 客户端/服务端 IP 获取,了解代理透传 实际IP 的概念
-
-客户端IP: $\_SERVER['REMOTE_ADDR']
-
-服务端IP: $\_SERVER['SERVER_ADDR']
-
-客户端IP(代理透传): $\_SERVER['HTTP_X_FORWARDED_FOR']
-
-### 类的静态调用和实例化调用
-
-- 占用内存
-
-静态方法在内存中只有一份,无论调用多少次,都是共用的
-
-实例化不一样,每一个实例化是一个对象,在内存中是多个的
-
-- 不同点
-
-静态调用不需要实例化即可调用
-
-静态方法不能调用非静态属性,因为非静态属性需要实例化后,存放在对象里
-
-静态方法可以调用非静态方法,使用 self 关键字。php 里,一个方法被 `self::` 后,自动转变为静态方法
-
-调用类的静态函数时不会自动调用类的构造函数
-
-### PHP 不实例化调用方法
-
-静态调用、使用 PHP 反射方式
-
-### php.ini 配置选项
-
-- 配置选项
-
-|名字|默认|备注|
-|-|-|-|
-|short_open_tag|"1"|是否开启缩写形式(` ?>`)|
-|precision|"14"|浮点数中显示有效数字的位数|
-|disable_functions|""|禁止某些函数|
-|disable_classes|""|禁用某些类|
-|expose_php|""|是否暴露 PHP 被安装在服务器上|
-|max_execution_time|30|最大执行时间|
-|memory_limit|128M|每个脚本执行的内存限制|
-|error_reporting|NULL|设置错误报告的级别 `E_ALL` & ~`E_NOTICE` & ~`E_STRICT` & ~`E_DEPRECATED`|
-|display_errors|"1"|显示错误|
-|log_errors|"0"|设置是否将错误日志记录到 error_log 中|
-|error_log|NULL|设置脚本错误将被记录到的文件|
-|upload_max_filesize|"2M"|最大上传文件大小|
-|post_max_size|"8M"|设置POST最大数据限制|
-
-```shell
-php -ini | grep short_open_tag //查看 php.ini 配置
-```
-
-- 动态设置
-
-```php
-ini_set(string $varname , string $newvalue);
-
-ini_set('date.timezone', 'Asia/Shanghai'); //设置时区
-ini_set('display_errors', '1'); //设置显示错误
-ini_set('memory_limit', '256M'); //设置最大内存限制
-```
-
-### php-fpm.conf 配置
-
-|名称|默认|备注|
-|-|-|-|
-|pid||PID文件的位置|
-|error_log||错误日志的位置|
-|log_level|notice|错误级别 alert:必须立即处理、error:错误情况、warning:警告情况、notice:一般重要信息、debug:调试信息|
-|daemonize|yes|设置 FPM 在后台运行|
-|listen|ip:port、port、/path/to/unix/socket|设置接受 FastCGI 请求的地址|
-|pm|static、ondemand、dynamic|设置进程管理器如何管理子进程|
-|request_slowlog_timeout|'0'|慢日志记录阀值|
-|slowlog||慢请求的记录日志|
-
-### 502、504 错误产生原因及解决方式
-
-#### 502
-
-502 表示网关错误,当 PHP-CGI 得到一个无效响应,网关就会输出这个错误
-
-- `php.ini` 的 memory_limit 过小
-- `php-fpm.conf` 中 max_children、max_requests 设置不合理
-- `php-fpm.conf` 中 request_terminate_timeout、max_execution_time 设置不合理
-- php-fpm 进程处理不过来,进程数不足、脚本存在性能问题
-
-#### 504
-
-504 表示网关超时,PHP-CGI 没有在指定时间响应请求,网关将输出这个错误
-
-- Nginx+PHP 架构,可以调整 FastCGI 超时时间,fastcgi_connect_timeout、fastcgi_send_timeout、fastcgi_read_timeout
-
-#### 500
-
-php 代码问题,文件权限问题,资源问题
-
-#### 503
-
-超载或者停机维护
-
-### 如何返回一个301重定向
-
-```php
-header('HTTP/1.1 301 Moved Permanently');
-header('Location: https://blog.maplemark.cn');
-```
-
-### PHP 与 MySQL 连接方式
-
-#### MySQL
-
-```php
-$conn = mysql_connect('127.0.0.1:3306', 'root', '123456');
-if (!$conn) {
- die(mysql_error() . "\n");
-}
-mysql_query("SET NAMES 'utf8'");
-$select_db = mysql_select_db('app');
-if (!$select_db) {
- die(mysql_error() . "\n");
-}
-$sql = "SELECT * FROM `user` LIMIT 1";
-$res = mysql_query($sql);
-if (!$res) {
- die(mysql_error() . "\n");
-}
-while ($row = mysql_fetch_assoc($res)) {
- var_dump($row);
-}
-mysql_close($conn);
-```
-
-#### MySQLi
-
-```php
-$conn = @new mysqli('127.0.0.1:3306', 'root', '123456');
-if ($conn->connect_errno) {
- die($conn->connect_error . "\n");
-}
-$conn->query("set names 'utf8';");
-$select_db = $conn->select_db('user');
-if (!$select_db) {
- die($conn->error . "\n");
-}
-$sql = "SELECT * FROM `user` LIMIT 1";
-$res = $conn->query($sql);
-if (!$res) {
- die($conn->error . "\n");
-}
-while ($row = $res->fetch_assoc()) {
- var_dump($row);
-}
-$res->free();
-$conn->close();
-```
-
-#### PDO
-
-```php
-$pdo = new PDO('mysql:host=127.0.0.1:3306;dbname=user', 'root', '123456');
-$pdo->exec("set names 'utf8'");
-$sql = "SELECT * FROM `user` LIMIT 1";
-$stmt = $pdo->prepare($sql);
-$stmt->bindValue(1, 1, PDO::PARAM_STR);
-$rs = $stmt->execute();
-if ($rs) {
- while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
- var_dump($row);
- }
-}
-$pdo = null;
-```
-
-### MySQL、MySQLi、PDO 区别
-
-#### MySQL
-
-- 允许 PHP 应用与 MySQL 数据库交互的早期扩展
-- 提供了一个面向过程的接口,不支持后期的一些特性
-
-#### MySQLi
-
-- 面向对象接口
-- prepared 语句支持
-- 多语句执行支持
-- 事务支持
-- 增强的调试能力
-
-#### PDO
-
-- PHP 应用中的一个数据库抽象层规范
-- PDO 提供一个统一的 API 接口,无须关心数据库类型
-- 使用标准的 PDO API,可以快速无缝切换数据库
-
-### 数据库持久连接
-
-把 PHP 用作多进程 web 服务器的一个模块,这种方法目前只适用于 Apache。
-
-对于一个多进程的服务器,其典型特征是有一个父进程和一组子进程协调运行,其中实际生成 web 页面的是子进程。每当客户端向父进程提出请求时,该请求会被传递给还没有被其它的客户端请求占用的子进程。这也就是说当相同的客户端第二次向服务端提出请求时,它将有可能被一个不同的子进程来处理。在开启了一个持久连接后,所有请求 SQL 服务的后继页面都能够重用这个已经建立的 SQL Server 连接。
-
-### 代码执行过程
-
-PHP 代码 => 启动 php 及 zend 引擎,加载注册拓展模块 => 对代码进行词法/语法分析 => 编译成opcode(opcache) => 执行 opcode
-
-> PHP7 新增了抽象语法树(AST),在语法分析阶段生成 AST,然后再生成 opcode 数组
-
-### base64 编码原理
-
-
-
-### ip2long 实现
-
-
-
-### MVC 的理解
-
-MVC 包括三类对象。模型 Model 是应用对象,视图 View 是它在屏幕上的表示,控制器 Controller 定义用户界面对用户输入的响应方式。不使用 MVC,用户界面设计往往将这些对象混在一起,而 MVC 则将它们分离以提高灵活性和复用性
-
-### 主流 PHP 框架特点
-
-#### Laravel
-
-易于访问,功能强大,并提供大型,强大的应用程序所需的工具
-
-- 简单快速的路由引擎
-- 强大的依赖注入容器
-- 富有表现力,直观的数据库 ORM
-- 提供数据库迁移功能
-- 灵活的任务调度器
-- 实时事件广播
-
-#### Symfony
-
-- Database engine-independent
-- Simple to use, in most cases, but still flexible enough to adapt to complex cases
-- Based on the premise of convention over configuration--the developer needs to configure only the unconventional
-- Compliant with most web best practices and design patterns
-- Enterprise-ready--adaptable to existing information technology (IT) policies and architectures, and stable enough for long-term projects
-- Very readable code, with phpDocumentor comments, for easy maintenance
-- Easy to extend, allowing for integration with other vendor libraries
-
-#### CodeIgniter
-
-- 基于模型-视图-控制器的系统
-- 框架比较轻量
-- 全功能数据库类,支持多个平台
-- Query Builder 数据库支持
-- 表单和数据验证
-- 安全性和 XSS 过滤
-- 全页面缓存
-
-#### ThinkPHP
-
-- 采用容器统一管理对象
-- 支持 Facade
-- 更易用的路由
-- 注解路由支持
-- 路由跨域请求支持
-- 验证类增强
-- 配置和路由目录独立
-- 取消系统常量
-- 类库别名机制
-- 模型和数据库增强
-- 依赖注入完善
-- 支持 PSR-3 日志规范
-- 中间件支持
-- 支持 Swoole/Workerman 运行
-
-### 对象关系映射/ORM
-
-#### 优点
-
-- 缩短编码时间、减少甚至免除对 model 的编码,降低数据库学习成本
-- 动态的数据表映射,在表结构发生改变时,减少代码修改
-- 可以很方便的引入附加功能(cache 层)
-
-#### 缺点
-
-- 映射消耗性能、ORM 对象消耗内存
-- SQL 语句较为复杂时,ORM 语法可读性不高(使用原生 SQL)
-
-### 链式调用实现
-
-类定义一个内置变量,让类中其他定义方法可访问到
-
-### 异常处理
-
-set_exception_handler — 设置用户自定义的异常处理函数
-
-使用 try / catch 捕获
-
-### 如何实现异步调用
-
-```php
-$fp = fsockopen("blog.maplemark.cn", 80, $errno, $errstr, 30);
-if (!$fp) {
- echo "$errstr ($errno)
\n";
-} else {
- $out = "GET /backend.php / HTTP/1.1\r\n";
- $out .= "Host: blog.maplemark.cn\r\n";
- $out .= "Connection: Close\r\n\r\n";
- fwrite($fp, $out);
- /*忽略执行结果
- while (!feof($fp)) {
- echo fgets($fp, 128);
- }*/
- fclose($fp);
-}
-```
-
-### 多进程同时写一个文件
-
-加锁、队列
-
-### PHP 进程模型,进程通讯方式,进程线程区别
-
-消息队列、socket、信号量、共享内存、信号、管道
-
-### PHP 支持回调的函数,实现一个
-
-array_map、array_filter、array_walk、usort
-
-is_callable + callbacks + 匿名函数实现
-
-### 发起 HTTP 请求有哪几种方式,它们有何区别
-
-cURL、file_get_contents、fopen、fsockopen
-
-### php for while foreach 迭代数组时候,哪个效率最高
-
-### 弱类型变量如何实现
-
-PHP 中声明的变量,在 zend 引擎中都是用结构体 zval 来保存,通过共同体实现弱类型变量声明
-
-### PHP 拓展初始化
-
-- 初始化拓展
-
-```shell
-$ php /php-src/ext/ext_skel.php --ext
-```
-
-- 定义拓展函数
-
-zend_module_entry 定义 Extension name 编写 PHP_FUNCTION 函数
-
-- 编译安装
-
-```shell
-$ phpize $ ./configure $ make && make install
-```
-
-### 如何获取扩展安装路径
-
-### 垃圾回收机制
-
-引用计数器
-
-### Trait
-
-自 PHP 5.4.0 起,PHP 实现了一种代码复用的方法,称为 trait
-
-### yield 是什么,说个使用场景 yield、yield 核心原理是什么
-
-一个生成器函数看起来像一个普通的函数,不同的是普通函数返回一个值,而一个生成器可以yield生成许多它所需要的值
-
-### traits 与 interfaces 区别 及 traits 解决了什么痛点
-
-### 如何 foreach 迭代对象、如何数组化操作对象 $obj[key]、如何函数化对象 $obj(123);
-
-### Swoole 适用场景,协程实现方式
-
-那你知道swoole的进程模型
-
-### PHP 数组底层实现 (HashTable + Linked list)
-
-### Copy on write 原理,何时 GC
-
-### 如何解决 PHP 内存溢出问题
-
-### ZVAL
-
-### HashTable
-
-### PHP7 新特性
-
-标量类型声明、返回值类型声明、通过 define() 定义常量数组、匿名类、相同命名空间类一次性导入
-
-### PHP7 底层优化
-
-ZVAL 结构体优化,占用由24字节降低为16字节
-
-内部类型 zend_string,结构体成员变量采用 char 数组,不是用 char*
-
-PHP 数组实现由 hashtable 变为 zend array
-
-函数调用机制,改进函数调用机制,通过优化参数传递环节,减少了一些指令
-
-### PSR 介绍,PSR-1, 2, 4, 7
-
-### Xhprof 、Xdebug 性能调试工具使用
-
-### 字符串、数字比较大小的原理,注意 0 开头的8进制、0x 开头16进制
-
-### BOM 头是什么,怎么除去
-
-### 模板引擎是什么,解决什么问题、实现原理(Smarty、Twig、Blade)
\ No newline at end of file
+# 问题与简答
+
+## PHP 篇
+
+### static、self、$this 的区别
+
+static:static 可以用于静态或非静态方法中,也可以访问类的静态属性、静态方法、常量和非静态方法,但不能访问非静态属性
+
+self:可以用于访问类的静态属性、静态方法和常量,但 self 指向的是当前定义所在的类,这是 self 的限制
+
+$this:指向的是实际调用时的对象,也就是说,实际运行过程中,谁调用了类的属性或方法,$this 指向的就是哪个对象。但 $this 不能访问类的静态属性和常量,且 $this 不能存在于静态方法中
+
+### include、require、include_once、require_once 的区别
+
+require 和 include 几乎完全一样,除了处理失败的方式不同之外。require 在出错时产生 E_COMPILE_ERROR 级别的错误。换句话说将导致脚本中止而 include 只产生警告(E_WARNING),脚本会继续运行
+
+include_once 语句在脚本执行期间包含并运行指定文件。此行为和 include 语句类似,唯一区别是如果该文件中已经被包含过,则不会再次包含。如同此语句名字暗示的那样,只会包含一次
+
+### 常见数组函数
+
+array_count_values — 统计数组中所有的值
+
+array_flip — 交换数组中的键和值
+
+array_merge — 合并一个或多个数组
+
+array_multisort — 对多个数组或多维数组进行排序
+
+array_pad — 以指定长度将一个值填充进数组
+
+array_pop — 弹出数组最后一个单元(出栈)
+
+array_push — 将一个或多个单元压入数组的末尾(入栈)
+
+array_rand — 从数组中随机(伪随机)取出一个或多个单元
+
+array_keys — 返回数组中部分的或所有的键名
+
+array_values — 返回数组中所有的值
+
+count — 计算数组中的单元数目,或对象中的属性个数
+
+sort — 对数组排序
+
+### Cookie 和 Session
+
+Cookie:PHP 透明的支持 HTTP cookie 。cookie 是一种远程浏览器端存储数据并以此来跟踪和识别用户的机制
+
+Session:会话机制(Session)在 PHP 中用于保持用户连续访问Web应用时的相关数据
+
+### 预定义变量
+
+对于全部脚本而言,PHP 提供了大量的预定义变量
+
+超全局变量 — 超全局变量是在全部作用域中始终可用的内置变量
+
+```text
+$GLOBALS — 引用全局作用域中可用的全部变量
+$_SERVER — 服务器和执行环境信息
+$_GET — HTTP GET 变量
+$_POST — HTTP POST 变量
+$_FILES — HTTP 文件上传变量
+$_REQUEST — HTTP Request 变量
+$_SESSION — Session 变量
+$_ENV — 环境变量
+$_COOKIE — HTTP Cookies
+$php_errormsg — 前一个错误信息
+$HTTP_RAW_POST_DATA — 原生POST数据
+$http_response_header — HTTP 响应头
+$argc — 传递给脚本的参数数目
+$argv — 传递给脚本的参数数组
+```
+
+- 超全局变量
+
+PHP 中的许多预定义变量都是“超全局的”,这意味着它们在一个脚本的全部作用域中都可用。在函数或方法中无需执行 global $variable; 就可以访问它们
+
+超全局变量:$GLOBALS、$\_SERVER、$\_GET、$\_POST、$\_FILES、$\_COOKIE、$\_SESSION、$\_REQUEST、$\_ENV
+
+### 传值和传引用的区别
+
+传值导致对象生成了一个拷贝,传引用则可以用两个变量指向同一个内容
+
+### 构造函数和析构函数
+
+构造函数:PHP 5 允行开发者在一个类中定义一个方法作为构造函数。具有构造函数的类会在每次创建新对象时先调用此方法,所以非常适合在使用对象之前做一些初始化工作
+
+析构函数:PHP 5 引入了析构函数的概念,这类似于其它面向对象的语言,如 C++。析构函数会在到某个对象的所有引用都被删除或者当对象被显式销毁时执行
+
+### 魔术方法
+
+\_\_construct(), \_\_destruct(), \_\_call(), \_\_callStatic(), \_\_get(), \_\_set(), \_\_isset(), \_\_unset(), \_\_sleep(), \_\_wakeup(), \_\_toString(), \_\_invoke() 等方法在 PHP 中被称为"魔术方法"(Magic methods)
+
+### public、protected、private、final 区别
+
+对属性或方法的访问控制,是通过在前面添加关键字 public(公有),protected(受保护)或 private(私有)来实现的。被定义为公有的类成员可以在任何地方被访问
+
+PHP 5 新增了一个 final 关键字。如果父类中的方法被声明为 final,则子类无法覆盖该方法。如果一个类被声明为 final,则不能被继承
+
+### 客户端/服务端 IP 获取,了解代理透传 实际IP 的概念
+
+客户端IP: $\_SERVER['REMOTE_ADDR']
+
+服务端IP: $\_SERVER['SERVER_ADDR']
+
+客户端IP(代理透传): $\_SERVER['HTTP_X_FORWARDED_FOR']
+
+### 类的静态调用和实例化调用
+
+- 占用内存
+
+静态方法在内存中只有一份,无论调用多少次,都是共用的
+
+实例化不一样,每一个实例化是一个对象,在内存中是多个的
+
+- 不同点
+
+静态调用不需要实例化即可调用
+
+静态方法不能调用非静态属性,因为非静态属性需要实例化后,存放在对象里
+
+静态方法可以调用非静态方法,使用 self 关键字。php 里,一个方法被 `self::` 后,自动转变为静态方法
+
+调用类的静态函数时不会自动调用类的构造函数
+
+### 接口和抽象的区别
+抽象用于描述不同的事物,接口用于描述事物的行为。
+
+### PHP 不实例化调用方法
+
+静态调用、使用 PHP 反射方式
+
+### php.ini 配置选项
+
+- 配置选项
+
+|名字|默认|备注|
+|-|-|-|
+|short_open_tag|"1"|是否开启缩写形式(` ?>`)|
+|precision|"14"|浮点数中显示有效数字的位数|
+|disable_functions|""|禁止某些函数|
+|disable_classes|""|禁用某些类|
+|expose_php|""|是否暴露 PHP 被安装在服务器上|
+|max_execution_time|30|最大执行时间|
+|memory_limit|128M|每个脚本执行的内存限制|
+|error_reporting|NULL|设置错误报告的级别 `E_ALL` & ~`E_NOTICE` & ~`E_STRICT` & ~`E_DEPRECATED`|
+|display_errors|"1"|显示错误|
+|log_errors|"0"|设置是否将错误日志记录到 error_log 中|
+|error_log|NULL|设置脚本错误将被记录到的文件|
+|upload_max_filesize|"2M"|最大上传文件大小|
+|post_max_size|"8M"|设置POST最大数据限制|
+
+```shell
+php -ini | grep short_open_tag //查看 php.ini 配置
+```
+
+- 动态设置
+
+```php
+ini_set(string $varname , string $newvalue);
+
+ini_set('date.timezone', 'Asia/Shanghai'); //设置时区
+ini_set('display_errors', '1'); //设置显示错误
+ini_set('memory_limit', '256M'); //设置最大内存限制
+```
+
+### php-fpm.conf 配置
+
+|名称|默认|备注|
+|-|-|-|
+|pid||PID文件的位置|
+|error_log||错误日志的位置|
+|log_level|notice|错误级别 alert:必须立即处理、error:错误情况、warning:警告情况、notice:一般重要信息、debug:调试信息|
+|daemonize|yes|设置 FPM 在后台运行|
+|listen|ip:port、port、/path/to/unix/socket|设置接受 FastCGI 请求的地址|
+|pm|static、ondemand、dynamic|设置进程管理器如何管理子进程|
+|request_slowlog_timeout|'0'|慢日志记录阀值|
+|slowlog||慢请求的记录日志|
+
+### 502、504 错误产生原因及解决方式
+
+#### 502
+
+502 表示网关错误,当 PHP-CGI 得到一个无效响应,网关就会输出这个错误
+
+- `php.ini` 的 memory_limit 过小
+- `php-fpm.conf` 中 max_children、max_requests 设置不合理
+- `php-fpm.conf` 中 request_terminate_timeout、max_execution_time 设置不合理
+- php-fpm 进程处理不过来,进程数不足、脚本存在性能问题
+
+#### 504
+
+504 表示网关超时,PHP-CGI 没有在指定时间响应请求,网关将输出这个错误
+
+- Nginx+PHP 架构,可以调整 FastCGI 超时时间,fastcgi_connect_timeout、fastcgi_send_timeout、fastcgi_read_timeout
+
+#### 500
+
+php 代码问题,文件权限问题,资源问题
+
+#### 503
+
+超载或者停机维护
+
+### 如何返回一个301重定向
+
+```php
+header('HTTP/1.1 301 Moved Permanently');
+header('Location: https://blog.maplemark.cn');
+```
+
+### PHP 与 MySQL 连接方式
+
+#### MySQL
+
+```php
+$conn = mysql_connect('127.0.0.1:3306', 'root', '123456');
+if (!$conn) {
+ die(mysql_error() . "\n");
+}
+mysql_query("SET NAMES 'utf8'");
+$select_db = mysql_select_db('app');
+if (!$select_db) {
+ die(mysql_error() . "\n");
+}
+$sql = "SELECT * FROM `user` LIMIT 1";
+$res = mysql_query($sql);
+if (!$res) {
+ die(mysql_error() . "\n");
+}
+while ($row = mysql_fetch_assoc($res)) {
+ var_dump($row);
+}
+mysql_close($conn);
+```
+
+#### MySQLi
+
+```php
+$conn = @new mysqli('127.0.0.1:3306', 'root', '123456');
+if ($conn->connect_errno) {
+ die($conn->connect_error . "\n");
+}
+$conn->query("set names 'utf8';");
+$select_db = $conn->select_db('user');
+if (!$select_db) {
+ die($conn->error . "\n");
+}
+$sql = "SELECT * FROM `user` LIMIT 1";
+$res = $conn->query($sql);
+if (!$res) {
+ die($conn->error . "\n");
+}
+while ($row = $res->fetch_assoc()) {
+ var_dump($row);
+}
+$res->free();
+$conn->close();
+```
+
+#### PDO
+
+```php
+$pdo = new PDO('mysql:host=127.0.0.1:3306;dbname=user', 'root', '123456');
+$pdo->exec("set names 'utf8'");
+$sql = "SELECT * FROM `user` LIMIT 1";
+$stmt = $pdo->prepare($sql);
+$stmt->bindValue(1, 1, PDO::PARAM_STR);
+$rs = $stmt->execute();
+if ($rs) {
+ while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
+ var_dump($row);
+ }
+}
+$pdo = null;
+```
+
+### MySQL、MySQLi、PDO 区别
+
+#### MySQL
+
+- 允许 PHP 应用与 MySQL 数据库交互的早期扩展
+- 提供了一个面向过程的接口,不支持后期的一些特性
+
+#### MySQLi
+
+- 面向对象接口
+- prepared 语句支持
+- 多语句执行支持
+- 事务支持
+- 增强的调试能力
+
+#### PDO
+
+- PHP 应用中的一个数据库抽象层规范
+- PDO 提供一个统一的 API 接口,无须关心数据库类型
+- 使用标准的 PDO API,可以快速无缝切换数据库
+
+### 数据库持久连接
+
+把 PHP 用作多进程 web 服务器的一个模块,这种方法目前只适用于 Apache。
+
+对于一个多进程的服务器,其典型特征是有一个父进程和一组子进程协调运行,其中实际生成 web 页面的是子进程。每当客户端向父进程提出请求时,该请求会被传递给还没有被其它的客户端请求占用的子进程。这也就是说当相同的客户端第二次向服务端提出请求时,它将有可能被一个不同的子进程来处理。在开启了一个持久连接后,所有请求 SQL 服务的后继页面都能够重用这个已经建立的 SQL Server 连接。
+
+### 代码执行过程
+
+PHP 代码 => 启动 php 及 zend 引擎,加载注册拓展模块 => 对代码进行词法/语法分析 => 编译成opcode(opcache) => 执行 opcode
+
+> PHP7 新增了抽象语法树(AST),在语法分析阶段生成 AST,然后再生成 opcode 数组
+
+### base64 编码原理
+
+
+
+### ip2long 实现
+
+
+
+
+```
+124.205.30.150=2093817494
+
+list($p1,$p2,$p3,$p4) = explode('.','124.205.30.150');
+
+$realNum = ($p1<<24)+($p2<<16)+($p3<<8)+$p4;
+```
+
+### MVC 的理解
+
+MVC 包括三类对象。模型 Model 是应用对象,视图 View 是它在屏幕上的表示,控制器 Controller 定义用户界面对用户输入的响应方式。不使用 MVC,用户界面设计往往将这些对象混在一起,而 MVC 则将它们分离以提高灵活性和复用性
+
+### 主流 PHP 框架特点
+
+#### Laravel
+
+易于访问,功能强大,并提供大型,强大的应用程序所需的工具
+
+- 简单快速的路由引擎
+- 强大的依赖注入容器
+- 富有表现力,直观的数据库 ORM
+- 提供数据库迁移功能
+- 灵活的任务调度器
+- 实时事件广播
+
+#### Symfony
+
+- Database engine-independent
+- Simple to use, in most cases, but still flexible enough to adapt to complex cases
+- Based on the premise of convention over configuration--the developer needs to configure only the unconventional
+- Compliant with most web best practices and design patterns
+- Enterprise-ready--adaptable to existing information technology (IT) policies and architectures, and stable enough for long-term projects
+- Very readable code, with phpDocumentor comments, for easy maintenance
+- Easy to extend, allowing for integration with other vendor libraries
+
+#### CodeIgniter
+
+- 基于模型-视图-控制器的系统
+- 框架比较轻量
+- 全功能数据库类,支持多个平台
+- Query Builder 数据库支持
+- 表单和数据验证
+- 安全性和 XSS 过滤
+- 全页面缓存
+
+#### ThinkPHP
+
+- 采用容器统一管理对象
+- 支持 Facade
+- 更易用的路由
+- 注解路由支持
+- 路由跨域请求支持
+- 验证类增强
+- 配置和路由目录独立
+- 取消系统常量
+- 类库别名机制
+- 模型和数据库增强
+- 依赖注入完善
+- 支持 PSR-3 日志规范
+- 中间件支持
+- 支持 Swoole/Workerman 运行
+
+### 对象关系映射/ORM
+
+#### 优点
+
+- 缩短编码时间、减少甚至免除对 model 的编码,降低数据库学习成本
+- 动态的数据表映射,在表结构发生改变时,减少代码修改
+- 可以很方便的引入附加功能(cache 层)
+
+#### 缺点
+
+- 映射消耗性能、ORM 对象消耗内存
+- SQL 语句较为复杂时,ORM 语法可读性不高(使用原生 SQL)
+
+### 链式调用实现
+
+类定义一个内置变量,让类中其他定义方法可访问到
+
+### 异常处理
+
+set_exception_handler — 设置用户自定义的异常处理函数
+
+使用 try / catch 捕获
+
+### 串行、并行、并发的区别
+串行:执行多个任务时,各个任务按顺序执行,完成一个之后才能进行下一个
+并行:多个任务在同一时刻执行
+并发:同一时刻需要执行多个任务
+
+### 同步与异步的理解
+**同步和异步是一种消息通信机制**。其关注点在于 `被调用者返回` 和 `结果返回` 之间的关系,描述对象是被调用对象的行为。
+
+### 阻塞与非阻塞的理解
+**阻塞和非阻塞是一种业务流程处理方式**。其关注点在于调用发生时 `调用者状态` 和 `被调用者返回结果` 之间的关系,描述对象是等待结果时候调用者的状态。
+
+### 同步阻塞与非同步阻塞的理解
+同步阻塞:打电话问老板有没有某书(调用),老板说查一下,让你别挂电话(同步),你一直等待老板给你结果,什么事也不做(阻塞)。
+
+同步非阻塞:打电话问老板有没有某书(调用),老板说查一下,让你别挂电话(同步),等电话的过程中你还一边嗑瓜子(非阻塞)。
+
+### 异步阻塞与异步非阻塞的理解
+异步阻塞:打电话问老板有没有某书(调用),老板说你先挂电话,有了结果通知你(异步),你挂了电话后(结束调用), 除了等老板电话通知结果,什么事情也不做(阻塞)。
+
+异步非阻塞:打电话问老板有没有某书(调用),老板说你先挂电话,有了结果通知你(异步),你挂电话后(结束调用),一遍等电话,一遍嗑瓜子。(非阻塞)
+
+### 如何实现异步调用
+
+```php
+$fp = fsockopen("blog.maplemark.cn", 80, $errno, $errstr, 30);
+if (!$fp) {
+ echo "$errstr ($errno)
\n";
+} else {
+ $out = "GET /backend.php / HTTP/1.1\r\n";
+ $out .= "Host: blog.maplemark.cn\r\n";
+ $out .= "Connection: Close\r\n\r\n";
+ fwrite($fp, $out);
+ /*忽略执行结果
+ while (!feof($fp)) {
+ echo fgets($fp, 128);
+ }*/
+ fclose($fp);
+}
+```
+
+### 多进程同时写一个文件
+
+加锁、队列
+
+### PHP 进程模型,进程通讯方式,进程线程区别
+
+消息队列、socket、信号量、共享内存、信号、管道
+
+### PHP 支持回调的函数,实现一个
+
+array_map、array_filter、array_walk、usort
+
+is_callable + callbacks + 匿名函数实现
+
+### 发起 HTTP 请求有哪几种方式,它们有何区别
+
+cURL、file_get_contents、fopen、fsockopen
+
+### php for while foreach 迭代数组时候,哪个效率最高
+
+### 弱类型变量如何实现
+
+PHP 中声明的变量,在 zend 引擎中都是用结构体 zval 来保存,通过共同体实现弱类型变量声明
+
+### PHP 拓展初始化
+
+- 初始化拓展
+
+```shell
+$ php /php-src/ext/ext_skel.php --ext
+```
+
+- 定义拓展函数
+
+zend_module_entry 定义 Extension name 编写 PHP_FUNCTION 函数
+
+- 编译安装
+
+```shell
+$ phpize $ ./configure $ make && make install
+```
+
+### 如何获取扩展安装路径
+
+### 垃圾回收机制
+
+引用计数器
+
+### Trait
+
+自 PHP 5.4.0 起,PHP 实现了一种代码复用的方法,称为 trait
+
+### yield 是什么,说个使用场景 yield、yield 核心原理是什么
+
+一个生成器函数看起来像一个普通的函数,不同的是普通函数返回一个值,而一个生成器可以yield生成许多它所需要的值。
+
+yield核心原理: PHP在使用生成器的时候,会返回一个Generator类的对象。每一次迭代,PHP会通过Generator实例计算出下一次需要迭代的值。简述即yield用于生成值。
+
+yield使用场景:读取大文件、大量计算。
+
+yield好处:节省内存、优化性能
+
+### traits 与 interfaces 区别 及 traits 解决了什么痛点
+
+### 如何 foreach 迭代对象、如何数组化操作对象 $obj[key]、如何函数化对象 $obj(123);
+
+### Swoole 适用场景,协程实现方式
+
+Swoole 是一个使用 C++ 语言编写的基于异步事件驱动和协程的并行网络通信引擎,为 PHP 提供协程、高性能网络编程支持。提供了多种通信协议的网络服务器和客户端模块,可以方便快速的实现 TCP/UDP服务、高性能Web、WebSocket服务、物联网、实时通讯、游戏、微服务等,使 PHP 不再局限于传统的 Web 领域。
+
+
+协程可以简单理解为线程,只不过这个线程是用户态的,不需要操作系统参与,创建销毁和切换的成本非常低,和线程不同的是协程没法利用多核 cpu 的,想利用多核 cpu 需要依赖 Swoole 的多进程模型。
+在底层实现上是单线程的,因此同一时间只有一个协程在工作,协程的执行是串行的。
+采用 CSP 编程模型,即不要以共享内存的方式来通信,相反,要通过通信来共享内存。
+swoole4.0采用双栈方式,通过栈桢切换来实现协程;即遇到IO等待就切换到。
+
+#### swoole的进程模型
+
+同一台主机上两个进程间通信 (简称 IPC) 的方式有很多种,在 Swoole 中使用了 2 种方式 Unix Socket 和 sysvmsg。
+
+swoole启动后会生成master进程、reactor线程、worker进程、task进程以及manager进程
+
+master进程是一个多线程进程,会生成多个reactor线程
+reactor线程负载网络监听、数据收发
+work进程处理reactor线程投递的请求数据
+task进程处理work进程投递的任务
+manager进程用于管理work进程和task进程
+
+### PHP 数组底层实现 (HashTable + Linked list)
+
+PHP 数组底层依赖的散列表数据结构,定义如下(位于 Zend/zend_types.h)。
+
+数据存储在一个散列表中,通过中间层来保存索引与实际存储在散列表中位置的映射。
+
+由于哈希函数会存在哈希冲突的可能,因此对冲突的值采用链表来保存。
+
+哈希表的查询效率是o(1),链表查询效率是o(n);因此PHP数据索引速度很快;但是相对比较占用空间。
+
+### Copy on write 原理,何时 GC
+
+### 如何解决 PHP 内存溢出问题
+
+### ZVAL
+
+### HashTable
+
+### PHP7 新特性
+
+标量类型声明、返回值类型声明、通过 define() 定义常量数组、匿名类、相同命名空间类一次性导入
+
+### PHP7 底层优化
+
+ZVAL 结构体优化,占用由24字节降低为16字节
+
+内部类型 zend_string,结构体成员变量采用 char 数组,不是用 char*
+
+PHP 数组实现由 hashtable 变为 zend array
+
+函数调用机制,改进函数调用机制,通过优化参数传递环节,减少了一些指令
+
+### PSR 介绍,PSR-1, 2, 4, 7
+
+### Xhprof 、Xdebug 性能调试工具使用
+
+### 字符串、数字比较大小的原理,注意 0 开头的8进制、0x 开头16进制
+
+### BOM 头是什么,怎么除去
+
+WINDOWS自带的记事本,在保存一个以 UTF-8 编码的文件时,会在文件开始的地方插入三个不可见的字符(0xEF 0xBB 0xBF,即BOM);它是一串隐藏的字符,用于让记事本等编辑器识别这个文件是否以UTF-8编码。
+去除方法:$result = trim($result, "\xEF\xBB\xBF");
+
+### 模板引擎是什么,解决什么问题、实现原理(Smarty、Twig、Blade)
+
+
+### 写一个函数,尽可能高效的从一个标准 URL 中取出文件的扩展名
+parse_str,explode
diff --git a/docs/03.PHP/assets/php-ip2long.png b/docs/03.PHP/assets/php-ip2long.png
index eaf06aa..981b6f3 100644
Binary files a/docs/03.PHP/assets/php-ip2long.png and b/docs/03.PHP/assets/php-ip2long.png differ
diff --git a/docs/05.MySQL/QA.md b/docs/05.MySQL/QA.md
index d1c6bfa..dda3a87 100644
--- a/docs/05.MySQL/QA.md
+++ b/docs/05.MySQL/QA.md
@@ -120,19 +120,31 @@ SELECT FORMAT(2.7895, 2); #2.79
多个查询需要在同一时刻修改数据,会产生并发控制的问题。使用锁可以有效解决这个问题
+#### 乐观锁与悲观锁
+
+我们都知道锁的种类一般分为乐观锁和悲观锁两种,InnoDB 存储引擎中使用的就是悲观锁,而按照锁的粒度划分,也可以分成行锁和表锁。
+
+- 乐观锁是一种思想,它其实并不是一种真正的『锁』,它会先尝试对资源进行修改,在写回时判断资源是否进行了改变,如果没有发生改变就会写回,否则就会进行重试,在整个的执行过程中其实都没有对数据库进行加锁;
+- 悲观锁就是一种真正的锁了,它会在获取资源前对资源进行加锁,确保同一时刻只有有限的线程能够访问该资源,其他想要尝试获取资源的操作都会进入等待状态,直到该线程完成了对资源的操作并且释放了锁后,其他线程才能重新操作资源;
+
+虽然乐观锁和悲观锁在本质上并不是同一种东西,一个是一种思想,另一个是一种真正的锁,但是它们都是一种并发控制机制。
+
+
+
+乐观锁不会存在死锁的问题,但是由于更新后验证,所以当冲突频率和重试成本较高时更推荐使用悲观锁,而需要非常高的响应速度并且并发量非常大的时候使用乐观锁就能较好的解决问题,在这时使用悲观锁就可能出现严重的性能问题;在选择并发控制机制时,需要综合考虑上面的四个方面(冲突频率、重试成本、响应速度和并发量)进行选择。
+
#### 读写锁
-- 共享锁:同一时刻可以同时读取同一个资源
-- 排他锁:一个写锁会阻塞其他的写锁和读锁
+- 共享锁(读锁):允许事务对一条行数据进行读取;
+- 互斥锁(写锁,也叫排他锁):允许事务对一条行数据进行删除或更新;
#### 锁粒度
- 表锁:开销最小,对表进行写操作,需要获得写锁,会阻塞该表的所有读写操作
- 行级锁:最大锁开销,可以最大程度地支持并发处理
-#### 乐观锁
+拓展阅读 [《『浅入浅出』MySQL 和 InnoDB》](https://draveness.me/mysql-innodb/)
-#### 悲观锁
### 事务
@@ -182,7 +194,7 @@ MySQL 默认采用自动提交(AUTOCOMMIT)模式,每个查询都当作一个
#### MyISAM
- 不支持事务和行级锁,崩溃后无法安全恢复,表锁非常影响性能
-- MyISAM 对整张表加锁,而不是针对行。读取时对需要读到的表加共享锁,写入则加排它锁。在表有读取查询的同事,也可以插入新记录(支持并发插入)
+- MyISAM 对整张表加锁,而不是针对行。读取时对需要读到的表加共享锁,写入则加排它锁。在表有读取查询的同时,也可以插入新记录(支持并发插入)
- 支持延迟更新索引健,极大的提升写入性能
- 支持全文索引,可以支持复杂的查询
- MyISAM 将表存储在两个文件中,数据文件和索引文件
@@ -273,4 +285,11 @@ MySQL 单表容量在`500万`左右,性能处于最佳状态,此时,MySQL
### my.cnf 配置
-### 慢查询
\ No newline at end of file
+### 慢查询
+
+
+### 优化 MYSQL 的方法
+- 数据超过一定数量或者体积,请拆分表,垂直或者水平分
+- 务必有自增主键。通过自增主键来查数据是最快的。
+- 常用的查询字段建立联合索引,写 SQL 一定要尊从最左原则,用到这个索引。
+- 不要把逻辑运算放到 sql 里
diff --git a/docs/05.MySQL/assets/Optimistic-Pessimistic-Locks.jpg b/docs/05.MySQL/assets/Optimistic-Pessimistic-Locks.jpg
new file mode 100644
index 0000000..6cfff4a
Binary files /dev/null and b/docs/05.MySQL/assets/Optimistic-Pessimistic-Locks.jpg differ
diff --git a/docs/06.Redis/QA.md b/docs/06.Redis/QA.md
index 6cf04b5..09d2222 100644
--- a/docs/06.Redis/QA.md
+++ b/docs/06.Redis/QA.md
@@ -40,7 +40,7 @@ Redis 是一个高性能的 key-value 数据库。每秒可执行操作高达 10
### 持久化策略
-#### 快照持久化
+#### 快照持久化 RDB
将某一时刻的所有数据写入硬盘。使用`BGSAVE`命令,随着内存使用量的增加,执行 BGSAVE 可能会导致系统长时间地停顿
@@ -190,6 +190,15 @@ Redis 是基于内存的操作,CPU 不是 Redis 的瓶颈,Redis 瓶颈最有
|ZREM|遍历压缩列表,删除所有包含给定成员的节点,以及被删除成员节点旁边的分值节点|遍历跳跃表,删除所有包含了给定成员的跳跃表节点。并在字典中解除被删除元素的成员和分值关联|
|ZSCORE|遍历压缩列表,查找包含了给定成员的节点,然后取出成员节点旁边的分值节点保存的元素分值|直接从字典中取出给定成员的分值|
+
+### redis 跳跃表
+
+跳跃表(skiplist)是一种有序数据结构,它通过在每个节点中维持多个指向其他节点的指针,从而达到快速访问节点的目的。
+
+跳跃表支持平均O(logN)、最坏O(N)复杂度的节点查找,还可以通过顺序性操作来批量处理节点。
+
+在大部分情况下,跳跃表的效率可以和平衡树相媲美,并且因为跳跃表的实现比平衡树要来得更为简单,所以有不少程序都使用跳跃表来代替平衡树。
+
### redis.conf 配置
### 慢查询
\ No newline at end of file
diff --git a/docs/07.Linux/QA.md b/docs/07.Linux/QA.md
index 91966fc..314f37f 100644
--- a/docs/07.Linux/QA.md
+++ b/docs/07.Linux/QA.md
@@ -148,20 +148,43 @@ X 个 CPU 的电脑,可接受的系统负荷最大为 `X.0` 。将`15分钟`
### Linux 内存管理
+### 函数
+malloc分配虚拟内存
+mmap虚拟内存映射方法
+hugepage虚拟内存映射方法,分配2MB或1GB
+#### 虚拟内存
+
+一种实现在计算机软硬件之间的内存管理技术,将程序使用到的内存地址映射到计算机内存中的物理地址
+32位虚拟内存大小为0-4g,一个内存也默认大小为4kb
+
+##### 优点
+提高内存安全性
+
+##### 特点
+每个进程都有它自己的虚拟内存
+虚拟内存的大小取决于系统的体系结构
+
### 进程、线程、协程区别
#### 进程
-进程是一个程序在一个数据集中的一次动态执行过程,可以简单理解为“正在执行的程序”,它是CPU 资源分配和调度的独立单位
-
+是一个动态概念;由程序、数据和进程控制块组成。系统进行资源分配、调度和管理的最小单位。
#### 线程
-线程是在进程之后发展出来的概念。 线程也叫轻量级进程,它是一个基本的 CPU 执行单元,也是程序执行过程中的最小单元,由线程 ID、程序计数器、寄存器集合和堆栈共同组成。一个进程可以包含多个线程
+是进程的活动成分,是处理器分配资源的最小单位;可以共享进程的资源与地址空间。
#### 协程
协程是一种用户态的轻量级线程,又称微线程,英文名 Coroutine,协程的调度完全由用户控制
+
+#### 并发执行机制
+
+把一个处理器划分为若干个短的时间片,每个时间片依次轮流地执行处理各个应用程序,由于一个时间片很短,相对于一个应用程序来说,就好像是处理器在为自己单独服务一样,从而达到多个应用程序在同时进行的效果。
+#### 多线程原理
+
+多线程就是把操作系统中的这种并发执行机制原理运用在一个程序中,把一个程序划分为若干个子任务,多个子任务并发执行,每一个任务就是一个线程
+
### 进程间通信与信号机制
#### 通信方式
diff --git a/docs/interview.png b/docs/assets/interview.png
similarity index 100%
rename from docs/interview.png
rename to docs/assets/interview.png
diff --git a/docs/assets/qr.png b/docs/assets/qr.png
new file mode 100644
index 0000000..3c36ff7
Binary files /dev/null and b/docs/assets/qr.png differ
diff --git a/docs/assets/questionnaire.jpeg b/docs/assets/questionnaire.jpeg
new file mode 100644
index 0000000..dde0fad
Binary files /dev/null and b/docs/assets/questionnaire.jpeg differ
diff --git a/docs/wechat.jpg b/docs/assets/wechat.jpg
similarity index 100%
rename from docs/wechat.jpg
rename to docs/assets/wechat.jpg
diff --git a/docs/php/FastCGI-Process-Manager.md b/docs/php/FastCGI-Process-Manager.md
new file mode 100644
index 0000000..b68dcb3
--- /dev/null
+++ b/docs/php/FastCGI-Process-Manager.md
@@ -0,0 +1 @@
+# FastCGI Process Manager
\ No newline at end of file
diff --git "a/docs/php/assets/\345\233\2761-\345\207\275\346\225\260\346\257\224\350\276\203.png" "b/docs/php/assets/\345\233\2761-\345\207\275\346\225\260\346\257\224\350\276\203.png"
new file mode 100644
index 0000000..ec86115
Binary files /dev/null and "b/docs/php/assets/\345\233\2761-\345\207\275\346\225\260\346\257\224\350\276\203.png" differ
diff --git "a/docs/php/assets/\345\233\2762-\346\235\276\346\225\243\346\257\224\350\276\203.png" "b/docs/php/assets/\345\233\2762-\346\235\276\346\225\243\346\257\224\350\276\203.png"
new file mode 100644
index 0000000..a75a658
Binary files /dev/null and "b/docs/php/assets/\345\233\2762-\346\235\276\346\225\243\346\257\224\350\276\203.png" differ
diff --git "a/docs/php/assets/\345\233\2763-\344\270\245\346\240\274\346\257\224\350\276\203.png" "b/docs/php/assets/\345\233\2763-\344\270\245\346\240\274\346\257\224\350\276\203.png"
new file mode 100644
index 0000000..692c208
Binary files /dev/null and "b/docs/php/assets/\345\233\2763-\344\270\245\346\240\274\346\257\224\350\276\203.png" differ
diff --git "a/docs/php/composer\345\214\205\345\215\207\347\272\247.md" "b/docs/php/composer\345\214\205\345\215\207\347\272\247.md"
new file mode 100644
index 0000000..bac5a65
--- /dev/null
+++ "b/docs/php/composer\345\214\205\345\215\207\347\272\247.md"
@@ -0,0 +1,110 @@
+# composer 包升级
+
+本文从 composer 包升级任务,引出 composer 包生产环境升级技巧。全文共计 2429 字,阅读时间约 10 分钟, 作者:凌枫。如果文章对你有帮助,请关注和转发,谢谢!
+
+## 一、把 composer 包升级下版本
+
+温馨提示:以下故事纯属虚构,如有雷同纯属巧合。
+
+### 1、无尽临时任务
+
+临近下班,刚想起身喝口水,突然弹出条消息。连忙跑去领导工位, xxx 包准备要升级下。心里想着,这玩意两周前不是刚升级过呢?这周必须上线,有点急,你看下怎么搞,领导强调。你还想再多问几句。我还有个会议,你先测试环境升级观察下,领导打断,表情异常严肃。
+
+回到工位,拿着口杯去打水,心里不停的犯嘀咕。手上一共还有 4 个任务在同时跟进,排期也是满满的,而领导只是交代这周上线,也没说我手上任务怎么办,难道这个包升级又要开发自测吗?马上到年底了,已经忙活了一整年。这时候水溢出来了。
+
+### 2、毫无意义的工作
+
+半小时后,独自一人踏进那家难以下咽的快餐店。吃完后,特意多沿着公司周围多绕了一圈,肚中的米饭和怨气似乎都消化掉了。回到工位,办公室已经没几个人了,自从降本增效后,爱加班的人几乎都消失了。
+
+打开本地终端,敲下熟练的命令行。进入本地 PHP7.x 容器,指定要升级的 composer 包,升级到了 1.2.4 版本。对比了本次更新的 1.2.4 版本,和上次 1.2.3 版本,差异点也就是把包依赖的网络配置文件从 A 域名换到 B 域名。看到这,心里莫名的谩骂:**某些人的 KPI 调优,却要自己来买单,对他们来说或许只是 1 个简单变更,但是对自己来说却要升级 5 个系统和走 1 次发布流程。**
+
+```bash
+$ docker exec -it php72-for-dev sh // 进入php 7.x 容器
+$ composer require "xxx/xxx: 1.2.4" -W // 升级到指定版本
+$ composer dump-autoload -o // 更新优化
+```
+
+**知识点1:进入 PHP 7.x 容器命令解释。**exec 是一个 docker 命令,用于在正在运行的容器中的执行命令。-i(--interactive) 参数指保持标准输入打开,允许向容器发送命令。-t(--tty)参数指分配一个伪终端,使容器内的 shell 能够以友好的交互模式运行。php72-for-dev 指一个正在运行的目标容器名称或者 ID。sh 指要在容器内执行的命令,这里指启动一个 shell 环境。
+
+**知识点2:升级到指定版本命令解释。**require 是 composer 子命令,用于添加依赖包。xxx/xxx: 1.2.4 指要安装的包名为 xxx/xxx,版本为精确 1.2.4,加引号确保命令行正确解析。-W(--with-all-dependencies)指 composer 在执行更新时候,若遇到依赖包和项目中现有包不兼容,可以更全面的尝试解决这些冲突,而不是直接报错中止。
+
+**知识点3:更新优化命令行解释。**dump-autoload 是一个用于优化 composer 自动加载性能的命令。不带 -o 为默认模式,依赖 PSR-4 / PSR-0 规则的动态查找,最终会生成 autoload\_psr4.php 等基于命名空间映射的文件,在运行时候需要按目录结构逐级查找文件有 I/O 开销,性能较低一般使用场景在开发环境。而带 -o 为优化模式,会预生成完整的类映射表,最终会生成 autolaod\_classmap.php 等包含类命与文件路径的对应关系,在运行时候直接通过数组键命查找路径而避免文件 I/O 开销,性能较高一般适合在生产环境部署。
+
+### 3、独自扛下了所有
+
+自测验证通过。按照对项目的熟悉度,挑选了几个适合的场景,抓了几个测试环境的请求,简单构造后,验证均通过。这里或许你有疑问,改动这么小,也需要自测吗?嗯嗯,大厂嘛,作业规范嘛。代码就绪后,发布前置准备流程也都准备就绪,一切就绪就准备火箭发射(生产发布)了。
+
+惊心动魄的上线。周五晚上,办公室依然是静悄悄的。心想,改动这么小,肯定也没什么问题,而且测试环境也跑了几天了。抱着侥幸的想法,发布就奔着快的方式,直接梭哈了。紧接着,短信、电话、领导问询等等纷纷来了。职业敏感度让我意识到大事不妙,根据报警及查看大盘二次确认后,条件反射般选择了发布回滚。回滚后,监控指标纷纷回落,紧接着定位原因,原来是网络不通:B 域名出现大量调用失败。于是找运维给域名 B 加白,心里再次默念:看来又是被选中吃螃蟹的那个人。
+
+无尽追问及复盘总结。当晚,手忙脚乱的把问题处理完,同时还要面对一堆人的追问。他们也一样会收到报警信息,他们在意的是饭碗,和上一级的问询应付,而并不在意你的实际感受。第二天,你还要被拉进另外一堆人,对这件事情的溯源,假设你不够机智,最后事故责任人可能还是你。
+
+温馨提示:以上故事纯属虚构,如有雷同纯属巧合。
+
+## 二、composer 简单介绍
+
+### 1、简单介绍
+
+composer 是什么呢?composer本意是:a person who writes music, especially as a professional occupation. 当然它不是用来艺术创作的。官网是这样介绍的:A Dependency Manager for PHP,简而言之就是:一个为 PHP 而生的依赖管理工具。
+
+相信绝大部分 PHP 开发者都使用过,那你有了解过它到底是怎么运行起来的吗?让我们一起来一探究竟。
+
+### 2、使用演示
+
+参照下列目录结构,进行 composer 项目初始化。先创建一个 composer.json 文件,再使用 composer install 命令进行安装,接着就可以在 index.php 中引入了。
+
+```shell
+.
+├── composer.json // 手动创建
+├── composer.lock
+├── index.php // 手动创建
+└── vendor
+```
+
+```json
+{
+ // composer.json 文件
+ "require": {
+ "monolog/monolog": "2.0.2"
+ },
+ "autoload": {
+ "psr-4": {
+ "Acme\\": "src/"
+ }
+ }
+}
+```
+
+```php
+// index.php 文件
+require __DIR__ . '/vendor/autoload.php';
+
+use Monolog\Logger;
+use Monolog\Handler\StreamHandler;
+
+// create a log channel
+$log = new Logger('name');
+$log->pushHandler(new StreamHandler('app.log', Logger::WARNING));
+
+// add records to the log
+$log->warning('Foo');
+$log->error('Bar');
+```
+
+紧接着,你执行 index.php 文件后,可以看到目录下生成了 app.log 文件,里面有 2 行日志。
+
+### 3、安装和运行
+
+在运行 composer install,会读取 composer.json 配置中的 require 字段,然后从默认的包仓库 packagist 上查找 monolog/monolog,并下载其 2.0.2 版本及其所有依赖项到项目的 vendor 目录。而 composer.json 中的另一项配置 autoload 则定义配置自动加载规则,使用 PSR-4 标准,将项目中的 PHP 类文件与命名空间进行映射,实现自动加载,无须手动 include 文件。
+
+在运行时,先假定已经执行过 composer dump-autoload -o 命令。首先,先通过 vendor/autoload.php 引导文件将 composer 引导类(CompoerAutoloaderInit....:getLoader())载入;再实例化自动加载的核心类;最后通过 spl\_autoload\_register 函数将加载方法注册到 PHP 的 SPL 自动加载队列中;在实例化类时候,加载器会按照预设的优先级策略去寻找类文件。
+
+## 三、生产实践经验
+
+在升级 composer 包时候,你必须清楚意识到,这个操作在应用层面是无法回滚的。意味着出问题了,你没办法快速恢复,肯定要影响生产的。如果你的应用无法接受不可用时间,甚至无法经受产生错误报警。那么你必须做好一下准备。
+
+永远不要当第一个吃螃蟹的人。除非你的包提供方,可以百分百承担责任,而且白纸黑字保证。除此之外,你永远不要当第一个吃螃蟹的人。
+
+可随时降级回退。既然无法在应用层回滚,那么我们可以考虑在运维层做好降级回退。即不要发全部机器,而是选择性发少量机器,把影响面控制在可以接受的程度,再逐步放量,这样可以用时间换空间。
+
+**如果文章对你有帮助,请关注和转发,谢谢!**
+
diff --git "a/docs/php/isset\345\222\214empty\347\232\204\345\214\272\345\210\253\344\271\213\345\246\202\344\275\225\345\210\244\347\251\272.md" "b/docs/php/isset\345\222\214empty\347\232\204\345\214\272\345\210\253\344\271\213\345\246\202\344\275\225\345\210\244\347\251\272.md"
new file mode 100644
index 0000000..9262403
--- /dev/null
+++ "b/docs/php/isset\345\222\214empty\347\232\204\345\214\272\345\210\253\344\271\213\345\246\202\344\275\225\345\210\244\347\251\272.md"
@@ -0,0 +1,108 @@
+# isset 和 empty 的区别之如何判空
+
+本文从 isset 和 empty 的区别,引出常见的类型如何判空方式,帮你梳理清楚开发中常见的判空误区。全文共计 1724 字,阅读时间约 8 分钟,作者:凌枫。如果文章对你有帮助,请关注和转发,谢谢!
+
+## 一、isset 和 empty 的区别
+
+### 1、是否声明 vs 是否设置
+
+我们先来看一下在 PHP 语境下,变量的是否声明与是否设置的区别。变量是声明在指的是变量是否创建,是否在当前作用域内诞生,当你尝试使用一个未被声明的变量时,PHP 会抛出一个 E\_NOTICE 级别的错误(如:undefined variable)。变量是否设置指的是变量已经声明好了并且值不为 null,首先满足变量已创建,而且在当前作用域诞生,值有两种情况,非 null 和 null。
+
+```php
+// 是否存在:key1 存在
+// 是否存在:key3 不存在
+// 是否设置:key1 已设置
+// 是否设置:key2 未设置
+$arr = ['key1' => '凌枫', 'key2' => null];
+```
+
+### 2、isset 与 empty 的区别
+
+isset 是用于检测变量是否已声明php并且其值不为 null。isset 可以一次传入多个参数,只有在全部参数都已被设置时返回 true,计算过程为从左往右,中途遇到未设置的变量就会即可停止。
+
+empty 是用于检查变量是否为空,如果变量不存在或者其值等于 false ,则认为变量为空。empty 不会在变量不存在时产生告警。
+
+```php
+$a; // isset($a)返回false empty($a)返回true
+$b = ''; // true true
+$b1 = '凌枫'; // true false
+$c = null; // false true
+$d = 0; // true true
+$d1 = 1; // true false
+$e = new stdClass(); // true true
+$f = []; // true true
+$f1 = ['凌枫']; // true false
+```
+
+## 二、PHP 的判空机制
+
+### 1、松散的类型系统
+
+造成编程中判空操作异常复杂都源于 PHP 的松散类型系统。这里我们暂不讨论松散的类型系统的优缺点。PHP 是一种弱类型编程语言,这意味着变量在声明时不需要预定义数据类型,并且可以在运行中根据上下文自动转换类型。我们可以看到这样的写法,前一刻变量还是整型类型,后一刻还是这个变量就变成字符类型。在某些情况下空数组、空字符串和 null 值似乎可以互通。而这些看似奇怪的特性,都源自 PHP 自身的松散的类型系统,进而导致增加了判空操作的复杂性。
+
+### 2、动态变量解析机制
+
+在判空操作中清楚的知道要检查的变量。动态变量解析机制是另一个体现 PHP 灵活的动态特性,同样也增加了代码的复杂性。在判空操作中,必须清楚的知道要检查的是哪个变量,以及变量名如何动态确定。当 PHP 解析器遇到 \$$name 时,执行操作顺序:首先获取 $name 的值,再将该值视为变量名去查找对应变量 $username,最终返回这个变量的值。
+
+```php
+$name = 'username';
+$username = '凌枫';
+echo $$name; // 输出: 凌枫
+echo $username; // 二者等价
+$nums = [1, 2, 3];
+echo "$number[1]"; // 输出:2
+echo "{$number[1]}"; // 输出:2
+```
+
+### 3、类型转换规则
+
+理解 PHP 的类型转换规则是掌握判空的基础。在 PHP 中,主要有两种类型转换方式:自动类型转换和强制类型转换。自动类型转换由 PHP 引擎在运行时根据上下文自动完成,即不同类型的值一起运算时,PHP 会自动将它们转换为统一的类型。强制类型转换指允许开发者显式的控制转换过程,包括类型转换语法、类型转换函数、settype 函数三种方式。
+
+```php
+// 自动转换
+$number = 1 + "0"; // 输出:1,字符串“0”转为整数0
+$number1 = 1 + "0abc"; // 输出:1,提取数字部分“0”
+$number2 = 1 + "abc0"; // 输出:1,字符串开头无数字转为0
+// 强制转换
+$str = "0abc";
+$number = (int)$str; // 输出:0
+$number1 = floatval($str); // 输出:0
+$number2 = settype($str, 'int'); // $str 现在是整数0
+```
+
+## 三、更多判空方式
+
+### 1、空有哪些形式
+
+这里我们先来看一下空有哪些形式。通过前面介绍,已经知道变量会经历以下过程:变量声明、变量赋值、变量使用;在变量声明时候可以知道变量类型,虽然在后续过程中变量类型并不是固定的;在变量使用中,又会发生变量动态解析和变量类型转换。
+
+所以,空会包括变量未声明和变量已声明;而已变量已声明又包括这些空:null、空字符、整型0、布尔 false、空数组、空对象。
+
+### 2、易错判空
+
+未声明、null、空字符、空白字符、整型0、布尔 false、空数组、空对象都会被认为满足 empty 条件。
+
+使用松散比较(==)替代严格比较(===),导致 0==null 返回 true 误判类型。
+
+混淆 empty($arr\['key']) 和 isset($arr\['key']) 语义。
+
+### 3、类型比较表
+
+以下表格清晰的显示在 PHP 中不同方式的比较差异,包括函数方式、松散比较、严格比较。
+
+
+
+
+
+
+
+## 四、总结概要
+
+通过本文的探讨,我们可以清晰地看到 PHP 判空操作背后的复杂性和重要性。常见的 isset()和 empty() 判空函数,看似相同实际上却又本质区别,但它们有着本质的区别。
+
+PHP 的松散类型系统和动态变量解析机制使得判空操作需要格外谨慎。类型自动转换规则虽然提供了便利,但也带来了潜在的风险。判空的最终目的是为业务逻辑服务,而非机械地套用函数。
+
+理解 PHP 的类型系统和转换规则,结合实际需求做出明智的判空决策,将帮助你编写出更加健壮、可靠的 PHP 代码。
+
+如果文章对你有帮助,请关注和转发,谢谢!
+
diff --git "a/docs/php/php\346\224\257\346\214\201\345\223\252\344\272\233\346\263\250\351\207\212\351\243\216\346\240\274.md" "b/docs/php/php\346\224\257\346\214\201\345\223\252\344\272\233\346\263\250\351\207\212\351\243\216\346\240\274.md"
new file mode 100644
index 0000000..8e5e2b7
--- /dev/null
+++ "b/docs/php/php\346\224\257\346\214\201\345\223\252\344\272\233\346\263\250\351\207\212\351\243\216\346\240\274.md"
@@ -0,0 +1 @@
+# php支持哪些注释风格
\ No newline at end of file
diff --git "a/docs/php/\344\270\200\346\235\241echo\350\276\223\345\207\272\350\257\255\345\217\245\346\230\257\345\246\202\344\275\225\346\211\247\350\241\214\347\232\204.md" "b/docs/php/\344\270\200\346\235\241echo\350\276\223\345\207\272\350\257\255\345\217\245\346\230\257\345\246\202\344\275\225\346\211\247\350\241\214\347\232\204.md"
new file mode 100644
index 0000000..20cd775
--- /dev/null
+++ "b/docs/php/\344\270\200\346\235\241echo\350\276\223\345\207\272\350\257\255\345\217\245\346\230\257\345\246\202\344\275\225\346\211\247\350\241\214\347\232\204.md"
@@ -0,0 +1,7 @@
+# 一条echo输出语句是如何执行的
+
+```php
+echo "Hello World!";
+```
+
+请简述在浏览器输入地址,到页面输出`Hello World!`,其中发生了什么?
\ No newline at end of file
diff --git "a/docs/php/\345\215\225\345\274\225\345\217\267\345\222\214\345\217\214\345\274\225\345\217\267\347\232\204\345\214\272\345\210\253.md" "b/docs/php/\345\215\225\345\274\225\345\217\267\345\222\214\345\217\214\345\274\225\345\217\267\347\232\204\345\214\272\345\210\253.md"
new file mode 100644
index 0000000..c39020d
--- /dev/null
+++ "b/docs/php/\345\215\225\345\274\225\345\217\267\345\222\214\345\217\214\345\274\225\345\217\267\347\232\204\345\214\272\345\210\253.md"
@@ -0,0 +1,60 @@
+# 单引号和双引号的区别
+
+本文主要从工程实践和语言设计层面的角度,介绍单引号和双引号的区别。全文共计 1757 字,作者:凌枫。如果文章对你有帮助,请关注和转发,谢谢!
+
+## 一、最主要区别
+
+### 1、初步印象
+
+当被问到单引号和双引号的区别,几乎本能反应都是,它们看起来都是一样的,难道真有什么区别?非要说有区别,难道就是语法习惯,最初我也是这样认为的。
+
+### 2、最核心差异
+
+单引号是“静态”的,双引号是“动态”的,一切差异均源于此。从 PHP 语言内部机制来看,则源于完全不同的编译和执行路径。在词法分析器识别过程中,单引号会被当做普通字符串值原样处理,双引号需要逐个扫描字符串,动态识别多种元素。
+
+## 二、内部处理机制差异
+
+我们接着从 PHP 语言特性,特别是其内部 Zend 引擎(Zend Engine)的角度来分析单引号和双引号字符串的处理机制。一般按执行顺序,会分为编译阶段和执行阶段。
+
+### 1、编译阶段
+
+在 PHP 代码运行时,首先会被 Zend Engine 的编译器转换成 Zend 操作码(OPCodes),这是 PHP 内部的一种中间代码。不管是单引号还是双引号编译后的操作码都会被 OPCache 缓存,因此在编译阶段的差异会被消除掉。单引号和双引号字符编译阶段对整体执行效率的影响不大。
+
+单引号字符会被 Zend 引擎视为一个简单的常量字符串,简单地收集引号内的所有字符。词法分析器将其内容原样存储,几乎无需额外的处理。
+
+双引号字符则会被 Zend 引擎识别为复杂的字符串,需要进行逐个扫描,词法分析器会识别片段为哪种元素,到底是普通字符、转义字符、变量标记,再采用不同的方式存储。所以双引号字符串最终不是作为一个整体存储,而是分解为一个包含多种类型 tokens 的序列。比如:字符串 "hello,$world\n"会被分解为,字符片段:"hello,"、变量:$world、换行符片段。
+
+### 2、执行阶段
+
+在 PHP 代码在执行阶段,操作码都是由 Zend Executor 执行。单引号字符串的执行,简单地从常量池中取出字符串并输出,这是一个极其快速的内存查找操作,没有额外的计算开销。
+
+双引号字符串的执行,需要按顺序计算序列的每一部分。字符串片段,可以直接使用;变量则需要进入当前符号表查找变量,这是一个哈希操作,比直接取常量更慢。再将所有内容连接成一个新字符串,这里会涉及到内存分配和字符串拷贝操作。最终输出拼接好的字符串整体。
+
+双引号字符串在运行时需要进行变量查找、值获取和字符串拼接等步骤,这些步骤都需要消耗 CPU 周期和内存资源。而单引号字符串则可以省去这些步骤。
+
+## 三、具体不同 case 最佳实践
+
+### 1、实践共识
+
+一般默认使用单引号。从性能层面上看,单引号性能优于双引号,原因是双引号需要额外的词法分析和运行时拼接开销,而在绝大多数应用场景下,性能差异几乎可忽略不计。选择原因不应将性能作为首要决策因素,代码的可读性和可维护性明显更重要。
+
+### 2、单引号优先 case
+
+从 PHP 内部机制看,可以清晰看到单引号字符串优势主要在运行时的查找和拼接开销,在现代 PHP 版本中,由于 Zend 引擎和 OPCache 的广泛应用,这种差异在绝大多数实际应用中变得微乎其微,执行中无法感知。唯一特例是在处理海量循环(如:百万次迭代)时,遵循“使用单引号除非你需要双引号的功能”这一原则仍然是最佳实践。
+
+### 3、双引号优先case
+
+想要动态拼接字符串,使用双引号是更佳选择。我们的考虑因素,主要是代码的可读性和可维护性。
+
+```php
+$message = 'key1:' . $value1 . ' key2:' . $value2 . ' key3:' . $value3 . '\n'; // 可读性稍差
+$message = "key1:{$value1} key2:{$value2} key3:{$value3}\n"; // 可读性更佳
+$message = spintf("key1:%s key2:%s key3:%s\n", $value1, $value2, $value2); // 可读性最佳,非本文讨论内容
+```
+
+## 四、总结概要
+
+回顾全文,我们可以清晰地认识到,在 PHP 中单引号与双引号的选择,并非谁优谁劣。在现代 PHP 开发中,性能常常不是决策的主导因素,最佳实践是意图清晰,能够让代码阅读者秒懂:这里是一个无需变化的字符串,还是需要动态生成的字符串,这才是至关重要的。
+
+如果文章对你有帮助,请关注和转发,谢谢!
+
diff --git "a/docs/php/\345\260\206\345\217\230\351\207\217\346\211\223\345\215\260\345\207\272\346\235\245\344\275\240\347\237\245\351\201\223\345\223\252\344\272\233\346\226\271\345\274\217.md" "b/docs/php/\345\260\206\345\217\230\351\207\217\346\211\223\345\215\260\345\207\272\346\235\245\344\275\240\347\237\245\351\201\223\345\223\252\344\272\233\346\226\271\345\274\217.md"
new file mode 100644
index 0000000..27c658e
--- /dev/null
+++ "b/docs/php/\345\260\206\345\217\230\351\207\217\346\211\223\345\215\260\345\207\272\346\235\245\344\275\240\347\237\245\351\201\223\345\223\252\344\272\233\346\226\271\345\274\217.md"
@@ -0,0 +1,131 @@
+# 将变量打印出来,你知道哪些方式?
+
+> 本文主要从 PHP 输出的角度,系统的介绍常见的变量打印方式。你肯定都见过,但是肯定没有系统总结过。全文共计 2533 字,作者:凌枫。如果文章对你有帮助,请关注和转发,谢谢!
+
+## 一、关键字输出语句
+
+### 1、echo 关键字
+
+PHP 中最常见、最高效的输出语句。echo 不是函数,而是语言结构,可以不使用括号。可以输出一个或多个参数,没有额外的换行符或者空格。echo 没有返回值,因此不能在表达式的上下文中使用。
+
+### 2、print 关键字
+
+print 同样不是函数,而是语言结构。可以输出一个字符串,并始终返回 1,因此可用于表达式。和 echo 最主要的区别是 print 仅接受一个参数。效率略低于 echo。
+
+```php
+print 'hello';
+if ($expr && print 'foo') {} // 可用于表达式
+$result = print 'hello'; // 输出hello,且$result的值为1
+echo $result; // 输出1
+```
+
+### 3、echo 和 print 如何选择
+
+绝大多数情况下使用 echo,因为它相对更灵活,可一次输出多个参数,且速度极微地快一点。只有在需要利用其返回值 1 的极特殊场景下,如:作为三元运算符的一部分,才会使用 print,这时候若换成 echo 则会报错。
+
+```php
+$isHello = true;
+$result = $isHello ? print 'hello' : print 'world'; // 使用print作为三元运算符的一部分
+echo "\n result: $result"; // 输出 hello result: 1
+```
+
+## 二、调试输出函数
+
+### 1、print_r()函数
+
+以人类易读的形式打印显示变量的信息。对于字符串、整数等简单类型,会直接输出值。对于数组和对象,会以缩进的格式显示其键和值,层次结构非常清晰。第二的可选参数设置为 true,则会将结果作为字符串返回,而不直接输出,常常用在处理响应体或者日志。
+
+在命中行终端(CLI)和网页浏览器之间的差异。首先 print\_r 函数本身在这两种模式下是完全一致的,而命令行似乎被格式化好了,而网页浏览器却没有格式化,二者差异主要在于网页浏览器是一个 HTML 渲染引擎。所以在浏览器下需要通过 echo 提前输出\并在 print\_r 之前。
+
+```php
+$arr = ['a', 'b', 'c'];
+echo ''; // 网页浏览器需要加上这个
+print_r($arr);
+// print_r($arr, true); // 无输出,直接返回
+// 输出结果
+Array
+(
+ [0] => a
+ [1] => b
+ [2] => c
+)
+```
+
+### 2、var_dump()函数
+
+PHP 中功能最强大的调试函数。用于输出一个或多个表达式的结构信息,包括表达式的类型和长度及值,对于数组或对象将递归按层级展开所有元素,并通过缩进显示其结构。没有返回选项,总是直接输出,如果结构特别复杂输出的信息会特别长。
+
+```php
+$age = 24;
+$people = 'phper';
+$arr = ['a', 'b', 'c'];
+echo '';
+var_dump($age, $people, $arr);
+// 输出结果
+int(24)
+string(5) "phper"
+array(3) {
+ [0]=>
+ string(1) "a"
+ [1]=>
+ string(1) "b"
+ [2]=>
+ string(1) "c"
+}
+```
+
+### 3、var\_export()函数
+
+输出或返回变量的可解析字符串表示。其输出是合法的 PHP 代码,可以直接复制到程序中使用。第二个参数为 true 时,会返回字符串而不是直接输出,这个特性使其非常适合用于缓存或序列化数据。
+
+```php
+$arr = ['a', 'b', 'c'];
+var_export($arr);
+// 输出结果
+array (
+ 0 => 'a',
+ 1 => 'b',
+ 2 => 'c',
+)
+```
+
+## 三、特殊输出场景
+
+### 1、printf() 和 sprintf()
+
+二者均用于格式化字符串输出。printf 会直接输出,sprintf 不会直接输出。sprintf 常常用于按顺序用参数替换格式字符串的占位符,简单理解 sprintf 里面第一个包含的相当于一个模板,可以非常直观的看到最终的效果。
+
+```php
+$name = '凌枫';
+$age = 24;
+printf("name:%s age:%d", $name, $age); // 输出 name:凌枫 age:24
+echo sprintf("name:%s age:%d", $name, $age); // 输出 name:凌枫 age:24
+$message = sprintf("my name is %s and i am %d years old", $name, $age); // 直观看到最终效果
+```
+
+### 2、JSON 输出方式
+
+一般在 Web 服务器可以看到。这种方式并非直接进行内容输出,而是先在输出主体内容之前,先告诉浏览器要输出的内容是 JSON 数据,再进行 JSON 编码,紧接着才输出内容本身。
+
+```php
+header('Content-Type: application/json');
+echo json_encode(['success' => true]);
+exit;
+```
+
+## 四、总结和对比
+
+综上所述,要将变量打印出来,上面一共列举了 8 种,分四大类:关键字、输出函数、格式化、JSON 输出。下面我们再通过一张表格,做一个简单的对比。
+
+|序号|输出类别|输出方式|主要用途|返回值|常用指数|
+|---|---|---|---|---|----|
+|1|关键字 | echo | 输出一个或多个字符串 | 无 | ✳️✳️✳️✳️✳️ |
+|2|关键字 | print | 输出一个字符串 | 始终返回 1 | ✳️ |
+|3|输出函数 | print_r() | 调试,打印变量 | 可选返回 | ✳️ |
+|4|输出函数 | var_dump() | 深度调试,打印类型和值 | 无 | ✳️✳️✳️✳️✳️ |
+|5|输出函数 | var_export() | 调试/缓存,生成合法 PHP 代码 | 可选返回 | ✳️✳️✳️ |
+|6|格式化 | printf() / sprintf() | 格式化字符串输出 | printf 无,sprintf 有 | ✳️✳️ |
+|7|JSON 输出| json 输出方式 | Web 服务器输出 | 无 | ✳️✳️✳️✳️✳️ |
+
+如果文章对你有帮助,请关注和转发,谢谢!
+
\ No newline at end of file
diff --git "a/docs/php/\345\275\223\344\270\213\346\234\200\346\265\201\350\241\214\347\232\204PHP\346\234\254\345\234\260\347\216\257\345\242\203\346\220\255\345\273\272\346\226\271\345\274\217.md" "b/docs/php/\345\275\223\344\270\213\346\234\200\346\265\201\350\241\214\347\232\204PHP\346\234\254\345\234\260\347\216\257\345\242\203\346\220\255\345\273\272\346\226\271\345\274\217.md"
new file mode 100644
index 0000000..027ff9c
--- /dev/null
+++ "b/docs/php/\345\275\223\344\270\213\346\234\200\346\265\201\350\241\214\347\232\204PHP\346\234\254\345\234\260\347\216\257\345\242\203\346\220\255\345\273\272\346\226\271\345\274\217.md"
@@ -0,0 +1,93 @@
+# 当下最流行的PHP本地环境搭建方式
+
+> 本文主要是互联网从业者视角,介绍一种PHP本地开发环境搭建的最佳实践方法。全文共计1630字,作者:凌枫。如果文章对你有帮助,请关注和转发,谢谢!
+
+## 一、传统环境搭建方式已过时
+
+### 1、曾经用过的本地环境搭建方式
+
+初学者福音,一键安装包。刚入行的时候,也曾经使用过PHPStudy、XAMP、MAMP。这是最简单、最快速的搭建方式,特别适合刚入行的初级开发者。假如没有这种便捷工具,估计自己也要被本地开发环境搭建给劝退。
+
+极致酷炫版,基于虚拟机的方式。在进阶到高级开发者后,要经常爬上服务器,于是迷上了CentOS。非常享受手撸本地开发环境的感觉,输入一行yum命令,终端就开始滚动起来,非常酷炫。可以非常轻松的安装Nginx、PHP、Redis、MySQL等等,而且可以手动修改各类配置。
+
+### 2、本地开发环境的核心痛点
+
+本地开发环境搭建究竟是容易还是难。在漫长的工作历程中,曾经遇到很多人搞不定本地开发环境,不管是刚入行的新人,还是有经验的从业者,都曾遇到过。对于大多数人来说,搭建本地开发环境,大概有这两种方式。方式一:现场Google搜索,现场安装;方式二:打开工具箱记事本,喝着咖啡安装。多问一句,公司用了什么奇怪奇奇的扩展版本,看着错误日志,你能搞定吗?
+
+开箱即用的本地开发环境,可定制、可分享、版本随切。你是否遇到以下问题?有多台电脑,需要配置多遍,还没法保持统一环境;每次换工作都要花1-2天时间跑项目;新员工入职,搞不定开发环境,有人用Mac有人用Windows;公司项目跑在7.x版本的PHP,想体验一下8.x版本的PHP。
+
+团队:需要一个定制的开箱即用本地开发环境,下次有人问起,直接甩过去。个人:一个属于自己的本地开发环境。
+
+### 3、让本地开发环境变得时髦些
+
+本地开发环境也要追求时髦,也可以内嵌到Docker里面。开箱即用 = docker-compose up。耳边天天都在响起起拥抱云原生,似乎跟普通开发不搭边。而当你把本地开发环境内嵌到Docker里面之后,脑海中的这种想法就彻底消失了,你发现在本地可以把4核CPU分配1核给Docker,换而言之,对公司容器化可以提高机器资源的利用率。
+
+公司测试和生产环境都在用容器,而通过本地环境Docker化,你将拥有一个本地实践的机会。在捣腾了很多年,贴合现在工作和个人诉求,终于找到一款好东西:DNMP — 当下最流行的PHP本地环境搭建方式。
+
+## 二、DNMP简单介绍
+
+### 1、DNMP简介
+
+什么是DNMP呢?DNMP = Docker + Nginx + MySQL + PHP + Redis + ElasticSearch + MongoDB + RabbitMQ,是一款全功能的LNMP一键安装程序,也支持Arm CPU。
+
+我心目中的DNMP是什么?基于当下流行的Docker方式,囊括PHP开发的所有运行依赖,只要稍加裁剪即可以完成定制。
+
+### 2、包含功能
+
+文件配置等于运行环境。之前不管是一键安装包,还是虚拟机方式,多少有点让人摸不着头脑的感觉。在你拥有了DNMP之后,瞬间让你感觉深入了源码的感觉。通过配置docker-compose.yml文件,可以定制所需要的services,比如nginx是一个service,php74也是一个service;每个运行的service的环境变量全部在env文件。
+
+### 3、内置丰富的PHP扩展
+
+内置多达152种常见和不常见的PHP扩展。被本地开发环境折磨的一个点,肯定少不了PHP扩展,不管你的编译安装还是源安装的方式,过程肯定非常痛苦。而DNMP内置了几乎所有的PHP扩展,数量多达152种,你需要做的就是设置为启用即可。
+
+## 三、从零开始搭建DNMP开发环境
+
+### 1、三步轻松完成初始化
+
+第一步:克隆项目,git clone https://github.com/zeszao/dnmp.git
+
+第二步:拷贝并命名配置文件,env.sample、docker-compose.sample.yml
+
+第三步:浏览器访问 https://localhost 即可看到效果
+
+### 2、如何在项目中使用
+
+第一步:将你的应用放进项目目录。将工作中需要用到的应用,都放进本地电脑的~/Workshop路径下。
+
+```text
+~/Workshop $ tree ~/Workshop -L 1
+/Users/colin/Workshop
+├── api-a
+├── api-b
+├── api-c
+└── api-d
+```
+
+第二步:将项目根目录挂载进容器。修改docker-compose.yml文件配置。
+
+```yaml
+version: "3"
+services:
+ php82:
+ volumes:
+ - ~/Workshop:/home/www
+```
+
+第三步:逐个配置nginx的root路径。文件路径为services/nginx/conf.d/api-x.conf
+
+```text
+server {
+ server_name api-x.com;
+ listen 80:
+
+ root /home/www/api-x/public;
+ index index.php index.html index.htm;
+}
+```
+
+嗯,在项目中使用,就是这么简单方便。
+
+综上所述:DNMP是一种当下最佳的PHP本地搭建方式,不管你是刚入行还是经验丰富开发者。
+
+如果文章对你有帮助,请关注和转发,谢谢!
+
diff --git "a/docs/php/\347\274\226\347\250\213\350\257\255\350\250\200\347\256\200\344\273\213.md" "b/docs/php/\347\274\226\347\250\213\350\257\255\350\250\200\347\256\200\344\273\213.md"
new file mode 100644
index 0000000..3f3e4bb
--- /dev/null
+++ "b/docs/php/\347\274\226\347\250\213\350\257\255\350\250\200\347\256\200\344\273\213.md"
@@ -0,0 +1,76 @@
+# 编程语言简介
+
+> 本文主要是从编程语言的角度出发,介绍编程语言,帮你打消学习PHP这门编程语言的顾虑。全文共计2958字,作者:凌枫。如果文章对你有帮助,请关注和转发,谢谢!
+
+拥抱PHP,开启你的开发者之旅。当看到这段文字时,还记得为什么选择学PHP?是因为入门简单?好找工作?项目上手快?还是搞不定Java或C++?等等原因。
+
+## 一、学编程语言究竟在学什么
+
+### 1、编程语言的终极目标
+作为多年的编程语言实践者,在学习和运用编程语言的生涯里,要追求的是以下两点。一是不同的编程语言犹如不同的武功招式,不一定要学遍天下武功,掌握一门的诀窍,必要时可以快速上手另外一门;二是我们的目标是发明一门新的编程语言,而不是追求掌握每一门具体编程语言的细节。因此在你的整个生涯中,追求的终极目标都是以不变应万变。
+
+### 2、作为专业工程师
+
+学习一门编程语言,远不止于记忆语法,而是一个分层次、多维度的过程。首先,需要掌握特定的语法规则和熟练使用开发工具,从语法基础到核心概念再到高级特性;再则,能够理解普遍适合的核心编程概念和数据结构,培养编程思维,理解不同的编程范式;最后,锤炼自己的工程实践能力,并保持热爱以持续学习。
+
+语法规则和开发工具。语法规则就像学习外语的单词和语法一样,是写出合法程序的必备基础。包括关键字、运算符、语法结构、代码组织形式等。而开发工具(IDE)就像你要上网需要一台手机一样,需要掌握代码编辑、调试、代码执行、代码部署等。
+
+理解编程核心概念到培养编程思维。几乎所有的高级语言都在共享这些概念,只是不同语言写法有差异,包括:变量与数据结构、控制结构、函数和方法等。而怎么写到怎么想的转变,决定最后代码的高效性和易维护,包括:代码组织、模块化、错误处理、编程范式等。
+能落地的工程实践能力。代码就像建筑师建造的房子,最终是给人住的,而代码最终是要在项目运行的,也是要解决具体问题的。作为专业的工程师,先要通过了解各方信息,把要解决的问题定义清楚,再调出你的经验库,找到最适合、成本最低、能够落地的解决方案,再不断打磨最终上线。
+
+## 二、扒一下编程语言历史
+
+### 1、何为高级语言
+常见的编程语言均为高级语言。叫做高级语言,原因是比较接近人类的自然语言和数学表达,通过它能让普通人更容易的写出代码,更适合人类阅读的代码,也更容易维护的代码。相对高级语言而言,机器语言被视为低级语言,原因是它更接近机器本身,取悦的是机器而不是人,需要针对特定的硬件进行设计。
+
+### 2、高级语言有哪些
+在以往历史中出现的编程语言,一共可以分为5个世代。第一代语言是机器语言;第二代语言是汇编语言;第三代语言是高级语言,例如C;第四代语言是极高级语言,例如SQL;第五代语言是逻辑导向语言,又称自然语言。常见的高级语言均为第三代语言。高级语言包括:c语言、Java、C++、Go、PHP等。
+
+## 三、常见编程语言
+
+### 1、常见分类方法
+
+其实不同的编程语言都有在借鉴对方特性。常见的分类方法,包括:面向对象和面向过程、动态语言和静态语言等。更为常见的分类方法是根据特定应用场景,比如:C语言更适合嵌入式、Java适合跨平台和安卓开发、Python更擅长在数据分析和人工智能、JavaScript适合在Web前端、PHP适合在网站和中小型创新项目等。
+
+### 2、每年都在吵的事
+编程语言之间的争论,像是互联网技术圈里的武林大会。大家争吵的焦点一直都是:孰优孰劣、排行榜变化、就业前景和到底该学哪门语言,而争论的背后是对技术趋势和职业发展的顾虑。
+
+编程语言之间的鄙视链一直都存在,根源在于语言特性的差异和从业者的社会心理。Java、C++由于科班必修课,而且本身学习曲线也更高,让开发者不自觉认为高人一等。而JavaScript和PHP由于本身的动态灵活,再加上众多非科班的从业者涌入,一直被人吐槽可维护性,视为低人一等。
+
+排行榜的权威与局限。众多排行榜流行度,各有侧重,并不能完全代表实际情况。而作为从业者,关注排行榜一定要有一个正确的认识,要关注的是长期趋势,而非短期的波动。排名高的语言意味着生态系统更成熟,工作机会多,但不一定最适合你。
+
+### 3、PHP面临问题
+近年PHP排名和热度似乎一直在下滑,主要原因为互联网投资回归理性投资项目减少。就业岗位需求集中于现有系统的维护、更新和迭代。在新兴领域,如人工智能、大数据,由PHP作为主力技术栈的岗位相对较少。在一些中小企业成长成为大型企业的时候,往往因为PHP生态问题和从业者招聘原因,放弃将PHP作为主要技术栈,将公司技术栈转型为Java或者Go。综上原因,导致高阶PHP从业者薪资会比同水平的Java或者Go从业者低20%-30%,进一步加剧高阶开发者流向其他编程语言。
+
+对别人来说PHP是劣势,对你来说PHP或许是优势。第一类是新晋开发者,没有具体语言学习经验,也没有任何项目经验,或者尝试过其他语言觉得太难放弃的人;第二类是PHP从业者,已经掌握编程基础,也有一定的项目经验。对于前者,我的理由是唯快不破,能让你快速上手并找到工作,就是最重要的,嗯,先活下去,才有资格留在牌桌吐槽PHP。对于后者,深挖PHP的同事再学习其他语言,保持现状再求发展。
+
+## 四、最快的速成办法
+
+### 1、通过官网文档
+官方文档从来都是最好的学习材料。对于初学者先过一遍官方文档的语法参考部分,包括看和练习。完成这步之后,对PHP就已经有了初步的认识了。有人说,为什么我老是记不住,哪怕刚看完或者敲完代码,还是记不住呢。即使作为计算机科班,最后从事开发者工作了,也并没有多少,很多人都转行了。而你,现在要么选择PHP,要么还选择继续留在这个行业,肯定你没有更好的选择。所以只能逼自己一把吧,如果还是记不住,那只能说明PHP不适合你。
+
+### 2、实际项目开发
+接着你就可以把重心转向项目了,以练代学,以练促学。学习编程最终都是要做项目。而做项目也是最好的学习方式,在项目过程会遇到各种问题,遇到问题之后再回过去继续学。
+
+学习PHP其实是一件脑力活,也是一件苦力活。
+
+## 五、学习其他语言
+
+### 1、为什么要学习其他语言
+对于初学者而言,是强烈不建议着急掌握太多编程语言,也不太建议走所谓全栈工程师路线。对于有一定经验的开发者而言,为什么要学习其他语言呢?答案是生活或者工作所需,要么想涨薪,要么被领导安排。不然你说你兴趣广泛,你相信我也不相信。
+
+### 2、有什么好处
+延长职业生涯时间,东边不亮西边亮。学习其他语言最大的好处,就是可以极大的延长你的职业生涯。如果你一定要进大厂,又非PHP岗不干,那将完全没有机会。而你在学一门Go,那你将收获两种额外机会,一种是纯Go技术栈,还有一种是PHP转Go的技术栈。
+
+## 六、编程语言终极归宿
+
+### 1、PHP爱好者
+促使我们一直有愿意学习或者使用PHP,我大体分为以下几个阶段。第一阶段,兴趣使然让你跟PHP能够双向奔赴,它能够给你一份能填饱肚子的工作,这个是基础前提;第二阶段,突然有一天发现,继续学习或者使用PHP也没有新的突破,然后就陷入了瓶颈期;第三阶段,你开始重新评估自身,找到了新的突破点,就比如我在这里敲字给你一样。
+
+### 2、终极归属
+假如你还会留在PHP的就业市场里,大概会有一个最终的发展方向:深入研究业务、研究框架设计、转行。输入研究业务,指DDD这类;框架设计,指的是架构类,还有业务组件这些;而转行,指的是脱离一线编码,要么换行业,要么转管理。
+
+综上所述:无论你是刚刚踏入编程世界的新手,还是希望在PHP领域深耕的专业开发者,关键是要保持学习的热情和适应变化的能力。PHP可能不是完美的语言,但它绝对是一门实用的语言。
+
+如果文章对你有帮助,请关注和转发,谢谢!
+
\ No newline at end of file
diff --git "a/docs/\345\217\202\350\200\203\350\265\204\346\226\231.md" "b/docs/\345\217\202\350\200\203\350\265\204\346\226\231.md"
index 5f4fce4..e5e274c 100644
--- "a/docs/\345\217\202\350\200\203\350\265\204\346\226\231.md"
+++ "b/docs/\345\217\202\350\200\203\350\265\204\346\226\231.md"
@@ -35,22 +35,21 @@
- [IBM Developer](https://www.ibm.com/developerworks/cn/topics/)
- [API 设计指南](https://cloud.google.com/apis/design/?hl=zh-cn)
- [Microsoft REST API Guidelines](https://github.com/Microsoft/api-guidelines/blob/master/Guidelines.md)
+- [MySQL实战45讲](https://time.geekbang.org/column/intro/100020801)
+- [12步通关求职面试](https://kaiwu.lagou.com/course/courseInfo.htm?courseId=18#/sale)
## 职级参考
-|职级|头衔|备注|
-|-|-|-|
-|P1~P3||客服、助理相当|
-|P4|研发工程师|原则上本科|
-|P5|高级工程师|原则上硕士|
-|P6|资深研发工程师|博士或5年以上工作经验|
-|P7|技术专家|大公司技术主管,小公司技术总监CTO相当|
-|P8|高级专家|管理多团队,包括技术、运营、产品、BD中至少2个|
-|P9|资深专家|没有机遇很难,当年阿里鬼脚七这个级别|
-|P10|研究员|普通人别想了|
-|P11|高级研究员|。。|
-|P12|科学家|
-|P13|高级科学家|
-|P14|首席科学家|
+|职级|名称|薪资|股票|
+|-|-|-|-|
+|P4|初级工程师|
+|P5|中级工程师|
+|P6|高级研发工程师|
+|P7|专家|
+|P9|资深专家|
+
+- 阿里薪资结构:一般是12+1+3=16薪
+- 年底的奖金为0-6个月薪资,90%人可拿到3个
+- 股票是工作满2年才能拿,第一次拿50%,4年能全部拿完
> 备注:阿里技术通道
\ No newline at end of file
diff --git "a/docs/\345\255\230\345\202\250/MySQL\344\270\272\344\273\200\344\271\210\346\234\211\346\227\266\345\200\231\344\274\232\351\200\211\351\224\231\347\264\242\345\274\225.md" "b/docs/\345\255\230\345\202\250/MySQL\344\270\272\344\273\200\344\271\210\346\234\211\346\227\266\345\200\231\344\274\232\351\200\211\351\224\231\347\264\242\345\274\225.md"
new file mode 100644
index 0000000..111f927
--- /dev/null
+++ "b/docs/\345\255\230\345\202\250/MySQL\344\270\272\344\273\200\344\271\210\346\234\211\346\227\266\345\200\231\344\274\232\351\200\211\351\224\231\347\264\242\345\274\225.md"
@@ -0,0 +1 @@
+# MySQL为什么有时候会选错索引
\ No newline at end of file
diff --git "a/docs/\345\255\230\345\202\250/MySQL\346\230\257\346\200\216\344\271\210\344\277\235\350\257\201\344\270\273\345\244\207\344\270\200\350\207\264\347\232\204.md" "b/docs/\345\255\230\345\202\250/MySQL\346\230\257\346\200\216\344\271\210\344\277\235\350\257\201\344\270\273\345\244\207\344\270\200\350\207\264\347\232\204.md"
new file mode 100644
index 0000000..ed7df1d
--- /dev/null
+++ "b/docs/\345\255\230\345\202\250/MySQL\346\230\257\346\200\216\344\271\210\344\277\235\350\257\201\344\270\273\345\244\207\344\270\200\350\207\264\347\232\204.md"
@@ -0,0 +1 @@
+# MySQL是怎么保证主备一致的
\ No newline at end of file
diff --git "a/docs/\345\255\230\345\202\250/MySQL\346\230\257\346\200\216\344\271\210\344\277\235\350\257\201\346\225\260\346\215\256\344\270\215\344\270\242\347\232\204.md" "b/docs/\345\255\230\345\202\250/MySQL\346\230\257\346\200\216\344\271\210\344\277\235\350\257\201\346\225\260\346\215\256\344\270\215\344\270\242\347\232\204.md"
new file mode 100644
index 0000000..bc473c5
--- /dev/null
+++ "b/docs/\345\255\230\345\202\250/MySQL\346\230\257\346\200\216\344\271\210\344\277\235\350\257\201\346\225\260\346\215\256\344\270\215\344\270\242\347\232\204.md"
@@ -0,0 +1 @@
+# MySQL是怎么保证数据不丢的
\ No newline at end of file
diff --git "a/docs/\345\255\230\345\202\250/MySQL\346\230\257\346\200\216\344\271\210\344\277\235\350\257\201\351\253\230\345\217\257\347\224\250\347\232\204.md" "b/docs/\345\255\230\345\202\250/MySQL\346\230\257\346\200\216\344\271\210\344\277\235\350\257\201\351\253\230\345\217\257\347\224\250\347\232\204.md"
new file mode 100644
index 0000000..1f5b9a2
--- /dev/null
+++ "b/docs/\345\255\230\345\202\250/MySQL\346\230\257\346\200\216\344\271\210\344\277\235\350\257\201\351\253\230\345\217\257\347\224\250\347\232\204.md"
@@ -0,0 +1 @@
+# MySQL是怎么保证高可用的
\ No newline at end of file
diff --git "a/docs/\345\255\230\345\202\250/MySQL\346\234\211\345\223\252\344\272\233\351\245\256\351\270\251\346\255\242\346\270\264\346\217\220\351\253\230\346\200\247\350\203\275\347\232\204\346\226\271\346\263\225.md" "b/docs/\345\255\230\345\202\250/MySQL\346\234\211\345\223\252\344\272\233\351\245\256\351\270\251\346\255\242\346\270\264\346\217\220\351\253\230\346\200\247\350\203\275\347\232\204\346\226\271\346\263\225.md"
new file mode 100644
index 0000000..7289834
--- /dev/null
+++ "b/docs/\345\255\230\345\202\250/MySQL\346\234\211\345\223\252\344\272\233\351\245\256\351\270\251\346\255\242\346\270\264\346\217\220\351\253\230\346\200\247\350\203\275\347\232\204\346\226\271\346\263\225.md"
@@ -0,0 +1 @@
+# MySQL有哪些饮鸩止渴提高性能的方法
\ No newline at end of file
diff --git "a/docs/\345\255\230\345\202\250/assets/\344\270\200\346\235\241SQL\346\233\264\346\226\260\350\257\255\345\217\245\346\230\257\345\246\202\344\275\225\346\211\247\350\241\214\347\232\204-update\350\257\255\345\217\245\346\211\247\350\241\214\346\265\201\347\250\213.png" "b/docs/\345\255\230\345\202\250/assets/\344\270\200\346\235\241SQL\346\233\264\346\226\260\350\257\255\345\217\245\346\230\257\345\246\202\344\275\225\346\211\247\350\241\214\347\232\204-update\350\257\255\345\217\245\346\211\247\350\241\214\346\265\201\347\250\213.png"
new file mode 100644
index 0000000..39dc6e0
Binary files /dev/null and "b/docs/\345\255\230\345\202\250/assets/\344\270\200\346\235\241SQL\346\233\264\346\226\260\350\257\255\345\217\245\346\230\257\345\246\202\344\275\225\346\211\247\350\241\214\347\232\204-update\350\257\255\345\217\245\346\211\247\350\241\214\346\265\201\347\250\213.png" differ
diff --git "a/docs/\345\255\230\345\202\250/assets/\344\270\200\346\235\241SQL\346\233\264\346\226\260\350\257\255\345\217\245\346\230\257\345\246\202\344\275\225\346\211\247\350\241\214\347\232\204-write-pos.png" "b/docs/\345\255\230\345\202\250/assets/\344\270\200\346\235\241SQL\346\233\264\346\226\260\350\257\255\345\217\245\346\230\257\345\246\202\344\275\225\346\211\247\350\241\214\347\232\204-write-pos.png"
new file mode 100644
index 0000000..ea7837d
Binary files /dev/null and "b/docs/\345\255\230\345\202\250/assets/\344\270\200\346\235\241SQL\346\233\264\346\226\260\350\257\255\345\217\245\346\230\257\345\246\202\344\275\225\346\211\247\350\241\214\347\232\204-write-pos.png" differ
diff --git "a/docs/\345\255\230\345\202\250/assets/\344\270\200\346\235\241SQL\346\237\245\350\257\242\350\257\255\345\217\245\346\230\257\345\246\202\344\275\225\346\211\247\350\241\214\347\232\204-\345\237\272\346\234\254\346\236\266\346\236\204\345\233\276.png" "b/docs/\345\255\230\345\202\250/assets/\344\270\200\346\235\241SQL\346\237\245\350\257\242\350\257\255\345\217\245\346\230\257\345\246\202\344\275\225\346\211\247\350\241\214\347\232\204-\345\237\272\346\234\254\346\236\266\346\236\204\345\233\276.png"
new file mode 100644
index 0000000..9f6ba7f
Binary files /dev/null and "b/docs/\345\255\230\345\202\250/assets/\344\270\200\346\235\241SQL\346\237\245\350\257\242\350\257\255\345\217\245\346\230\257\345\246\202\344\275\225\346\211\247\350\241\214\347\232\204-\345\237\272\346\234\254\346\236\266\346\236\204\345\233\276.png" differ
diff --git "a/docs/\345\255\230\345\202\250/assets/\344\272\213\345\212\241\351\232\224\347\246\273-\344\270\272\344\273\200\344\271\210\344\275\240\346\224\271\344\272\206\346\210\221\350\277\230\347\234\213\344\270\215\350\247\201-\344\272\213\345\212\241\346\217\220\344\272\244.png" "b/docs/\345\255\230\345\202\250/assets/\344\272\213\345\212\241\351\232\224\347\246\273-\344\270\272\344\273\200\344\271\210\344\275\240\346\224\271\344\272\206\346\210\221\350\277\230\347\234\213\344\270\215\350\247\201-\344\272\213\345\212\241\346\217\220\344\272\244.png"
new file mode 100644
index 0000000..2fb1164
Binary files /dev/null and "b/docs/\345\255\230\345\202\250/assets/\344\272\213\345\212\241\351\232\224\347\246\273-\344\270\272\344\273\200\344\271\210\344\275\240\346\224\271\344\272\206\346\210\221\350\277\230\347\234\213\344\270\215\350\247\201-\344\272\213\345\212\241\346\217\220\344\272\244.png" differ
diff --git "a/docs/\345\255\230\345\202\250/assets/\344\272\213\345\212\241\351\232\224\347\246\273-\344\270\272\344\273\200\344\271\210\344\275\240\346\224\271\344\272\206\346\210\221\350\277\230\347\234\213\344\270\215\350\247\201-\345\233\236\346\273\232\346\227\245\345\277\227\350\256\260\345\275\225.png" "b/docs/\345\255\230\345\202\250/assets/\344\272\213\345\212\241\351\232\224\347\246\273-\344\270\272\344\273\200\344\271\210\344\275\240\346\224\271\344\272\206\346\210\221\350\277\230\347\234\213\344\270\215\350\247\201-\345\233\236\346\273\232\346\227\245\345\277\227\350\256\260\345\275\225.png"
new file mode 100644
index 0000000..49b3233
Binary files /dev/null and "b/docs/\345\255\230\345\202\250/assets/\344\272\213\345\212\241\351\232\224\347\246\273-\344\270\272\344\273\200\344\271\210\344\275\240\346\224\271\344\272\206\346\210\221\350\277\230\347\234\213\344\270\215\350\247\201-\345\233\236\346\273\232\346\227\245\345\277\227\350\256\260\345\275\225.png" differ
diff --git "a/docs/\345\255\230\345\202\250/assets/\346\267\261\345\205\245\346\265\205\345\207\272\347\264\242\345\274\225-\344\270\212-InnoDB\347\232\204\347\264\242\345\274\225\347\273\204\347\273\207\347\273\223\346\236\204.png" "b/docs/\345\255\230\345\202\250/assets/\346\267\261\345\205\245\346\265\205\345\207\272\347\264\242\345\274\225-\344\270\212-InnoDB\347\232\204\347\264\242\345\274\225\347\273\204\347\273\207\347\273\223\346\236\204.png"
new file mode 100644
index 0000000..f43a9e4
Binary files /dev/null and "b/docs/\345\255\230\345\202\250/assets/\346\267\261\345\205\245\346\265\205\345\207\272\347\264\242\345\274\225-\344\270\212-InnoDB\347\232\204\347\264\242\345\274\225\347\273\204\347\273\207\347\273\223\346\236\204.png" differ
diff --git "a/docs/\345\255\230\345\202\250/assets/\346\267\261\345\205\245\346\265\205\345\207\272\347\264\242\345\274\225-\344\270\212-\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221.png" "b/docs/\345\255\230\345\202\250/assets/\346\267\261\345\205\245\346\265\205\345\207\272\347\264\242\345\274\225-\344\270\212-\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221.png"
new file mode 100644
index 0000000..0193f97
Binary files /dev/null and "b/docs/\345\255\230\345\202\250/assets/\346\267\261\345\205\245\346\265\205\345\207\272\347\264\242\345\274\225-\344\270\212-\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221.png" differ
diff --git "a/docs/\345\255\230\345\202\250/assets/\346\267\261\345\205\245\346\265\205\345\207\272\347\264\242\345\274\225-\344\270\212-\345\223\210\345\270\214\347\264\242\345\274\225.png" "b/docs/\345\255\230\345\202\250/assets/\346\267\261\345\205\245\346\265\205\345\207\272\347\264\242\345\274\225-\344\270\212-\345\223\210\345\270\214\347\264\242\345\274\225.png"
new file mode 100644
index 0000000..c4ee2c4
Binary files /dev/null and "b/docs/\345\255\230\345\202\250/assets/\346\267\261\345\205\245\346\265\205\345\207\272\347\264\242\345\274\225-\344\270\212-\345\223\210\345\270\214\347\264\242\345\274\225.png" differ
diff --git "a/docs/\345\255\230\345\202\250/assets/\346\267\261\345\205\245\346\265\205\345\207\272\347\264\242\345\274\225-\344\270\212-\346\234\211\345\272\217\346\225\260\347\273\204.png" "b/docs/\345\255\230\345\202\250/assets/\346\267\261\345\205\245\346\265\205\345\207\272\347\264\242\345\274\225-\344\270\212-\346\234\211\345\272\217\346\225\260\347\273\204.png"
new file mode 100644
index 0000000..c566e9e
Binary files /dev/null and "b/docs/\345\255\230\345\202\250/assets/\346\267\261\345\205\245\346\265\205\345\207\272\347\264\242\345\274\225-\344\270\212-\346\234\211\345\272\217\346\225\260\347\273\204.png" differ
diff --git "a/docs/\345\255\230\345\202\250/count()\350\277\231\344\271\210\346\205\242\357\274\214\346\210\221\350\257\245\346\200\216\344\271\210\345\212\236.md" "b/docs/\345\255\230\345\202\250/count()\350\277\231\344\271\210\346\205\242\357\274\214\346\210\221\350\257\245\346\200\216\344\271\210\345\212\236.md"
new file mode 100644
index 0000000..aaa9635
--- /dev/null
+++ "b/docs/\345\255\230\345\202\250/count()\350\277\231\344\271\210\346\205\242\357\274\214\346\210\221\350\257\245\346\200\216\344\271\210\345\212\236.md"
@@ -0,0 +1 @@
+# count()这么慢,我该怎么办
\ No newline at end of file
diff --git "a/docs/\345\255\230\345\202\250/order-by\346\230\257\346\200\216\344\271\210\345\267\245\344\275\234\347\232\204.md" "b/docs/\345\255\230\345\202\250/order-by\346\230\257\346\200\216\344\271\210\345\267\245\344\275\234\347\232\204.md"
new file mode 100644
index 0000000..e1c3845
--- /dev/null
+++ "b/docs/\345\255\230\345\202\250/order-by\346\230\257\346\200\216\344\271\210\345\267\245\344\275\234\347\232\204.md"
@@ -0,0 +1 @@
+# order by是怎么工作的
\ No newline at end of file
diff --git "a/docs/\345\255\230\345\202\250/\344\270\200\346\235\241SQL\346\233\264\346\226\260\350\257\255\345\217\245\346\230\257\345\246\202\344\275\225\346\211\247\350\241\214\347\232\204.md" "b/docs/\345\255\230\345\202\250/\344\270\200\346\235\241SQL\346\233\264\346\226\260\350\257\255\345\217\245\346\230\257\345\246\202\344\275\225\346\211\247\350\241\214\347\232\204.md"
new file mode 100644
index 0000000..7d45c3f
--- /dev/null
+++ "b/docs/\345\255\230\345\202\250/\344\270\200\346\235\241SQL\346\233\264\346\226\260\350\257\255\345\217\245\346\230\257\345\246\202\344\275\225\346\211\247\350\241\214\347\232\204.md"
@@ -0,0 +1,124 @@
+# 一条SQL更新语句是如何执行的
+
+前面我们系统了解了一个查询语句的执行流程,并介绍了执行过程中涉及的处理模块。相信你还记得,一条查询语句的执行过程一般是经过连接器、分析器、优化器、执行器等功能模块,最后到达存储引擎。
+
+那么,一条更新语句的执行流程又是怎样的呢?
+
+之前你可能经常听 DBA 同事说,MySQL 可以恢复到半个月内任意一秒的状态,惊叹的同时,你是不是心中也会不免会好奇,这是怎样做到的呢?
+
+我们还是从一个表的一条更新语句说起,下面是这个表的创建语句,这个表有一个主键 ID 和一个整型字段 c:
+
+> mysql> create table T(ID int primary key, c int);
+如果要将 ID=2 这一行的值加 1,SQL 语句就会这么写:
+
+> mysql> update T set c=c+1 where ID=2;
+
+前面我有跟你介绍过 SQL 语句基本的执行链路,这里我再把那张图拿过来,你也可以先简单看看这个图回顾下。首先,可以确定的说,查询语句的那一套流程,更新语句也是同样会走一遍。
+
+
+
+你执行语句前要先连接数据库,这是连接器的工作。
+
+前面我们说过,在一个表上有更新的时候,跟这个表有关的查询缓存会失效,所以这条语句就会把表 T 上所有缓存结果都清空。这也就是我们一般不建议使用查询缓存的原因。
+
+接下来,分析器会通过词法和语法解析知道这是一条更新语句。优化器决定要使用 ID 这个索引。然后,执行器负责具体执行,找到这一行,然后更新。
+
+与查询流程不一样的是,更新流程还涉及两个重要的日志模块,它们正是我们今天要讨论的主角:redo log(重做日志)和 binlog(归档日志)。如果接触 MySQL,那这两个词肯定是绕不过的,我后面的内容里也会不断地和你强调。不过话说回来,redo log 和 binlog 在设计上有很多有意思的地方,这些设计思路也可以用到你自己的程序里。
+
+## 重要的日志模块:redo log
+
+不知道你还记不记得《孔乙己》这篇文章,酒店掌柜有一个粉板,专门用来记录客人的赊账记录。如果赊账的人不多,那么他可以把顾客名和账目写在板上。但如果赊账的人多了,粉板总会有记不下的时候,这个时候掌柜一定还有一个专门记录赊账的账本。
+
+如果有人要赊账或者还账的话,掌柜一般有两种做法:
+
+- 一种做法是直接把账本翻出来,把这次赊的账加上去或者扣除掉;
+- 另一种做法是先在粉板上记下这次的账,等打烊以后再把账本翻出来核算
+
+在生意红火柜台很忙时,掌柜一定会选择后者,因为前者操作实在是太麻烦了。首先,你得找到这个人的赊账总额那条记录。你想想,密密麻麻几十页,掌柜要找到那个名字,可能还得带上老花镜慢慢找,找到之后再拿出算盘计算,最后再将结果写回到账本上。
+
+这整个过程想想都麻烦。相比之下,还是先在粉板上记一下方便。你想想,如果掌柜没有粉板的帮助,每次记账都得翻账本,效率是不是低得让人难以忍受?
+
+同样,在 MySQL 里也有这个问题,如果每一次的更新操作都需要写进磁盘,然后磁盘也要找到对应的那条记录,然后再更新,整个过程 IO 成本、查找成本都很高。为了解决这个问题,MySQL 的设计者就用了类似酒店掌柜粉板的思路来提升更新效率。
+
+而粉板和账本配合的整个过程,其实就是 MySQL 里经常说到的 WAL 技术,WAL 的全称是 Write-Ahead Logging,它的关键点就是先写日志,再写磁盘,也就是先写粉板,等不忙的时候再写账本。
+
+具体来说,当有一条记录需要更新的时候,InnoDB 引擎就会先把记录写到 redo log(粉板)里面,并更新内存,这个时候更新就算完成了。同时,InnoDB 引擎会在适当的时候,将这个操作记录更新到磁盘里面,而这个更新往往是在系统比较空闲的时候做,这就像打烊以后掌柜做的事。
+
+如果今天赊账的不多,掌柜可以等打烊后再整理。但如果某天赊账的特别多,粉板写满了,又怎么办呢?这个时候掌柜只好放下手中的活儿,把粉板中的一部分赊账记录更新到账本中,然后把这些记录从粉板上擦掉,为记新账腾出空间。
+
+与此类似,InnoDB 的 redo log 是固定大小的,比如可以配置为一组 4 个文件,每个文件的大小是 1GB,那么这块“粉板”总共就可以记录 4GB 的操作。从头开始写,写到末尾就又回到开头循环写,如下面这个图所示。
+
+
+
+write pos 是当前记录的位置,一边写一边后移,写到第 3 号文件末尾后就回到 0 号文件开头。checkpoint 是当前要擦除的位置,也是往后推移并且循环的,擦除记录前要把记录更新到数据文件。
+
+write pos 和 checkpoint 之间的是“粉板”上还空着的部分,可以用来记录新的操作。如果 write pos 追上 checkpoint,表示“粉板”满了,这时候不能再执行新的更新,得停下来先擦掉一些记录,把 checkpoint 推进一下。
+
+有了 redo log,InnoDB 就可以保证即使数据库发生异常重启,之前提交的记录都不会丢失,这个能力称为crash-safe。
+
+要理解 crash-safe 这个概念,可以想想我们前面赊账记录的例子。只要赊账记录记在了粉板上或写在了账本上,之后即使掌柜忘记了,比如突然停业几天,恢复生意后依然可以通过账本和粉板上的数据明确赊账账目。
+
+## 重要的日志模块:binlog
+
+前面我们讲过,MySQL 整体来看,其实就有两块:一块是 Server 层,它主要做的是 MySQL 功能层面的事情;还有一块是引擎层,负责存储相关的具体事宜。上面我们聊到的粉板 redo log 是 InnoDB 引擎特有的日志,而 Server 层也有自己的日志,称为 binlog(归档日志)。
+
+我想你肯定会问,为什么会有两份日志呢?
+
+因为最开始 MySQL 里并没有 InnoDB 引擎。MySQL 自带的引擎是 MyISAM,但是 MyISAM 没有 crash-safe 的能力,binlog 日志只能用于归档。而 InnoDB 是另一个公司以插件形式引入 MySQL 的,既然只依靠 binlog 是没有 crash-safe 能力的,所以 InnoDB 使用另外一套日志系统——也就是 redo log 来实现 crash-safe 能力。
+
+这两种日志有以下三点不同。
+
+1、redo log 是 InnoDB 引擎特有的;binlog 是 MySQL 的 Server 层实现的,所有引擎都可以使用。
+
+2、redo log 是物理日志,记录的是“在某个数据页上做了什么修改”;binlog 是逻辑日志,记录的是这个语句的原始逻辑,比如“给 ID=2 这一行的 c 字段加 1 ”。
+redo log 是循环写的,空间固定会用完;
+
+3、binlog 是可以追加写入的。“追加写”是指 binlog 文件写到一定大小后会切换到下一个,并不会覆盖以前的日志。
+
+有了对这两个日志的概念性理解,我们再来看执行器和 InnoDB 引擎在执行这个简单的 update 语句时的内部流程。
+
+1、执行器先找引擎取 ID=2 这一行。ID 是主键,引擎直接用树搜索找到这一行。如果 ID=2 这一行所在的数据页本来就在内存中,就直接返回给执行器;否则,需要先从磁盘读入内存,然后再返回。
+
+2、执行器拿到引擎给的行数据,把这个值加上 1,比如原来是 N,现在就是 N+1,得到新的一行数据,再调用引擎接口写入这行新数据。
+
+3、引擎将这行新数据更新到内存中,同时将这个更新操作记录到 redo log 里面,此时 redo log 处于 prepare 状态。然后告知执行器执行完成了,随时可以提交事务。
+
+4、执行器生成这个操作的 binlog,并把 binlog 写入磁盘。
+
+5、执行器调用引擎的提交事务接口,引擎把刚刚写入的 redo log 改成提交(commit)状态,更新完成。
+
+这里我给出这个 update 语句的执行流程图,图中浅色框表示是在 InnoDB 内部执行的,深色框表示是在执行器中执行的。
+
+
+
+你可能注意到了,最后三步看上去有点“绕”,将 redo log 的写入拆成了两个步骤:prepare 和 commit,这就是”两阶段提交”。
+
+## 两阶段提交
+
+为什么必须有“两阶段提交”呢?这是为了让两份日志之间的逻辑一致。要说明这个问题,我们得从文章开头的那个问题说起:怎样让数据库恢复到半个月内任意一秒的状态?
+
+前面我们说过了,binlog 会记录所有的逻辑操作,并且是采用“追加写”的形式。如果你的 DBA 承诺说半个月内可以恢复,那么备份系统中一定会保存最近半个月的所有 binlog,同时系统会定期做整库备份。这里的“定期”取决于系统的重要性,可以是一天一备,也可以是一周一备。
+
+当需要恢复到指定的某一秒时,比如某天下午两点发现中午十二点有一次误删表,需要找回数据,那你可以这么做:
+
+- 首先,找到最近的一次全量备份,如果你运气好,可能就是昨天晚上的一个备份,从这个备份恢复到临时库;
+- 然后,从备份的时间点开始,将备份的 binlog 依次取出来,重放到中午误删表之前的那个时刻。
+
+这样你的临时库就跟误删之前的线上库一样了,然后你可以把表数据从临时库取出来,按需要恢复到线上库去。
+
+好了,说完了数据恢复过程,我们回来说说,为什么日志需要“两阶段提交”。这里不妨用反证法来进行解释。
+
+由于 redo log 和 binlog 是两个独立的逻辑,如果不用两阶段提交,要么就是先写完 redo log 再写 binlog,或者采用反过来的顺序。我们看看这两种方式会有什么问题。
+
+仍然用前面的 update 语句来做例子。假设当前 ID=2 的行,字段 c 的值是 0,再假设执行 update 语句过程中在写完第一个日志后,第二个日志还没有写完期间发生了 crash,会出现什么情况呢?
+
+1、先写 redo log 后写 binlog。假设在 redo log 写完,binlog 还没有写完的时候,MySQL 进程异常重启。由于我们前面说过的,redo log 写完之后,系统即使崩溃,仍然能够把数据恢复回来,所以恢复后这一行 c 的值是 1。 但是由于 binlog 没写完就 crash 了,这时候 binlog 里面就没有记录这个语句。因此,之后备份日志的时候,存起来的 binlog 里面就没有这条语句。 然后你会发现,如果需要用这个 binlog 来恢复临时库的话,由于这个语句的 binlog 丢失,这个临时库就会少了这一次更新,恢复出来的这一行 c 的值就是 0,与原库的值不同。
+
+2、先写 binlog 后写 redo log。如果在 binlog 写完之后 crash,由于 redo log 还没写,崩溃恢复以后这个事务无效,所以这一行 c 的值是 0。但是 binlog 里面已经记录了“把 c 从 0 改成 1”这个日志。所以,在之后用 binlog 来恢复的时候就多了一个事务出来,恢复出来的这一行 c 的值就是 1,与原库的值不同。
+可以看到,如果不使用“两阶段提交”,那么数据库的状态就有可能和用它的日志恢复出来的库的状态不一致。
+
+你可能会说,这个概率是不是很低,平时也没有什么动不动就需要恢复临时库的场景呀?
+
+其实不是的,不只是误操作后需要用这个过程来恢复数据。当你需要扩容的时候,也就是需要再多搭建一些备库来增加系统的读能力的时候,现在常见的做法也是用全量备份加上应用 binlog 来实现的,这个“不一致”就会导致你的线上出现主从数据库不一致的情况。
+
+简单说,redo log 和 binlog 都可以用于表示事务的提交状态,而两阶段提交就是让这两个状态保持逻辑上的一致。
\ No newline at end of file
diff --git "a/docs/\345\255\230\345\202\250/\344\270\200\346\235\241SQL\346\237\245\350\257\242\350\257\255\345\217\245\346\230\257\345\246\202\344\275\225\346\211\247\350\241\214\347\232\204.md" "b/docs/\345\255\230\345\202\250/\344\270\200\346\235\241SQL\346\237\245\350\257\242\350\257\255\345\217\245\346\230\257\345\246\202\344\275\225\346\211\247\350\241\214\347\232\204.md"
new file mode 100644
index 0000000..556e161
--- /dev/null
+++ "b/docs/\345\255\230\345\202\250/\344\270\200\346\235\241SQL\346\237\245\350\257\242\350\257\255\345\217\245\346\230\257\345\246\202\344\275\225\346\211\247\350\241\214\347\232\204.md"
@@ -0,0 +1,59 @@
+# 一条SQL查询语句是如何执行的
+
+## SQL内部执行过程
+
+假如你有一张表T,表里只有一个id字段,在执行下面这个查询语句,简述一下这条语句在MySQL内部的执行过程。
+
+> mysql > SELECT * FROM T WHERE id=10;
+
+## MySQL架构概览
+
+这是一张MySQL的基本架构示意图,通过图可以清晰的看到SQL语句在MySQL的各个模块中的执行过程。
+
+
+
+- 大体来说,MySQL可以分为Server层和存储引擎层两部分。
+- Server层包括连接器、查询缓存、分析器、优化器、执行器等核心服务功能,以及所有内置函数,比如日期、时间和加密函数等;所有跨存储引擎的功能都在这一层实现,比如存储过程、触发器、视图等。
+- 存储引擎层负责数据的存储和提取,其架构模式是插件式,支持InnoDB、MyISAM、Memory等多个存储引擎,其中InnoDB是最常用的存储引擎,从MySQL 5.5.5版本开始成为默认引擎。
+
+## 连接器
+
+- 连接器负责与客户端建立连接、获取权限、维持和管理连接。
+- 连接命令包括用户名、密码等认证信息。
+- 连接成功后,权限判断逻辑依赖于此时读到的权限,即使后续权限被修改,已建立的连接权限不变。
+
+> Q:在使用中减少连接动作尽量使用长连接,但全部使用长连接后,有些时候MySQL占用内存涨的特别快?
+
+## 查询缓存
+
+- 查询缓存用于存储之前执行过的语句及其结果,以提高查询效率。
+- 但由于查询缓存的频繁失效和命中率低,大多数情况下建议不使用查询缓存。
+- MySQL 8.0版本中,查询缓存功能被完全移除。
+
+> 查询缓存的失效非常频繁,只要有对一个表的更新,这个表上所有的查询缓存都会被清空。
+
+> mysql> SELECT SQL_CACHE * FROM T WHERE id=10;
+
+## 分析器
+
+- 分析器对SQL语句进行词法分析和语法分析,识别语句中的字符串和语法规则。
+- 如果SQL语句有语法错误,会提示错误信息。
+
+> 词法分析,识别出SQL语句各个字符分别是什么代表什么,比如把字符串T识别成表T,把字符串id识别成列ID。
+> 语法分析,根据词法分析的结果,语法分析器再根据语法规则,判断输入的SQL语句是否满足MySQL语法。
+
+## 优化器
+
+- 优化器决定使用哪个索引或表的连接顺序,以提高执行效率。
+- 优化器的选择可能影响查询性能。
+
+> mysql> SELECT * FROM t1 JOIN t2 USING(id) WHERE t1.c=10 AND t2.d=20;
+> 既可以先从表 t1 里面取出 c=10 的记录的 ID 值,再根据 ID 值关联到表 t2,再判断 t2 里面 d 的值是否等于 20。
+> 也可以先从表 t2 里面取出 d=20 的记录的 ID 值,再根据 ID 值关联到 t1,再判断 t1 里面 c 的值是否等于 10。
+> 优化器的作用就是决定选择哪种方案,以便达到最佳效率。
+
+## 执行器
+
+- 执行器根据分析器和优化器的结果执行SQL语句。
+- 执行过程中,会检查权限,并根据表的存储引擎使用相应的接口。
+- 对于没有索引的表,执行器会遍历表中的每一行来查找满足条件的数据。
\ No newline at end of file
diff --git "a/docs/\345\255\230\345\202\250/\344\270\272\344\273\200\344\271\210\346\210\221\345\217\252\346\224\271\344\270\200\350\241\214\347\232\204\350\257\255\345\217\245\357\274\214\351\224\201\350\277\231\344\271\210\345\244\232.md" "b/docs/\345\255\230\345\202\250/\344\270\272\344\273\200\344\271\210\346\210\221\345\217\252\346\224\271\344\270\200\350\241\214\347\232\204\350\257\255\345\217\245\357\274\214\351\224\201\350\277\231\344\271\210\345\244\232.md"
new file mode 100644
index 0000000..96d0208
--- /dev/null
+++ "b/docs/\345\255\230\345\202\250/\344\270\272\344\273\200\344\271\210\346\210\221\345\217\252\346\224\271\344\270\200\350\241\214\347\232\204\350\257\255\345\217\245\357\274\214\351\224\201\350\277\231\344\271\210\345\244\232.md"
@@ -0,0 +1 @@
+# 为什么我只改一行的语句,锁这么多
\ No newline at end of file
diff --git "a/docs/\345\255\230\345\202\250/\344\270\272\344\273\200\344\271\210\346\210\221\345\217\252\346\237\245\344\270\200\350\241\214\347\232\204\350\257\255\345\217\245\357\274\214\344\271\237\346\211\247\350\241\214\350\277\231\344\271\210\346\205\242.md" "b/docs/\345\255\230\345\202\250/\344\270\272\344\273\200\344\271\210\346\210\221\345\217\252\346\237\245\344\270\200\350\241\214\347\232\204\350\257\255\345\217\245\357\274\214\344\271\237\346\211\247\350\241\214\350\277\231\344\271\210\346\205\242.md"
new file mode 100644
index 0000000..704f875
--- /dev/null
+++ "b/docs/\345\255\230\345\202\250/\344\270\272\344\273\200\344\271\210\346\210\221\345\217\252\346\237\245\344\270\200\350\241\214\347\232\204\350\257\255\345\217\245\357\274\214\344\271\237\346\211\247\350\241\214\350\277\231\344\271\210\346\205\242.md"
@@ -0,0 +1 @@
+# 为什么我只查一行的语句,也执行这么慢
\ No newline at end of file
diff --git "a/docs/\345\255\230\345\202\250/\344\270\272\344\273\200\344\271\210\346\210\221\347\232\204MySQL\344\274\232\346\212\226\344\270\200\344\270\213.md" "b/docs/\345\255\230\345\202\250/\344\270\272\344\273\200\344\271\210\346\210\221\347\232\204MySQL\344\274\232\346\212\226\344\270\200\344\270\213.md"
new file mode 100644
index 0000000..442d136
--- /dev/null
+++ "b/docs/\345\255\230\345\202\250/\344\270\272\344\273\200\344\271\210\346\210\221\347\232\204MySQL\344\274\232\346\212\226\344\270\200\344\270\213.md"
@@ -0,0 +1 @@
+# 为什么我的MySQL会抖一下
\ No newline at end of file
diff --git "a/docs/\345\255\230\345\202\250/\344\270\272\344\273\200\344\271\210\350\241\250\346\225\260\346\215\256\345\210\240\346\216\211\344\270\200\345\215\212\357\274\214\350\241\250\346\226\207\344\273\266\345\244\247\345\260\217\344\270\215\345\217\230.md" "b/docs/\345\255\230\345\202\250/\344\270\272\344\273\200\344\271\210\350\241\250\346\225\260\346\215\256\345\210\240\346\216\211\344\270\200\345\215\212\357\274\214\350\241\250\346\226\207\344\273\266\345\244\247\345\260\217\344\270\215\345\217\230.md"
new file mode 100644
index 0000000..6aa5c1a
--- /dev/null
+++ "b/docs/\345\255\230\345\202\250/\344\270\272\344\273\200\344\271\210\350\241\250\346\225\260\346\215\256\345\210\240\346\216\211\344\270\200\345\215\212\357\274\214\350\241\250\346\226\207\344\273\266\345\244\247\345\260\217\344\270\215\345\217\230.md"
@@ -0,0 +1 @@
+# 为什么表数据删掉一半,表文件大小不变
\ No newline at end of file
diff --git "a/docs/\345\255\230\345\202\250/\344\270\272\344\273\200\344\271\210\350\277\231\344\272\233SQL\350\257\255\345\217\245\351\200\273\350\276\221\347\233\270\345\220\214\357\274\214\346\200\247\350\203\275\345\215\264\345\267\256\345\274\202\345\267\250\345\244\247.md" "b/docs/\345\255\230\345\202\250/\344\270\272\344\273\200\344\271\210\350\277\231\344\272\233SQL\350\257\255\345\217\245\351\200\273\350\276\221\347\233\270\345\220\214\357\274\214\346\200\247\350\203\275\345\215\264\345\267\256\345\274\202\345\267\250\345\244\247.md"
new file mode 100644
index 0000000..c5abe3a
--- /dev/null
+++ "b/docs/\345\255\230\345\202\250/\344\270\272\344\273\200\344\271\210\350\277\231\344\272\233SQL\350\257\255\345\217\245\351\200\273\350\276\221\347\233\270\345\220\214\357\274\214\346\200\247\350\203\275\345\215\264\345\267\256\345\274\202\345\267\250\345\244\247.md"
@@ -0,0 +1 @@
+# 为什么这些SQL语句逻辑相同,性能却差异巨大
\ No newline at end of file
diff --git "a/docs/\345\255\230\345\202\250/\344\270\273\345\272\223\345\207\272\351\227\256\351\242\230\344\272\206\357\274\214\344\273\216\345\272\223\346\200\216\344\271\210\345\212\236.md" "b/docs/\345\255\230\345\202\250/\344\270\273\345\272\223\345\207\272\351\227\256\351\242\230\344\272\206\357\274\214\344\273\216\345\272\223\346\200\216\344\271\210\345\212\236.md"
new file mode 100644
index 0000000..9fd3598
--- /dev/null
+++ "b/docs/\345\255\230\345\202\250/\344\270\273\345\272\223\345\207\272\351\227\256\351\242\230\344\272\206\357\274\214\344\273\216\345\272\223\346\200\216\344\271\210\345\212\236.md"
@@ -0,0 +1 @@
+# 主库出问题了,从库怎么办
\ No newline at end of file
diff --git "a/docs/\345\255\230\345\202\250/\344\272\213\345\212\241\345\210\260\345\272\225\346\230\257\351\232\224\347\246\273\347\232\204\350\277\230\346\230\257\344\270\215\351\232\224\347\246\273\347\232\204.md" "b/docs/\345\255\230\345\202\250/\344\272\213\345\212\241\345\210\260\345\272\225\346\230\257\351\232\224\347\246\273\347\232\204\350\277\230\346\230\257\344\270\215\351\232\224\347\246\273\347\232\204.md"
new file mode 100644
index 0000000..12639a6
--- /dev/null
+++ "b/docs/\345\255\230\345\202\250/\344\272\213\345\212\241\345\210\260\345\272\225\346\230\257\351\232\224\347\246\273\347\232\204\350\277\230\346\230\257\344\270\215\351\232\224\347\246\273\347\232\204.md"
@@ -0,0 +1 @@
+# 事务到底是隔离的还是不隔离的
\ No newline at end of file
diff --git "a/docs/\345\255\230\345\202\250/\344\272\213\345\212\241\351\232\224\347\246\273-\344\270\272\344\273\200\344\271\210\344\275\240\346\224\271\344\272\206\346\210\221\350\277\230\347\234\213\344\270\215\350\247\201.md" "b/docs/\345\255\230\345\202\250/\344\272\213\345\212\241\351\232\224\347\246\273-\344\270\272\344\273\200\344\271\210\344\275\240\346\224\271\344\272\206\346\210\221\350\277\230\347\234\213\344\270\215\350\247\201.md"
new file mode 100644
index 0000000..668afd5
--- /dev/null
+++ "b/docs/\345\255\230\345\202\250/\344\272\213\345\212\241\351\232\224\347\246\273-\344\270\272\344\273\200\344\271\210\344\275\240\346\224\271\344\272\206\346\210\221\350\277\230\347\234\213\344\270\215\350\247\201.md"
@@ -0,0 +1,107 @@
+# 事务隔离:为什么你改了我还看不见?
+
+提到事务,你肯定不陌生,和数据库打交道的时候,我们总是会用到事务。最经典的例子就是转账,你要给朋友小王转 100 块钱,而此时你的银行卡只有 100 块钱。
+
+转账过程具体到程序里会有一系列的操作,比如查询余额、做加减法、更新余额等,这些操作必须保证是一体的,不然等程序查完之后,还没做减法之前,你这 100 块钱,完全可以借着这个时间差再查一次,然后再给另外一个朋友转账,如果银行这么整,不就乱了么?这时就要用到“事务”这个概念了。
+
+简单来说,事务就是要保证一组数据库操作,要么全部成功,要么全部失败。在 MySQL 中,事务支持是在引擎层实现的。你现在知道,MySQL 是一个支持多引擎的系统,但并不是所有的引擎都支持事务。比如 MySQL 原生的 MyISAM 引擎就不支持事务,这也是 MyISAM 被 InnoDB 取代的重要原因之一。
+
+今天的文章里,我将会以 InnoDB 为例,剖析 MySQL 在事务支持方面的特定实现,并基于原理给出相应的实践建议,希望这些案例能加深你对 MySQL 事务原理的理解。
+
+## 隔离性与隔离级别
+
+提到事务,你肯定会想到 ACID(Atomicity、Consistency、Isolation、Durability,即原子性、一致性、隔离性、持久性),今天我们就来说说其中 I,也就是“隔离性”。
+
+当数据库上有多个事务同时执行的时候,就可能出现脏读(dirty read)、不可重复读(non-repeatable read)、幻读(phantom read)的问题,为了解决这些问题,就有了“隔离级别”的概念。
+
+在谈隔离级别之前,你首先要知道,你隔离得越严实,效率就会越低。因此很多时候,我们都要在二者之间寻找一个平衡点。SQL 标准的事务隔离级别包括:读未提交(read uncommitted)、读提交(read committed)、可重复读(repeatable read)和串行化(serializable )。下面我逐一为你解释:
+
+- 读未提交是指,一个事务还没提交时,它做的变更就能被别的事务看到。
+- 读提交是指,一个事务提交之后,它做的变更才会被其他事务看到。
+- 可重复读是指,一个事务执行过程中看到的数据,总是跟这个事务在启动时看到的数据是一致的。当然在可重复读隔离级别下,未提交变更对其他事务也是不可见的。
+- 串行化,顾名思义是对于同一行记录,“写”会加“写锁”,“读”会加“读锁”。当出现读写锁冲突的时候,后访问的事务必须等前一个事务执行完成,才能继续执行。
+
+其中“读提交”和“可重复读”比较难理解,所以我用一个例子说明这几种隔离级别。假设数据表 T 中只有一列,其中一行的值为 1,下面是按照时间顺序执行两个事务的行为。
+
+> mysql> create table T(c int) engine=InnoDB;
+> mysql> insert into T(c) values(1);
+
+
+
+我们来看看在不同的隔离级别下,事务 A 会有哪些不同的返回结果,也就是图里面 V1、V2、V3 的返回值分别是什么。
+
+- 若隔离级别是“读未提交”, 则 V1 的值就是 2。这时候事务 B 虽然还没有提交,但是结果已经被 A 看到了。因此,V2、V3 也都是 2。
+- 若隔离级别是“读提交”,则 V1 是 1,V2 的值是 2。事务 B 的更新在提交后才能被 A 看到。所以, V3 的值也是 2。
+- 若隔离级别是“可重复读”,则 V1、V2 是 1,V3 是 2。之所以 V2 还是 1,遵循的就是这个要求:事务在执行期间看到的数据前后必须是一致的。
+- 若隔离级别是“串行化”,则在事务 B 执行“将 1 改成 2”的时候,会被锁住。直到事务 A 提交后,事务 B 才可以继续执行。所以从 A 的角度看, V1、V2 值是 1,V3 的值是 2。
+
+在实现上,数据库里面会创建一个视图,访问的时候以视图的逻辑结果为准。在“可重复读”隔离级别下,这个视图是在事务启动时创建的,整个事务存在期间都用这个视图。在“读提交”隔离级别下,这个视图是在每个 SQL 语句开始执行的时候创建的。这里需要注意的是,“读未提交”隔离级别下直接返回记录上的最新值,没有视图概念;而“串行化”隔离级别下直接用加锁的方式来避免并行访问。
+
+我们可以看到在不同的隔离级别下,数据库行为是有所不同的。Oracle 数据库的默认隔离级别其实就是“读提交”,因此对于一些从 Oracle 迁移到 MySQL 的应用,为保证数据库隔离级别的一致,你一定要记得将 MySQL 的隔离级别设置为“读提交”。
+
+配置的方式是,将启动参数 transaction-isolation 的值设置成 READ-COMMITTED。你可以用 show variables 来查看当前的值。
+
+```text
+mysql> show variables like 'transaction_isolation';
+
++-----------------------+----------------+
+
+| Variable_name | Value |
+
++-----------------------+----------------+
+
+| transaction_isolation | READ-COMMITTED |
+
++-----------------------+----------------+
+```
+
+总结来说,存在即合理,哪个隔离级别都有它自己的使用场景,你要根据自己的业务情况来定。我想你可能会问那什么时候需要“可重复读”的场景呢?我们来看一个数据校对逻辑的案例。
+
+假设你在管理一个个人银行账户表。一个表存了每个月月底的余额,一个表存了账单明细。这时候你要做数据校对,也就是判断上个月的余额和当前余额的差额,是否与本月的账单明细一致。你一定希望在校对过程中,即使有用户发生了一笔新的交易,也不影响你的校对结果。
+
+这时候使用“可重复读”隔离级别就很方便。事务启动时的视图可以认为是静态的,不受其他事务更新的影响。
+
+## 事务隔离的实现
+
+理解了事务的隔离级别,我们再来看看事务隔离具体是怎么实现的。这里我们展开说明“可重复读”。
+
+在 MySQL 中,实际上每条记录在更新的时候都会同时记录一条回滚操作。记录上的最新值,通过回滚操作,都可以得到前一个状态的值。
+
+假设一个值从 1 被按顺序改成了 2、3、4,在回滚日志里面就会有类似下面的记录。
+
+
+
+当前值是 4,但是在查询这条记录的时候,不同时刻启动的事务会有不同的 read-view。如图中看到的,在视图 A、B、C 里面,这一个记录的值分别是 1、2、4,同一条记录在系统中可以存在多个版本,就是数据库的多版本并发控制(MVCC)。对于 read-view A,要得到 1,就必须将当前值依次执行图中所有的回滚操作得到。
+
+同时你会发现,即使现在有另外一个事务正在将 4 改成 5,这个事务跟 read-view A、B、C 对应的事务是不会冲突的。
+
+你一定会问,回滚日志总不能一直保留吧,什么时候删除呢?答案是,在不需要的时候才删除。也就是说,系统会判断,当没有事务再需要用到这些回滚日志时,回滚日志会被删除。
+
+什么时候才不需要了呢?就是当系统里没有比这个回滚日志更早的 read-view 的时候。
+
+基于上面的说明,我们来讨论一下为什么建议你尽量不要使用长事务。
+
+长事务意味着系统里面会存在很老的事务视图。由于这些事务随时可能访问数据库里面的任何数据,所以这个事务提交之前,数据库里面它可能用到的回滚记录都必须保留,这就会导致大量占用存储空间。
+
+在 MySQL 5.5 及以前的版本,回滚日志是跟数据字典一起放在 ibdata 文件里的,即使长事务最终提交,回滚段被清理,文件也不会变小。我见过数据只有 20GB,而回滚段有 200GB 的库。最终只好为了清理回滚段,重建整个库。
+
+除了对回滚段的影响,长事务还占用锁资源,也可能拖垮整个库,这个我们会在后面讲锁的时候展开。
+
+## 事务的启动方式
+
+如前面所述,长事务有这些潜在风险,我当然是建议你尽量避免。其实很多时候业务开发同学并不是有意使用长事务,通常是由于误用所致。MySQL 的事务启动方式有以下几种:
+
+1、显式启动事务语句, begin 或 start transaction。配套的提交语句是 commit,回滚语句是 rollback。
+
+2、set autocommit=0,这个命令会将这个线程的自动提交关掉。意味着如果你只执行一个 select 语句,这个事务就启动了,而且并不会自动提交。这个事务持续存在直到你主动执行 commit 或 rollback 语句,或者断开连接。
+有些客户端连接框架会默认连接成功后先执行一个 set autocommit=0 的命令。这就导致接下来的查询都在事务中,如果是长连接,就导致了意外的长事务。
+
+因此,我会建议你总是使用 set autocommit=1, 通过显式语句的方式来启动事务。
+
+但是有的开发同学会纠结“多一次交互”的问题。对于一个需要频繁使用事务的业务,第二种方式每个事务在开始时都不需要主动执行一次 “begin”,减少了语句的交互次数。如果你也有这个顾虑,我建议你使用 commit work and chain 语法。
+
+在 autocommit 为 1 的情况下,用 begin 显式启动的事务,如果执行 commit 则提交事务。如果执行 commit work and chain,则是提交事务并自动启动下一个事务,这样也省去了再次执行 begin 语句的开销。同时带来的好处是从程序开发的角度明确地知道每个语句是否处于事务中。
+
+你可以在 information_schema 库的 innodb_trx 这个表中查询长事务,比如下面这个语句,用于查找持续时间超过 60s 的事务。
+
+> select * from information_schema.innodb_trx where TIME_TO_SEC(timediff(now(),trx_started))>60
\ No newline at end of file
diff --git "a/docs/\345\255\230\345\202\250/\345\205\250\345\261\200\351\224\201\345\222\214\350\241\250\351\224\201-\347\273\231\350\241\250\345\212\240\344\270\252\345\255\227\346\256\265\346\200\216\344\271\210\346\234\211\350\277\231\344\271\210\345\244\232\351\230\273\347\242\215.md" "b/docs/\345\255\230\345\202\250/\345\205\250\345\261\200\351\224\201\345\222\214\350\241\250\351\224\201-\347\273\231\350\241\250\345\212\240\344\270\252\345\255\227\346\256\265\346\200\216\344\271\210\346\234\211\350\277\231\344\271\210\345\244\232\351\230\273\347\242\215.md"
new file mode 100644
index 0000000..4c70adb
--- /dev/null
+++ "b/docs/\345\255\230\345\202\250/\345\205\250\345\261\200\351\224\201\345\222\214\350\241\250\351\224\201-\347\273\231\350\241\250\345\212\240\344\270\252\345\255\227\346\256\265\346\200\216\344\271\210\346\234\211\350\277\231\344\271\210\345\244\232\351\230\273\347\242\215.md"
@@ -0,0 +1 @@
+# 全局锁和表锁:给表加个字段怎么有这么多阻碍
\ No newline at end of file
diff --git "a/docs/\345\255\230\345\202\250/\345\244\207\345\272\223\344\270\272\344\273\200\344\271\210\344\274\232\345\273\266\350\277\237\345\245\275\345\207\240\344\270\252\345\260\217\346\227\266.md" "b/docs/\345\255\230\345\202\250/\345\244\207\345\272\223\344\270\272\344\273\200\344\271\210\344\274\232\345\273\266\350\277\237\345\245\275\345\207\240\344\270\252\345\260\217\346\227\266.md"
new file mode 100644
index 0000000..5374561
--- /dev/null
+++ "b/docs/\345\255\230\345\202\250/\345\244\207\345\272\223\344\270\272\344\273\200\344\271\210\344\274\232\345\273\266\350\277\237\345\245\275\345\207\240\344\270\252\345\260\217\346\227\266.md"
@@ -0,0 +1 @@
+# 备库为什么会延迟好几个小时
\ No newline at end of file
diff --git "a/docs/\345\255\230\345\202\250/\345\246\202\344\275\225\345\210\244\346\226\255\344\270\200\344\270\252\346\225\260\346\215\256\345\272\223\346\230\257\344\270\215\346\230\257\345\207\272\351\227\256\351\242\230\344\272\206.md" "b/docs/\345\255\230\345\202\250/\345\246\202\344\275\225\345\210\244\346\226\255\344\270\200\344\270\252\346\225\260\346\215\256\345\272\223\346\230\257\344\270\215\346\230\257\345\207\272\351\227\256\351\242\230\344\272\206.md"
new file mode 100644
index 0000000..6a946bf
--- /dev/null
+++ "b/docs/\345\255\230\345\202\250/\345\246\202\344\275\225\345\210\244\346\226\255\344\270\200\344\270\252\346\225\260\346\215\256\345\272\223\346\230\257\344\270\215\346\230\257\345\207\272\351\227\256\351\242\230\344\272\206.md"
@@ -0,0 +1 @@
+# 如何判断一个数据库是不是出问题了
\ No newline at end of file
diff --git "a/docs/\345\255\230\345\202\250/\345\246\202\344\275\225\346\255\243\347\241\256\345\234\260\346\230\276\347\244\272\351\232\217\346\234\272\346\266\210\346\201\257.md" "b/docs/\345\255\230\345\202\250/\345\246\202\344\275\225\346\255\243\347\241\256\345\234\260\346\230\276\347\244\272\351\232\217\346\234\272\346\266\210\346\201\257.md"
new file mode 100644
index 0000000..d0144b6
--- /dev/null
+++ "b/docs/\345\255\230\345\202\250/\345\246\202\344\275\225\346\255\243\347\241\256\345\234\260\346\230\276\347\244\272\351\232\217\346\234\272\346\266\210\346\201\257.md"
@@ -0,0 +1 @@
+# 如何正确地显示随机消息
\ No newline at end of file
diff --git "a/docs/\345\255\230\345\202\250/\345\271\273\350\257\273\346\230\257\344\273\200\344\271\210\357\274\214\345\271\273\350\257\273\346\234\211\344\273\200\344\271\210\351\227\256\351\242\230.md" "b/docs/\345\255\230\345\202\250/\345\271\273\350\257\273\346\230\257\344\273\200\344\271\210\357\274\214\345\271\273\350\257\273\346\234\211\344\273\200\344\271\210\351\227\256\351\242\230.md"
new file mode 100644
index 0000000..0240110
--- /dev/null
+++ "b/docs/\345\255\230\345\202\250/\345\271\273\350\257\273\346\230\257\344\273\200\344\271\210\357\274\214\345\271\273\350\257\273\346\234\211\344\273\200\344\271\210\351\227\256\351\242\230.md"
@@ -0,0 +1 @@
+# 幻读是什么,幻读有什么问题
\ No newline at end of file
diff --git "a/docs/\345\255\230\345\202\250/\346\200\216\344\271\210\347\273\231\345\255\227\347\254\246\344\270\262\345\255\227\346\256\265\345\212\240\347\264\242\345\274\225.md" "b/docs/\345\255\230\345\202\250/\346\200\216\344\271\210\347\273\231\345\255\227\347\254\246\344\270\262\345\255\227\346\256\265\345\212\240\347\264\242\345\274\225.md"
new file mode 100644
index 0000000..bd51313
--- /dev/null
+++ "b/docs/\345\255\230\345\202\250/\346\200\216\344\271\210\347\273\231\345\255\227\347\254\246\344\270\262\345\255\227\346\256\265\345\212\240\347\264\242\345\274\225.md"
@@ -0,0 +1 @@
+# 怎么给字符串字段加索引
\ No newline at end of file
diff --git "a/docs/\345\255\230\345\202\250/\346\231\256\351\200\232\347\264\242\345\274\225\345\222\214\345\224\257\344\270\200\347\264\242\345\274\225\357\274\214\345\272\224\350\257\245\346\200\216\344\271\210\351\200\211\346\213\251.md" "b/docs/\345\255\230\345\202\250/\346\231\256\351\200\232\347\264\242\345\274\225\345\222\214\345\224\257\344\270\200\347\264\242\345\274\225\357\274\214\345\272\224\350\257\245\346\200\216\344\271\210\351\200\211\346\213\251.md"
new file mode 100644
index 0000000..6fc4b2c
--- /dev/null
+++ "b/docs/\345\255\230\345\202\250/\346\231\256\351\200\232\347\264\242\345\274\225\345\222\214\345\224\257\344\270\200\347\264\242\345\274\225\357\274\214\345\272\224\350\257\245\346\200\216\344\271\210\351\200\211\346\213\251.md"
@@ -0,0 +1 @@
+# 普通索引和唯一索引,应该怎么选择
\ No newline at end of file
diff --git "a/docs/\345\255\230\345\202\250/\346\267\261\345\205\245\346\265\205\345\207\272\347\264\242\345\274\225-\344\270\212.md" "b/docs/\345\255\230\345\202\250/\346\267\261\345\205\245\346\265\205\345\207\272\347\264\242\345\274\225-\344\270\212.md"
new file mode 100644
index 0000000..142bd37
--- /dev/null
+++ "b/docs/\345\255\230\345\202\250/\346\267\261\345\205\245\346\265\205\345\207\272\347\264\242\345\274\225-\344\270\212.md"
@@ -0,0 +1,144 @@
+# 深入浅出索引(上)
+
+提到数据库索引,我想你并不陌生,在日常工作中会经常接触到。比如某一个 SQL 查询比较慢,分析完原因之后,你可能就会说“给某个字段加个索引吧”之类的解决方案。但到底什么是索引,索引又是如何工作的呢?今天就让我们一起来聊聊这个话题吧。
+
+数据库索引的内容比较多,我分成了上下两篇文章。索引是数据库系统里面最重要的概念之一,所以我希望你能够耐心看完。在后面的实战文章中,我也会经常引用这两篇文章中提到的知识点,加深你对数据库索引的理解。
+
+一句话简单来说,索引的出现其实就是为了提高数据查询的效率,就像书的目录一样。一本 500 页的书,如果你想快速找到其中的某一个知识点,在不借助目录的情况下,那我估计你可得找一会儿。同样,对于数据库的表而言,索引其实就是它的“目录”。
+
+## 索引的常见模型
+
+索引的出现是为了提高查询效率,但是实现索引的方式却有很多种,所以这里也就引入了索引模型的概念。可以用于提高读写效率的数据结构很多,这里我先给你介绍三种常见、也比较简单的数据结构,它们分别是哈希表、有序数组和搜索树。
+
+下面我主要从使用的角度,为你简单分析一下这三种模型的区别。
+
+哈希表是一种以键 - 值(key-value)存储数据的结构,我们只要输入待查找的值即 key,就可以找到其对应的值即 Value。哈希的思路很简单,把值放在数组里,用一个哈希函数把 key 换算成一个确定的位置,然后把 value 放在数组的这个位置。
+
+不可避免地,多个 key 值经过哈希函数的换算,会出现同一个值的情况。处理这种情况的一种方法是,拉出一个链表。
+
+假设,你现在维护着一个身份证信息和姓名的表,需要根据身份证号查找对应的名字,这时对应的哈希索引的示意图如下所示:
+
+
+
+图中,User2 和 User4 根据身份证号算出来的值都是 N,但没关系,后面还跟了一个链表。假设,这时候你要查 ID_card_n2 对应的名字是什么,处理步骤就是:首先,将 ID_card_n2 通过哈希函数算出 N;然后,按顺序遍历,找到 User2。
+
+需要注意的是,图中四个 ID_card_n 的值并不是递增的,这样做的好处是增加新的 User 时速度会很快,只需要往后追加。但缺点是,因为不是有序的,所以哈希索引做区间查询的速度是很慢的。
+
+你可以设想下,如果你现在要找身份证号在 [ID_card_X, ID_card_Y] 这个区间的所有用户,就必须全部扫描一遍了。
+
+所以,哈希表这种结构适用于只有等值查询的场景,比如 Memcached 及其他一些 NoSQL 引擎。
+
+而有序数组在等值查询和范围查询场景中的性能就都非常优秀。还是上面这个根据身份证号查名字的例子,如果我们使用有序数组来实现的话,示意图如下所示:
+
+
+
+这里我们假设身份证号没有重复,这个数组就是按照身份证号递增的顺序保存的。这时候如果你要查 ID_card_n2 对应的名字,用二分法就可以快速得到,这个时间复杂度是 O(log(N))。
+
+同时很显然,这个索引结构支持范围查询。你要查身份证号在 [ID_card_X, ID_card_Y] 区间的 User,可以先用二分法找到 ID_card_X(如果不存在 ID_card_X,就找到大于 ID_card_X 的第一个 User),然后向右遍历,直到查到第一个大于 ID_card_Y 的身份证号,退出循环。
+
+如果仅仅看查询效率,有序数组就是最好的数据结构了。但是,在需要更新数据的时候就麻烦了,你往中间插入一个记录就必须得挪动后面所有的记录,成本太高。
+
+所以,有序数组索引只适用于静态存储引擎,比如你要保存的是 2017 年某个城市的所有人口信息,这类不会再修改的数据。
+
+二叉搜索树也是课本里的经典数据结构了。还是上面根据身份证号查名字的例子,如果我们用二叉搜索树来实现的话,示意图如下所示:
+
+
+
+二叉搜索树的特点是:每个节点的左儿子小于父节点,父节点又小于右儿子。这样如果你要查 ID_card_n2 的话,按照图中的搜索顺序就是按照 UserA -> UserC -> UserF -> User2 这个路径得到。这个时间复杂度是 O(log(N))。
+
+当然为了维持 O(log(N)) 的查询复杂度,你就需要保持这棵树是平衡二叉树。为了做这个保证,更新的时间复杂度也是 O(log(N))。
+
+树可以有二叉,也可以有多叉。多叉树就是每个节点有多个儿子,儿子之间的大小保证从左到右递增。二叉树是搜索效率最高的,但是实际上大多数的数据库存储却并不使用二叉树。其原因是,索引不止存在内存中,还要写到磁盘上。
+
+你可以想象一下一棵 100 万节点的平衡二叉树,树高 20。一次查询可能需要访问 20 个数据块。在机械硬盘时代,从磁盘随机读一个数据块需要 10 ms 左右的寻址时间。也就是说,对于一个 100 万行的表,如果使用二叉树来存储,单独访问一个行可能需要 20 个 10 ms 的时间,这个查询可真够慢的。
+
+为了让一个查询尽量少地读磁盘,就必须让查询过程访问尽量少的数据块。那么,我们就不应该使用二叉树,而是要使用“N 叉”树。这里,“N 叉”树中的“N”取决于数据块的大小。
+
+以 InnoDB 的一个整数字段索引为例,这个 N 差不多是 1200。这棵树高是 4 的时候,就可以存 1200 的 3 次方个值,这已经 17 亿了。考虑到树根的数据块总是在内存中的,一个 10 亿行的表上一个整数字段的索引,查找一个值最多只需要访问 3 次磁盘。其实,树的第二层也有很大概率在内存中,那么访问磁盘的平均次数就更少了。
+
+N 叉树由于在读写上的性能优点,以及适配磁盘的访问模式,已经被广泛应用在数据库引擎中了。
+
+不管是哈希还是有序数组,或者 N 叉树,它们都是不断迭代、不断优化的产物或者解决方案。数据库技术发展到今天,跳表、LSM 树等数据结构也被用于引擎设计中,这里我就不再一一展开了。
+
+你心里要有个概念,数据库底层存储的核心就是基于这些数据模型的。每碰到一个新数据库,我们需要先关注它的数据模型,这样才能从理论上分析出这个数据库的适用场景。
+
+截止到这里,我用了半篇文章的篇幅和你介绍了不同的数据结构,以及它们的适用场景,你可能会觉得有些枯燥。但是,我建议你还是要多花一些时间来理解这部分内容,毕竟这是数据库处理数据的核心概念之一,在分析问题的时候会经常用到。当你理解了索引的模型后,就会发现在分析问题的时候会有一个更清晰的视角,体会到引擎设计的精妙之处。
+
+现在,我们一起进入相对偏实战的内容吧。
+
+在 MySQL 中,索引是在存储引擎层实现的,所以并没有统一的索引标准,即不同存储引擎的索引的工作方式并不一样。而即使多个存储引擎支持同一种类型的索引,其底层的实现也可能不同。由于 InnoDB 存储引擎在 MySQL 数据库中使用最为广泛,所以下面我就以 InnoDB 为例,和你分析一下其中的索引模型。
+
+## InnoDB 的索引模型
+
+在 InnoDB 中,表都是根据主键顺序以索引的形式存放的,这种存储方式的表称为索引组织表。又因为前面我们提到的,InnoDB 使用了 B+ 树索引模型,所以数据都是存储在 B+ 树中的。
+
+每一个索引在 InnoDB 里面对应一棵 B+ 树。
+
+假设,我们有一个主键列为 ID 的表,表中有字段 k,并且在 k 上有索引。
+
+这个表的建表语句是:
+
+```text
+mysql> create table T(
+id int primary key,
+k int not null,
+name varchar(16),
+index (k))engine=InnoDB;
+```
+
+表中 R1~R5 的 (ID,k) 值分别为 (100,1)、(200,2)、(300,3)、(500,5) 和 (600,6),两棵树的示例示意图如下。
+
+
+
+从图中不难看出,根据叶子节点的内容,索引类型分为主键索引和非主键索引。
+
+主键索引的叶子节点存的是整行数据。在 InnoDB 里,主键索引也被称为聚簇索引(clustered index)。
+
+非主键索引的叶子节点内容是主键的值。在 InnoDB 里,非主键索引也被称为二级索引(secondary index)。
+
+根据上面的索引结构说明,我们来讨论一个问题:基于主键索引和普通索引的查询有什么区别?
+
+- 如果语句是 select * from T where ID=500,即主键查询方式,则只需要搜索 ID 这棵 B+ 树;
+- 如果语句是 select * from T where k=5,即普通索引查询方式,则需要先搜索 k 索引树,得到 ID 的值为 500,再到 ID 索引树搜索一次。这个过程称为回表。
+
+也就是说,基于非主键索引的查询需要多扫描一棵索引树。因此,我们在应用中应该尽量使用主键查询。
+
+## 索引维护
+
+B+ 树为了维护索引有序性,在插入新值的时候需要做必要的维护。以上面这个图为例,如果插入新的行 ID 值为 700,则只需要在 R5 的记录后面插入一个新记录。如果新插入的 ID 值为 400,就相对麻烦了,需要逻辑上挪动后面的数据,空出位置。
+
+而更糟的情况是,如果 R5 所在的数据页已经满了,根据 B+ 树的算法,这时候需要申请一个新的数据页,然后挪动部分数据过去。这个过程称为页分裂。在这种情况下,性能自然会受影响。
+
+除了性能外,页分裂操作还影响数据页的利用率。原本放在一个页的数据,现在分到两个页中,整体空间利用率降低大约 50%。
+
+当然有分裂就有合并。当相邻两个页由于删除了数据,利用率很低之后,会将数据页做合并。合并的过程,可以认为是分裂过程的逆过程。
+
+基于上面的索引维护过程说明,我们来讨论一个案例:
+
+> 你可能在一些建表规范里面见到过类似的描述,要求建表语句里一定要有自增主键。当然事无绝对,我们来分析一下哪些场景下应该使用自增主键,而哪些场景下不应该。
+
+自增主键是指自增列上定义的主键,在建表语句中一般是这么定义的: NOT NULL PRIMARY KEY AUTO_INCREMENT。
+
+插入新记录的时候可以不指定 ID 的值,系统会获取当前 ID 最大值加 1 作为下一条记录的 ID 值。
+
+也就是说,自增主键的插入数据模式,正符合了我们前面提到的递增插入的场景。每次插入一条新记录,都是追加操作,都不涉及到挪动其他记录,也不会触发叶子节点的分裂。
+
+而有业务逻辑的字段做主键,则往往不容易保证有序插入,这样写数据成本相对较高。
+
+除了考虑性能外,我们还可以从存储空间的角度来看。假设你的表中确实有一个唯一字段,比如字符串类型的身份证号,那应该用身份证号做主键,还是用自增字段做主键呢?
+
+由于每个非主键索引的叶子节点上都是主键的值。如果用身份证号做主键,那么每个二级索引的叶子节点占用约 20 个字节,而如果用整型做主键,则只要 4 个字节,如果是长整型(bigint)则是 8 个字节。
+
+显然,主键长度越小,普通索引的叶子节点就越小,普通索引占用的空间也就越小。
+
+所以,从性能和存储空间方面考量,自增主键往往是更合理的选择。
+
+有没有什么场景适合用业务字段直接做主键的呢?还是有的。比如,有些业务的场景需求是这样的:
+
+只有一个索引;
+该索引必须是唯一索引。
+你一定看出来了,这就是典型的 KV 场景。
+
+由于没有其他索引,所以也就不用考虑其他索引的叶子节点大小的问题。
+
+这时候我们就要优先考虑上一段提到的“尽量使用主键查询”原则,直接将这个索引设置为主键,可以避免每次查询需要搜索两棵树。
\ No newline at end of file
diff --git "a/docs/\345\255\230\345\202\250/\346\267\261\345\205\245\346\265\205\345\207\272\347\264\242\345\274\225-\344\270\213.md" "b/docs/\345\255\230\345\202\250/\346\267\261\345\205\245\346\265\205\345\207\272\347\264\242\345\274\225-\344\270\213.md"
new file mode 100644
index 0000000..b2e4f81
--- /dev/null
+++ "b/docs/\345\255\230\345\202\250/\346\267\261\345\205\245\346\265\205\345\207\272\347\264\242\345\274\225-\344\270\213.md"
@@ -0,0 +1 @@
+# 深入浅出索引(下)
\ No newline at end of file
diff --git "a/docs/\345\255\230\345\202\250/\350\241\214\351\224\201\345\212\237\350\277\207-\346\200\216\344\271\210\345\207\217\345\260\221\350\241\214\351\224\201\345\257\271\346\200\247\350\203\275\347\232\204\345\275\261\345\223\215.md" "b/docs/\345\255\230\345\202\250/\350\241\214\351\224\201\345\212\237\350\277\207-\346\200\216\344\271\210\345\207\217\345\260\221\350\241\214\351\224\201\345\257\271\346\200\247\350\203\275\347\232\204\345\275\261\345\223\215.md"
new file mode 100644
index 0000000..bdb219a
--- /dev/null
+++ "b/docs/\345\255\230\345\202\250/\350\241\214\351\224\201\345\212\237\350\277\207-\346\200\216\344\271\210\345\207\217\345\260\221\350\241\214\351\224\201\345\257\271\346\200\247\350\203\275\347\232\204\345\275\261\345\223\215.md"
@@ -0,0 +1 @@
+# 行锁功过:怎么减少行锁对性能的影响
\ No newline at end of file
diff --git "a/docs/\345\255\230\345\202\250/\350\257\273\345\206\231\345\210\206\347\246\273\346\234\211\345\223\252\344\272\233\345\235\221.md" "b/docs/\345\255\230\345\202\250/\350\257\273\345\206\231\345\210\206\347\246\273\346\234\211\345\223\252\344\272\233\345\235\221.md"
new file mode 100644
index 0000000..3ed3f7f
--- /dev/null
+++ "b/docs/\345\255\230\345\202\250/\350\257\273\345\206\231\345\210\206\347\246\273\346\234\211\345\223\252\344\272\233\345\235\221.md"
@@ -0,0 +1 @@
+# 读写分离有哪些坑
\ No newline at end of file
diff --git "a/docs/\346\234\257\350\257\255\345\257\271\347\205\247\350\241\250.md" "b/docs/\346\234\257\350\257\255\345\257\271\347\205\247\350\241\250.md"
index a04f7c7..0caf026 100644
--- "a/docs/\346\234\257\350\257\255\345\257\271\347\205\247\350\241\250.md"
+++ "b/docs/\346\234\257\350\257\255\345\257\271\347\205\247\350\241\250.md"
@@ -48,6 +48,10 @@ ACK (Acknowledgement)即是确认字符,在数据通信中,接收站发给
传输层安全性协议(英语:Transport Layer Security,缩写作 TLS),及其前身安全套接层(Secure Sockets Layer,缩写作 SSL)是一种安全协议,目的是为互联网通信提供安全及数据完整性保障
+## ADT
+
+抽象数据类型(Abstract Data Type,ADT)是计算机科学中具有类似行为的特定类别的数据结构的数学模型;或者具有类似语义的一种或多种程序设计语言的数据类型。抽象数据类型是间接定义的,通过其上的可执行的操作以及这些操作的效果的数学约束(与可能的代价)
+
## PHP
PHP(全称:PHP:Hypertext Preprocessor,即“PHP:超文本预处理器”)是一种开源的通用计算机脚本语言,尤其适用于网络开发并可嵌入 HTML 中使用
diff --git "a/docs/\347\225\252\345\244\226/assets/\347\274\226\347\240\201\347\203\255\346\203\205-01-tiobe-2025-dec.png" "b/docs/\347\225\252\345\244\226/assets/\347\274\226\347\240\201\347\203\255\346\203\205-01-tiobe-2025-dec.png"
new file mode 100644
index 0000000..64ab6d4
Binary files /dev/null and "b/docs/\347\225\252\345\244\226/assets/\347\274\226\347\240\201\347\203\255\346\203\205-01-tiobe-2025-dec.png" differ
diff --git "a/docs/\347\225\252\345\244\226/assets/\347\274\226\347\240\201\347\203\255\346\203\205-02-21\345\244\251\345\255\246\351\200\232PHP.png" "b/docs/\347\225\252\345\244\226/assets/\347\274\226\347\240\201\347\203\255\346\203\205-02-21\345\244\251\345\255\246\351\200\232PHP.png"
new file mode 100644
index 0000000..e83d42c
Binary files /dev/null and "b/docs/\347\225\252\345\244\226/assets/\347\274\226\347\240\201\347\203\255\346\203\205-02-21\345\244\251\345\255\246\351\200\232PHP.png" differ
diff --git "a/docs/\347\225\252\345\244\226/assets/\347\274\226\347\240\201\347\203\255\346\203\205-03-\346\273\264\346\273\264PHP\345\262\227\344\275\215.png" "b/docs/\347\225\252\345\244\226/assets/\347\274\226\347\240\201\347\203\255\346\203\205-03-\346\273\264\346\273\264PHP\345\262\227\344\275\215.png"
new file mode 100644
index 0000000..823dc3c
Binary files /dev/null and "b/docs/\347\225\252\345\244\226/assets/\347\274\226\347\240\201\347\203\255\346\203\205-03-\346\273\264\346\273\264PHP\345\262\227\344\275\215.png" differ
diff --git "a/docs/\347\225\252\345\244\226/assets/\347\274\226\347\240\201\347\203\255\346\203\205-04-\344\272\272\347\224\237\346\204\217\344\271\2111.jpg" "b/docs/\347\225\252\345\244\226/assets/\347\274\226\347\240\201\347\203\255\346\203\205-04-\344\272\272\347\224\237\346\204\217\344\271\2111.jpg"
new file mode 100644
index 0000000..27ad8b6
Binary files /dev/null and "b/docs/\347\225\252\345\244\226/assets/\347\274\226\347\240\201\347\203\255\346\203\205-04-\344\272\272\347\224\237\346\204\217\344\271\2111.jpg" differ
diff --git "a/docs/\347\225\252\345\244\226/assets/\347\274\226\347\240\201\347\203\255\346\203\205-05-\344\272\272\347\224\237\346\204\217\344\271\2112.jpg" "b/docs/\347\225\252\345\244\226/assets/\347\274\226\347\240\201\347\203\255\346\203\205-05-\344\272\272\347\224\237\346\204\217\344\271\2112.jpg"
new file mode 100644
index 0000000..0a556f5
Binary files /dev/null and "b/docs/\347\225\252\345\244\226/assets/\347\274\226\347\240\201\347\203\255\346\203\205-05-\344\272\272\347\224\237\346\204\217\344\271\2112.jpg" differ
diff --git "a/docs/\347\225\252\345\244\226/\344\275\240\347\232\204\347\274\226\347\240\201\347\203\255\346\203\205\346\230\257\345\246\202\344\275\225\346\266\210\351\200\200\347\232\204.md" "b/docs/\347\225\252\345\244\226/\344\275\240\347\232\204\347\274\226\347\240\201\347\203\255\346\203\205\346\230\257\345\246\202\344\275\225\346\266\210\351\200\200\347\232\204.md"
new file mode 100644
index 0000000..6bd5d55
--- /dev/null
+++ "b/docs/\347\225\252\345\244\226/\344\275\240\347\232\204\347\274\226\347\240\201\347\203\255\346\203\205\346\230\257\345\246\202\344\275\225\346\266\210\351\200\200\347\232\204.md"
@@ -0,0 +1,131 @@
+# 你的编码热情是如何消退的?
+
+本文基于 PHP 从业者**编码热情会随时间逐渐消退**这是事实,探讨导致消退的原因,分享自己重拾热情的方式,抛砖引玉,**助你找到自己重拾热情的方式**。全文共计 **3163 字**,阅读时间约 **16 分钟**,作者:凌枫。如果文章对你有帮助,请关注和转发,谢谢!
+
+## 一、热情消退现象
+
+作为一名 PHP 开发者,你是否察觉到曾经那种初学时的热情在逐渐消退?从渴望编写代码,到逐渐将编程视为例行公事,而简单归结为:**提不起劲?**这种转变在技术领域尤为常见。
+
+**技术学习动力匮乏**是热情消退的首要信号。当发现自己对新框架和语言更新不再感兴趣,宁愿重复使用旧技术而不愿探索新方案时,就需要警惕了。**工作倦怠**则表现为将编程视为重复性劳动,创造力明显下降,只求完成功能而不追求代码优美。**创新意识减弱**则体现在满足于完成需求而非追求技术卓越,对代码质量和架构设计失去往日的热情。
+
+许多 PHP 开发者都经历过这样的阶段:曾经乐在其中的代码实现变成了单调的复制粘贴,问题解决能力退化为机械式的功能堆砌。更令人担忧的是,PHP 在全球编程语言生态中的地位正在经历显著变化,TIOBE 指数显示 PHP 的排名已跌至历史最低点第 16 位(2025 年 12 月),另外 PHP 高端岗位均面临 Java 和 Go 的直接竞争,这些原因无疑加速了 PHP 开发者的热情消退。
+
+
+
+## 二、原因剖析
+
+### 1、技术学习热情消退
+
+PHP 开发者技术学习热情的消退,往往始于技术成长的“S型曲线”陷阱。**许多开发者在职业生涯初期经历了急速成长后,会进入一个漫长的平台期。**这个阶段最显著的特点是:缺乏有挑战性的任务,日常工作中充斥着重复的 CRUD(增删改查)业务逻辑开发,难以接触到高并发、分布式系统等更有深度的技术场景。
+
+随着升职加薪节奏变缓,技术成长的经济回报边际效应递减,进一步削弱了学习动力。当技术能力达到一定水平后,单纯的薪资激励不再像早期那样有效,而 PHP 开发者在中小型企业的薪资上限通常不如中大型企业就职的 Java 或 Go 等语言。此外,家庭琐事的打扰也不容忽视——随着年龄增长,开发者需要投入更多时间在家庭责任上,用于深度学习和思考的完整时间块被碎片化。
+更深层次的问题是,部分 PHP 开发者陷入了“工具化”的舒适区,仅将编程视为谋生手段而非创造活动。当编码不再带来成就感,而沦为机械式的任务完成时,热情自然逐渐消退。
+
+
+
+### 2、语言局限性与生态劣势
+
+在生态系统方面,PHP 的局限性尤为明显。相比 Java 在桌面软件、Android、大数据、金融系统、电商平台的成熟生态,Python 在 AI 和数据科学领域的主导地位,以及 Go 在云原生和基础服务器端软件方面的优势,PHP 的生态相对单一,主要集中在传统 Web 开发领域。这种生态劣势使得 PHP 开发者难以参与到技术发展的前沿领域中。语言本身的局限性。**相较 Java 语言,大厂成熟工程实践经验可直接复用到中小企业,进一步挤压 PHP 开发者的生存空间。**
+
+### 3、职业发展瓶颈与工作挑战
+
+随着技术发展,PHP 开发者的职业路径面临显著挑战。许多 PHP 开发者长期局限于业务代码的实现,缺乏对系统架构、设计模式等深层技术原理的理解,这限制了职业发展空间。尤其是在小型软件公司或外包公司工作的开发者,很难有机会经历完整的大型项目开发。
+复杂项目经验的缺乏使不少 PHP 开发者难以胜任架构师等高级角色。随着移动互联网、云计算等新技术兴起,软件系统变得越来越复杂,大型网站对高并发、可用性的要求越来越高。而 PHP 在这些场景下的表现明显处于劣势。
+最终,**PHP 开发者为获得更高端岗位常常面临更换技术栈的艰难抉择。**大厂的核心高并发系统很少采用 PHP,而更多使用 Java 或 Go 等语言,这使得有志于进入一线互联网企业的 PHP 开发者不得不考虑转型。这种为职业发展而放弃擅长技术栈的抉择,本身就是热情消退的重要表现。
+
+
+
+## 三、重拾方式:从消费者到生产者
+
+面对热情消退的困境,探索出了一条转型之路:**从 PHP 消费者转变为 PHP 生产者。**这一转变不仅重燃对 PHP 开发的热情,更为职业发展开辟了新天地。
+
+> PHP 消费者:依托现有游戏玩法,解决业务上的问题。PHP 生产者:质疑现有游戏玩法,设计游戏新玩法,解决业务上的问题。
+
+### 1、深耕工程规范与最佳实践
+
+突然意识到,提升工程规范是保持长期开发热情的关键。PHP 社区已形成了许多优秀实践,包括:
+
+* Composer:PHP 的依赖管理工具,可以快速安装、更新和管理项目依赖库。
+
+* PSR 规范:社区制定的一系列 PHP 编码规范,涵盖自动加载、编码风格等方面。
+
+* PHPStan:静态分析检查工具,帮助提前发现代码问题。
+
+采用测试驱动开发(TDD) 模式后,代码质量显著提升,后续维护成本大大降低。同时,重视代码可读性,确保后续维护者都能轻松理解代码逻辑。
+
+### 2、技术深度上的"蜕变"
+
+蜕变是深度优先的成长,是工匠精神的体现。先从简单的脚本开发转向注重软件设计原则,实践领域驱动设计(DDD)和整洁架构。这一转变使代码从"能用"升级到"优美且可维护"。
+参与开源项目是转变身份的重要一步。通过阅读高质量源代码并向资深开发者学习,逐渐从被动的代码使用者转变为积极的贡献者。当你的代码被广泛使用时,这种成就感极大地激发了进一步探索的动力。
+
+### 3、技术广度上的"裂变"
+
+**裂变是广度优先的成长**,通过不断打破边界引发知识和影响力的链式反应。可行的裂变路径包括:
+
+* PHP + Vue/React(全栈开发)。
+
+* PHP + Go(微服务架构)。
+
+* DevOps 与容器化技术。
+
+特别是通过 phpy 扩展,可以在 PHP 中直接调用 Python 的 AI 库,运行 AI 大模型推理和训练,这为 PHP 开发者打开了通向人工智能领域的大门。
+
+### 4、打造个人生产链条
+
+建立适合自己的开发环境是提升效率的基础。选择强大的 IDE(如 PhpStorm)可以显著提升编码体验,它们提供代码自动补全、语法检查、调试等功能。以及在工作中体验 VScode 并输出最佳实践;拥抱 cursor 等最新 AI 工具并输出 mdc 规则集。
+更重要的是,可以创建了个人工具集,开发专属的代码生成器、自动化测试脚本和部署工具。这些工具不仅解决日常开发中的痛点,还被团队其他成员采用,**真正实现了从代码"消费者"到价值"生产者"的转变**。
+
+## 四、属于你的方式
+
+**转型为生产者不是单一路径**,而是根据个人情况选择合适的成长模式。以下是几种可行的路径:
+
+### 1、"蜕变"优先路径
+
+如果你感到迷茫和瓶颈,请优先选择 **"蜕变"** 。具体方式包括:
+
+* 深入理解 PHP 内核:学习 Zend 引擎、内存管理等底层原理。
+
+* 研究优秀框架源码:阅读 Laravel、Symfony 等框架的源代码,理解设计模式应用。
+
+* 参与开源项目:从解决 issue 开始,逐步参与代码审查和功能开发。
+
+### 2、"裂变"优先路径
+
+如果你感到厌倦和重复,可以尝试 **"裂变"** 。具体方向包括:
+
+* 全栈开发:学习 Vue.js、React 等前端技术,理解前后端协作。
+
+* 微服务架构:探索 Go、Rust 等语言在特定场景下的应用。
+
+* 技术管理:培养项目管理、团队协作能力,扩展职业边界。
+
+### 3、螺旋式成长模型
+
+理想的成长模型是螺旋式上升的,在"深度蜕变"与"广度裂变"之间不断循环。每个循环都让你站在更高维度:
+
+* 阶段一:专注蜕变,夯实 PHP 核心基础。
+
+* 阶段二:触发裂变,拓展技术边界。
+
+* 阶段三:在新领域再次蜕变,深耕新技术点。
+
+* 阶段四:整合升华,形成 T 型或 π 型能力。
+
+> T 型:有一项核心专长(深度),同时具备跨领域知识(广度),如:精通 PHP,又懂 Java / Go,帮助企业转型技术栈。
+>
+> π 型:有至少两项专长(深度),同时具备跨领域知识(广度),如:精通 PHP,又懂其他语言,也懂业务,帮助企业在细分市场站稳脚跟。
+
+## 五、结束语
+
+PHP 开发者热情消退是一个复杂因素最终导致的现象,但并非不可逆转。**通过重新定义自己的技术定位,从被动的代码实现者转变为主动的价值创造者,我们完全可以重拾对 PHP 开发的热情。**
+
+"生产者"心态的核心在于,不再将 PHP 视为单纯的谋生工具,而是作为创造和表达的平台。当你开始构建自己的工具、参与开源项目、分享知识并探索新应用领域时,你会发现自己与 PHP 的关系发生了根本性变化。
+
+从今天开始,选择一条适合自己的转型路径,迈出从消费者到生产者的第一步。**这不仅是技术层面的提升,更是职业态度和人生观的蜕变。**
+
+
+
+
+
+如果文章对你有帮助,请关注和转发,谢谢!
+
diff --git "a/docs/\351\235\242\350\257\225/assets/\345\246\202\344\275\225\350\256\251\345\267\245\344\275\234\345\271\264\351\231\220\345\217\230\346\210\220\344\274\230\345\212\277-\345\276\267\351\233\267\347\246\217\346\226\257\346\250\241\345\236\213.png" "b/docs/\351\235\242\350\257\225/assets/\345\246\202\344\275\225\350\256\251\345\267\245\344\275\234\345\271\264\351\231\220\345\217\230\346\210\220\344\274\230\345\212\277-\345\276\267\351\233\267\347\246\217\346\226\257\346\250\241\345\236\213.png"
new file mode 100644
index 0000000..3b37187
Binary files /dev/null and "b/docs/\351\235\242\350\257\225/assets/\345\246\202\344\275\225\350\256\251\345\267\245\344\275\234\345\271\264\351\231\220\345\217\230\346\210\220\344\274\230\345\212\277-\345\276\267\351\233\267\347\246\217\346\226\257\346\250\241\345\236\213.png" differ
diff --git "a/docs/\351\235\242\350\257\225/assets/\350\256\276\350\256\241\344\270\200\344\273\275\345\220\270\345\274\225\351\235\242\350\257\225\345\256\230\347\232\204\347\256\200\345\216\206-\344\270\252\344\272\272\344\274\230\345\212\277.png" "b/docs/\351\235\242\350\257\225/assets/\350\256\276\350\256\241\344\270\200\344\273\275\345\220\270\345\274\225\351\235\242\350\257\225\345\256\230\347\232\204\347\256\200\345\216\206-\344\270\252\344\272\272\344\274\230\345\212\277.png"
new file mode 100644
index 0000000..d748247
Binary files /dev/null and "b/docs/\351\235\242\350\257\225/assets/\350\256\276\350\256\241\344\270\200\344\273\275\345\220\270\345\274\225\351\235\242\350\257\225\345\256\230\347\232\204\347\256\200\345\216\206-\344\270\252\344\272\272\344\274\230\345\212\277.png" differ
diff --git "a/docs/\351\235\242\350\257\225/assets/\350\256\276\350\256\241\344\270\200\344\273\275\345\220\270\345\274\225\351\235\242\350\257\225\345\256\230\347\232\204\347\256\200\345\216\206-\344\270\252\344\272\272\344\277\241\346\201\257\345\217\215\344\276\213.png" "b/docs/\351\235\242\350\257\225/assets/\350\256\276\350\256\241\344\270\200\344\273\275\345\220\270\345\274\225\351\235\242\350\257\225\345\256\230\347\232\204\347\256\200\345\216\206-\344\270\252\344\272\272\344\277\241\346\201\257\345\217\215\344\276\213.png"
new file mode 100644
index 0000000..432843a
Binary files /dev/null and "b/docs/\351\235\242\350\257\225/assets/\350\256\276\350\256\241\344\270\200\344\273\275\345\220\270\345\274\225\351\235\242\350\257\225\345\256\230\347\232\204\347\256\200\345\216\206-\344\270\252\344\272\272\344\277\241\346\201\257\345\217\215\344\276\213.png" differ
diff --git "a/docs/\351\235\242\350\257\225/assets/\350\256\276\350\256\241\344\270\200\344\273\275\345\220\270\345\274\225\351\235\242\350\257\225\345\256\230\347\232\204\347\256\200\345\216\206-\344\270\252\344\272\272\344\277\241\346\201\257\347\244\272\344\276\213.png" "b/docs/\351\235\242\350\257\225/assets/\350\256\276\350\256\241\344\270\200\344\273\275\345\220\270\345\274\225\351\235\242\350\257\225\345\256\230\347\232\204\347\256\200\345\216\206-\344\270\252\344\272\272\344\277\241\346\201\257\347\244\272\344\276\213.png"
new file mode 100644
index 0000000..8eab36c
Binary files /dev/null and "b/docs/\351\235\242\350\257\225/assets/\350\256\276\350\256\241\344\270\200\344\273\275\345\220\270\345\274\225\351\235\242\350\257\225\345\256\230\347\232\204\347\256\200\345\216\206-\344\270\252\344\272\272\344\277\241\346\201\257\347\244\272\344\276\213.png" differ
diff --git "a/docs/\351\235\242\350\257\225/assets/\350\256\276\350\256\241\344\270\200\344\273\275\345\220\270\345\274\225\351\235\242\350\257\225\345\256\230\347\232\204\347\256\200\345\216\206-\345\267\245\344\275\234\347\273\217\351\252\214.png" "b/docs/\351\235\242\350\257\225/assets/\350\256\276\350\256\241\344\270\200\344\273\275\345\220\270\345\274\225\351\235\242\350\257\225\345\256\230\347\232\204\347\256\200\345\216\206-\345\267\245\344\275\234\347\273\217\351\252\214.png"
new file mode 100644
index 0000000..9ca2938
Binary files /dev/null and "b/docs/\351\235\242\350\257\225/assets/\350\256\276\350\256\241\344\270\200\344\273\275\345\220\270\345\274\225\351\235\242\350\257\225\345\256\230\347\232\204\347\256\200\345\216\206-\345\267\245\344\275\234\347\273\217\351\252\214.png" differ
diff --git "a/docs/\351\235\242\350\257\225/assets/\350\256\276\350\256\241\344\270\200\344\273\275\345\220\270\345\274\225\351\235\242\350\257\225\345\256\230\347\232\204\347\256\200\345\216\206-\346\225\231\350\202\262\347\273\217\345\216\206.png" "b/docs/\351\235\242\350\257\225/assets/\350\256\276\350\256\241\344\270\200\344\273\275\345\220\270\345\274\225\351\235\242\350\257\225\345\256\230\347\232\204\347\256\200\345\216\206-\346\225\231\350\202\262\347\273\217\345\216\206.png"
new file mode 100644
index 0000000..c1fec36
Binary files /dev/null and "b/docs/\351\235\242\350\257\225/assets/\350\256\276\350\256\241\344\270\200\344\273\275\345\220\270\345\274\225\351\235\242\350\257\225\345\256\230\347\232\204\347\256\200\345\216\206-\346\225\231\350\202\262\347\273\217\345\216\206.png" differ
diff --git "a/docs/\351\235\242\350\257\225/assets/\350\256\276\350\256\241\344\270\200\344\273\275\345\220\270\345\274\225\351\235\242\350\257\225\345\256\230\347\232\204\347\256\200\345\216\206-\346\225\231\350\202\262\347\273\217\345\216\2062.png" "b/docs/\351\235\242\350\257\225/assets/\350\256\276\350\256\241\344\270\200\344\273\275\345\220\270\345\274\225\351\235\242\350\257\225\345\256\230\347\232\204\347\256\200\345\216\206-\346\225\231\350\202\262\347\273\217\345\216\2062.png"
new file mode 100644
index 0000000..4dc3fcf
Binary files /dev/null and "b/docs/\351\235\242\350\257\225/assets/\350\256\276\350\256\241\344\270\200\344\273\275\345\220\270\345\274\225\351\235\242\350\257\225\345\256\230\347\232\204\347\256\200\345\216\206-\346\225\231\350\202\262\347\273\217\345\216\2062.png" differ
diff --git "a/docs/\351\235\242\350\257\225/assets/\350\256\276\350\256\241\344\270\200\344\273\275\345\220\270\345\274\225\351\235\242\350\257\225\345\256\230\347\232\204\347\256\200\345\216\206-\346\225\231\350\202\262\350\203\214\346\231\257.png" "b/docs/\351\235\242\350\257\225/assets/\350\256\276\350\256\241\344\270\200\344\273\275\345\220\270\345\274\225\351\235\242\350\257\225\345\256\230\347\232\204\347\256\200\345\216\206-\346\225\231\350\202\262\350\203\214\346\231\257.png"
new file mode 100644
index 0000000..73179f0
Binary files /dev/null and "b/docs/\351\235\242\350\257\225/assets/\350\256\276\350\256\241\344\270\200\344\273\275\345\220\270\345\274\225\351\235\242\350\257\225\345\256\230\347\232\204\347\256\200\345\216\206-\346\225\231\350\202\262\350\203\214\346\231\257.png" differ
diff --git "a/docs/\351\235\242\350\257\225/assets/\350\256\276\350\256\241\344\270\200\344\273\275\345\220\270\345\274\225\351\235\242\350\257\225\345\256\230\347\232\204\347\256\200\345\216\206-\347\256\200\345\216\206\346\250\241\347\211\210.png" "b/docs/\351\235\242\350\257\225/assets/\350\256\276\350\256\241\344\270\200\344\273\275\345\220\270\345\274\225\351\235\242\350\257\225\345\256\230\347\232\204\347\256\200\345\216\206-\347\256\200\345\216\206\346\250\241\347\211\210.png"
new file mode 100644
index 0000000..864311a
Binary files /dev/null and "b/docs/\351\235\242\350\257\225/assets/\350\256\276\350\256\241\344\270\200\344\273\275\345\220\270\345\274\225\351\235\242\350\257\225\345\256\230\347\232\204\347\256\200\345\216\206-\347\256\200\345\216\206\346\250\241\347\211\210.png" differ
diff --git "a/docs/\351\235\242\350\257\225/assets/\350\257\273\346\207\202\345\262\227\344\275\215\347\262\276\345\207\206\346\212\225\351\200\222-pm\346\213\233\350\201\230\350\246\201\346\261\202.png" "b/docs/\351\235\242\350\257\225/assets/\350\257\273\346\207\202\345\262\227\344\275\215\347\262\276\345\207\206\346\212\225\351\200\222-pm\346\213\233\350\201\230\350\246\201\346\261\202.png"
new file mode 100644
index 0000000..ea04a2c
Binary files /dev/null and "b/docs/\351\235\242\350\257\225/assets/\350\257\273\346\207\202\345\262\227\344\275\215\347\262\276\345\207\206\346\212\225\351\200\222-pm\346\213\233\350\201\230\350\246\201\346\261\202.png" differ
diff --git "a/docs/\351\235\242\350\257\225/assets/\351\235\242\350\257\225\346\275\234\350\247\204\345\210\231-12\346\255\245\351\200\232\345\205\263\346\261\202\350\201\214\351\235\242\350\257\225.jpg" "b/docs/\351\235\242\350\257\225/assets/\351\235\242\350\257\225\346\275\234\350\247\204\345\210\231-12\346\255\245\351\200\232\345\205\263\346\261\202\350\201\214\351\235\242\350\257\225.jpg"
new file mode 100644
index 0000000..5e5046e
Binary files /dev/null and "b/docs/\351\235\242\350\257\225/assets/\351\235\242\350\257\225\346\275\234\350\247\204\345\210\231-12\346\255\245\351\200\232\345\205\263\346\261\202\350\201\214\351\235\242\350\257\225.jpg" differ
diff --git "a/docs/\351\235\242\350\257\225/\344\272\206\350\247\243\350\241\214\344\270\232\350\226\252\350\265\204\357\274\214\346\270\205\346\231\260\346\211\276\345\207\206\345\256\232\344\275\215.md" "b/docs/\351\235\242\350\257\225/\344\272\206\350\247\243\350\241\214\344\270\232\350\226\252\350\265\204\357\274\214\346\270\205\346\231\260\346\211\276\345\207\206\345\256\232\344\275\215.md"
new file mode 100644
index 0000000..069b9b8
--- /dev/null
+++ "b/docs/\351\235\242\350\257\225/\344\272\206\350\247\243\350\241\214\344\270\232\350\226\252\350\265\204\357\274\214\346\270\205\346\231\260\346\211\276\345\207\206\345\256\232\344\275\215.md"
@@ -0,0 +1,19 @@
+# 了解行业薪资,清晰找准定位
+
+## 清晰找准自己的定位
+
+相信面试到这里你已经在谈薪资了,此时的你是否会有这样的疑惑:我所期望的薪资是否能给到呢?在这里我建议你一定要对自己有清晰的定位,比如可根据你的工作年限、工作经验以及对市场行情等全方位的了解后,才能拿到合理的薪资,也会让企业认为你物有所值。 那如何才能争取比较合适的薪资呢?很多小伙伴会根据身边的朋友来判断自己的薪资是否合理。但是很多人没有考虑到,大家的学历不同、做过的项目不同、所应聘的公司也不同,那么薪资水平也很可能会有较大的差距,所以一定要明确自己的情况是怎么样的。
+
+### 如果你是应届生
+
+如果你是一个刚刚毕业的小伙伴,如果从事的是基础的岗位一般薪资基本在 4 ~ 8K,但如果选择做程序员,假如学校背景还不错的话,薪资可在 10 ~ 15 K。 不过,不用太在意薪资这一块,毕竟找一个有前景的工作会更重要,建议对自己有一个短期(1~2 年)的职业规划,相信在不久的将来,薪资也会翻倍的。
+
+### 如果你有工作经验
+
+如果你已经是一个在专业领域工作多年的候选人,行业经验也非常丰富,相信丰富的经验可以为你创造比较高的收入,你可以比对行业的知名公司职级的薪资结构去判断自己的薪资情况。
+
+### 如果你有项目经验
+
+当然也可能有小伙伴会问,如果我前一家公司的薪资高于市场行情,换一家公司是否需要继续要求增加薪资,还是考虑降薪? 这个问题我认为可以根据你的项目经验来考虑。如果你的项目经验是行业非常急需而且比较难得的,同时你又做得比较突出,你要求一个合理涨幅,很多公司也是愿意的。但是如果你的工作表现一般,只是一个负责副线项目的人,我认为对你来说很难争取到新的提成,所以不如脚踏实地地去做一个比较稳定的项目,为自己多积累一些相关的经验,也为后面的涨薪做铺垫。
+
+## 一些行业的薪酬报告
\ No newline at end of file
diff --git "a/docs/\351\235\242\350\257\225/\345\201\232\345\245\275\345\205\205\345\210\206\347\232\204\345\207\206\345\244\207\345\216\273\351\235\242\350\257\225.md" "b/docs/\351\235\242\350\257\225/\345\201\232\345\245\275\345\205\205\345\210\206\347\232\204\345\207\206\345\244\207\345\216\273\351\235\242\350\257\225.md"
new file mode 100644
index 0000000..8e53ded
--- /dev/null
+++ "b/docs/\351\235\242\350\257\225/\345\201\232\345\245\275\345\205\205\345\210\206\347\232\204\345\207\206\345\244\207\345\216\273\351\235\242\350\257\225.md"
@@ -0,0 +1,69 @@
+# 做好充分的准备去面试
+
+## 日常HR的工作流程解析
+
+可能你会问:HR 不就是每天守在电脑前等着投简历,然后第一时间去筛选简历吗?为什么还会有“投递黄金时间段”这样的说法?不应该是随时投递简历都可以吗?有这样疑惑的你就太误解 HR 的工作了,接收简历只是他们手上工作的一部分。HR 每天还需要处理其他很多的工作,就像很多不同岗位的小伙伴同时负责很多工作一样。
+
+首先,电话沟通是 HR 核心工作内容的一部分,电话沟通并不是简单的通知候选人何时何地来面试。可是,大部分人反馈说:我每次接到电话就是通知面试,并没有说其他的。其实在电话沟通之前,HR 就已经仔细阅读过简历内容了,有疑问的地方会标记出来,在电话沟通过程中与你确认具体的问题点在哪里。
+
+所以,电话沟通分为两种:一种是电话预约;另外一种是电话确认。
+
+电话预约已经很清晰了,就是确认面试的时间。
+
+电话确认一般发生在 HR 不确认你对招聘的岗位是否有兴趣或者简历存在比较大的问题的情况下。也就是说在接到电话沟通时不要表现的太过随意,因为你在电话另外一端说的任何一句话 HR 都会有一个潜意识的判断,这个判断很有可能会影响到你的面试环节。
+
+如何在电话沟通时表现良好呢?
+
+一定要对投递的公司有所了解,也正如前面说过的,很多人都是随便投递简历,最终也不记得都投递了哪些公司,所以在电话沟通时,招聘人员很不喜欢听到“请问你们公司是做什么的?”、“这个岗位的职位 JD 可以发给我看看吗?”、……,类似的声音,他们会认为你都没有认真对待这个岗位。
+
+电话沟通时语气非常冷漠,明显表现出非常不高兴的情绪。其实 HR 在电话另外一端可以很清晰地听出对方的性格和表现。例如,有的人声音很消极,给 HR 的感觉是这个人对工作没有热情;有的人声音非常强硬,很容易给 HR 对方不是很好相处的印象。
+
+因此,一定要记住自己投递过的公司和岗位信息,给 HR 一种你已经做好准备的感觉;然后掌握沟通的技巧,清晰地表达自己的想法和观点,语气尽量亲切一些,这样 HR 应该很愿意和你沟通,还能留下不错的印象。
+
+其次,面试安排其实也会占据 HR 的很多工作时间。这个环节和电话沟通一样,你的表现也很容易被 HR 作出初步的判断。如何在面试安排时表现良好呢?
+
+要有时间观念,尽量提前 5 ~ 10 分钟到达面试地点。很多招聘企业非常喜欢遵守时间的人,而且 HR 每天都会安排很多场面试,可能每个候选人的面试时间都是相连的,如果迟到很有可能会影响面试官的时间安排。如果有特殊原因,最好提前 0.5 ~ 1 个小时通知 HR,争取能调整面试的时间。
+
+要保持个人卫生,相信不论到任何场合,个人卫生非常差的话很难受到欢迎。虽然不需要你穿着有多奢华,只要保持衣着整洁、干净,会给 HR 留下不错的印象。
+
+保持礼貌,中国有句古话“礼多人不怪”,虽然 HR 只是帮你协调面试,但也起到了你是否可以入职的关键因素。所以保持礼貌和谦虚的心态和行为,可以得到不少的加分。
+
+当然,除了上面提到的工作内容,很多 HR 还会负责面试、发放 Offer 以及办理入职相关的手续,这些内容将在后面详细讲解。
+
+## 其他投递渠道分析
+
+目前 HR 收取简历的主要渠道有招聘网站、猎头、内推、校园招聘这几类。接下来说说这些渠道都适合什么样的求职者,去帮助你准确地判断通过哪种渠道可以更好的找到工作以及心仪的公司。
+
+### 招聘网站
+
+不用过多介绍,目前很多求职者都在使用,比如拉勾网,其是一家专注垂直互联网领域的公司,如果有研发、产品、运营等互联网方向的岗位需求,可以到该网站上发布岗位或寻找人才。
+
+我在面试的时候经常有人问:常年累月挂着招聘是真的有招人的需求吗?企业究竟是真的想要招人,还是只挂在网上做做样子?
+
+你可能经常也会有这样的疑惑,其实很多企业挂出去的岗位目前都是在持续招聘的,可能招聘的紧急度并没有那么高,也有可能是一个储备的岗位,HR 会先将岗位挂出去,对投递来的简历会仔细审阅,直到选出最合适的人选才会安排面试。
+
+### 猎头
+
+猎头渠道对候选人的要求可能会更高,一般是针对高级管理者或者行业专家使用的渠道。如果你只有 1 ~ 3 年的工作经验,可能现在还用不到这个渠道。
+
+此时的你是否有过这样的疑惑:看岗位是合适的,为什么最后得到的反馈就是不适合?
+
+这个时候就要审视一下自己的简历,正如第01讲所分析的,是不是真的将自己的优势都凸显出来了?招聘岗位所说的内容是不是都在简历中有所体现?工作年限真的都留意到了吗?自己的项目经验是不是也都体现出来了?
+
+### 内推
+
+内部推荐是一个非常好的渠道,成功率非常高。如果你身边有不错关系的同学或者朋友在心仪的公司,请他内推给 HR,可能反馈非常快,不过面试结果还要看个人的努力了。
+
+那为什么同一家公司自己投简历就没后续了,猎头推荐或内推就有面试机会呢?
+
+其实猎头的工作并没有那么神奇,每位猎头顾问在推荐你简历的时候都会与你进行沟通,在沟通的过程中会提炼出你简历里面没有展现的优势,然后猎头会对你的简历进行修改,以突出工作中的重点,以便让 HR 清晰地捕捉到想要的信息。所以说将自己的简历写出价值是有多么重要。
+
+### 校园招聘
+
+校园招聘相信都经历过,这个渠道主要是针对应届毕业生的,每年都会在 3 月或者 10 月份进行。如果你已经离开校园了,也就没有办法参与这个渠道的招聘了。
+
+那互联网企业招聘现在更看重是学历?还是本身具备的技能?
+
+可能有的人比较忐忑:我学历背景并不是很好,企业在招聘的时候更看重学历还是看中我本身的技能呢?当然很多人会告诉你学历是非常重要的,同时企业也会注意你的学习能力。如果你在后期努力进修了更好的学历,其实可以充分的展现学习主动性,也会很获得企业的欢迎。当然如果你的项目经验非常完善,在过去的工作经历中负责过比较好的项目,那完全可以掩盖你学历上的差距。
+
+希望通过对以上渠道的分析,能准确地使用它并获得邀约的机会和面试的流程。
\ No newline at end of file
diff --git "a/docs/\351\235\242\350\257\225/\345\210\244\346\226\255\345\205\254\345\217\270\350\203\214\346\231\257\357\274\214\345\201\232\345\207\272\345\220\210\347\220\206\351\200\211\346\213\251.md" "b/docs/\351\235\242\350\257\225/\345\210\244\346\226\255\345\205\254\345\217\270\350\203\214\346\231\257\357\274\214\345\201\232\345\207\272\345\220\210\347\220\206\351\200\211\346\213\251.md"
new file mode 100644
index 0000000..7af41ab
--- /dev/null
+++ "b/docs/\351\235\242\350\257\225/\345\210\244\346\226\255\345\205\254\345\217\270\350\203\214\346\231\257\357\274\214\345\201\232\345\207\272\345\220\210\347\220\206\351\200\211\346\213\251.md"
@@ -0,0 +1,25 @@
+# 判断公司背景,做出合理选择
+
+## 通过网站上展示的相关信息来判断
+
+互联网对于大家来说已经不是那么陌生了,所以很多企业的信息都可以在互联网上获得。我们可以通过这家公司的官网去了解它的基础业务和公司发展信息;也可以通过拉勾招聘网站上的企业界面介绍页去了解这家公司的基础信息。如果还不放心的话,还可以到“天眼查”或者“企查查”官网上查一下这家公司是否是一家正常运营的公司。 当查到这些信息后该如何判断公司的背景呢?
+
+(1)公司的主营业务。可以查看目前这个主营业务是不是你希望从事的,是行业内的蓝海还是一个比较传统的业务。比如可以通过传播媒体的报道来了解;或者如果一家公司在一年内迅速扩张,那这家公司必然是蓝海企业。
+
+(2)公司的融资情况。可以通过了解公司的融资轮次以及投资的金融机构来验证是否是一个成熟的公司,因为优秀的金融机构对公司进行投资会非常谨慎。
+
+(3)公司的人员规模和办公地点。这些也可以判断一家公司的情况,假如公司人员比较多,则说明业务可能更为稳定一些,办公地点在比较正规的办公大厦里也代表了一种稳定的因素。当然不是说好的办公地点和公司人员数量多就是最好的公司,也有不少几个人的初创公司也是很值得考虑的。
+
+(4)公司的创办时间。除了以上因素以外,肯定要考虑公司的创办时间,可能刚刚开始创办的公司不具备那么好的条件。如果你比较喜欢初创业的公司,那么可以通过公司经营的业务和投资机构的名气去判断;但是如果是一个创办时间比较久的公司,可能就要考虑得稍微多一些了。 (5)收集创始人在网上的演讲稿。从他们的演讲稿中获得一些信息,通过对这个人的看法对比是否和你期望的企业形式一致,也可以判断出他是否具有行业的眼光,但是尽量避免跳入公关稿的坑里去。 当然不排除一些经营很好,但是企业规模和融资情况一般的公司,这个也需要通过其他方面的信息去判断。
+
+## 通过来自内部人员的信息判断
+
+以上是通过拉勾招聘网站上的公司介绍页以及企业官网来判断公司的背景,但只是了解这个公司的表面信息,想了解这家公司真实的具体情况和管理风格,通过以下的方式可能会更清晰一些。
+
+(1)如果这家公司中有熟悉的朋友(或前同事)或者学长学姐的话就比较方便了,可以问一下他们关于公司内部的团队、部门、上下班时间、福利等情况,甚至可以问一下团队领导的风格是怎样的。
+
+(2)如果你没有这样的朋友关系,也可以通过职言或者论坛的讨论去看看这个公司内部的员工是怎么评价公司的。
+
+## 面试时通过面试官的言行举止判断
+
+在面试的过程中,还可以通过与面试官的交流去判断这家公司的情况,如果面试官在面试过程中表现的比较有条理、沟通比较有素质,则可以说明这家公司还是不错的选择;也可以通过对公司环境的观察来判断这家公司的情况。当然你也可以看看拉勾网企业界面的面试评价区,去了解一下其他面试者对这家公司的评价。 相信通过以上几种方法,可以比较清晰地了解一家公司的情况,也可以帮助你更好的去判断这家公司是否值得去。
\ No newline at end of file
diff --git "a/docs/\351\235\242\350\257\225/\345\246\202\344\275\225\350\256\251\345\267\245\344\275\234\345\271\264\351\231\220\345\217\230\346\210\220\344\274\230\345\212\277.md" "b/docs/\351\235\242\350\257\225/\345\246\202\344\275\225\350\256\251\345\267\245\344\275\234\345\271\264\351\231\220\345\217\230\346\210\220\344\274\230\345\212\277.md"
new file mode 100644
index 0000000..023744a
--- /dev/null
+++ "b/docs/\351\235\242\350\257\225/\345\246\202\344\275\225\350\256\251\345\267\245\344\275\234\345\271\264\351\231\220\345\217\230\346\210\220\344\274\230\345\212\277.md"
@@ -0,0 +1,75 @@
+# 如何让工作年限变成优势
+
+在软件开发招聘中,“有多少年工作经验”是一个重要的招聘指标。但实际上,技术能力和工作年限并不是正相关的,特别是工作三五年以后,很多人的技术能力进步就几乎停滞了。但是招聘面试的时候,面试官是期待他有着和工作年限相匹配的技术能力的。
+
+如果一个人空有十几年工作经验,却没有相应的技术能力,那么这十几年的工作经验甚至可能会成为他的劣势,至少反映了他已经没有成长空间了。反而是工作年限不如他,但是技术能力和他相当的其他候选人更有优势,因为这个人可能还有进步的空间。
+
+事实上,就我这些年的面试经验而言,空有十几年工作经验而没有相应技术能力的人大有人在。其实从简历上就能看的出来:最近几年的时间他承担的工作职责几乎没有变化,使用的技术、开发的项目几乎和头几年一样,那么很难相信这些年他的技术会有什么进步。
+
+那么如何保持技术能力持续进步,使工作年限成为自己的优势而不是缺点呢?
+
+## 德雷福斯模型
+
+我们先看一个德雷福斯模型。德雷福斯是一个专业人员能力成长模型,这个模型认为所有专业人员都需要经历5个成长阶段,不管是医生还是律师,或者是软件开发,任何专业技能的从业者都需要经历新手、高级新手、胜任者、精通者、专家5个阶段。
+
+
+
+通常一个人进入专业的技能领域,即使在学校已经系统学习过这个专业的相关知识,但依然无法独立完成工作,必须在有经验的同事指导下,学习相关的技能。这里主要学习的是有关工作的规则和套路。比如用什么工具、什么框架,如何开发程序,如何开会、写周报,如何和同事合作,业务领域的名词术语是什么意思等等这些各种各样和工作有关的大小事情。这个阶段叫做新手阶段。
+
+通常说来,一个人大约工作两三年后,就差不多掌握了工作的各种套路,可以摆脱新手阶段,独立完成一些基本的工作了。通过新手阶段的人,少部分会直接进入胜任者阶段,而大多数则进入高级新手阶段。
+
+高级新手其实是新手的自然延续,他不需要别人指导工作,也不需要学习工作的规则和套路,因为高级新手已经在新手阶段掌握了这些套路,他可以熟练应用这些规则套路完成他的工作。但是高级新手的能力也仅限于此,他不明白这些规则是如何制定出来的,为什么使用这个框架开发而不是另一个框架,也不明白这个框架是如何开发出来的。
+
+因此,一旦需要解决的问题和过往的问题有很大不同,以前的规则套路无法解决这些新问题的时候,高级新手就抓瞎了,不知道该怎么办。
+
+一个悲观的事实是,新手会自然进入高级新手阶段,而高级新手却无法自然进入其后的其他等级阶段。实际上,在各个专业领域中,超过半数的人终其一生都停留在高级新手阶段,也就是说,大多数人一生的工作就是基于其专业领域的规则在进行重复性的劳动。他们不了解这些规则背后的原理,也无法在面对新的问题时,开创出新的方法和规则。那些简历上十多年如一日使用相同的技术方案、开发类似软件项目的资深工程师大部分都是高级新手。
+
+导致一个人终身停留在高级新手阶段的原因有很多,其中一个重要的原因是:高级新手不知道自己是高级新手。高级新手觉得自己在这个专业领域混得很不错,做事熟练,经验丰富。
+
+事实上,这种熟练只是对既有规则的熟练,如果岁月静好,一切都循规蹈矩,也没什么问题。而一旦行业出现技术变革或者工作出现新情况,高级新手就会遇到巨大的工作困难。事实上,各行各业都存在大量的高级新手,只是软件开发领域的技术变革更加频繁,问题变化也更加快速,使高级新手问题更加突出。
+
+少部分新手和高级新手会在工作中学习、领悟规则背后的原理,当需要解决的问题变化,或者行业出现技术革新时,能够尝试学习新技术,解决新问题,这样的人就进入胜任者阶段。胜任者工作的一个显著特点是,做事具有主动性。他们在遇到新问题时,会积极寻求新的解决方案去解决问题,而不是像高级新手那样,要么束手无策,要么还是用老办法解决新问题,使问题更加恶化。
+
+胜任者能够解决新问题,但他们通常只会见招拆招,局限于解决问题本身,而缺乏反思精神以及全局思维:为什么会出现这样的问题?如何避免类似问题再发生?这个问题在更宏大的背景下处于什么位置?还有哪些类似的问题?
+
+而拥有反思精神和全局思维,即使没有新问题也能够进行自我突破、寻求新的出路的人,就进入了精通者阶段。精通者需要通过主动学习进行提升,主动进行大量的阅读和培训,而不是仅仅依靠工作中的经验和实践。他们在完成一个工作后会反思:哪些地方可以改进,下次怎么做会更好?
+
+精通者拥有了自我改进的能力。
+
+高级新手会把规则当做普适性的真理而使用,甚至引以为豪;而精通者则会明白所有的规则都只在特定的场景中才会有效,工作中最重要的不是规则,而是对场景的理解。
+
+而最终,各行各业大约只有1%的人会进入专家阶段,专家把过往的经验都融汇贯通,然后形成一种直觉,他们直觉地知道事情应该怎么做,然后用最直接、最简单的方法把问题解决。专家通常也是他所在领域的权威,精通者和胜任者会学习、研究专家是如何解决问题的,然后把这种解决方案形成套路,成为行业做事的规则。
+
+## 如何在工作中成长
+
+德雷福斯模型告诉我们,人的专业能力不会随着工作年限的增加而自然增长,多数人会终身停留在高级新手阶段。那么如何在工作不断成长,提升自我,最终成为专家呢?以下三个建议供你参考。
+
+### 勇于承担责任
+
+好的技术都是经过现实锤炼的,能够真正解决现实问题的,得到大多数人拥护的。所以自己去学习各种各样的新技术固然重要,但是更重要的是要将这些技术应用到实践中,去领悟技术背后的原理和思想。
+
+而所有真正的领悟都是痛的领悟,只有你对自己工作的结果承担责任和后果,在出现问题或者可能出现问题的时候,倒逼自己思考技术的关键点,技术的缺陷与优势,才能真正地理解这项技术。
+
+如果你只是去遵循别人的指令,按别人的规则去做事情,你永远不会知道事物的真相是什么。只有你对结果负责的时候,在压力之下,你才会看透事物的本质,才会抓住技术的核心和关键,才能够让你去学好技术,用好技术,在团队中承担核心的技术职责和产生自己的技术影响,并巩固自己的技术地位。
+
+### 在实践中保持技能
+
+有个说法叫做1万小时定律,是说要想成为某个领域的专家,必须经过1万小时高强度的训练才可以,对软件开发这样更强调技术的领域来说,这一点尤其明显。我们必须要经过长时间的编程实践,从持续的编程实践中提升技术认知,才能够理解技术的精髓,感悟到技术的真谛。
+
+但是1万小时的编程时间并不是说你重复的编程1万小时就能够自动提升成为专家的。真正对你有帮助的是不断超越自我,挑战自我的工作。也就是说,每一次在完成一个工作以后,下一次的工作都要比上一次的工作难度再增加一点点,不断地让自己去挑战更高难度的工作,从而拥有更高的技术能力和技术认知。
+
+通俗说来,就是要摘那些跳起来才能够得着的苹果,不要摘那些伸手就能够得着的苹果。但是如果难度太高,注定要失败的任务,其实对技术提升也没有什么帮助。所以最好是选择那些跳起来能够摘得到的苹果,你要努力再进步一点点,才能够完成。通过这样持续的工作训练和挑战,在实践中持续地获得进步,你就可以不断从新手向专家这个方向前进。
+
+### 关注问题场景
+
+现实中,很多人觉得,学好某一个技术就大功告成了。但事实上是,即使你熟练掌握了强大的技术,但如果对问题不了解,对上下文缺乏感知,也不会真正地用好技术,也就无法去解决真正的问题。试图用自己擅长的技术去解决所有问题,就好像是拿着锤子去找钉子,敲敲打打大半天,才发现打的根本就不是一个钉子。
+
+所谓的专家其实是善于根据问题场景发现解决方法的那个人,如果你关注场景,根据场景去寻找解决办法,也许你会发现解决问题的办法可能会非常简单,也许并不需要多么高深的工具和方法就能够解决,这时候你才能成为真正的专家。也就是在这个时候你会意识到方法、技术、工具这些都不是最复杂的,而真正复杂的是问题的场景,是如何真正地理解问题。
+
+这个世界没有万能的方法,没有一劳永逸的银弹。每一种方法都有适用的场景,每一种技术都有优点和缺点,你必须要理解问题的关键细节、上下文场景,才能够选择出最合适的技术方案,真正地解决问题
+
+## 结束语
+
+如果你是一个新手,刚刚工作不久,那么不要被所谓的工作经验和所谓的资深工程师的说教局限住,你要去思考规则背后的原理,主动发现新问题然后去解决问题,越过高级新手阶段,直接向着胜任者、精通者和专家前进吧。
+
+如果你是一个有多年经验的资深工程师,那么忘了你的工作年限吧,去问自己,我拥有和工作年限相匹配的工作技能吗?我在德雷福斯模型的哪个阶段?我该如何超越当前阶段,成为一个专家?
\ No newline at end of file
diff --git "a/docs/\351\235\242\350\257\225/\345\267\245\344\275\234\344\272\244\346\216\245\346\265\201\347\250\213\347\246\217\345\210\251\350\241\224\346\216\245.md" "b/docs/\351\235\242\350\257\225/\345\267\245\344\275\234\344\272\244\346\216\245\346\265\201\347\250\213\347\246\217\345\210\251\350\241\224\346\216\245.md"
new file mode 100644
index 0000000..cd873d9
--- /dev/null
+++ "b/docs/\351\235\242\350\257\225/\345\267\245\344\275\234\344\272\244\346\216\245\346\265\201\347\250\213\347\246\217\345\210\251\350\241\224\346\216\245.md"
@@ -0,0 +1,53 @@
+# 工作交接流程福利衔接
+
+## 工作交接流程
+
+### 如何不伤和气的提出辞呈
+
+终于拿到了自己心仪公司的 Offer 了,可能有很多小伙伴又开始发愁了:如何与领导顺利提出辞呈,又不伤和气呢?这个时候一定要做好最坏的打算,你要明白,心软拖着不说会更伤害自己与前公司的关系,不如直截了当、当机立断。 一般提出离职的方式分为两种:
+
+通过邮件的形式提出辞呈;
+
+直接找直属 leader 沟通。 具体采用哪种方式,可根据自己的个性来判断,比如不太擅长沟通、偏内向的可以通过邮件的方式;如果已经想好了怎么和上级沟通,也可以直接找 leader 阐明心意。那在写邮件或直接沟通时需要注意哪些呢?img首先,可以先表达出对公司和领导在工作中的指导和帮助的感激,以及这段时间在公司的工作和成长的开心,同时说明一下做出辞职的决定对自己来说是多么难的一次选择。相信这样的表达可以让领导对你有个不错的印象。 其次,不论你的离职原因是不满意薪资、不适应团队的管理风格还是发展空间到达了上限等,都不要在这里抱怨出来,因为每个公司的 leader 都清楚公司里的问题,与其这样,不如直接告诉 leader,辞职的原因是希望可以有更好的发展,或者是让自己有更好的学习成长的空间。相信你的决心加上这样的理由,leader 一定会领会里面的意思。
+
+如果这时 leader 突然问:找到下家了么?该怎么回答?建议这样委婉地回答:手里有好几个 Offer,还没确定好去哪家…… 最不建议的离职理由:经常会有小伙伴为了避免双方尴尬,会选择“家人生病需要较长的时间照顾”、“家人要求我回老家工作”等类似这样的理由,如果是真实的当然不会有问题,如果是虚构的,以后万一被发现,则会给前公司留下一个不诚信的印象,以后再相见时会更尴尬。 当然也有小伙伴提出离职是为了通过拿到的 Offer 要求涨薪,这样的“小聪明”玩不好可能就把自己“玩”进去了,不但在拿到 Offer 的公司名声坏了,也不会被现在的公司重用的。
+
+最后,可以和前司表示一下,自己一定会负责任地把手里的工作交接清楚,站好最后一班岗,这样也可以给前司 leader 留下一个让人踏实的印象。毕竟你的面试背调还在人家手里,总不希望闹得不可开交,拿不到一个好的背调反馈吧。
+
+### 合理安排交接工作
+
+一般来说,如果你是一位已经转正的全职员工,那么交接的时间为一个月,所以公司也会要求你在这一个月里正常工作,那么,如何清晰地在这一个月里合理安排交接工作呢?
+
+先和直属 leader 协商找到一个靠谱的工作交接人;
+
+把自己以往的项目文档整理好,分类发给交接人;
+
+如果你手里还有未结束的项目,可以带着交接人熟悉一下,一起对这个项目做收尾工作;
+
+通知同事或者项目对接人自己已经离职,接下来的项目由被交接人负责;
+
+空出两周的时间,协助交接人熟悉你手里的工作内容,在旁做好支持工作。
+
+如果新的公司期望你能尽快入职的话,多数情况下会担心你拒绝入职,此时建议你诚恳地向新公司解释,并和新公司同步交接工作的进度。 交接文档有以下注意事项,比如:
+
+清晰的文档归类,发现问题可以马上与你沟通;
+
+尽可能将相关的文档都涉及到,让你的交接文档更容易查找;
+
+记得文档转出时抄送给领导,这个很重要,一定要记得; 我相信这样的交接流程不会让自己手忙脚乱,也可以给前司留下不错的印象。 离职最后一天走的时候,记得和同事们一一打招呼,感谢大家以往的照顾和帮助,以后要常保持联系。更重要的一点是,一定要拿到“离职证明”文件或“解除 / 终止劳动合同报告书”。
+
+### 福利衔接
+
+交接工作都做完了,很多小伙伴会问:我的社保、公积金怎么办?下面来讲讲 3 种常用的福利交接事项。
+
+### 社保公积金
+
+各个公司的社保、公积金都是以每个月的 15 日作为分界点,如果你是在 15 号前入职的新公司,那么就会帮你交当月的社保和公积金,如果你是在 15 号后从前公司离职,社保、公积金会由前公司承担。当然也会有特殊情况,要看人才局的具体安排。 如果你正好是 15 号前离职,中间休息了一段时间,15 号后入职新公司的,可能需要你自己找第三方保险代缴公司自行缴纳社保公积金了。img
+
+### 年假
+
+通常,公司会按照你出勤的月份帮你做年假的换算,然后与你协商安排延后几天离职,或结算成工资,或者按照公司的规定有其他操作。img
+
+### 工作居住证
+
+如果在前司有工作居住证的话,需要问问新公司是否可以接收,如果可以当然就直接转出,如果不可以,需要问问是否有第三方机构接收。
\ No newline at end of file
diff --git "a/docs/\351\235\242\350\257\225/\345\267\247\345\246\231\346\216\250\351\224\200\350\207\252\345\267\261\347\232\2043\344\270\252\346\212\200\345\267\247.md" "b/docs/\351\235\242\350\257\225/\345\267\247\345\246\231\346\216\250\351\224\200\350\207\252\345\267\261\347\232\2043\344\270\252\346\212\200\345\267\247.md"
new file mode 100644
index 0000000..807f5de
--- /dev/null
+++ "b/docs/\351\235\242\350\257\225/\345\267\247\345\246\231\346\216\250\351\224\200\350\207\252\345\267\261\347\232\2043\344\270\252\346\212\200\345\267\247.md"
@@ -0,0 +1,37 @@
+# 巧妙推销自己的3个技巧
+
+## 平和的心态,展现你的热情
+
+对于任何一家企业在选择合适的人选时,一般都会从这几个方面进行筛选:首先是否具有相关的项目经验;其次是否聪明或者是否具有独自解决问题的能力;最后判断能否融入到团队的氛围中,以及是否对企业或者行业具有热情的态度来面对。
+
+前两个方面所说的是面试者的行业经验和智商,对于一家公司在招聘时当然重要,但这并不是一个团队可以获得成功的关键因素。相信很多企业在选择五年经验以内的候选人时,这两个方面的考察一定会低于最后性格部分的考察。
+
+相信很多小伙伴会有疑问,性格(工作热情)相比情商或工作经验对于一家企业真有那么重要吗?这个我可以肯定的告诉你,面试官非常喜欢性格开朗、积极主动、乐于挑战的候选人;同样也很排斥在乎个人得失、把责任都推给前司的候选人。相信你在工作中也会遇到过类似的同事,可以回忆一下,当时你是不是也很排斥呢?
+
+在一个团队里如果存在一位性格比较消极的员工,很容易将其他员工传染,从而导致整个团队产出效率低下。也就是我们常说的“酒与污水定律”:是指把一勺酒倒入到一桶污水里,得到是一桶污水;如果把一勺污水倒入倒一桶酒中,得到的还是一桶污水。所以,对于面试官来说,候选人的性格和态度是至关重要的。
+
+如何在面试官面前表现出积极正向、乐观的心态呢?
+
+首先,需要表现出对应聘岗位和企业的认同感,也让面试官看到你为了这份工作做了很充分的准备,或者积极的介绍之前做过的项目与应聘企业项目的相似度。这些表现都可以让面试官感受到你的热情和积极正向的输出,非常不建议面试时问什么答什么的做法。
+
+比如,当面试官问「你为什么选择目前的这份工作」时?如果只是单纯地回答「我喜欢这份工作」且没有任何的解释,那面试官无法判断你所说的真实性。此时建议这样回答:“因为目前这份工作和我之前做过的 xxx 项目非常相像。我在参与上一份项目时学习到了 xxx 技能,找到了一个新的发展方向,从而喜欢上了这样的一份职业。”,相信这样的表述面试官才能感受到你的热情和积极正向的态度。
+
+其次,可以和面试官介绍一下,你在上一家公司与同事和领导相处融洽的案例,让面试官感受到你是一个积极融入团队中的人。比如「在前司获得的成长有哪些,与前 leader 的身上都学习到了哪些工作思路和成长思路等」,相信面试官会认为你是一个非常值得培养和积极主动学习的人。
+
+## 了解行业发展,清晰表达你的见解
+
+除了表现出积极和热情以外,如果在面试的过程中可以介绍一些你对行业以及对自己所从事工作的理解或见解,相信面试官一定会被你的表述深深吸引,也同样加强了希望可以录取你的信心。
+
+比如,当面试官问「你怎么看对目前所从事的工作价值」时,如果这样回答「我觉得这是一份收入,并没有太多的感受,也不知道自己未来的发展是什么样的」,面试官会判断你是一个没有任何思考的人,应该也不会在自己的岗位上有什么作为。
+
+此时建议这样回答:“我非常喜欢我的工作,我感觉我的岗位在目前行业的发展中起到了非常重要的作用,我们所做的几个项目都在推动公司的发展,也帮助公司的业绩从 XX% 提升到了 XX%(在这里举一些自己做过的项目经验),而且我也希望可以继续从事这样的工作,因为它可以让我获得更多的成就感。相信这个行业的发展是 xxxxxxxxx,我的职业规划也会跟随这个行业的发展而得到很大的提升。”
+
+当面试官听到这样的介绍时,会非常清晰地了解你对自己的工作已经有了深入的思考,同时也能感受到你不止局限在自己的工作领域中,还在通过行业的变化和了解,来规划自己的职业,是一个很有潜力的候选人。
+
+## 真诚的对待每一次面试
+
+当然除了积极的态度以及清晰的定位以外,还必须是一个真诚、正直的人。如果在面试的过程中表现良好、思考很全面,但是与实际工作的内容只有 50% 的真实度,这样会很容易在面试官面前露馅,然后给你打上一个不真诚的标签,自然而然,面试也就到此结束了。
+
+因此,很多企业非常在乎候选人是否诚实或者真诚。也许你的职业经历并不是很丰富、项目内容并没有那么完美,但如果将自己所做的内容真实、完整地呈现给面试官,同时加上自己的思考,相信很多面试官会参考你的工作年限然后给你一个非常公平的反馈。
+
+通过以上三个方面的讲述,可以了解到面试官在面试的时候更看重的是品德,然后是性格,最后才是工作经验和学历。希望你听完这一讲的内容后,可以积极主动地面对自己的岗位,更好的去思考如何巧妙的推销自己。
\ No newline at end of file
diff --git "a/docs/\351\235\242\350\257\225/\346\212\200\346\234\257\345\262\227\351\235\242\350\257\225\346\275\234\350\247\204\345\210\231.md" "b/docs/\351\235\242\350\257\225/\346\212\200\346\234\257\345\262\227\351\235\242\350\257\225\346\275\234\350\247\204\345\210\231.md"
new file mode 100644
index 0000000..252b2b4
--- /dev/null
+++ "b/docs/\351\235\242\350\257\225/\346\212\200\346\234\257\345\262\227\351\235\242\350\257\225\346\275\234\350\247\204\345\210\231.md"
@@ -0,0 +1,71 @@
+# 技术岗面试潜规则
+
+开启上帝视角你会发现,在技术岗面试,竟有如此多不为人知的潜规则。
+
+## 一、岗位如何诞生
+
+### 1、岗位招聘指标
+
+岗位招聘指标哪里来的呢?首先肯定不是无中生有,也不是领导异想天开而来。那公司或部门什么时候会进行岗位招聘呢?即产生岗位招聘指标。根据个人以往经验,常常会产生在这两种情况:公司业务扩展期和为解决特定问题。公司业务扩展期,往往需要提前进行人员储备,会逐层递进下发岗位指标,最终抵达各部门和小组;另一种情况则是在发生棘手问题,而问题又是非解决不可,为解决问题先经过问题深层次的分析,恰好人力又是解决问题的关键路径,岗位招聘指标就顺应而生。
+
+### 2、挂上招聘页面前
+
+岗位指标定好就挂上招聘页面?其实还有很多我们看不到的过程。假设是因棘手问题产生的岗位招聘指标,技术总监需要向CTO汇报该问题解决方案和进展,技术总监的解决方案有一个关键路径是新增某类岗位人力若干。请问技术总监如何说服人事部门新增这笔预算?或者技术总监是否有这个权限决定这笔新支出?即使技术总监有这个权限新增(超强话语),也需要在流程上获取人事部门的支持,因为在招聘过程中也是需要人事部门的工作支持。
+
+因此在岗位指标制定后,还有个我们看不到的关键点:`新增人力预算需要说服人事部门`。
+
+可见招聘指标看起来有了,实际上还需要来回确认。包括薪资预算再逐步拆分,招聘多少人,什么级别,薪资范围,期望到位时间。接着技术部门和人事部门再临时组成一个虚拟工作组,明确分工职责,如简历筛选,制定面试流程。在这一系列的操作后,最终才有我们在招聘页面上看到的岗位信息。
+
+## 二、精准的岗位描述
+
+### 1、精准的岗位描述
+
+招聘页面上的岗位描述,一般都是HR挂上去的。但是也有特例,公司员工为了赚内推费用,随意写的挂上去收简历内推挣台iPhone。比较好的方式是HR事先跟用人方沟通,用人方根据岗位实际工作内容,罗列工作内容和技能要求。但是用人方,不了解现实市场行情,也不知道岗位预算(级别和薪资范围),所以在浏览招聘岗位时,常看到精通某某的描述语句。
+
+### 2、流水线岗位描述
+
+招聘页面上的岗位描述,一般常看到的都是流水线式。要么HR拿到一段岗位描述,统一挂到招聘页面,要么HR找用人方,用人方从别处复制简单修改下。你很难看到用心写的岗位描述,所以常常会遇到投的岗位描述跟实际面试官介绍的不一致。这里我称为流水线岗位描述,即招聘页面看到的岗位描述也仅供参考。
+
+## 三、流畅的面试流程
+
+### 1、标准化面试流程
+
+你遇到专业标准化面试流传概率非常低。在从业十年,面试百余场,只遇到一家公司有专门培训面试官,即面试你的人都没有经过上岗培训。面试流程包括岗位制定和岗位招聘两大部分。岗位制定指为什么要招聘这个岗位,解决什么问题,大概花费多少预算,岗位的职业发展通道;岗位招聘指发岗位到招聘网站,收简历进行面试,发放offer,新人入职到转正。理论上从公司角度普遍认为自己的这套流程很专业,但是从参与者角度看这套流程其实是很不专业的。面试官没有上岗培训,求职者无法从招聘页面上看到真实的岗位描述,新人导师只是一份额外临时工作。
+
+### 2、临时拼凑面试流程
+
+作为求职者需要很清楚明白遇到的面试流程只是临时拼凑的。你会遇到面试官打听你的薪资期望,因为他想了解市场行情。你会遇到明明简历上写了介绍,但是似乎面试官没看过,因为他只是5分钟前被临时安排面试你。
+
+## 四、最终面试结果
+
+### 1、面试通过发放offer
+
+终面后很久才发放offer。常常遇到有些公司面试次数特别多,而且终面后很久才收到offer通知。大公司一般审核流程很长,面试本身有流程,每次面试后都要填写面试结论。面试结束后综合考虑录用,也要发起定级定薪审核,需要部门/公司/人事审核,所以审核本身就很慢了,如果遇到领导出差,审核人处理更紧急的事情,那耗费时间就更长了。
+
+一直没消息突然打电话。已经入职新一个月公司,突然接到HR电话,说邀请你入职让你考虑一下。其中原因终面通过那批人中你的综合条件没那么优秀,简单说你是备胎。先发放offer给其他人,但是其他人拿到offer推迟入职,最后又去了更好的公司,然后备胎转正想起你了。
+
+### 2、面试不通过无音讯
+
+预算不够没通过。明明各轮面试下来感觉不错,甚至终面还问你住的远不远,但是还是没有等来offer。面试官只是考核你岗位匹配度,出发点肯定是越优秀越好。但是每个岗位都有相应的硬指标—预算,岗位预算不够,那怕很想要你,公司最终审批也是没法通过的。
+
+岗位突然没了。大公司信息常常不太透明,组织架构调整往往是高层的决策,底层常常是不知道的,所以就会造成招聘这拨人和组织架构调整这波人信息不互通, 组织架构调整公告时候才告诉你需要停止招聘。
+
+## 五、其他潜规则
+
+### 面试参与人员
+
+在面试环节,参与人员常常有很多,包括岗位用人方、招聘HR、各轮面试官、公司管理层。岗位用人方:最终招聘人员使用方,一般会充当第一次面试官,或者加一轮面试,也有可能不参与面试环节,但是肯定要充当新人导师,帮助新人快速上手;招聘HR:寻找适合的候选人,初次筛选简历,邀约候选人,各个环节润滑加速流程。各轮面试官:包括N轮面试,先考察技术基本功,再考察综合实力,有适合也会有跨部门面试,级别不同流程往往也不同。公司管理层:往往岗位级别达到一定才需要管理层参与,薪资审批也只是人事部门审核。
+
+### 551定律
+
+你知道招聘市场的“551 定律”吗? 551 定律:每一层筛选环节都会有百分之十的折损率。一个岗位从接收简历到发下offer至少要筛选500份左右的简历、面试50人左右、只有5人左右通过面试,最终也只有1位候选人可以顺利入职。
+
+对于企业内的招聘人员平均每天至少在一个岗位上要收到几百份简历,至少要面试十几个候选人,每周至少会发出4-5个offer;一周内至少同时会招聘5-7个不同的岗位。因此,可以看出,招聘人员的工作强度是非常巨大的,面试者需要把控好每个环节的节奏并表现优秀,才能得到最好的结果。 所以说你的简历是否对自己的工作内容和项目经历描述清晰,你的面试表达是否可以直击面试官的问题要点,你的Offer沟通是表现的完美无缺,都对你能否赢得心仪的岗位至关重要。
+
+### 面试的那些事
+
+简历已被阅读却迟迟没有回应 相信大部分人都会有这样的疑惑:每个求职的早上都会迫不及待的打开手机查看是否收到昨天投递简历的回复,发现都显示为“您的简历已经被阅读”的状态,带着兴奋的心情等待着心仪企业的面试邀请电话,上午过去了没有接到电话,午饭时间过去了没有接到电话,下班了仍然没有接到电话,第二天、第三天……一直没有收到任何的信息,一度以为自己的手机是否坏掉了或者怀疑招聘人员是不是忘记了拨打电话…
+
+面试很顺利却迟迟没有收到录用通知 相信你也会有这样的困惑:好不容易收到面试电话,兴奋的不能自已,提前和公司请了假,穿上非常体面的衣服,吃一个元气满满的早餐,做好充分的准备去面试。面试时费尽心力地展示自己,把从事过的工作内容和听说过的项目经验全部展示在面试官面前,这时的你侃侃而谈,表现得非常自信且积极正能量。但是,不知是否留意过面试官有时候针会对一个问题进行深入的提问或者偶尔出现锁眉的动作?
+
+面试了很多公司,难道能力已被透支 相信你有过这样的经历:面试了很久,也面试过 N 家公司,最后一份录用通知书也没有收到,此时是否开始对自己的工作能力表示深深的怀疑,真的是自己不够努力吗?之前的工作能力真的那么水吗?有没有想过也许就是与招聘人员沟通时的语气,与部门负责人的一次错误的意见表达等,导致公司对你的看法完全改变了,进而错过了接受心仪公司录用通知的机会。 这时候的你是不是感觉面试的道路上充满了坎坷,对自己的能力也产生了深深的质疑? 其实求职之路并没有想象的那么复杂,接下来我会从一个面试官的角度来告诉你在简历上需要注意的细节点以及哪些内容是必须要提到的;在面对面试官时如何张弛有度地展示自己,在沟通中如何让面试官感觉到你就是那个公司一直在寻找的人选。
\ No newline at end of file
diff --git "a/docs/\351\235\242\350\257\225/\346\212\212\346\217\241\351\235\242\350\257\225\346\227\266\347\232\204\345\205\263\351\224\256\347\202\271.md" "b/docs/\351\235\242\350\257\225/\346\212\212\346\217\241\351\235\242\350\257\225\346\227\266\347\232\204\345\205\263\351\224\256\347\202\271.md"
new file mode 100644
index 0000000..ba1f004
--- /dev/null
+++ "b/docs/\351\235\242\350\257\225/\346\212\212\346\217\241\351\235\242\350\257\225\346\227\266\347\232\204\345\205\263\351\224\256\347\202\271.md"
@@ -0,0 +1,101 @@
+# 把握面试时的关键点
+
+## 面试前的准备工作
+
+先说说面试前的准备吧。常规的准备相信你一定知道,比如制作一份吸引 HR 的简历、穿一身体面的衣服、整理一下自己的发型等。简历相关的准备前面已经详细讲过,这里就不多介绍了。
+
+下面说说穿着相关的准备,很多小伙伴认为面试时的穿着并不是很重要,面试官肯定更看重个人魅力和知识的储备。当然这么说是没错的,但如果你和面试官首次见面,在还没有开始正式聊天之前,他是无法感知你的个人魅力或者知识储备的。
+
+假如第一次见面就看到邋遢的外表或者奇怪的着装,面试官会怎么给你贴标签呢?首先他一定会认为你并不尊重这次面试,给他造成一种没有礼貌的印象;然后就是被你身上的味道熏倒无法和你多交流;最后根本来不及了解你的个人魅力和知识储备就草草地结束了这次面试。相信这个结果一定不是你想碰到的吧?所以,干净得体的着装是面试非常重要的一个环节。
+
+面试官也会通过你的着装去判断你的性格,以及判断与公司的文化、团队的气氛是否匹配。这时可能你会问:我也没有进入到这家公司和团队,该如何判断面试当天穿什么衣服才符合这个公司的文化或者符合这个团队的气氛呢?当然,我们没有办法做到“把面试官的感受照顾到很细”的层面。
+
+但是不同的穿着一定会表现出你的性格,有些表现出来的性格可能不会被大众所接受的,希望可以回避一下。下面简单说说几种可以表现性格的穿着:
+
+喜欢穿简单朴素衣服的人,往往给人的印象是性格比较沉着稳重、为人比较真诚和随和,无论是在工作或学习上,还是在生活中,会给人一种勤奋好学、诚实肯干的感觉;
+
+喜欢穿样式繁杂、颜色多样、花里胡哨的衣服的人,多是虚荣心比较强,爱表现自己而且又是乐于炫耀的人,会给人一种性格有些飞扬跋扈的感觉;
+
+喜欢穿浅色衣服的人,性格比较活泼好动,十分健谈,会给人一种喜欢交朋友的感觉;
+
+喜欢穿深色衣服的人,性格比较稳重,显得城府很深,会给人一种比较沉默,做人做事深谋远虑的感觉。
+
+如果你希望在面试中表现的不是那么具有攻击力或者给人比较亲和、稳重性格的话,建议穿简单、朴素、纯色的衣服,会显得整个人比较清爽,且比较容易亲近,相信面试官也愿意和你多聊几句。当然不仅穿着干净,而且一定要注意个人卫生,最好不要让自己身上的体味过重或者使用太重味道的香水。化妆时,不建议浓妆艳抹,自然的淡妆让自己看起来很精神就可以。
+
+## 如何全面的介绍自己
+
+接下来就是面试的过程了,首先面试官会说:“请简单介绍一下自己。”
+
+面试官有两个目的:(1)希望通过你的简单描述可以和简历上的经历做校对;(2)通过简单地介绍来看看你的逻辑和总结能力如何。所以自我介绍也是非常重要的一个环节,好的自我介绍一定要做到以下几点。
+
+### 面试时的自我介绍
+
+一定要把握住时间。面试时的自我介绍一般控制3~5分钟最合适,尽量不要超过10分钟。时间过短说明你根本没有清晰的介绍自己,这时面试官很难了解你到底做了什么;时间过长可能很多内容不是面试官需要的信息,这时大部分的面试官会主动打断你,从而留下了不太好的印象。
+
+那如何把握好时间呢?建议在介绍时包含以下几个部分就好:(1)情况介绍,包括教育经历;(2)工作经验的介绍;(3)介绍最有价值的经历。这样的一个自我介绍应该可以很好的控制在5分钟左右了,既可以让面试官清晰的了解你的情况,也能表现出你的优势。
+
+### 面试过程中需突出的几个点
+
+在面试过程中一定要突出以下几个点:做过什么、有哪些工作业绩、优势是什么,这样可以很好的突出自己。
+
+做过什么:介绍自己,把自己曾经做过的事情说清楚,每段工作对应时间节点的公司名称、担任职务、工作内容等,尤其是对最近两份工作做过的事情要重点说说,较早之前的工作经验,或者学习的经验可以一带而过,要把握“重点突出”的原则。
+
+有哪些工作业绩:把自己在不同阶段做成的有代表性的项目经验介绍清楚,但是一定要注意:(1) 应与应聘岗位需要的能力相关的业绩多介绍,不相关的一笔带过或不介绍,因为面试官关注的是对用人单位有用的业绩;(2)要注意介绍你个人的业绩而不是团队业绩,要把自己最精彩的一两段业绩加以重点呈现。当然也要做好充足的准备,可以迎接面试官的提问。
+
+突出自己的优势:注意介绍自己的优势一定要与应聘的岗位密切相关,主要是围绕自己专业特长来介绍。除专业特长以外的特长,特别突出可以介绍,但要点到为止。
+
+举个例子:你好,我是某某,2018年3月加入XXX公司,担任产品经理一职,主要负责公司核心产品的规划和设计工作;在这段期间,我独立完成过XX项目的产品跟进和上线的工作,将产品的数据提升了30%,业绩突出,获得了公司的认可。在项目中,我通过学习和与外部专家的沟通,获许了XXX新策略的信息,并积极尝试,达成了我的目标。
+
+### 每段工作的离职原因
+
+在面试的过程中一定要突出自己职业规划的逻辑性,也就是说需要让面试官感受到你的每次工作变动都是为了个人成长以及有规划的进行变动。所以在表述的时候最好可以清晰地说出你在每段工作中的收获和成长点,当然如果在陈述这些内容时可以体现出你的个人思考,就更是画龙点睛了。
+
+## 如何回答面试中的问题
+
+相信你经常会碰到面试官问以下的问题,这些问题也是面试官给你的一些考验,如果更好地回答这些问题可能会成为你入职心仪公司的敲门砖。
+
+### 你为什么选择我们公司?
+
+这个问题相信不少小伙伴遇到过,可能你的原因是随便投递、公司离自己住的地方近、工资给的高、公司不加班、公司有各种补助等。如果这些答案出现在你的面试回答中,那 HR 会重新考虑是否要录用你了。
+
+所以在回答这个问题时需要有一些准备:
+
+可以先描述一下自己的能力与岗位要求的契合度,表现出在公司提供的岗位上有机会可以一展所长;
+
+说出几个被企业所吸引的优点,这些优点能为以后的工作带来什么好处;
+
+自己的职业发展与公司前景作出总结。
+
+相信这些回答可以很容易抓住面试官的心,不过前期也是需要你对这家企业,以及所招聘的岗位做了一定的功课。
+
+### 你为什么从上家公司离职?
+
+也许你在前公司受到了委屈、也许前公司人事关系复杂所以离职,但无论前公司有多么的糟糕,都千万不能在面试时说出来。因为你在上家公司离职的原因,会使面试官联想到你会不会因为在新公司受到委屈而轻易离职?再者,面试官其实并不关心你为什么要离职,所以面试时只需要给在场所有的人一个都可以接受的答案就可以了。
+
+例如,可以这样回答:为了更好的发展,所以选择离职。切记在回答这个问题的时候,不能贬低前公司、不要损害前领导的形象。
+
+### 你的优点和缺点是什么?
+
+相信很多小伙伴对这个问题都很头疼,自己的优点说的太多会让面试官感觉过于自大,可在面试的过程中又有谁愿意说自己的缺点呢?下面列举几个简单的方向,希望可以帮助你解决这个尴尬的困境。
+
+优点:可以结合过往的工作经历和工作业绩等讲述一下自己的优势。例如,我曾经参加过某某项目,相信我的这个工作经验可以很好的帮助到公司解决什么方面的问题等。当然也可以通过一些例子说明自己的人品或性格方面的优势,哪家企业可以拒绝一位性格和能力都很好的候选人呢?
+
+缺点:金无足赤、人无完人,要勇敢的面对自己的缺点,可以向面试官说明,你针对自己的缺点做了哪些改变,以此来说明你正在积极地改变自己去成为更优秀的人。
+
+### 未来3年或5年,你的职业规划是什么?
+
+当面试官问到这个问题时,是希望看到你的自我学习力和未来牵引你的职业动力是什么。对职业规划不清晰的人,很难获得成功,也不会在一个岗位上待很久,所以也不是公司最合适的人选。
+
+当被问到你的职业规划是什么的时候,此时可以设定一个短期就能实现的规划和一个未来希望实现的目标。
+
+例如,我希望可以在未来的 1 ~ 2 年内,梳理和参与到几个完整的项目中,从中学习和看到整个项目进度是什么样的,从而提升自己的工作能力和项目经验。在未来的 3 ~ 5 年内我希望可以独立承担项目,做一个可以让大家都能使用并且体验良好的产品出来。
+
+这样的回答,在短期规划上会让面试官认为你是一个脚踏实地,希望可以通过学习而成长的人,而且也在积极的改变自己;在长期规划上也能让面试官感受到你对这份工作的热情,具有很强的成就动机。
+
+### 在选工作中更看重的是什么?
+
+很多小伙伴反馈,这个问题很难回答,其实也能想到面试官肯定更看重你的是个人成长和发展空间。当然也许你的内心想的是涨薪或者培训,虽然薪资是一定的,但是如果让面试官认为你是一个物质的人,并没有长久的培养空间,那面试的结果就可想而知了。
+
+### 你还有什么问题吗?
+
+这是面试结束前的最后一个问题,也可以认为是个形式问题或走个流程,此时可根据前面面试过程中的表现程度来适当的提问,比如公司福利、上下班时间、团队氛围、个人岗位发展等,但尽量不要问从网上就能查到公司信息的问题。
\ No newline at end of file
diff --git "a/docs/\351\235\242\350\257\225/\346\215\225\346\215\211\351\235\242\350\257\225\345\256\230\345\276\256\350\241\250\346\203\205\357\274\214\345\201\232\345\207\272\345\272\224\345\257\271\347\255\226\347\225\245.md" "b/docs/\351\235\242\350\257\225/\346\215\225\346\215\211\351\235\242\350\257\225\345\256\230\345\276\256\350\241\250\346\203\205\357\274\214\345\201\232\345\207\272\345\272\224\345\257\271\347\255\226\347\225\245.md"
new file mode 100644
index 0000000..ead10c2
--- /dev/null
+++ "b/docs/\351\235\242\350\257\225/\346\215\225\346\215\211\351\235\242\350\257\225\345\256\230\345\276\256\350\241\250\346\203\205\357\274\214\345\201\232\345\207\272\345\272\224\345\257\271\347\255\226\347\225\245.md"
@@ -0,0 +1,63 @@
+# 捕捉面试官微表情,做出应对策略
+
+在面试的过程中,如何判断自己所陈述的信息是面试官感兴趣的呢?怎么才能在恰当的时间更好地展示自己擅长的内容呢?同样,如何在不恰当的时候适可而止,更好地转换话题呢?此时需要精准地捕捉到面试官的微表情,以便在合适的时间突出自己。
+
+## 沟通时需注意的小细节
+
+你有没有经历过这样的窘境:当在描述项目经验时,突然被面试官打断了,虽然此时你正在兴头上,但也请你马上停止,面试官的打断说明他对你的这段经历比较了解,或者刚才的这段描述有了自己的判断,所以要想想刚才的描述是否有漏洞,如果有机会建议再重新解释一下。
+
+有时候也能发现面试官重复提问同样类型的问题,说明他对你之前回答的问题有质疑,希望可以通过重复提问的方式,再次确定这件事情的真实性,此时需要你给出不同的答案或挑选重点内容来回答,如果没有察觉,很有可能就错失了这次机会。
+
+甚至有时候面试官针对某个项目经验进行深入提问,不断地细化你所做的项目数据。这时一定要提高警惕,因为面试官对你的这段经历比较感兴趣,需要通过非常细致地提问,才能了解你在这个项目中真实参与的程度和担任的角色。如果你的回答不够细化或者给出的数据不够精细,那么很容易被误解为并没有参与这个项目的核心内容。
+
+## 面试时需留意的微表情
+
+观察面部微表情可以解读很多信息,进而可以判断面试官是否真的对你所说的内容感兴趣,下面来讲讲面试过程中常见的几个微表情。
+
+当看到面试官的下嘴唇往前撇时,说明他对接收到的信息持有怀疑的态度, 此时需要转化角度或思路来陈述。
+
+当看到用牙齿咬嘴唇的时候,说明面试官正在仔细听你的介绍,同时也在默默的思考你所表达的另一层含义是什么。
+
+当看到面试官调整自己的坐姿时,比如身体向前移动,很有可能对你所讲的内容很感兴趣;如果发现面试官身体逐渐的后退,说明很有可能对你的这段介绍没有兴趣聆听,此时要及时的调整陈述的思路。
+
+当发现面试官双臂交叉时,这是防卫的一种表现。很有可能你说的内容与他的认知完全不相符,也表现出面试官对你表述的观点完全不认同或者完全没有听懂你所表达的意思。
+
+上面简单讲了一些面试过程中可能碰到的情况,希望你在以后的面试过程中及时捕捉到面试官的微表情,以做出应对的策略。
+
+其实很多时候面试官也在捕捉你的面部表情。当你在阐述的过程中,面试官在倾听是否有漏洞,也许不经意的某个动作或者某句话,也能让面试官察觉到你的问题点,然后做出不一样的决定。所以管理好自己的微表情也是非常有必要的,下面我们来说说在面试时做出的一些不经意的错误微表情有哪些。
+
+## 面试时需改掉不好的习惯
+
+有时候一个沟通时的习惯,也能透露出一些问题,比如:
+
+当习惯说“啊”、“呀”、“这个”、“那个”、“嗯”等口头语时,一般给人留下词汇量小或者思维慢的印象,在说话时需要利用间歇的方式让自己思考;
+
+沟通时喜欢使用中英搭配,这样很容易给人一种虚荣心比较强、好表现或夸耀自己的错觉;
+
+如果口头禅出现频率过高的话,很容易给人一种办事不干练、意志不坚定的印象。
+
+当然说话声音的大小或者语速的快慢等这些信息也能让面试官初步判断你是一个什么性格的人。
+
+说话声音的大小和一个人的性格联系非常紧密,喜欢大声说话的人,其性格比较以自我为中心,积极主动、行动力和支配欲强,也就是富有攻击性的一类人;说话声音小的人其性格比较偏内向,考虑的因素比较多,很压制自己的情感。
+
+语速快慢和声音大小一样,一般语速快的人性格比较外向,有冲劲且有活力,但是常常给人一种紧张和压迫感,让人有种焦躁、混乱甚至有些粗鲁的感觉;但是语速慢的人容易让人感觉比较木讷,容易犹豫不决,甚至有时候有消极悲观的想法。
+
+所以说需要根据你所从事的工作或者要应聘的岗位来调整自己说话的方式,才更能获得面试官的青睐。假如你是一位声音小而且语速慢的人,去面试一家公司的销售岗位,相信这家公司不会对你抛出橄榄枝,因为他们很难从你的沟通中看出你的销售潜力。
+
+## 面试中透露出的动作,也需要多多留意
+
+很多小伙伴可能没有留意在面试过程中做的一些小动作,也许就是这些小动作导致面试官对你的印象减分。下面简单说几个常见的小动作,希望可以帮到你。
+
+吐舌头:一般在感受到有压力时,舌头不自觉地做出舔嘴唇或者看似是在舔嘴唇的动作,说明是对自我的一种安慰。如果做了这个动作说明当时你备感尴尬,希望可以缓解一下气氛。
+
+用手捂住嘴巴:这个动作一般表示自己对刚刚说的话已经意识到了错误,下意识的去捂住自己的嘴巴。
+
+十指交叉:这个动作很可能是自信的表现,也有可能是在掩盖你的紧张。如果你的十指无意识的交叉在一起,而且眼神也在躲避面试官,很有可能是怕面试官发现你的紧张。
+
+抚摸颈部:这个动作说明你并不是很自信,当然也有可能是你正在释放压力,这是一种普遍有力的信号,说明大脑正在积极处理某种消极的情绪。
+
+眼神躲避:很多候选人在面试的过程中,经常左顾右看,躲避面试官的眼神,给面试官一种心虚的表现。
+
+当然还有一些其他的小动作,比如揉鼻子、挠头或者摸耳朵、翘二郎腿或抖腿、常扶眼镜、玩弄随身小物件、咬指甲等,这些小动作也都说明你比较紧张或者不够自信。
+
+希望你可以通过这一课时的学习,合理地控制一下自己的微表情,在面试时更好地表现自己。
\ No newline at end of file
diff --git "a/docs/\351\235\242\350\257\225/\347\233\256\346\240\207\346\230\216\347\241\256\357\274\214\351\230\220\346\230\216\346\262\237\351\200\232.md" "b/docs/\351\235\242\350\257\225/\347\233\256\346\240\207\346\230\216\347\241\256\357\274\214\351\230\220\346\230\216\346\262\237\351\200\232.md"
new file mode 100644
index 0000000..6104b98
--- /dev/null
+++ "b/docs/\351\235\242\350\257\225/\347\233\256\346\240\207\346\230\216\347\241\256\357\274\214\351\230\220\346\230\216\346\262\237\351\200\232.md"
@@ -0,0 +1,31 @@
+# 目标明确,阐明沟通
+
+## 知道自己想要什么
+
+在开始谈薪资之前,需要明确自己到底想要什么,希望在这次的工作变动中有什么收获,比如想在团队氛围很和谐的公司里工作、希望积累更多的项目经验、还是仅仅为了涨薪等。 当你明确自己想要的是什么,同时清晰的表达出来以后,HR 会根据你的需求去匹配这个职位是否可以给到你所期望的东西,或者你也可以直接询问 HR 来判断是否能得到你想要的。
+
+很多小伙伴会说,如果我确实不知道自己这次换工作想要得到什么,该怎么办? 你可以参考在之前的工作过程中,是不是有让自己感觉不舒服或者有挫败感的时候,同时想想是什么原因造成的,然后把它们整理出来写在纸上,标出来哪些是你希望可以得到改善和需要得到成长的。
+
+通过这样的方式,再去想想在面试的过程中或者在和面试官沟通的过程中,这家企业是否可以给到你想要的东西。
+
+## 明确自己的优势
+
+明确了自己想要的,也要知道你能给企业创造出什么样的价值,这样才可以在薪资上做更有利的争取。面试结束后,HR 已经对你的表现做了公正的评价,相信这些评价一定都是你对企业有价值的地方。 那怎么评估自己优势的价值呢? 首先要明确,你的优势是软性的优势还是硬性的优势:
+
+软性的优势是指性格方面(比如性格好、踏实),相信很多人都具备,所以这个优势的价值可能就没有那么大的竞争力;
+
+硬性的优势是指之前的工作经历给到的优势(比如项目经历、专业经历),这样的优势相比软性优势要更有竞争力
+
+其次如果你的硬性优势又是比较稀缺的项目经验或者专业经历的话,那就更有竞争力了。
+
+## 不要敌化与HR的关系
+
+在谈 Offer 的时候,最终肯定会落在谈薪资的问题上,你是不是也会有这样的感觉:明明招聘网站上写的很高,HR 却说给不了这么高? 因为招聘网站上显示的薪资范围,为了吸引用户会稍微提高一点薪酬水平。但是主要确定你薪资的并不是网站上的薪酬范围,而是你的真实能力。因为 HR 会根据你的真实能力去判断你在什么薪酬档位上,然后给出你合适的薪资。所以并不是 HR 不愿意给你高薪,要判断自己是否具有拿到高薪的能力。
+
+如果 HR 问你期望的薪资是多少,该怎么回答呢? 如果你不清楚企业的薪酬结构,可以考虑给 HR 说一个年薪的的范围。但是建议提出的薪资涨幅不要超过你之前薪资的 20%,当然如果你特别优秀或者岗位是非常紧俏的岗位可以考虑多要一些涨幅,但是也不要太离谱。
+
+因此,不管怎么谈薪资,建议你都要明确心态,尽量不要把 HR 当作自己的敌人,因为 HR 也有指标,也希望优秀的候选人可以顺利接受 Offer。 把 HR 当做朋友,先以平和的心态和他确认一下自己的各种疑惑或者不清晰的信息,然后再清晰地表达出期望得到什么,或者也可以让 HR 说一下他们可以给到你的都有什么,然后给彼此一些时间考虑一下(最好不要超过一周,不然会错失这个机会),相信这样的沟通方式大家都比较愉快
+
+## 坦诚地沟通
+
+前面经历了多轮的面试和沟通后,最后在沟通 Offer 的时候同样要表现出你的真诚,不要在最后的关键时刻给到 HR 比较滑头的感觉, 不然结果会前功尽弃。
\ No newline at end of file
diff --git "a/docs/\351\235\242\350\257\225/\350\256\276\350\256\241\344\270\200\344\273\275\345\220\270\345\274\225\351\235\242\350\257\225\345\256\230\347\232\204\347\256\200\345\216\206.md" "b/docs/\351\235\242\350\257\225/\350\256\276\350\256\241\344\270\200\344\273\275\345\220\270\345\274\225\351\235\242\350\257\225\345\256\230\347\232\204\347\256\200\345\216\206.md"
new file mode 100644
index 0000000..e1a30e7
--- /dev/null
+++ "b/docs/\351\235\242\350\257\225/\350\256\276\350\256\241\344\270\200\344\273\275\345\220\270\345\274\225\351\235\242\350\257\225\345\256\230\347\232\204\347\256\200\345\216\206.md"
@@ -0,0 +1,91 @@
+# 设计一份吸引面试官的简历
+
+> 简历是什么?可以理解成:如何花两分钟初步了解你?
+
+## 简历模板
+
+简洁干净的纯色底简历模版可能是最好的选择。面试官也会把更多的注意力放在简历内容上,从而可以更好地判断你的经历是否与工作内容相符。
+
+下面是一个比较清晰的简历模版,可供参考。整体简历的排版清晰;文字描述段落清晰和明确;重点比较突出。
+
+
+
+## 组成部分
+
+分为这几部分进行阐述:个人信息、教育情况、工作经历、项目经历、自我评价、其他信息。
+
+### 个人信息
+
+很多小伙伴在构思自己个人信息的时候,很喜欢把自己完全展示出来,如身高、体重、性别、民族、婚姻情况、政治面貌、家庭住址、籍贯等,统统都写在简历上。
+
+但有没有思考过:这些信息是面试官所需要的吗?当然,特殊岗位可能需要提供身高、体重、籍贯、民族或者政治面貌。但是在如今这个互联网公司占据了很大就业市场的情形下,并没有太多的互联网公司在乎这些比较表面的信息,面试官往往更在乎的是姓名有没有写完整、电话号码和邮箱地址是否填写正确等,只有这些信息完整,面试官才可以快速地联系到你。其次面试官也会留意你的求职意向是否与应聘的职位相符,以及期望薪资是否在应聘岗位的范围内等。
+
+
+
+上图的简历过于繁琐,罗列的很多个人信息不是 HR 所需要的,而且很难快速地找到个人的联系方式和邮件信息,这样会给招聘人员带来很大的困扰。简单的突出自己的关键信息既可以让招聘人员轻松的获取,也能让招聘人员认为这是一个逻辑清晰的候选人。
+
+
+
+### 教育情况
+
+首先,建议求职的小伙伴在教育情况的部分只需要体现出正规被认证的学习经历即可,比如本科、研究生、博士生等的经历。很多小伙伴会将自己的高中,甚至初中的学习经历都要写上,也许你的初中、高中学校在家乡非常有名,但是对于企业来说很难判定和考究。因为学信网可查的学校只有大学院校,所以只需要填写高中毕业后的教育经历就好。
+
+其次,在填写学校经历的时候只需要突出就学时间(入学时间—毕业时间)、学校名称、专业名称、学历(统招或非统招)即可。对于企业方可以很容易通过就学专业和学校判定出来你所学的内容,而不太需要你做过多的说明和解释。经常看到一些刚刚踏入职场的小伙伴在自己学校和专业信息下面会长篇大论地介绍自己的专业以及学习的科目,往往是非常徒劳无功的表现。
+
+最后,部分小伙伴也会分享在校期间获得的所有证书和参与的活动,相信很多面试官在这里的停留不会超过5秒,所以,即使展示自己学习有多好也不会吸引太多的注意。倒不如在这里保持一个整洁干净的排版,将自己获得的证书或者参与自己擅长的活动信息挑一些重要的放在最后的其他信息中,这样也能给简历加分。如果觉得这里是否有些单调,可以放一些真正具有含金量的奖项。
+
+
+
+
+
+
+
+### 工作经历
+
+工作经历往往是企业方非常在乎的一部分,这一块也是招聘方停留时间最长的地方。在写工作经历的时候一定要清晰标注这几个内容:公司名称、工作时间(开始时间—结束时间)、职位名称、工作内容、业绩成果。
+
+a. 公司名称。目前很多互联网公司的对外名称和他们的注册名称完全不同,所以在书写公司注册名称的时候建议在后面也标注一下公司的对外名称,也是帮助面试官判定你上一家所在的公司行业和领域,因为很多互联网公司的注册名称普及度并不是很高。
+
+b. 职位名称。公司名称后面建议标注所在公司的职位名称,职位名称可以写上职位的层级 + 具体做的事情,如招聘专员、招聘主管、招聘经理、招聘总监。往往面试官会根据岗位层级看你简历内容负责的事情是否与层级相符,进而来判定你的能力。目前大多数公司内部都有岗位职级,可以在职位名称后面标注上自己目前的职级,以方便面试官清晰的判定。
+
+c. 工作时间。建议具体到年、月,如2016.07~2019.03,这样的书写方式,面试官可以很清晰的了解你的工作年限。
+
+提示:在写工作时间的时候一定要注意每段工作时间之间的结合期是否连贯。如果没有连贯,且中间相隔的时间周期比较长,最好增加一个说明,为什么会有那么长的空白期、这段时间在做什么等。如果连续几段经历都出现这样的断档,需要慎重思考一下是不是要改变已有的工作习惯。
+
+如果有很多段经历,建议优先写最近的经历,然后采用倒叙的顺序来写比较合适,因为大部分企业方习惯从最近的一份工作去了解。
+
+d. 工作内容。接下来我们聊一下简历中最重要的一个部分,也就是工作内容的描述。我知道很多小伙伴在写职位描述的时候,习惯的做法是借鉴与自己相同岗位的职位 JD,甚至有的小伙伴直接把大公司的职位 JD 粘贴到自己的简历中,表示自己做过相关的工作。但有没有仔细阅读过这些岗位描述?往往企业在发布岗位描述的时候希望招的都是按照最全面的要求去撰写的,但是候选人的能力很少具备全部的要求,如果复制粘贴,很容易被 HR 怀疑简历的真实性。所以最好的做法是在设计简历之前,先认真的思考一下自己上一段的工作内容是什么,然后把这些工作内容按照重要程度依次精简描述出来,写到简历中。
+
+当然,也有小伙伴说:我不太擅长文字的书写怎么办?没关系,如果你已经清晰知道自己的日常工作是什么了,也可以借鉴企业招聘职位中的描述。假设你是一位销售助理,日常的工作为: A.拜访客户与客户进行销售产品的沟通 B.收集客户的资料 C.日常的文档整理、合同的归档。对于 HR 来说,A 和 B 的内容更为重要,所以放在前两条来展现自己日常工作的重要性,两件或多件内容中间要做好分段,描述完一件工作内容后记得另起一段来描述下一个工作职责。
+
+如果有多份工作经历,且工作内容都比较相似的话,最好有一个递进的关系,每一段突出一个工作重点。
+
+来看下下面的一个简历截图,能看出里面的问题吗?
+
+
+
+有以下几个问题点:工作时间倒序,并非HR的日常阅读习惯;两段工作经历之间留有1年时间的空档期,很容易让HR表示怀疑;工作描述过于简单,几乎没有突出自己工作的亮点。
+
+e. 业绩成果。如果工作中有过一些公司认可的奖状或者某一期的绩效非常优异的话,可以在“工作内容描述”后面增加一栏“业绩成果的展示”,但是这一栏的内容不易过多,把最重要或者很有价值的公司奖项或绩效按照重要程度精简出 1 ~ 3 条即可,如「公司年度优秀员工奖」、「上季度绩效为 A」等。
+
+### 项目经历
+
+项目经历其实和工作内容描述表现的形式类似,只不过项目经历不用把每段都写在简历里,只需要选出一些自己作为主要参与人或者由自己负责的项目添加在简历里就好了。
+
+项目经历的展示也需要体现出项目名称、项目时间、项目中担任的职务、项目职责和项目业绩。如果补充项目经历的介绍,则会给简历加分,也能更容易打动面试官。
+
+### 自我评价
+
+不要小看自我评价哦,这一部分是上述简历整体的一个总结,大部分面试官很希望从自我评价中整体了解候选人的情况。
+
+所以,建议从两个方面整体的评价自己:首先先对自己过去的工作内容或者过去的学习经历做个总结;然后对自己的个性以及工作态度做一个工作展示。
+
+比如下面的「个人优势」其思路比较清晰:
+
+
+
+上面的自我评价是一个可参考的模板:候选人不但突出了自己的优势,而且还清晰地展示了自己的学习主动性和学习能力,进而会给招聘人员留下很好的印象。
+
+### 其他信息
+
+这里如果真的写不出来,可以忽略,当然如果有一些非常值得或者有帮助的奖项亦或培训内容也可以在这里展示,比如某某专栏的发表、CPA的认证、司法考试的证书等。
\ No newline at end of file
diff --git "a/docs/\351\235\242\350\257\225/\350\257\273\346\207\202\345\262\227\344\275\215\347\262\276\345\207\206\346\212\225\351\200\222.md" "b/docs/\351\235\242\350\257\225/\350\257\273\346\207\202\345\262\227\344\275\215\347\262\276\345\207\206\346\212\225\351\200\222.md"
new file mode 100644
index 0000000..16ec34c
--- /dev/null
+++ "b/docs/\351\235\242\350\257\225/\350\257\273\346\207\202\345\262\227\344\275\215\347\262\276\345\207\206\346\212\225\351\200\222.md"
@@ -0,0 +1,39 @@
+# 读懂岗位精准投递
+
+## 清晰的了解用人部门的招聘要求
+
+上一讲是关于如何设计简历,相信大部分小伙伴可以很轻松的掌握,但这只是投递简历前的一个开始,明确工作方向才是真正的关键点。 很多小伙伴在投递简历的时候,很少仔细阅读招聘公司的招聘简章,只是投递出去了,甚至一个岗位投递多次或者一个公司投递多个岗位,尤其在刚刚毕业的小伙伴身上表现非常明显。可能大部分人会认为多投递几次会被面试官看中的几率更高,但往往是相反的,如果你自己的工作内容与职位的内容完全没有关联,只会被 HR 淘汰掉,然后放进简历库,而且目前很多公司在简历库里都会对投递来不合适的简历做备注,下次使用简历的时候面试官也会查看上次的评价。
+
+Tips:如果不想在心仪的公司里面留下污点,建议谨慎地投递简历。
+
+需要注意,投递的内容除了职位描述以外,还需要留意公司对人才的工作年限要求和工作的职级。例如,经常看到一些刚刚工作 1 年左右的小伙伴,直接投递公司需要 8 年以上要求的总监岗位。这样会给 HR 留下非常不好的印象,会认为这份简历的候选人对自己的定位非常不清晰,甚至有时候会觉得比较浮躁。
+
+第一印象一旦形成是非常难改变的,所以建议各位小伙伴在投递简历时一定要做好两个准备:
+
+要对投递的公司做好充分的了解,清晰地知道自己投递公司的业务是否和自己的发展方向一致;
+投递的岗位是否与你之前的工作内容相符合。
+一份满足以上条件的简历才会获得用人公司的邀请。
+
+下面是一个某公司“产品经理”的招聘要求:
+
+
+
+通过上面的职位描述,有几点可以注意一下:
+
+在职位描述中,不断提到需要具有“独立负责…”、“负责具体…”等字样,说明这个岗位需要你能独立完成一些项目。如果你还是一个需要别人带着干活的话,最好不要盲目投递哦。
+
+职位要求年限,这是一个要求有工作经验的岗位,比如需要具备 3 ~ 5 年的工作经验。往往 HR 希望求职者最好有 5 年左右的工作经验,具有 3 年工作经验是最低的要求。如果你的工作经验低于 3 年的话,就不要考虑尝试了,即使投递了也会被刷掉。
+
+任职要求中的第4点,说明这份工作的强度非常大,成长性也很高。如果你是一个不希望太大工作强度或者想找一份轻松工作的小伙伴,也要好好的思考一下哦。
+
+建议:在投递简历的时候一定要注意 HR 在职位描述中的用词和一些细节,这样才能更准确地投递到心仪的岗位,进而获得一份满意的录用通知书。
+
+## 最合理的助攻来自自己内心的力量
+
+好的简历内容并不是通过简单地编写就可以实现了,一定是通过每天的努力工作和不断地反思才实现的。所以,即使简历构思再完美、逻辑再缜密,如果不是自己亲身经历和努力付出过的项目经验都会很容易的被发现漏洞。
+
+一定要认真的对待自己的工作,每次的工作变动也要对自己的职业规划做好充分思考,这样才会拥有一份完美的简历和一份完整的职业规划。
+
+可能很多刚刚毕业的小伙伴会问:“我没有工作经历,也不知道自己做什么。如果我不去尝试怎么可能知道自己适合什么呢?”其实很多小伙伴在大学读的专业也就已经明确了自己可以从事的方向,当然如果你认为自己读的专业不是你喜欢的,也许可以选择管培生的岗位,用 1 年的时间去体会各个岗位也许会对你有所帮助。
+
+而对于工作 2 ~ 5 年的小伙伴,相信你们已经在一个岗位上至少工作了 2 年以上,如果这个时候还在反复,此时需要慎重的思考一下自己的规划了。
\ No newline at end of file