状态码:

1xx 类状态码属于提示信息,是协议处理中的一种中间状态,实际用到的比较少。

2xx 类状态码表示服务器成功处理了客户端的请求,也是我们最愿意看到的状态。

  • 「200 OK」是最常见的成功状态码,表示一切正常。如果是非 HEAD 请求,服务器返回的响应头都会有 body 数据。
  • 「204 No Content」也是常见的成功状态码,与 200 OK 基本相同,但响应头没有 body 数据。
  • 「206 Partial Content」是应用于 HTTP 分块下载或断点续传,表示响应返回的 body 数据并不是资源的全部,而是其中的一部分,也是服务器处理成功的状态。

3xx 类状态码表示客户端请求的资源发生了变动,需要客户端用新的 URL 重新发送请求获取资源,也就是重定向。

  • 「301 Moved Permanently」表示永久重定向,说明请求的资源已经不存在了,需改用新的 URL 再次访问。
  • 「302 Found」表示临时重定向,说明请求的资源还在,但暂时需要用另一个 URL 来访问。

301 和 302 都会在响应头里使用字段 Location,指明后续要跳转的 URL,浏览器会自动重定向新的 URL。

  • 「304 Not Modified」不具有跳转的含义,表示资源未修改,重定向已存在的缓冲文件,也称缓存重定向,也就是告诉客户端可以继续使用缓存资源,用于缓存控制。

4xx 类状态码表示客户端发送的报文有误,服务器无法处理,也就是错误码的含义。

  • 「400 Bad Request」表示客户端请求的报文有错误,但只是个笼统的错误。
  • 「403 Forbidden」表示服务器禁止访问资源,并不是客户端的请求出错。
  • 「404 Not Found」表示请求的资源在服务器上不存在或未找到,所以无法提供给客户端。

5xx 类状态码表示客户端请求报文正确,但是服务器处理时内部发生了错误,属于服务器端的错误码。

  • 「500 Internal Server Error」与 400 类型,是个笼统通用的错误码,服务器发生了什么错误,我们并不知道。
  • 「501 Not Implemented」表示客户端请求的功能还不支持,类似“即将开业,敬请期待”的意思。
  • 「502 Bad Gateway」通常是服务器作为网关或代理时返回的错误码,表示服务器自身工作正常,访问后端服务器发生了错误。
  • 「503 Service Unavailable」表示服务器当前很忙,暂时无法响应客户端,类似“网络服务正忙,请稍后重试”的意思。

TCP和UDP的主要区别在于连接性、可靠性和传输方式。

TCP是面向连接的,提供可靠的数据传输,适用于需要高可靠性的应用;而UDP是无连接的,传输速度快但不可靠,适用于实时性要求高的应用。

此外,TCP具有流量控制和拥塞控制机制,头部开销较大;UDP则没有这些控制机制,头部开销较小。

选择使用哪种协议取决于应用场景的具体需求。

TCP可靠的面向连接的传输方式,UDP不可靠的高效传输方式;

各自的应用之处:

UDP和TCP各有其独特的特点和适用场景。

UDP是无连接的,传输速度快、延迟低,但不可靠,适用于对实时性要求高且可容忍少量丢包的应用,如视频会议、在线游戏、DNS查询和VoIP。

而TCP是面向连接的,提供可靠的数据传输,保证数据包的顺序和完整性,适用于对数据可靠性要求高的应用,如网页浏览、电子邮件传输、文件下载和数据库访问。

选择哪种协议主要取决于应用对实时性、可靠性和网络环境的特定需求。对实时性要求高且可以容忍丢包的场景,适合使用UDP。对数据完整性、顺序和可靠性要求高的场景,适合使用TCP

可靠TCP,其它UDP;

是什么?

域名解析服务,把域名解析为目标的IP

