面试八股文
八股文
计算机网络
HTTP 相关
HTTP 定义
HTTP 是一个在计算机中「两点」之间「传输」文字/图片/音频等「超文本」的「约定和规范」
常见的 HTTP 状态码有哪些?
1×× : 请求处理中,请求已被接受,正在处理
- 属于提示类信息,是一种中间状态,实际中用的比较少
- 100-Continue:继续
2×× : 请求成功,请求被成功处理 200 OK
200-OK:成功。如果是非 HEAD 请求,响应头会有 body 数据
202-Accepted
- 已接受。已经接受请求,但未处理完成
204-No Content:与 200 基本相同,但响应没有 body 数据
206-Partial Content:应用于 HTTP 断点续传,返回的 body 是资源的一部分
3×× : 重定向,要完成请求必须进行进一步处理
301-Moved Permanently:永久重定向
302-Found:临时重定向
- 301 和 302 都会在响应头中添加字段 Location 表明 URL
304-Not Modified:已缓存(资源没修改,用之前缓存就行)
4×× : 客户端错误,请求报文不合法
400-Bad Request:请求有语法问题
401-Unauthorized:缺乏身份验证
403-Forbidden:服务器禁止访问资源
- 这个状态类似于
401
,但进入403
状态后即使重新验证也不会改变该状态。该访问是长期禁止的,并且与应用逻辑密切相关
- 这个状态类似于
404-Not Found:请求的资源在服务器上找不到
5×× : 服务器端错误,服务器不能处理合法请求
500-Internal Server Error:发生错误(比较笼统)
501-Not Implemented:该功能还不支持
502-Bad Gateway:服务器作为网关/代理返回,表示服务器自身工作正常,但访问后端服务器发送错误
503-Service Unavailable:当前忙,暂时无法响应
- 此响应代码表明 HTTP 服务器正常,只是下层 web 服务不能正常工作
- 最可能的理由是资源不足:服务器突然收到太多请求,以至于无法全部处理
- 由于此问题多半由客户端反复发送请求造成,因此 HTTP 服务器可以选择拒绝客户端请求并返回 503
- 重试
- 服务器可以在响应头的 Retry-After 字段告知客户端何时可以重试
504-Gateway Timeout:网关超时
- 502 和 504 的区别
- 从网络角度,502 已经与后端建立了连接,但超时(电话打通了,但没人接);
- 504 与后端连接未建立,超时(电话没打通)。
- 502 和 504 的区别
http 中常见的 header 字段有哪些?
通用首部字段
请求/响应报文都会使用的首部
Cache-Control 字段
控制缓存的工作机制
no-cache/max-age=…/public/private
Connection 字段
控制不再转发给代理的首部字段
管理持久连接
控制网络连接在当前会话完成后是否仍然保持打开状态。如果发送的值是
keep-alive
,则连接是持久的,不会关闭,允许对同一服务器进行后续请求。
Date 字段
- 创建 HTTP 报文的日期和时间
请求首部字段
Accept 字段
客户端接受的媒体类型和优先级(加权)
text/html q=0.3,text/plain
Accept-Encoding 字段
客户端接受的内容编码和优先级(加权)
gzip
Authorization 字段
- 客户端的认证信息
Host 字段
请求的资源所处的互联网主机名和端口号
HTTP1.1 规定的唯一一个必须包含的请求首部字段
Range 字段
- 获取指定资源范围
Referer 字段
可以用来防御 CSRF 攻击
告知服务器请求的原始资源 URI,可以知道 URI 是从哪个 Web 页面发起的
User-Agent 字段
- 浏览器/用户代理等信息
Cookie 字段
告知服务端,想获取 Cookie 支持
Status=enable
响应首部字段
Accept-Ranges 字段
能否处理范围请求
bytes–能,none–不能
Age 字段
- 源服务器多少秒前创建响应,单位为秒
Location 字段
- 引导至指定 URL(重定向)
Set-Cookie 字段
告知客户端信息
NAME, expires, path, domain, HttpOnly
HttpOnly 使得 JavaScript 脚本无法获得 Cookie,从而防止了跨站脚本攻击(XSS)
实体首部字段
针对请求 / 响应报文的实体部分使用的首部
Allow 字段
- 服务端允许的 HTTP 方法
Content-Encoding 字段
- 服务端内容编码格式
Content-Length 字段
- 实体主题部分大小,单位字节
Content-Range 字段
- 针对范围请求,指定返回实体的部分
Content-Type 字段
- 实体主题内对象的媒体类型
请求方式
GET 与 POST 的区别
GET 一般用来从服务器上获取资源,POST 一般用来创建资源;
GET 是幂等的,即读取同一个资源,总是得到相同的数据,而 POST 不是幂等的。
从请求参数形式上看,GET 请求的数据会附在
URL 之后
;而 POST 请求会把提交的数据则放置在是 HTTP 请求报文的请求体
中。POST 的安全性要比 GET 的安全性高,因为 GET 请求提交的数据将明文出现在 URL 上,而 POST 请求参数则被包装到请求体中,相对更安全。
- GET 的历史参数会保留在浏览器历史中
GET 请求的长度受限于浏览器或服务器对 URL 长度的限制,允许发送的数据量比较小,而 POST 请求则是没有大小限制的。
从攻击的角度,无论是 GET 还是 POST 都不够安全,因为 HTTP 本身是明文协议。每个 HTTP 请求和返回的每个 byte 都会在网络上明文传播,不管是 url,header 还是 body。
为了避免传输中数据被窃取,必须做从客户端到服务器的端端加密。业界的通行做法就是 HTTPS —— 即用 SSL 协议协商出的密钥加密明文的 http 数据。
HEAD
HEAD 方法与 GET 方法类似,也是请求从服务器获取资源,服务器的处理机制也是一样的,但服务器不会返回请求的实体数据,只会传回响应头,也就是资源的“元信息”。
HEAD 方法可以看做是 GET 方法的一个 “简化版” 或者 “轻量版”。因为它的响应头与 GET 完全相同,所以可以用在很多并不真正需要资源的场合,避免传输 body 数据的浪费。
比如,想要检查一个文件是否存在,只要发个 HEAD 请求就可以了,没有必要用 GET 把整个文件都取下来。再比如,要检查文件是否有最新版本,同样也应该用 HEAD,服务器会在响应头里把文件的修改时间传回来。
HTTP 0.9/1.0/1.1
HTTP 0.9
第一个版本,极简单
只允许 get
没有请求头,因此只支持纯文本;
具有典型的无状态性,每个事务独立处理,处理完后就释放
HTTP 1.0
支持请求头
响应对象不止文本
支持 GET/HEAD/POST 方法
支持长连接(但默认短)
支持缓存
身份认证
HTTP 1.1
持久连接 / 长连接
- 在一个 TCP 连接上可以传送多个 HTTP 请求和响应。使用 TCP 长连接的方式改善了 HTTP/1.0 短连接造成的性能开销。
请求管道化
增加缓存处理(新的字段如 cache-control)
增加 Host 字段、支持断点传输等
提供范围请求功能,减少带宽浪费
HTTP 2.0/3.0
HTTP 2.0
二进制分帧
将响应报文划分为两个帧,首部 Header 和消息负载 Payload,并采用二进制编码
头部压缩
HTTP1.1 中 Header 部分字段固定、字段值重复、字段是 ASCII 码,效率低
HTTP2.0 使用 HPACK 算法压缩头部
静态表/静态字典
为高频出现在头部的字符串建立了一张静态表,共 61 组
动态表/动态字典
不在静态表范围内的头部字符串自行构建动态表,Index 从 62 起
前提:必须是同一个连接上,重复传输完全相同的 HTTP 头部
动态表过大,占用内存过大,影响性能
- 通过 http2_max_requests 配置,限制一个连接上传输的请求数量。请求数达到上限,则关闭 HTTP2.0 连接来释放内存
Huffman 编码
并发传输(多路复用 / 连接共享)
多路复用前,文件是串行传输的,请求 a 文件,b 文件只能等待,并且连接数过多。引入多路复用,a 文件 b 文件可以同时传输。
队头阻塞问题
HTTP1.1 的队头阻塞
- HTTP1.1 基于请求-响应模型,同一个连接中,HTTP 收到上一个请求的响应才能开始下一个请求
HTTP2.0 在 HTTP 层面解决了 1.1 的队头阻塞问题,但 TCP 层仍然存在队头阻塞问题,彻底解决需要放弃使用 TCP => HTTP3.0
三个概念
Stream,Message,Frame
一个 TCP 连接中包含一个或多个 Stream
Stream 里包含一个或多个 Message,Message 对应 HTTP1.1 中的请求或响应,由 HTTP 头部和体组成
Message 里包含一个或多个 Frame,Frame 为 HTTP2.0 最小单位,以二进制格式存放 HTTP1.1 中的头部和体
HTTP2.0 中,不同的 Stream 的帧可以乱序发送,因此可以并发不同的 Stream
- 原因在于每个帧的头部都会携带 Stream ID,而同一 Stream 内部的帧必须是严格有序的
- 可以类比 kafka 中的分区(内部的帧数据)有序而不保证主题(Stream)有序
- 原因在于每个帧的头部都会携带 Stream ID,而同一 Stream 内部的帧必须是严格有序的
CS 双方都可以建立 Stream,客户端 StreamID 必须为奇数,服务器为偶
可以通过帧头的标志位对每个 Stream 设置优先级
- 例如先传 HTML/CSS,再传图片,提高用户体验
HTTP2.0 实现 100 个并发 Stream,只需要建立一次 TCP 连接;而 1.1 需要建立 100 次,每个连接都要经过 TCP 握手、慢启动、SSL/TLS 握手
Nginx 中可以通过 http2_max_concurrent_streams 配置 Stream 上限
服务器主动推送
- HTTP1.1 不支持服务器主动推送资源,只能客户端发起请求
- 服务器推送资源时,通过 PUSH_PROMISE 帧传输 HTTP 头部,并通过 Promised Stream ID 告知客户端,接下来会在哪个偶数 Stream ID 中发送消息体
HTTP 3.0
HTTP2.0 的问题
队头阻塞
- 一个 TCP 连接中包含多个请求,当 TCP 丢包,需要等待重传,就会阻塞该 TCP 连接中的所有请求
TCP 和 TLS 的握手延迟
发起 HTTP 请求需要经过 TCP 三次握手和 TLS(1.2)四次握手,总共需要 3 个 RTT 时延才能发出请求数据
拥塞控制的慢启动
网络迁移需要重新连接
- IP 地址或端口变动,需要重新握手
QUIC
0RTT
无队头阻塞
QUIC 协议也是可以在同一连接上并发多个 Stream
UDP 不关心数据包顺序和丢包问题
QUIC 保证数据包可靠,每个数据包都有一个序号唯一标识。当某个数据包丢失,即使该 Stream 中的其他数据包到达,数据也无法被读取,直到重传丢失的包成功
- 相比于 HTTP2.0,多个 Stream 间没有依赖,丢包只会影响当前 Stream
更快的连接建立
HTTP3.0 传输前需要 QUIC 握手, 需要 1RTT,目的是确认双方的连接 ID
QUIC 内部包含了 TLS,并且使用的是 TLS1.3,因此只需一个 RTT 就可以同时完成建立连接与密钥协商。
- 在第二次连接时,数据包可以和握手信息一起发送,达到 0RTT
连接迁移
- QUIC 协议中通过连接 ID 标识双方,因此 IP/端口变更后,只要仍有上下文信息(连接 ID、TLS 密钥),就可以复用原连接
HTTP3.0 的帧头只有类型和长度两个字段
头部压缩,升级为 QPACK 算法,和 HPACK 类似。
静态表由 61 项扩大到 91 项
由于动态表具有时序性,如果首次请求丢包,导致无法解码出 HPACK 头部,将阻塞请求,QPACK 解决了这一问题
QUIC 有两个特殊的单向流,一个是 QPACK Encoder Stream,用来将一个 KV 传递给对方;另一个 QPACK Decoder Stream,用来响应,告诉对方刚才的 KV 已经更新到本地动态表中,从而确认加入动态表成功
我的理解:因为动态表的确能节约很大一部分编码、传输上的开销,所以即使额外维护两个单向流,也是值得的。本质上是一种 trade-off
HTTP 缓存
- 客户端将第一次请求的 URL 和响应数据分别作为 KV,保存在本地磁盘
- 服务端在回应时会通过头部字段返回估算的数据过期时间
- 若过期,则请求头带 Etag,附上第一次响应头的摘要
- 服务端进行判断,若仍有效,则返回不含有消息体 body 的 304 Not Modified,这样一来就减少了响应资源的传输带宽
HTTPS
HTTPS 协议(HyperText Transfer Protocol over Secure Socket Layer):可以理解为 HTTP + SSL/TLS
HTTPS 的安全基础是 SSL,因此加密的详细内容就需要 SSL,用于安全的 HTTP 数据传输。
SSL/TLS 握手
SSL(Secure Socket Layer,安全套接字层):SSL 协议位于 TCP/IP 协议与各种应用层协议之间,为数据通讯提供安全支持。
TLS(Transport Layer Security,传输层安全):其前身是 SSL。
HTTPS 的连接过程RSA (非对称加密算法)“四次握手”
ClientHello
- 发送:客户端使用的 TLS 版本号、支持的密码套件、随机数 Client Random
ServerHello
发送:确认 TLS 版本号是否支持、从密码套件中选择一个(密钥交换算法 + 签名算法 + 对称加密算法 + 摘要算法)、随机数 Server Random
发送:服务端的证书(包括公钥)
Server Hello Done
客户端回应
通过证书链验证服务端身份、随机数 pre-master,并用服务器公钥加密,发送给服务端,双方根据三个随机数生成会话密钥 Master Secret,之后开始使用密钥进行通话
再把之前发送过的数据的摘要,用会话密钥加密发送给服务端,确认之前的信息没有被篡改
服务器最后回应
- 同客户端回应
缺陷
不支持前向保密
长期使用的主密钥泄漏会导致过去的会话密钥泄漏
客户端传随机数给服务端时用的是公钥加密,一旦服务器私钥泄漏,所有通讯密文都会被破解
HTTP 和 HTTPS 的区别
HTTPS 协议需要到 CA 申请证书,一般免费证书较少,因而需要一定费用。
HTTP 是超文本传输协议,信息是明文传输,HTTPS 则是具有安全性的 SSL 加密传输协议
HTTP 和 HTTPS 使用的是完全不同的连接方式,用的端口也不一样,前者是 80,后者是 443
HTTP 的连接很简单,是无状态的;HTTPS 协议是由 SSL + HTTP 协议构建的可进行加密传输、身份认证的网络协议,比 HTTP 协议安全。
说说 OSI 七层、TCP/IP 四层的关系和区别?
OSI 七层从下往上依次是:物理层
、数据链路层
、网络层
、传输层
、会话层
、表示层
、应用层
。
TCP/IP 四层从下往上依次是:网络接口层
、网络层
、传输层
、应用层
特点:
- 层与层之间相互独立又相互依靠
- 上层依赖于下层,下层为上层提供服务
TCP/IP 四层是 OSI 七层的简化版,已经成为事实国际标准
OSI 七层举例
- 应用层
- HTTP、FTP、SMTP、TELNET、DNS、SOCKS、DHCP
- 表示层
- 会话层
- SSL/TLS、RPC
- 传输层
- TCP/UDP
- 网络层(IP 地址)
- IPv4/v6、ICMP、IGMP、RIP、OSPF、BGP、MPLS
- 数据链路层(MAC 物理地址)
- ARP、RARP、PPP
- 物理层(比特流)
TCP / UDP
说说 TCP 与 UDP 的区别?
TCP 如何实现数据的可靠性
一句话:通过 校验和
、序列号
、确认应答
、超时重传
、连接管理
、流量控制
、拥塞控制
等机制来保证可靠性。
校验和
在数据传输过程中,将发送的数据段都当做一个 16 位的整数,将这些整数加起来,并且前面的进位不能丢弃,补在最后,然后取反,得到校验和。
发送方:在发送数据之前计算校验和,并进行校验和的填充。接收方:收到数据后,对数据以同样的方式进行计算,求出校验和,与发送方进行比较。
序列号 seq
TCP 传输时将每个数据包都进行了编号,这就是序列号。序列号的作用不仅仅是应答作用,有了序列号能够将接收到的数据根据序列号进行排序,并且去掉重复的数据。
确认应答 ack
TCP 传输过程中,每次接收方接收到数据后,都会对传输方进行确认应答,也就是发送 ACK 报文,这个 ACK 报文中带有对应的确认序列号,告诉发送方,接收了哪些数据,下一次数据从哪里传。
超时重传
TCP 在发送数据包后会启动一个定时器,如果在规定时间内没有收到接收方的确认应答 ACK,就会重新发送数据包,直到收到确认应答为止。
连接管理
就是指三次握手、四次挥手的过程。
流量控制
以接收方为主体,基于滑动窗口
如果发送方的发送速度太快,会导致接收方的接收缓冲区填充满了,这时候继续传输数据,就会造成大量丢包,进而引起丢包重传等等一系列问题。TCP 支持根据接收端的处理能力来决定发送端的发送速度,这就是流量控制机制。
具体实现方式:接收端将自己的接收缓冲区大小(还能接受多少字节数据)放入 TCP 首部的『窗口大小 rwnd』(Receiver Window)字段中,通过 ACK 通知发送端。
拥塞控制
以发送方为主体,基于拥塞窗口
TCP 传输过程中一开始就发送大量数据,如果当时网络非常拥堵,可能会造成拥堵加剧。
TCP 发送方根据网络质量来动态控制拥塞窗口的大小
TCP 如何提高传输效率
也就是问 TCP 的流量控制
一句话:TCP 协议提高效率的方式有 滑动窗口
、快重传
、延迟应答
、捎带应答
等。
滑动窗口
如果每一个发送的数据段,都要收到 ACK 应答之后再发送下一个数据段,这样的话我们效率很低,大部分时间都用在了等待 ACK 应答上了。
为了提高效率我们可以一次发送多条数据,这样就能使等待时间大大减少,从而提高性能。 窗口大小指的是无需等待确认应答而可以继续发送数据的最大值。
快重传
基于滑动窗口,应该是对超时重传的一种优化
快重传
也叫 高速重发控制
。
那么如果出现了丢包,需要进行重传。一般分为两种情况:
情况一:数据包已经抵达,ACK 丢了。这种情况下,发送方不会进行重传,部分 ACK 丢了并不影响,因为可以通过后续的 ACK 进行确认;
情况二:数据包直接丢了。发送端会连续收到多个相同的 ACK 确认,发送端立即将对应丢失的数据重传。
延迟应答
如果接收数据的主机立刻返回 ACK 应答,这时候返回的窗口大小可能比较小。
- 假设接收端缓冲区为 1M,一次收到了 512K 的数据;如果立刻应答,返回的窗口就是 512K;
- 但实际上可能处理端处理速度很快,10ms 之内就把 512K 的数据从缓存区消费掉了;
- 在这种情况下,接收端处理还远没有达到自己的极限,即使窗口再放大一些,也能处理过来;
- 如果接收端稍微等一会在应答,比如等待 200ms 再应答,那么这个时候返回的窗口大小就是 1M;
窗口越大,网络吞吐量就越大,传输效率就越高;我们的目标是在保证网络不拥塞的情况下尽量提高传输效率。
捎带应答
在延迟应答的基础上,很多情况下,客户端服务器在应用层也是一发一收的。这时候常常采用捎带应答的方式来提高效率,而 ACK 响应常常伴随着数据报文共同传输。如:三次握手。
TCP 拥塞控制
拥塞避免机制、慢开始、设置门限变量、区分不同的丢包事件
拥塞造成丢包和分组延迟增大,发送方丢过丢包时间来判断拥塞
- 重传定时器超时
- 收到三个相同(重复)的 ACK
发送方维持一个拥塞窗口 cwnd(Congestion Window)来限制发送窗口,从而间接控制发送速度;拥塞窗口动态变化,取决于网络的拥塞程度
调节策略:AIMD 拥塞避免
- 乘法减小
- 发送包检测到丢包后,cwnd 大小减半
- 加法增大
- 若无丢包,每经过一个 RTT(Round-Trip Time,往返时延),将 cwnd 增大一个 MSS,直到检测到丢包
慢开始/慢启动
在新建连接上指数增大 cwnd,直到检测到丢包
设置慢开始门限状态变量 ssthresh
当 cwnd < ssthresh 时,使用慢开始算法。
当 cwnd > ssthresh 时,停止使用慢开始算法而改用拥塞避免算法。
当 cwnd = ssthresh 时,既可使用慢开始算法,也可使用拥塞避免算法
当遇到丢包时,ssthresh 变为当前 cwnd 的一半
区分不同的丢包事件
超时:网络交付能力差
- cwnd 直接降到初始值,然后指数增大
收到重复三个 ACK:网络仍有一定交付能力
- cwnd 减半,然后加法增大,是为快重传、快恢复
三次握手和四次挥手全过程
三次握手
四次挥手
为什么 TCP 连接需要三次握手,两次不可以嘛?
两次握手只能保证单向连接是畅通的
第一步,客户端给服务端发送一条消息:你好,服务端。 第二步,服务端收到消息,同时给客户端回复一条消息:收到!你好客户端。
这样的两次握手过程, 客户端给服务端打招呼,服务端收到了,说明客户端可以正常给服务端发送数据。但是服务端给客户端打招呼,服务端没有收到反馈,也就不能确保服务端是否能正常给客户端发送消息。
只有经过第三次握手,才能确保双向都可以接收到对方的发送的数据
第三步,客户端收到服务端发送的消息,回复:收到!这样就证明了客户端能正常收到服务端的消息。
TCP 粘包现象
TCP 是面向流协议,发送的单位是字节流,因此会将多个小尺寸数据被封装在一个 tcp 报文中发出去的可能性。 可以简单的理解成客户端调用了两次 send,服务器端一个 recv 就把信息都读出来了。
处理方法:
- 固定发送信息长度
- 在两个信息之间加入分隔符。
半连接队列
TCP 握手中,当服务器处于 SYN_RCVD 状态(第一次握手完成),服务器会把此种状态下请求连接放在一个队列里,该队列称为半连接队列。
SYN Flood 攻击
泛洪攻击
SYN 攻击即利用 TCP 协议缺陷,通过发送大量的半连接请求,占用半连接队列,耗费 CPU 和内存资源。
优化方式:
- 缩短 SYN Timeout 时间
- 记录 IP,若连续受到某个 IP 的重复 SYN 报文,从这个 IP 地址来的包会被一概丢弃。
- SYN Cookie
SYN Cookie
服务器在收到 syn 包时并不马上分配储存连接的数据区,而是根据这个 syn 包计算出一个 cookie,把这个 cookie 填入 tcp 的 Sequence Number 字段发送 syn+ack 包,等对方回应 ack 包时检查回复的 Acknowledgment Number 字段的合法性,如果合法再分配专门的数据区。
开启 SYN Cookie:
|
|
IP
IP 地址是怎样分类的,你知道吗?
先说一下 IP 的基本特点:
- IP 地址由四段组成,每个字段是一个字节,8 位,最大值是 255。
- IP 地址由两部分组成,即网络地址和主机地址。网络地址表示其属于互联网的哪一个网络,主机地址表示其属于该网络中的哪一台主机。
IP 地址主要分为 A、B、C 三类及特殊地址 D、E 这五类,甩一张图:
A 类:(1.0.0.0-126.0.0.0) 一般用于大型网络。
B 类:(128.0.0.0-191.255.0.0) 一般用于中等规模网络。
C 类:(192.0.0.0-223.255.255.0) 一般用于小型网络。
D 类:是多播地址,地址的网络号取值于 224~239 之间,一般用于多路广播用户。
E 类:是保留地址。地址的网络号取值于 240~255 之间。
URI 和 URL
URI
Uniform Resource Identifier
URI 在于 I(Identifier)是统一资源标示符,可以唯一标识一个资源。
URL
Uniform Resource Location
URL 在于 Locater,一般来说(URL)统一资源定位符,可以提供找到该资源的路径
URN
- Uniform Resource Name
区别和联系
URL 和 URN 是 URI 的子集
原来 uri 包括 url 和 urn,后来 urn 没流行起来,导致几乎目前所有的 uri 都是 url
你知道对称加密和非对称加密的区别和原理吗?
对称加密是指加密和解密使用同一个密钥的方式,这种方式存在的最大问题就是密钥发送问题,即如何安全地将密钥发给对方;
非对称加密是指使用一对非对称密钥,即 公钥
和 私钥
,公钥可以随意发布,但私钥只有自己知道。发送密文的一方使用对方的公钥进行加密处理,对方接收到加密信息后,使用自己的私钥进行解密。
由于非对称加密的方式不需要发送用来解密的私钥,所以可以保证安全性;但是和对称加密比起来,非对称加密比较慢,所以我们还是要用对称加密来传送消息,但对称加密所使用的密钥我们可以通过非对称加密的方式发送出去。
Session、Cookie 和 Token 的区别
会话跟踪:https://www.cnblogs.com/l199616j/p/11195667.html
cookie 和 session 都是用来跟踪浏览器用户身份的会话方式
- session 存储于服务器,可以理解为一个状态列表,拥有一个唯一识别符号 sessionId,通常存放于 cookie 中。服务器收到 cookie 后解析出 sessionId,再去 session 列表中查找,才能找到相应 session。
- cookie 类似一个令牌,装有 sessionId,存储在客户端,浏览器通常会自动添加。
- token 也类似一个令牌,无状态,用户信息都被加密到 token 中,服务器收到 token 后解密就可知道是哪个用户。需要开发者手动添加。
- jwt 只是一个跨域认证的方案
JWT
JWT 就是 token 的一种实现方式,并且基本是 java web 领域的事实标准。
JWT 全称是 JSON Web Token。基本可以看出是使用 JSON 格式传输 token
构成:
- Header:描述 JWT 的元数据。定义了生成签名的算法以及 Token 的类型。
- Payload(负载):用来存放实际需要传递的数据
- Signature(签名):服务器通过 Payload、Header 和一个密钥 (secret) 使用 Header 里面指定的签名算法(默认是 HMAC SHA256)生成。
- 用于验证消息在传递过程中有没有被更改
流程:
- 在基于 Token 进行身份验证的的应用程序中,用户登录时,服务器通过 Payload、Header 和一个密钥(secret)创建令牌(Token)并将 Token 发送给客户端。
- 然后客户端将 Token 保存在 Cookie 或者 localStorage 里面,以后客户端发出的所有请求都会携带这个令牌。你可以把它放在 Cookie 里面自动发送,但是这样不能跨域,所以更好的做法是放在 HTTP Header 的 Authorization 字段中
有哪些 web 性能优化技术?
- DNS 查询优化
- 客户端缓存
- 优化 TCP 连接
- 避免重定向
- 网络边缘的缓存
- 条件缓存
- 压缩和代码极简化
- 图片优化
常见攻击
XSS
XSS(Cross Site Scripting 跨站脚本攻击),攻击用户
恶意攻击者在 web 页面中会插入一些恶意的 script 代码。当用户浏览该页面的时候,那么嵌入到 web 页面中 script 代码会执行,因此会达到恶意攻击用户的目的
XSS 攻击最主要有如下分类:反射型
、存储型
、及 DOM-based 型
。 反射性和 DOM-baseed 型可以归类为非持久性 XSS 攻击
。存储型可以归类为持久性 XSS 攻击
。
CSRF
CSRF(Cross Site Request Forgery,跨站域请求伪造)通过伪造受信任用户的请求来攻击网站
攻击者通过伪造用户的浏览器的请求,向访问一个用户自己曾经认证访问过的网站发送出去,使目标网站接收并误以为是用户的真实操作而去执行命令。
过程
- 用户 C 打开浏览器,访问受信任网站 A,输入用户名和密码请求登录网站 A;
- 在用户信息通过验证后,网站 A 产生 Cookie 信息并返回给浏览器,此时用户登录网站 A 成功,可以正常发送请求到网站 A;
- 用户未退出网站 A 之前,在同一浏览器中,打开一个 TAB 页访问网站 B;
- 网站 B 接收到用户请求后,返回一些攻击性代码,并发出一个请求要求访问第三方站点 A;
- 浏览器在接收到这些攻击性代码后,根据网站 B 的请求,在用户不知情的情况下携带 Cookie 信息,向网站 A 发出请求。网站 A 并不知道该请求其实是由 B 发起的,所以会根据用户 C 的 Cookie 信息以 C 的权限处理该请求,导致来自网站 B 的恶意代码被执行。
防御措施
验证 HTTP Referer 字段,来检查请求来自的源网站,告知请求是由哪个 web 页面发起的。
优点
- 简单易行
缺点
Referer 的值是由浏览器提供的,虽然 HTTP 协议上有明确的要求,但是每个浏览器对于 Referer 的具体实现可能有差别,并不能保证浏览器自身没有安全漏洞。使用验证 Referer 值的方法,就是把安全性都依赖于第三方(即浏览器)来保障,从理论上来讲,这样并不安全。
侵犯隐私:即便是使用最新的浏览器,黑客无法篡改 Referer 值,这种方法仍然有问题。因为 Referer 值会记录下用户的访问来源,有些用户认为这样会侵犯隐私
与 XSS 攻击相比,CSRF 攻击往往不大流行(因此对其进行防范的资源也相当稀少)和难以防范,所以被认为比 XSS 更具危险性。
了解 REST API 吗
REST API 全称为表述性状态转移(Representational State Transfer,REST)即利用 HTTP 中 get、post、put、delete 以及其他的 HTTP 方法构成 REST 中数据资源的增删改查操作:
- Create : POST
- Read : GET
- Update : PUT (整体更新) / PATCH (局部更新)
- Delete: DELETE
转发和重定向的区别
转发是服务器行为
- 服务器直接向目标地址访问 URL,将相应内容读取之后发给浏览器
- 用户浏览器地址栏 URL 不变,转发页面和转发到的页面可以共享 request 里面的数据。
- 服务器直接向目标地址访问 URL,将相应内容读取之后发给浏览器
重定向是浏览器行为,利用服务器返回的状态码来实现,如果服务器返回 301 或者 302,浏览器收到新的消息后自动跳转到新的网址重新请求资源。
- 用户的地址栏 url 会发生改变,而且不能共享数据。
DNS 的寻址过程
本地缓存 -> 本地 DNS 服务器 -> 根域名 DNS 服务器 -> 递归查询
DNS(Domain Name System,域名系统),因特网上作为域名和 IP 地址互相映射的一个分布式数据。
客户机发出查询请求,在本地计算机缓存查找;如果缓存没有,检查有没有被手动配置,例如 hosts 文件;若还是没有,就会将请求发送给 dns 服务器
本地 / 局部 dns 服务器(例如 8.8.8.8)会在自己的区域里面查找,找到即根据此记录进行解析,若没有找到,就会在本地的缓存里面查找
本地服务器没有找到客户机查询的信息,就会将此请求发送到根域名 dns 服务器
根域名服务器解析客户机请求的根域部分,它把包含的下一级的 dns 服务器的地址返回到客户机的 dns 服务器地址
客户机的 dns 服务器根据返回的信息接着访问下一级的 dns 服务器
这样递归的方法一级一级接近查询的目标,最后在有目标域名的服务器上面得到相应的 IP 信息
客户机的本地的 dns 服务器会将查询结果返回给我们的客户机
客户机根据得到的 ip 信息访问目标主机,完成解析过程
在浏览器中输入一个 http://www.baidu.com 后执行的全部过程?
域名解析 -> 建立 TCP 连接(三次握手)-> 发起 http 请求 -> 服务器响应 http 请求,浏览器得到 html 代码 -> 浏览器解析 html 代码,并请求 html 代码中的资源(如 js、css、图片等)-> 浏览器对页面进行渲染呈献给用户。
CDN
Content Delivery Network,内容分发网络
将源站内容(image、html、js、css 等)分发至全国所有的节点,从而缩短用户查看对象的延迟,提高用户访问网站的响应速度与网站的可用性。
CDN 的主要功能是将原本离用户比较远的源站服务器,通过丰富的节点(缓存服务器)放到离用户最近的地方,实现用户对互联网上资源的快速访问。
好处:
加速网站访问
保障网站安全(负载均衡和分布式存储,加强网站可靠性)
实现跨运营商、跨地域的全网覆盖
CDN 本质上是一种 DNS 劫持,只不过是良性的
组成元素
智能调度 DNS
- 智能调度 DNS 负责处理域名解析请求,把当时最接近用户的节点地址提供给用户
缓存功能服务
负载均衡设备(如 lvs,F5 的 BIG/IP)
内容 Cache 服务器(如 squid)
共享存储(根据缓存数据量多少决定是否需要)
流程
- 例如向已经接入 CDN 服务的域名发起获取静态资源请求,首先对域名进行 DNS 解析,发现已经配置了 CNAME,直接交给智能调度 DNS
- 智能调度 DNS 通过调度机制返回一个最佳的节点 IP
- 用户向该 IP 发起请求,首先经过 CDN 中间源
- 如果已经有相应资源缓存,则直接返回资源;
- 否则对源站发起请求,获取资源,根据设定的策略对资源进行缓存,最终返回给用户。
CNAME 记录与 A 记录
简单来说,A 记录就是把一个域名解析到一个 IP 地址,而 CNAME 记录就是把域名解析到另外一个域名。
A 记录即地址记录(Address Record)。这种记录允许您将多个域名映射到一个 IP 地址。
CNAME 记录即别名记录(Canonical Name Record)。这种记录允许您将多个域名映射到另外一个域名。
域名是有顶级域名(baidu.com),二级域名(www.baidu.com) 之分的,当多个域名都指向一个网站服务器上时,需要将这些子域名(顶级域名下面的二级域名、三级域名都称之为子域名)设置并指向自己的网站服务器上的,这个动作一般称之为 A 记录,又称 IP 指向。
这里实际上就会产生一个问题,就是当服务器需要更换时,这些原本指向这台服务器的域名就需要重新设置,并指向新的服务器,这样就会产生比较大的工作量。
比如 www.baidu.com,这个二级域名解析到的是一个服务器的 IP 地址,比如 8.8.8.8,而 CNAME 是将新域名,比如:a.www.baidu.com 解析到另外一个域名,比如:www.baidu.com。
当新域名产生后都指向 CNAME 域名后,在发生服务器需要更换或者迁移时,就只需要把 www.baidu.com 这个域名做重新设置就可以了,这样就减少了很多工作量。
CNAME 在 CDN 中的应用
CNAME 在 CDN(内容分发网络)上也是不可缺少的一环。
CDN 的主要功能是将原本离用户比较远的源站服务器,通过丰富的节点(缓存服务器)放到离用户最近的地方,实现用户对互联网上资源的快速访问。
这个快速访问的过程就需要 CNAME 的参与。
原理是这样的:
用户向浏览器提供要访问的域名,浏览器对域名进行解析,由于 CDN 参与后,对域名解析过程进行了调整,解析的结果不再一个 IP 地址,而是该域名对应的 CNAME 。
但 CNAME 无法完成最终内容的获取,所以,浏览器需要再次对获得的 CNAME 进行解析,以得到实际的 IP 地址。在此过程中,CDN 会根据用户的实际地理位置信息解析对应的 IP 地址,使得用户能就近访问。
这个过程中, CNAME 的主要作用是配合 CDN 的负载均衡系统将 CNAME 背后对应的节点 IP 分配给不同的用户去访问。
总的来讲, CNAME 提供了单一服务器和海量服务器的在管理访问上的灵活性。单一服务器的场景下,通过将大量子域名指向到 CNAME,再由 CNAME 指向到单一域名,解决了服务器更换、迁移带来的大量域名重新指向的问题。
另一方面,CNAME 配合负载均衡系统,还可以实现将大量访问需求通过 CNAME 指向到多台服务器,以提高用户访问的速度。
Ping
Ping 是一种常用的网络工具,它的原理是通过向目标主机发送 ICMP(Internet Control Message Protocol)回显请求,来测试主机之间的连通性和延迟时间。
PING 是应用层直接使用网络层 ICMP 的一个例子,它没有通过运输层的 TCP 或 UDP
比原来的 ICMP 报文多了两个字段
标识符
- 用来区分是哪个应用程序发送 ICMP 包,比如 PID 作为标识符
序号
- 从 0 开始,每发送一次新的回送应答会加 1,用来确认是否丢包
工作流程
假设有两个主机,主机 A(192.168.0.1)和主机 B(192.168.0.2),现在我们要监测主机 A 和主机 B 之间网络是否可达,那么我们在主机 A 上输入命令:ping 192.168.0.2
此时,ping 命令会在主机 A 上构建一个 ICMP 的请求数据包(数据包里的内容后面再详述),然后 ICMP 协议会将这个数据包以及目标 IP(192.168.0.2)等信息一同交给 IP 层协议。
网络层的 IP 协议得到这些信息后,将源地址(即本机 IP)、目标地址(即目标 IP:192.168.0.2)、再加上一些其它的控制信息,构建成一个 IP 数据包。
IP 数据包构建完成后,还不够,还需要加上 MAC 地址,因此,还需要通过 ARP 映射表找出目标 IP 所对应的 MAC 地址。当拿到了目标主机的 MAC 地址和本机 MAC 后,一并交给数据链路层,组装成一个数据帧,依据以太网的介质访问规则,将它们传送出出去。
当主机 B 收到这个数据帧之后,会首先检查它的目标 MAC 地址是不是本机,如果是就接收下来处理,接收之后会检查这个数据帧,将数据帧中的 IP 数据包取出来,交给本机的 IP 层协议,然后 IP 层协议检查完之后,再将 ICMP 数据包取出来交给 ICMP 协议处理,当这一步也处理完成之后,就会构建一个 ICMP 应答数据包,回发给主机 A
在一定的时间内,如果主机 A 收到了应答包,则说明它与主机 B 之间网络可达,如果没有收到,则说明网络不可达。除了监测是否可达以外,还可以利用应答时间和发起时间之间的差值,计算出数据包的延迟耗时。
操作系统
操作系统的分类
批处理操作系统、分时操作系统、实时操作系统。
若一个操作系统兼顾批操作和分时的功能,则称该系统为通用操作系统。
什么是内核态和用户态?
都是处理机的执行状态
用户程序运行在用户态,操作系统内核运行在内核态。
用户态
非特权状态、目态
在此状态下,执行的代码被硬件限定,不能执行特权指令
内核态
特权状态、管态
核心态是操作系统内核所运行的模式,运行在该模式的代码,可以无限制地对系统存储、外部设备进行访问。
如何实现内核态和用户态的切换?
处理器从用户态切换到内核态的方法有三种:系统调用、异常和外部中断。
- 系统调用:操作系统的最小功能单位,是操作系统提供的用户接口,系统调用本身是一种软中断。
- 异常:也叫做内中断,是由错误引起的,如文件损坏、缺页故障等。
- 外部中断:是通过两根信号线来通知处理器外设的状态变化,是硬中断。
并发和并行的区别
- 并发(concurrency):指宏观上看起来两个程序在同时运行,比如说在单核 cpu 上的多任务。但是从微观上看两个程序的指令是交织着运行的,指令之间交错执行,在单个周期内只运行了一个指令。这种并发并不能提高计算机的性能,只能提高效率(如降低某个进程的相应时间)。
- 并行(parallelism):指严格物理意义上的同时运行,比如多核 cpu,两个程序分别运行在两个核上,两者之间互不影响,单个周期内每个程序都运行了自己的指令,也就是运行了两条指令。这样说来并行的确提高了计算机的效率。
进程和线程
进程和线程的区别
- 基本单位:进程作为拥有资源的基本单位;线程作为调度的基本单位
- 并发性:不仅进程之间可以并发执行,同一个进程的多个线程之间也可以并发执行。
- 拥有资源
- 进程是拥有资源的一个独立单位,线程不拥有系统资源,但可以共享隶属于进程的资源。
- 进程有自己的独立地址空间,线程共享进程中的地址空间。
- 系统开销
- 创建或撤消进程时,系统都要为之分配或回收资源,如内存空间、I/O 设备等,OS 所付出的开销显著大于在创建或撤消线程时的开销;
- 进程切换的开销也远大于线程切换的开销。
进程是进程实体的运行过程,是系统进行资源分配和独立调度的基本单位
进程的经典定义就是一个执行中程序的实例。系统中的每个程序都运行在某个进程的上下文(context)中。
进程是资源分配的最小单位,线程是程序执行的最小单位。
进程有自己的独立地址空间,每启动一个进程,系统就会为它分配地址空间,建立数据表来维护代码段、堆栈段和数据段,这种操作非常昂贵。
而线程是共享进程中的数据的,使用相同的地址空间,因此 CPU 切换一个线程的花费远比进程要小很多,同时创建一个线程的开销也比进程要小很位。
线程之间的通信更方便,同一进程下的线程共享全局变量、静态变量等数据。而进程之间的通信需要以通信的方式 (IPC) 进行。不过如何处理好同步与互斥是编写多线程程序的难点。
但是多进程程序更健壮,多线程程序只要有一个线程死掉,整个进程也死掉了,而一个进程死掉并不会对另外一个进程造成影响,因为进程有自己独立的地址空间。
线程共享与独享的资源
共享:堆、全局变量、静态变量、文件等公用资源
独享:栈、寄存器
进程间通信方法
进程之间可以看到一份公共资源;而提供这份资源的形式或者提供者不同,造成了通信方式不同。
管道、系统 IPC(包括消息队列、信号量、信号、共享内存等)、以及套接字 socket。(socket 会比较常用)
- 管道 (pipe):管道是一种半双工的通信方式,数据只能单向流动,而且只能在具有亲缘关系的进程间使用。 进程的亲缘关系通常是指父子进程关系。
- 有名管道 (named pipe): 有名管道也是半双工的通信方式,但是它允许无亲缘关系进程间的通信。
- 信号量 (semophore): 信号量是一个计数器,可以用来控制多个进程对共享资源的访问。它常作为一种锁机制,防止某进程正在访问共享资源时,其他进程也访问该资源。因此,主要作为进程间以及同一进程内不同线程之间的同步手段。
- 消息队列 (message queue): 消息队列是由消息的链表,存放在内核中并由消息队列标识符标识。消息队列克服了信号传递信息少、管道只能承载无格式字节流以及缓冲区大小受限等缺点。
- 信号 (signal): 信号是一种比较复杂的通信方式,用于通知接收进程某个事件已经发生。
- 共享内存 (shared memory):共享内存就是映射一段能被其他进程所访问的内存,这段共享内存由一个进程创建,但多个进程都可以访问。
- 共享内存是最快的 IPC 方式,它是针对其他进程间通信方式运行效率低而专门设计的。它往往与其他通信机制,如信号两,配合使用,来实现进程间的同步和通信。
- 套接字 (socket): 套解口也是一种进程间通信机制,与其他通信机制不同的是,它可用于不同主机间的进程通信
线程间通信方式
锁机制:包括互斥锁、条件变量、读写锁。
互斥锁:提供了以排他方式防止数据结构被并发修改的方法。
读写锁:允许多个线程同时读共享数据,而对写操作是互斥的。
条件变量:可以以原子的方式阻塞进程,直到某个特定条件为真为止。对条件的测试是在互斥锁的保护下进行的。
- 条件变量始终与互斥锁一起使用。
信号量机制 (Semaphore):包括无名线程信号量和命名线程信号量。
信号机制 (Signal):类似进程间的信号处理。
线程间的通信目的主要是用于线程同步,所以线程没有像进程通信中的用于数据交换的通信机制。
进程调度
进程调度的时机
- 当前运行的进程运行结束。
- 当前运行的进程由于某种原因阻塞。
- 执行完系统调用等系统程序后返回用户进程。
- 在使用抢占调度的系统中,具有更高优先级的进程就绪时。
- 分时系统中,分给当前进程的时间片用完。
不能进行进程调度的情况
- 在中断处理程序执行时。
- 在操作系统的内核程序临界区内。
- 其它需要完全屏蔽中断的原子操作过程中。
进程的调度策略
- 先到先服务调度算法
- 短作业优先调度算法
- 优先级调度算法
- 时间片轮转调度算法
- 高响应比优先调度算法
- 多级队列调度算法
- 多级反馈队列调度算法
进程调度策略的基本设计指标
CPU 利用率
系统吞吐率,即单位时间内 CPU 完成的作业的数量。
响应时间。
周转时间。是指作业从提交到完成的时间间隔。从每个作业的角度看,完成每个作业的时间也是很关键
平均周转时间
带权周转时间
平均带权周转时间
什么是信号
一个信号就是一条小消息,它通知进程系统中发生了一个某种类型的事件。 Linux 系统上支持的 30 种不同类型的信号。 每种信号类型都对应于某种系统事件。
低层的硬件异常是由内核异常处理程序处理的,正常情况下,对用户进程而言是不可见的。信号提供了一种机制,通知用户进程发生了这些异常。
发送信号:内核通过更新目的进程上下文中的某个状态,发送(递送)一个信号给目的进程。发送信号可以有如下两种原因:
内核检测到一个系统事件,比如除零错误或者子进程终止。
—个进程调用了 kill 函数, 显式地要求内核发送一个信号给目的进程。一个进程可以发送信号给它自己。
接收信号:当目的进程被内核强迫以某种方式对信号的发送做出反应时,它就接收了信号。进程可以忽略这个信号,终止或者通过执行一个称为信号处理程序 (signal handler) 的用户层函数捕获这个信号。
进程的状态与状态转换
进程在运行时有三种基本状态:就绪态、运行态和阻塞态。
运行(running)态:进程占有处理器正在运行的状态。进程已获得 CPU,其程序正在执行。在单处理机系统中,只有一个进程处于执行状态; 在多处理机系统中,则有多个进程处于执行状态。
就绪(ready)态:进程具备运行条件,等待系统分配处理器以便运行的状态。 当进程已分配到除 CPU 以外的所有必要资源后,只要再获得 CPU,便可立即执行,进程这时的状态称为就绪状态。在一个系统中处于就绪状态的进程可能有多个,通常将它们排成一个队列,称为就绪队列。
阻塞(wait)态:又称等待态或睡眠态,指进程不具备运行条件,正在等待某个时间完成的状态。
各状态之间的转换:
- 就绪 → 执行:处于就绪状态的进程,当进程调度程序为之分配了处理机后,该进程便由就绪状态转变成执行状态。
- 执行 → 就绪:处于执行状态的进程在其执行过程中,因分配给它的一个时间片已用完而不得不让出处理机,于是进程从执行状态转变成就绪状态。
- 执行 → 阻塞:正在执行的进程因等待某种事件发生而无法继续执行时,便从执行状态变成阻塞状态。
- 阻塞 → 就绪:处于阻塞状态的进程,若其等待的事件已经发生,于是进程由阻塞状态转变为就绪状态。
孤儿进程和僵尸进程
孤儿进程(似无实有): 父进程退出,子进程还在运行的这些子进程都是孤儿进程,孤儿进程将被 init 进程(1 号进程)所收养,并由 init 进程对他们完成状态收集工作。
僵尸进程(似有实无): 进程使用 fork 创建子进程,如果子进程退出,而父进程并没有调用 wait 获 waitpid 获取子进程的状态信息,那么子进程的进程描述符仍然保存在系统中,这些进程是僵尸进程。
多线程模型
- 多对一模型。将多个用户级线程映射到一个内核级线程上。该模型下,线程在用户空间进行管理,效率较高。缺点就是一个线程阻塞,整个进程内的所有线程都会阻塞。几乎没有系统继续使用这个模型。
- 一对一模型。将内核线程与用户线程一一对应。优点是一个线程阻塞时,不会影响到其它线程的执行。该模型具有更好的并发性。缺点是内核线程数量一般有上限,会限制用户线程的数量。更多的内核线程数目也给线程切换带来额外的负担。linux 和 Windows 操作系统家族都是使用一对一模型。
- 多对多模型。将多个用户级线程映射到多个内核级线程上。结合了多对一模型和一对一模型的特点。
死锁是怎样产生的?
死锁是指两个或两个以上进程在执行过程中,因争夺资源而造成的相互等待的现象。 产生死锁需要满足下面四个条件:
- 互斥条件(Mutual Exclusion)
- 资源要求互斥访问
- 请求和保持条件(Hold and wait)
- 提出的请求得不到满足,手头的资源释放不出来
- 不可抢占条件(No preemption)
- 资源只能由占有者资源释放
- 循环等待条件(Circular wait)
- 必有一个进程-资源的环形链,环路中的进程形成等待链
如何解决死锁问题?
解决死锁的方法即破坏产生死锁的四个必要条件之一,主要方法如下:
- 不让死锁发生
- 预防死锁:静态策略,破坏死锁产生的必要条件
- 避免死锁:动态策略,不限制必要条件,而去防止系统进入不安全状态(银行家算法)
- 让死锁发生
- 检测死锁:通过检测机构及时发现死锁,再采取措施(资源分配图)
- 解除死锁:当死锁发生,撤销一些进程,回收资源再分配
优先级反转是什么?如何解决
由于多进程共享资源,具有最高优先权的进程被低优先级进程阻塞,反而使具有中优先级的进程先于高优先级的进程执行,导致系统的崩溃。这就是所谓的优先级反转 (Priority Inversion)。
其实,优先级反转是在高优级 (假设为 A) 的任务要访问一个被低优先级任务 (假设为 C) 占有的资源时,被阻塞;而此时又有优先级高于占有资源的任务(C) 而低于被阻塞的任务 (A) 的优先级的任务 (假设为 B) 时,于是,占有资源的任务就被挂起 (占有的资源仍为它占有),因为占有资源的任务优先级很低,所以,它可能一直被另外的任务挂起;而它占有的资源也就一直不能释放;这样,引起任务 A 一直没办法执行,而比它优先低的任务却可以执行。
目前解决优先级反转有许多种方法。其中普遍使用的有 2 种方法:
- 优先级继承 (priority inheritance):将低优先级任务的优先级提升到等待它所占有的资源的最高优先级任务的优先级
- 当高优先级任务由于等待资源而被阻塞时,此时资源的拥有者的优先级将会自动被提升。
- 优先级天花板 (priority ceilings):将申请某资源的任务的优先级提升到可能访问该资源的所有任务中最高优先级任务的优先级 (这个优先级称为该资源的优先级天花板)。
Linux
top 命令详解
top 命令经常用来监控 linux 的系统状况,是常用的性能分析工具,能够实时显示系统中各个进程的资源占用情况。
Cpu
|
|
内容 | 含义 |
---|---|
us | (user Space)用户空间占用 CPU 百分比 |
sy | (system Space)内核空间占用 CPU 百分比 |
ni | (nice)以较低优先级运行的用户进程所使用的 CPU 时间百分比 |
id | (idle)空闲 CPU 百分比 |
wa | (Wait)等待 I/O 完成的 CPU 时间百分比。这包括等待磁盘 I/O、网络 I/O 等操作的时间。 |
hi | (Hardware IRQ)硬中断占用 CPU 的百分比 |
si | (Software Interrupts)软中断占用 CPU 的百分比 |
st | (Steal Time)用于有虚拟 cpu 的情况,用来指示被虚拟机偷掉的 cpu 时间 |
- us 表示正在执行的用户进程代码的 CPU 时间百分比。较高的
us
值表示用户进程消耗了较多的 CPU 时间。 - sy 表示操作系统内核执行系统级别任务的 CPU 时间百分比。这包括处理系统调用、中断、进程调度等内核级别的操作。较高的
sy
值表示操作系统内核消耗了较多的 CPU 时间。 - 这两个指标(
us
和sy
)加在一起通常给出了总的 CPU 使用率(也就是 1 - id)
Mem
这里的内存均指物理内存
|
|
内容 | 含义 |
---|---|
total | 物理内存总量 |
used | 使用的物理内存总量 |
free | 空闲内存总量 |
buffers | (Buffer Cache)用于缓存文件系统数据的内存量 |
cached | (Page Cache)用于缓存块设备数据的内存量 |
total = used + free + buff/cache
在 top
命令的输出中,buff/cache
是 buffers 和 cached 的总和
Swap
交换区
MiB Swap: 2048.0 total, 1063.6 free, 984.4 used. 1069.0 avail Mem
内容 | 含义 |
---|---|
total | 交换区总量 |
used | 使用的交换区总量 |
free | 空闲交换区总量 |
avail | 可用的交换区总量 |
total = used + free
测试开发
定位测试方法
确认网络环境是否正常
抓包看接口返回
查看服务端日志
其他
爬虫 url 去重方法
https://blog.csdn.net/weixin_42425970/article/details/102532185
- 放到列表中(烂中之烂)
- 放到数据库中(利用唯一性索引)
- 放到 HashSet 中
- md5 编码后放到 HashSet 中
- 位图 Bitmap
为什么大循环在内,小循环在外可以提高程序的运行效率
预测指令和转移指令
程序对于计算机来说,最终都会编译生成计算机可以识别的指令;
如今的计算机为了提高效率,指令执行机制都会存在预处理指令的分支;
对于循环会存在转移指令的情况,比如一个 100 次的循环,除第一次和最后一次预测指令出现错误,其他预测的指令都可以预测循环体内的指令;避免了执行转移指令时重新取出新指令造成的时间浪费。
对于两个 A 和 B 两个循环来说,当 A >> B
的时候,循环会有嵌套的两种情况
A 在外,B 在内,每次进行循环的时候,B 都会出现两次错误,一共循环 A 次;A 循环本身也会出现两次预测错误,所以最终得出的指令预测错误是 A*2 +2 ;
B 在外,A 在内,每次循环都会出现 2 次预测错误,一共循环 B 次;B 循环本身也会出现两次错误,所以,最终得出的指令预测错误是 B*2 + 2;
因为 A 远大于 B,所以最终第一种方式预测错误的次数 A*2 +2>B*2 + 2
;第一种情况重新取新指令造成更多的时间浪费;
所以,在处理循环嵌套的时候,“大循环在内,小循环在外”是很好的选择;