解析流程

  1. 一开始就会去看浏览器本地缓存是否有
  2. 没有就去本地host文件看看有没有
  3. host文件没有的话才会去向本地DNS服务发请求
  4. 如果本都DNS服务器有缓存,就返回。没有就会去向根域的DNS服务器发请求,根域名服务器并不负责实际的域名解析,而是告诉本地DNS服务器应该去哪个顶级域的DNS服务器查询
  5. 顶级域的DNS服务器也不负责具体的域名解析,而是告诉本地DNS服务器可以去哪个权威DNS服务器查询
  6. 本地DNS服务器最后就会向权威DNS服务器发查询请求。权威DNS服务器就是负责将IP地址和域名进行映射存储的服务器,查到了就返回
  7. DNS服务器把IP返回给浏览器后,并且会把查询结果缓存到本地,以便下次快速查询。

整个 HTTPS 的通信过程还是比较复杂的,粗略的来说,可以分成四步。

第一步是 DNS 解析,将域名转换成 IP。

第二步是建立 TCP 连接,也就是三次握手过程。

第三步是在 TCP 的基础上完成 TLS 握手过程。

第四步就是利用 TLS 握手过程交换的密钥进行通信,发送数据的加密,接收数据的解密。

这其中最复杂的就是 TLS 握手过程,具体来说,

首先是打招呼,客户端和服务端就 TLS 版本,加密算法和压缩算法达成一致,并且交换随机数。

其次,服务端发送证书,而客户端验证证书。

第三,客户端再次生成一个随机数 Pre-Master Secret,加密(用CA证书里的公钥)之后发送给服务端,服务端解密(用服务端自己的私钥)就能得到这个随机数。

第四,利用交换的随机数和 Pre-Master Secret,按照算法生成密钥,这个就是会话密钥,后续 HTTPS 数据传输就是用这个密钥。

最后完成握手,双方互相发送 Finished 结束握手过程。

简述

一打招呼,二验证书,三换随机数,四生密钥,完成握手;

重点

TLS握手过程;

引导

DNS解析;三次握手过程

TLS为什么安全,效果更好

从上面的过程也能看出来,TLS握手的安全性源于其多重保障机制:

首先,通过密钥交换和随机数生成确保数据加密,防止窃听;

其次,利用数字证书和证书链验证服务器身份,杜绝中间人攻击;

第三,TLS 每个消息都有一个验证码(MAC),使用消息认证码保护消息完整性;

最后协议的分层设计和版本协商进一步提升安全性,有效抵御重放、时序等常见攻击。

因此虽然看上去 TLS 握手的前面打招呼和证书验证过程是明文传输,但是依靠着证书和三个随机数,还是能够保障很强的安全性

用CA证书里的公钥对 会话密钥进行加密 (非对称加密)

把加密后的 会话密钥发送给服务端,服务端用私钥进行解密 (非对称加密)

状态码…..

常见的状态吗有很多,我列举几个:

200 代表 OK,服务器处理了请求。201 代表已接收,一般是异步接口返回,表达请求已经收到了,但是不一定处理好了。

301 代表永久重定向,302 代表临时重定向

400 是请求有问题,401 是未授权,403 是禁止访问。

500 是系统错误,503 是服务不可用,在触发了熔断的时候可以返回 503。

缓存

Http缓存分为两种,一种是那个强制缓存,一种是协商缓存

强制缓存指的是只要浏览器的缓存没过期,那就使用缓存,决定是否使用缓存的决定权在浏览器这边

浏览器第一次请求服务器的时候,服务器返回请求的同时会在请求头里塞Cache-control这个参数,

这个参数注明了缓存的过期时间

浏览器再次请求时,会先根据请求的时间和Cache-control 计算出缓存是否过期,如果没有就直接访问

本地缓存,如果过期就发请求

服务器收到请求后,会更新请求头里的Cache-control

协商缓存

就是通过服务端协商后,通过协商结果判断是否使用本地缓存

报文格式:

HTTP请求报文由四部分组成:

第一部分是请求行,包含请求方法、URI和HTTP版本,如GET /index.html HTTP/1.1;

第二部分是请求头部,它包含一系列键值对,传递附加信息,如Host: example.com;

第三部分是空行,用来分隔头部和主体请求体;

第四部分是请求体,这一部分是可选的,通常用来传递请求的具体内容;

响应报文也是类似的。第一个部分是状态行,包含HTTP版本、状态码和状态消息,如HTTP/1.1 200 OK。后续依次是响应头部、空行和响应体。

请求方式

GET 和 POST 是用得最多的两个方法。

GET 主要用来访问服务器上的资源,并不改变资源的状态。而 POST 则是主要用于向服务端提交数据,更新或者创建资源,但是 POST 可以不是幂等的。

除了这些,PUT 可以用来表达更新或者创建资源,但是操作应该是幂等的,大多数情况下是整体更新。PATCH 也是更新资源,但是一般是代表更新资源的一部分属性。DELETE 则是删除资源。

还有一个很特殊的 OPTIONS,一般是浏览器遇到跨域问题时候发送的预检(preflight)请求就是使用 OPTIONS 方法。

剩下的 HEAD,TRACE,CONNECT 方法就用得比较少了。

HTTP短连接,HTTP长连接

HTTP长连接和短连接主要区别在于TCP连接的持续时间和资源占用。长连接在一个TCP连接上可以发送多个HTTP请求和响应,通过Connection: keep-alive头部来维持连接,适用于频繁请求的场景,如加载多个资源的网页,减少了TCP握手的开销,提高了性能。

而短连接则在每次HTTP请求完成后立即关闭TCP连接,适用于简单查询或对资源占用敏感的场景,虽然每次请求都需要进行TCP握手,但资源释放快。

在 HTTP 1.1 以后就默认使用长连接了,如果没有遇到问题,就不要去修改这个配置。

简述

长连接高性能,短连接释放快

  • HTTP/TCP → 通信协议(规定如何传输数据)。
  • JSON/Protobuf → 数据序列化协议(规定数据内容怎么编码)。

他们都是用于管理用户状态和身份验证的技术。因为HTTP通信是无状态的,每次请求都是独立的。所以需要一种技术来存储用户的信息

就是服务器向browser发的一小型文本,存在浏览器,用来存储用户信息。它会在下一次browser向服务器发请求时携带上,进行身份识别

session

Token

简单来说就是一字符串,用于用户的身份鉴权

是什么?

如何保证安全通信的

  1. 内容加密
  2. 身份验证:使用数字证书来验证通信双方的身份。但可以伪造证书
  3. 内容摘要算法,确保内容在传输过程中不会被篡改or损失

非对称和对称加密的区别

对称:加密和解密都是用同一把密钥

非对称:加密和解密不用密钥,一般有公钥和私钥之分,公钥用于加密,私钥用于解密

详解

在网络出现拥堵时,如果继续发送大量数据包,可能会导致数据包时延、丢失等,这时 TCP 就会重传数据,但是一重传就会导致网络的负担更重,于是会导致更大的延迟以及更多的丢包,这个情况就会进入恶性循环被不断地放大……

所以,TCP 不能忽略网络上发生的事,它被设计成一个无私的协议,当网络发送拥塞时,TCP 会自我牺牲,降低发送的数据量。

于是,就有了拥塞控制,控制的目的就是避免「发送方」的数据填满整个网络。

为了在「发送方」调节所要发送数据的量,定义了一个叫做「拥塞窗口」的概念。

拥塞窗口 cwnd是发送方维护的一个的状态变量,它会根据网络的拥塞程度动态变化的。

我们在前面提到过发送窗口 swnd 和接收窗口 rwnd 是约等于的关系,那么由于加入了拥塞窗口的概念后,此时发送窗口的值是swnd = min(cwnd, rwnd),也就是拥塞窗口和接收窗口中的较小值。

拥塞窗口 cwnd 变化的规则:

只要网络中没有出现拥塞,cwnd 就会增大;

但网络中出现了拥塞,cwnd 就减少;

只要「发送方」没有在规定时间内接收到 ACK 应答报文,也就是发生了超时重传,就会认为网络出现了拥塞。

拥塞控制算法:

  • 慢启动:

当发送方每收到一个 ACK,拥塞窗口 cwnd 的大小就会加 1(表示能发送1个MSS大小)

有一个叫慢启动门限 ssthresh (slow start threshold,65535字节)状态变量。

- 当 cwnd < ssthresh 时,使用慢启动算法。 
- 当 cwnd >= ssthresh 时,就会使用「拥塞避免算法」。 
  • 拥塞避免算法:

每当收到一个 ACK 时,cwnd 增加 1/cwnd。

  • 拥塞发生:

当网络出现拥塞,也就是会发生数据包重传,重传机制主要有两种:

- 超时重传,一直没收到ACK,从丢失的ACK开始超时重传 
- 快速重传,收到三个相同的ACK,表明某个包丢失了,快速重传丢失的包 
- 当发生了「超时重传」,则就会使用拥塞发生算法 

这个时候,ssthresh 和 cwnd 的值会发生变化:

    * ssthresh 设为 cwnd/2, 
    * cwnd 重置为 1(假设为1,其实是恢复为 cwnd 初始化值,默认初始值为10) 

接着,就重新开始慢启动

这种方案会导致如果只丢了一个包,却要立马刹车减速回到解放前, 重新慢启动

- 当发生了「快速重传」,TCP 认为这种情况不严重,因为大部分没丢,只丢了一小部分,则 ssthresh 和 cwnd 变化如下: 
    * cwnd = cwnd/2 ,也就是设置为原来的一半; 
    * ssthresh = cwnd; 
    * 进入快速恢复算法 
    * 即慢启动门限和拥塞窗口都变为拥塞窗口的一半 
  • 快速恢复:

快速重传和快速恢复算法一般同时使用,快速恢复算法是认为,你还能收到 3 个重复 ACK 说明网络也不那么糟糕,所以没有必要像 RTO 超时那么强烈。算法如下:

- 拥塞窗口 cwnd = ssthresh + 3 ( 3 的意思是确认有 3 个数据包被收到了),之前设置为ssthresh = cwnd,所以其实这里就是设为cwnd = cwnd/2 + 3;如下图为12变成9 
- 重传丢失的数据包; 
- 如果再收到重复的 ACK,那么 cwnd 增加 1; 
- 如果收到新数据的 ACK 后,把 cwnd 设置为第一步中的 ssthresh (cwnd / 2)的值,原因是该 ACK 确认了新的数据,说明从 duplicated ACK 时的数据都已收到,该恢复过程已经结束,可以回到恢复之前的状态了,也即再次进入拥塞避免状态; 

为什么收到新数据后cwnd变为ssthresh?

首先,快速恢复是拥塞发生后慢启动的优化,其首要目的仍然是降低 cwnd 来减缓拥塞,所以必然会出现 cwnd 从大到小的改变。

其次,cwnd逐渐加1的存在是为了尽快将丢失的数据包发给目标,从而解决拥塞的根本问题(三次相同的 ACK 导致的快速重传),所以这一过程中 cwnd 反而是逐渐增大的。

面试快答

TCP的拥塞控制主要通过慢启动、拥塞避免、快速重传和快速恢复等机制来运作。

初始阶段,TCP使用慢启动算法,每次收到一个 ACK,窗口大小就翻倍,这个阶段窗口是指数增长。

当拥塞窗口达到慢启动阈值后,进入拥塞避免阶段,此时窗口是线性增长。

如果检测到数据包丢失(通过超时或重复ACK),TCP会启动快速重传机制,立即重传丢失的数据包。

并且窗口会调整为原本窗口的 1/2,也就是快开始。

而后进入快速恢复(快开始)阶段,保持窗口线性增长。

这些机制共同作用,确保了TCP在避免网络拥塞的同时,提供稳定可靠的数据传输。

简述

慢启动指数增长,拥塞避免线性增长,快速重传窗口减半,快速恢复线性增长;

TCP滑动窗口

TCP的滑动窗口机制是用于控制数据传输流量和保证数据可靠性的重要机制。它通过动态调整窗口大小,来管理发送方和接收方之间的数据传输。

首先,在 TCP 的发送方和接收方各有一个窗口。并且因为 TCP 是一个全双工通信的协议,所以大多数时候,客户端和服务端都是既有接收窗口,又有发送窗口。

发送窗口

整体分为三个部分:

  • 在整个窗口左边的,就是已经发送并且 ACK 的报文。比如说上图中编号小于 100 的报文;
  • 滑动窗口内的报文,又可以分成三部分:
    • 已经收到 ACK 的报文,例如说 101 和 102;
    • 已经发送但是没收到 ACK 的报文,比如说 100, 103 和 104;
    • 还没发送的报文,也就是 105,106 和 107;
  • 在整个窗口右边的,窗口还没滑过去,所以暂时它们不可能被发送,在上图是编号大于 107 的报文;

进一步看,这里有一个细节,就是虽然 100 编号比较小,但是它的 ACK 反而有可能比 101 和 102 后收到。假设说现在收到了 100 的 ACK,那么这时候窗口就要开始滑动了。滑动的距离就是从窗口的左边开始出发,直到遇到第一个还没收到 ACK 的报文,在这里就是 103。

接受窗口

而接收窗口,也是类似的:

可以看到,在接收窗口也遇到不连续的问题,比如说先收到了 104。

显然,一旦接收方收到了 100 之后,它的窗口也会开始移动,移动的逻辑是类似的,找到最小的没有收到的报文。如下图。但是要注意到,因为 100 之后的 101 和 102 都收到了,所以实际上它可以直接 ACK 102。

因此你基本上可以想到整个工作流程

  • 初始化:连接建立时,双方协商初始窗口大小。协商是发生在 TCP 三次握手的第一次握手中。
  • 发送数据:发送方根据窗口大小发送数据包,并等待接收方的确认。
  • 接收确认:接收方收到数据包后,发送ACK确认,并更新接收窗口。
  • 滑动窗口:发送方收到ACK后,滑动窗口向前移动,允许发送新的数据包。
  • 动态调整:根据网络状况和接收方的处理能力,窗口大小可以动态调整。

动态调整窗口(最难)

这里的难点就是动态调整的策略。

就接收方来说,它主要是考虑自己的缓冲区。如果要是还有很多空闲缓冲区,那么接收方就可以增大自己的窗口,并且在发给发送方的报文里面带上新的窗口大小。反之则是减小窗口。最极端的情况下,接收方会返回零缓冲区,也就是提醒发送方不要再发了,自己已经没有空闲缓冲区可用了。

而发送方主要是受到两方面的影响。

一方面是受到 TCP 协议内部的慢开始、拥塞避免、快开始、快重传和快恢复策略的影响。另外一方面则是还会受到接收方窗口大小的影响。

@Transtional 的实现原理

创建了个了代理对象,然后它就会帮我们创建事务,然后执行方法,最后提交事务,方法报错就可能回滚事务

涉及到事务嵌套场景,默认的事务传播机制为 外层有事务就沿用外层的事务,没有内层就新建事务

而事务是基于JDBC的connection来实现的,当创建事务时,会把connection放到ThreadLocal里。然后内层方法就会去从ThreadLocal拿到connection对象,实现对事务的控制

但由于ThreadLocal每个线程都是独立,那么@ Transitional 在多线程情况下就会失效了。

而我们要解决这个,无法就是解决线程之间connection无法传递的问题。

TransactionSynchronizationManager+方法加注解 @Transactional

缺点就是 事务粒度太大了

1
2
3
4
5
6

ConnectionHolder connectionHolder=(ConnectionHolder) TransactionSynchronizationManager.getResource(dataSource);




2PC

成绩分析引入多线程后 事务问题的最终解决方案:

分析内容表脏了没关系,在分析总记录表中加一个字段为status:0表示进行中,1表示已完成

如果分析过程中出错了,那分析记录状态就会一直为0,进行中是不能被查看的,只有已完成的分析才能被查

看。后续会开一个定时任务每天 凌晨 根据分析记录时间和状态去把脏数据清空,即把前天的脏数据清空

类似于事务的两阶段提交