My八股整理

面试整理

文章目录

    • 自我介绍
    • 项目
      • 项目介绍
      • Redis 实现购物车缓存
      • 数据库表的设计
      • Nginx 反向代理
    • 数据结构
        • 排序算法
        • 查找算法
        • 满二叉树和完全二叉树
    • 计网
        • TCP/IP 网络模型
        • TCP 和 UDP 区别
        • IP 和 MAC 地址
        • 3. 键入网址到网页显示的过程
        • 4. TCP 三次连接
        • 5. TCP 四次挥手
        • 6. TCP 重传机制
        • 7. TCP 流量控制
        • 8. TCP 拥塞控制
        • 9. TCP 分片和 IP 分片
        • 粘包问题
        • 10. IP 协议相关技术
        • 11. HTTP 协议
        • 12. HTTP 演进
        • 13. HTTPS
        • Get 和 Post 区别
    • 操作系统
      • 硬件结构
        • 冯诺依曼结构
        • 指令
        • 多级存储器结构
        • CPU Cache
        • CPU 调度
        • 软中断
        • 数值存储
      • OS 结构
        • 内核态和用户态
      • 内存管理
        • 虚拟内存
        • Linux 内存管理
        • 内存分配
        • 内存回收
        • Swap 机制
      • 进程管理
        • 进程
        • 线程
        • 进程和线程对比
        • 进程调度
        • 上下文切换
        • 进程间通信
        • OS 实现锁的几种对象
      • 文件系统
        • IO 模型
      • 网络系统
        • 零拷贝
        • I/O 多路复用
        • 网络模式
        • 一致性哈希
    • Java
      • 集合
        • ArrayList
        • HashMap
        • ConcurrentHashMap
        • CopyOnWriteArrayList
        • 并发安全的 Queue
        • ConcurrentSkipListMap
      • IO
        • 1. Java IO 体系
        • 2. IO 中的设计模式
        • 3. IO 模型
      • 并发
        • 创建线程的方式
        • 线程生命周期
        • 线程池
        • sleep()和wait()对比
        • Volatile 关键字
        • CAS 底层实现
        • ThreadLocal 原理 1
        • Synchronized 锁机制
        • AQS
        • 公平锁和非公平锁的实现
      • JVM
        • 内存区域
        • 2. 对象创建
        • 3. 对象存活判断
        • 4. GC算法
        • 5. GC
        • 6. 类文件结构
        • 7. 类加载过程
        • 8. 类加载器
      • 其它
        • 反射机制
        • 代理模式
        • 异常机制
    • MySQL
      • 三范式
      • InnoDb 和 MyISAM 区别
      • 索引
        • 索引类型
        • B+树 对比 哈希、B树、红黑树
      • 事务
        • 四个特征
        • 并发问题
        • 隔离级别
      • 三大日志
        • Bin Log
        • Redo Log
        • Undo Log
      • MVVC 机制
      • 锁机制
        • 表级锁
        • 行级锁
      • 索引失效情况
      • SQL 语句
    • Redis
        • Redis 常用的数据结构
        • Redis 速度快的原因 1
        • Redis 线程模型
        • 过期删除策略
        • 内存淘汰机制
        • Redis 持久化机制
        • 缓存三大问题
        • 三种常用缓存读写策略
        • 缓存一致性问题
    • Spring
      • IoC
        • IoC 理解
        • 声明 Bean
        • 注入 Bean
        • Bean 作用域
        • Bean 生命周期
        • 自动装配
        • 解决循环依赖
      • AOP
        • AOP 理解
        • 通知类型
      • MVC
        • MVC 理解
        • 核心组件和原理
      • 其它
        • 常用注解
          • SpringBoot 优势
        • SpringBoot 缺点
        • 事务传播行为
        • 事务隔离级别
        • JPA 取消持久化的方法
    • 分布式
        • 概念
        • CAP 和 BASE
        • Paxos
        • Raft
        • API 网关
        • 分布式 ID
        • 分布式锁
        • 远程调用
        • 读写分离
        • 分库分表
    • 消息队列
      • 基本概念
      • Kafka
      • RabbitMQ
        • 概念
        • 常见问题
    • 开发工具
      • Linux
      • Maven
      • Git
      • Docker
    • 系统设计
      • RestFul
      • 软件工程
      • 认证授权
      • 设计模式
          • Java 单例
    • 手撕算法
        • LRU
        • 堆排
        • 背包

自我介绍

面试官您好,我是钱超,来自湖南大学信息科学与工程学院软件系,目前是研二在读,我的研究方向是视频流传输协议。研究生期间,我的学分绩点3.82,位列专业第一,科研方面发表了一篇 CCF-B 会议论文,并有一项发明专利进入实审。英语水平通过了CET6 568分。
专业技能方面熟悉 计网、操作系统 等计算机基础知识,了解 Java并发、JVM、Spring框架 等技术。项目经历的话有一个自学的基于 SpringBoot 的开发项目,使用 MyBatisPlus 完成对数据库的CRUD,使用阿里云OSS实现图片的上传,实现 MySQL 的主从同步,并且使用 Redis 实现了购物车缓存以加快数据访问等。最近我也在学习微服务相关知识,尝试把这个单体项目改造成基于 SpringCloud 的微服务项目。大致的情况就是这样。

项目

项目介绍

小林奶茶店是专门为奶茶饮品店定制的一款软件产品,包括系统管理后台和移动端应用两部分。其中系统管理后台主要提供给餐饮内部员工使用,可以对餐厅的菜品、套餐、订单进行管理和维护。移动端应用主要提供给消费者使用,可以在线浏览菜品、添加购物车、下单等。

项目总体基于 SpringBoot + MybatisPlus 进行开发,使用 MySQL 数据库进行数据存储,使用 Redis 进行项目优化,使用 git 和 maven 进行版本控制和项目管理。

Redis 实现购物车缓存

当用户数量较多时,系统访问量大,频繁的访问数据库,数据库压力大,系统的性能下降,用户体验感差。因此使用Redis对数据进行缓存,从而减小数据库的压力,有效提高系统的性能和访问速度。

具体操作:导入Spring Cache和Redis依赖坐标,ttl过期时间设为30分钟,@EnableCaching 开启缓存,在对应的控制器方法上标注 @Cacheable 注解对结果缓存。在 save 和 delete 方法上标注 @CacheEvict 标注,对数据库做修改时删除缓存,保证数据一致性。

  • 以用户 ID 作为key
  • 以商品 id 作为field
  • 以商品的数量作为 value

数据库表的设计

数据库设计共为11张表,分为员工、用户、地址、饮品、订单、套餐等等。套餐为饮品的各类组合,套餐和饮品的关系由 单独一张 表来维系,饮品包括不同口味,由dish_flavor 表来维系,一个订单可能包括多个内容(即饮品或套餐),这些内容由 order_detail 表来维系,order表则记录每次付钱后的订单

Nginx 反向代理

正向代理代理客户端,反向代理代理服务器。

数据结构

排序算法

冒泡 O(n), 选择 O(n^2), 插入 O(n^2), 归并 O(nlogn), 快排 O(nlogn), 堆排 O(nlogn)

查找算法

顺序查找、二分查找、哈希查找、树表排序树(二叉排序树、平衡树、红黑树)

满二叉树和完全二叉树

满二叉树:每一层的节点数都达到最大值,即 2 h − 1 2^{h-1} 2h1个,其中h是树的高度。满二叉树的总节点数是 2 h − 1 2^h-1 2h1个。
完全二叉树:除了最后一层外,其他层的节点数都达到最大值,且最后一层的节点都连续集中在最左边。总节点数在 2 h − 1 2^{h-1} 2h1 2 h − 1 2^h-1 2h1之间。

满二叉树一定是完全二叉树,但完全二叉树不一定是满二叉树。

计网

TCP/IP 网络模型

物 数 网 传 应。其中只有应用层在用户空间,其它层都在OS内核中。

  1. 应用层:网络应用程序和网络之间的接口。比如HTTP、FTP、DNS等等
  2. 传输层:负责端到端的通信,比如 TCP、UDP 协议
  3. 网络层:负责数据的路由、转发、分片,比如 IP、ICMP 等
    • 为了在网络中定位另一台设备,需要用IP地址标识。
    • IP地址和子网掩码配合可以得到网络号和主机号,从而确定一台设备。
    • MTU 最大传输单元,1500字节
  4. 网络接口层(物理层+数据链路层):负责网络包在物理网络中的传输,比如网络包的封帧、 MAC 寻址、差错检测等
    • 通过 ARP 协议(IP -> MAC)获得下一跳的 MAC 地址(没有就走默认路由,从小局域网 -> 大局域网)

TCP 和 UDP 区别

  • TCP是面向连接的协议,UDP是无连接的协议。
  • TCP提供可靠的服务,通过TCP连接传送的数据,无差错、不丢失、不重复,按序到达;UDP尽最大努力交付,即不保证可靠交付。
  • TCP提供流量控制,即源端通过滑动窗口来告诉对端自己的发送窗口大小,从而控制对端发送数据的速度;UDP没有流量控制。
  • TCP提供拥塞控制,即当网络拥塞时,TCP会降低自己的发送速度,从而避免网络拥塞的恶性循环;UDP没有拥塞控制。
  • TCP是面向字节流的,UDP是面向数据报的。
  • TCP的头部较大,至少20个字节,而UDP的头部只有8个字节。

IP 和 MAC 地址

  1. MAC地址的作用是实现「直连」的两个设备之间通信,在传输过程中是一直变化的。
  2. 而 IP 则负责在「没有直连」的两个网络之间进行通信传输,源IP地址和目标IP地址在整个传输过程中是不会变化的(除非 NAT)
  3. 如果只用MAC地址,路由器就需要记住每个MAC地址所在的子网,而MAC地址有48位,路由器无法存储这么多子网信息
  4. IP地址是设备上线以后,才能根据进入哪个子网来分配的,在设备还没有IP的时候需要用MAC地址来区分不同的设备

IP地址类似住址门牌号,住在不同地方就有不同门牌号,快递根据门牌号找到所在位置。而MAC地址类似身份证号,设备出厂就固定写死了,但是知道身份证号是没法找到人的,身份证号和地理位置无关。

3. 键入网址到网页显示的过程

  1. 对URL网址进行解析,生成HTTP请求消息
  2. DNS 查询:域名 -> IP地址
    • 查询顺序:浏览器缓存 -> OS缓存 -> 本地DNS, 还没有就由本地DNS发出查询:根DNS -> 顶级DNS -> 权威DNS
  3. 和目标服务器通过三次握手,建立TCP连接。连接建立后,封装TCP报文,交付网络层
  4. 网络层封装IP数据包,写入源IP地址、目标IP地址、协议等等信息,然后交付网络接口层
  5. 网络接口层通过ARP协议获得下一跳MAC地址,封装数据帧发送出去。
  6. 然后数据包经过若干个交换机/路由器的转发,来到目标IP所在的子网,再交给目标IP对应的的服务器
  7. 服务器一层层解析数据包,根据端口交付给对应的进程。
  8. 进程将响应数据封装成HTTP响应报文,然后也一层层封装,发回给客户端进程,也就是浏览器。
  9. 客户端的浏览器对接收到的数据包解析,然后渲染整个网页的显示。
  10. 最后,如果没有别的数据请求了,双方就进行TCP 四次挥手断开连接

4. TCP 三次连接

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nwCwQz8G-1679660470777)(.assets/三次握手.png)]

过程:

  • 首先服务端主动监听某个端口,处于 Listen 状态
  • 客户端随机一个序列号,并发送 SYN 报文给服务端。此时客户端处于 SYN-SENT 状态
  • 服务端接收到客户端的 SYN 报文后,也随机一个序列号,然后发送 SYN+ACK 报文给客户端,同时确认客户端报文的序列号。此时服务端处于 SYN-RCVD 状态
  • 客户端收到服务端报文后,序列号+1,再次向服务端回应一个 ACK 报文,同时确认服务端报文的序列号。此次报文已经可以携带数据了。之后客户端处于 ESTABLISHED 状态
  • 服务端收到客户端应答报文后,也进入 Established 状态。三次握手完成。

为什么需要三次握手:

  • 首要原因是防止旧的(阻塞在网络中)重复连接初始化造成混乱。如果只有两次握手,服务端没有中间状态给客户端来阻止旧连接,导致服务端可能建立一个旧连接,造成资源浪费。
  • 同步双方的初始序列号,两次握手只能保证服务端确认了客户端的序列号,不能保证客户端确认了服务端的序列号。

5. TCP 四次挥手

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-RqVUrIBG-1679660470779)(.assets/四次挥手.png)]

过程:

  • 客户端打算关闭连接时,会发送一个 FIN 报文,之后客户端进入 FIN_WAIT_1 状态。
  • 服务端收到该报文后,回复一个 ACK 应答,进入 CLOSE_WAIT 状态。
  • 客户端收到服务端的 ACK 应答后,进入 FIN_WAIT_2 状态。
  • 等服务端处理完数据后,也向客户端发送 FIN 报文,之后服务端进入 LAST_ACK 状态。
  • 客户端收到服务端的 FIN 报文后,也回复一个 ACK 应答,之后进入 TIME_WAIT 状态
  • 服务端收到了 ACK 应答报文后,就进入了 CLOSE 状态,至此服务端已经完成连接的关闭。
  • 客户端在经过 2MSL(最大报文生存时间,Linux中为30s) 时间后,自动进入 CLOSE 状态,至此客户端也完成连接的关闭。

为什么需要四次挥手?

  • 关闭连接时,客户端向服务端发送 FIN 时,仅仅表示客户端不再发送数据了但是还能接收数据。
  • 服务端收到客户端的 FIN 报文时,先回一个 ACK 应答报文,而服务端可能还有数据需要处理和发送,等服务端不再发送数据时,才发送 FIN 报文给客户端来表示现在同意关闭连接。

也就是要等待服务端把手上的数据处理发送完再关闭。

为什么需要 TIME_WAIT 状态?

  • 等待 2MSL 让两个方向上的现有数据包都被丢弃,使得旧连接的数据包在网络中都自然消失,防止被后面相同四元组的新连接错误的接收
  • 等待足够的时间以确保最后的 ACK 能让被动关闭方接收,从而帮助其正常关闭

6. TCP 重传机制

超时重传:
在发送数据时,设定一个定时器,当超过指定的时间后,没有收到对方的 ACK 确认应答报文(数据包丢失/确认应答丢失),就会重发该数据。

问题:超时重传时间 RTO 的设定,理论上应略大于 RTT。但RTT无法准确计算,Linux采用加权移动平均,采样估计。

快速重传:
当收到三个相同的 ACK 报文时,会在定时器过期之前,重传丢失的报文段。

问题:重传时是重传一个还是重传所有已经发出去的数据包,只重传一个可能造成延迟重传,重传所有可能浪费网络资源

SACK: Selective ACK
在 TCP 头部「选项」字段里加一个 SACK,将已收到的数据信息发给「发送方」,这样发送方就可以只重传丢失的数据。

Duplicate SACK:
使用 SACK 来告诉「发送方」有哪些数据被重复接收了,这样「发送方」就知道数据没有丢,是「接收方」的 ACK 确认报文丢了。

7. TCP 流量控制

滑动窗口:
为了提高网络的传输效率,引入滑动窗口,双方各自维护发送窗口和接收窗口。
在发送窗口范围内的数据都可以发送出去,窗口后延之外的数据都是暂时不能发送的数据。随着接收到的数据,窗口会向后移动。
一般由接收方告诉发送方自己还有多少缓冲区可以用于接收数据,发送方根据接收方的处理能力调整窗口大小。但双方窗口只是近似相等,传输过程存在延迟,窗口也时刻在变化。发送窗口 = min(拥塞窗口,接收窗口)

为了防止资源紧张时,操作系统减小缓存,同时收缩窗口,导致丢包和窗口变负值的情况,TCP规定必须先收缩窗口,再减少缓存。
窗口缩减为0后,需要定时发送窗口探测报文,确认当前窗口大小,避免双方持久等待。

糊涂窗口综合征:发送方为了填满接收方几个字节的窗口,发送一整个TCP报文,而TCP+IP首部就有40字节,会造成极大资源浪费。
为了解决这一问题,接收方在窗口小于min(MSS, 0.5*cache)时,就发送0窗口通告;而发送发采用Nagle延迟处理,必须等窗口>=MSS且数据大小>=MSS,或者收到之前发送数据的ACK,才会继续发送。即接收方得满足「不通告小窗口给发送方」+ 发送方开启 Nagle 算法,才能避免糊涂窗口综合症。

8. TCP 拥塞控制

流量控制是为了避免「发送方」的数据填满「接收方」的缓存,但是并不知道网络中发生了什么。而拥塞控制是为了避免「发送方」的数据填满整个网络。

拥塞窗口:由发送方维护,根据网络的拥塞程度动态变化的。

慢启动
TCP刚建立完成后,需要一点一点提高发包速度。
每当发送方收到一个ACK,拥塞窗口的大小就会加1,发包数呈指数增长,直到 cwnd >= ssthresh 慢启动门限。

拥塞避免
cwnd超过慢启动门限后,进入拥塞避免算法。
每收到一个ACK报文,拥塞窗口cwnd增加1/cwnd。发包数呈线性增长。

拥塞发生
一旦发生丢包、延时导致重传,进入拥塞发生阶段。
超时重传:ssthresh = 0.5 * cwnd,cwnd重置为1 (Linux初始值为10)

快重传
当接收方发现一个乱序到达的报文段,就会发送三次前一个包的 ACK。于是发送端收到三个相同的ACK报文,就会快速重传,不必等到超时再重传。
这时 cwnd /= 2,ssthresh = cwnd,进入快恢复。

快恢复
快速恢复算法是认为,你还能收到 3 个重复 ACK 说明网络也不那么糟糕,所以没有必要像 RTO 超时那么强烈。
快重传阶段更新完成后,cwnd = ssthresh + 3,重传丢失数据包。
如果再收到重复的ACK,cwnd + 1;如果收到新数据的ACK,cwnd设为原始 ssthresh(+3前的),再次进入拥塞避免。

9. TCP 分片和 IP 分片

如果TCP层不进行分片,仅在IP层分片,那么当一个TCP报文段的某个IP分片丢失,接收方的IP层无法组装成一个完整的TCP报文,也就不会响应ACK给发送方。于是发送方就会一直等待直到超时重传,因此由IP层进行分片传输效率很低。

所以,为了达到最佳的传输效能 TCP 协议在建立连接的时候通常要协商双方的 MSS 值,使得IP包长度不会大于MTU,也就不用IP分片了。这样即使一个IP分片丢失,进行重发时也是以 MSS 为单位。

粘包问题

对于UDP,OS不会对消息进行拆分,每个UDP报文就是一个完整的用户消息。
而对于TCP,消息可能会被操作系统分组成多个 TCP 报文,因此接收方的程序如果不知道发送方发送的消息长度/边界,就无法读出一个有效的用户消息。因此我们说 TCP 是面向字节流的协议。

当两个消息的某个部分内容被分到同一个 TCP 报文时,即 TCP 粘包问题,这时接收方不知道消息的边界的话,无法读出有效的消息。

解决方法
由应用程序负责:

  • 固定长度的消息:不灵活
  • 特殊字符作为边界:两个用户消息之间插入特殊字符,例如 HTTP 协议通过回车符+换行符作为报文的边界(注意转义)
  • 自定义消息结构:分包头和数据,在包头里记录数据部分的长度,接收方通过解析包头就可以知道消息的边界了。

10. IP 协议相关技术

DNS 域名解析协议
作用:域名 -> IP地址
查询顺序:

  • 浏览器缓存 -> OS缓存 -> 本地DNS (主机和本地DNS服务器之间递归查询)
  • 还没有就由本地DNS发出查询:根DNS -> 顶级DNS -> 权威DNS (DNS服务器之间迭代查询)

ARP 地址解析解析
作用:IP -> MAC
原理:广播 ARP 请求 -> 解包匹配 -> 单播 ARP 响应 -> 有限缓存
RARP:MAC -> IP,用于打印机服务器等小型嵌入式设备接入网络

DHCP 动态主机配置协议
作用:动态获取IP地址
原理(全程 UDP广播):

  • 客户端(0.0.0.0:68)使用 UDP 广播(255.255.255.255:67),发起 DHCP DISCOVER
  • DHCP 服务器响应 DHCP OFFER,携带可租约的 IP 地址、子网掩码、默认网关、DNS 服务器以及 IP 地址租用期等信息
  • 客户端收到一个 DHCP OFFER 后,回复 DHCP REQUEST,回显配置的参数
  • DHCP 服务器响应 DHCP ACK 确认配置信息

NAT 网络地址转换协议
作用:私有IP -> 公有IP (NAPT:网络地址和端口转化协议)
原理:转换表
缺点:外网无法主动连接、性能开销、重启连接断开
解决:IPv6、NAT穿透(应用程序主动建立端口映射)

ICMP 互联网控制报文协议
作用:确认 IP 包是否成功送达目标地址、报告发送过程中 IP 包被废弃的原因和改善网络设置等。
分类:查询报文(如 Ping 命令)、差错报文(如 Traceroute 命令)

IGMP 因特网组管理协议
作用:维护 IGMP 路由表,管理加入、离开组播组的主机

11. HTTP 协议

超文本传输协议,超文本指文字、图片、视频等等信息,传输指在多个设备之间,协议指规定了通信的方式。

状态码

  • 1xx 提示信息
  • 2xx 成功。如 200 OK;204 No Content
  • 3xx 重定向。如 301 永久重定向;304 资源未修改
  • 4xx 发送报文有误。如 400 请求错误;404 资源不存在
  • 5xx 服务器处理出错。如 500 服务器内部错误;503 服务器忙

字段

  • Host: 服务器域名
  • Content-Length: 本次回应的数据长度
  • Connection: 是否使用长连接 Keep-Alive。只要任意一端没有提出断开,就保持TCP连接状态
  • Content-Type: 服务器回应客户端本次数据的格式 Content-Type: text/html; Charset=utf-8
  • Accept: 客户端声明自己接收的数据格式,Accept: */*表示任意
  • Content-Encoding / Accept-Encoding: 发送 / 可接受的压缩格式

缓存

  1. 强制缓存:根据响应中的 Cache-Control (相对时间) 和 Expires (绝对时间) 判断请求是否过期,没过期直接从缓存中取响应结果
  2. 协商缓存:强制缓存没有命中时,可以与服务端协商之后,通过协商结果来判断是否使用本地缓存,一般响应304告知使用缓存。两种头部实现
    • Last-Modified 和 If-Modified-Since 根据时间判断是否有更新
    • Etag 和 If-None-Match 根据唯一标识判断 (类似CAS)

12. HTTP 演进

HTTP/1.1
优点:简单、灵活、易于扩展、应用广泛、跨平台。相比于1.0,HTTP/1.1 使用长连接(减少连接建立释放的开销),支持管道化传输(一次发起多个请求)
缺点:

  • 无状态,得用Cookie解决
  • 不安全:明文传输
  • 但仍存在响应的队头阻塞问题,性能一般

HTTP/2

  • 基于HTTPS,安全性得到保证
  • 头部压缩
  • 二进制格式
  • 并发传输:一个TCP连接包含多个Stream,不同的HTTP请求通过Stream ID区分
  • 服务器主动推送资源
  • 缺陷:由于基于TCP,仍然存在TCP层队头阻塞问题

HTTP/3
使用基于UDP的 QUIC (一个在 UDP 之上的伪 TCP + TLS + HTTP/2 的多路复用的协议)协议。特点:

  • 无队头阻塞
  • 更快的连接建立:QUIC本身包含TLS,仅需进行一次握手
  • 连接迁移

13. HTTPS

  • HTTPS 在 TCP 和 HTTP 网络层之间加入了 SSL/TLS 安全协议,使得报文能够加密传输。
    • 混合加密:在通信建立前采用非对称加密的方式交换「会话秘钥」,通信过程中使用对称加密的「会话秘钥」的方式加密明文数据
    • 摘要算法 + 数字签名:通过哈希函数计算传输内容的指纹,保证消息完整性。对内容的哈希通过「私钥加密,公钥解密」的方式,来确保消息可靠性
    • 数字签名:将服务器公钥放在数字证书(由数字证书认证机构颁发)中,只要证书是可信的,公钥就是可信的
  • HTTP 连接建立只要三次握手,而HTTPS除了三次握手,还要继续 SSL/TLS 握手
    • 客户端向服务器索要并验证服务器的公钥。
    • 双方协商生产「会话秘钥」。
    • 双方采用「会话秘钥」进行加密通信。
  • HTTP默认端口80,HTTPS默认端口443
  • HTTPS需要向CA申请数字证书,来保证服务器的身份是可信的

TODO

Get 和 Post 区别

  • Get 的语义是从服务器获取指定的资源,请求的参数一般是以 KV 形式写在 URL 中(浏览器会对 URL 的长度有限制, HTTP协议没有)
  • POST 的语义是根据请求体对指定的资源做出处理,请求携带的数据一般是在报文 body 中,格式任意,大小不限
  • Get 方法是安全且幂等的,不会破坏服务器上的资源,且多次执行的结果相同。(因此 GET 请求的数据可以缓存,POST 需要手动设置。)
  • Post 方法不是安全,也不是幂等的。

HTTP 请求都是明文,因此GET/POST都不安全,此外GET没有规定不能携带请求体,POST请求URL也可以有参数。

操作系统

硬件结构

冯诺依曼结构

运算器、控制器、存储器、输入设备、输出设备

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZRQ49Wgm-1679660470780)(.assets/%E5%86%AF%E8%AF%BA%E4%BE%9D%E6%9B%BC%E6%A8%A1%E5%9E%8B.webp)]

  • CPU = 控制单元 + 逻辑运算单元 + 寄存器
  • 寄存器分 通用寄存器、指令寄存器、程序计数器
  • 总线分 地址总线(指定内存地址)、控制总线(指定读/写)、数据总线(传输数据)

指令

指令周期的四级流水线:Fetch -> Decode -> Execute -> Store

硬件32/64位指CPU位宽,软件32/64位指指令的位宽。

64位相比32位的优势:

  1. 64位CPU可以一次计算超过32位的数字,但很少有程序计算这么大的数字,只有计算大数字才能体现超过32位CPU的性能
  2. 64位CPU可以寻址更大的物理内存空间,32位最高寻址4G

多级存储器结构

  • 寄存器: 一般在半个CPU周期内完成读写
  • CPU Cache:RAM 静态随机存储器,断电丢失。
    • L1:2-4个时钟周期,几十KB。分数据缓存、指令缓存
    • L2:10-20个时钟周期,几百KB
    • L3: 20-60个时钟周期,几十MB。多核共享
  • 内存:DRAM 动态随机存取存储器,电容需要定时刷新。200-300个时钟周期
  • SSD/HDD 硬盘:断电后数据不丢失,SSD比内存慢10-1000倍,HDD比内存慢10W倍

每个存储器只和相邻的一层存储器设备进行交互,形成缓存体系。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6Umuap03-1679660470781)(.assets/%E4%B8%89%E7%BA%A7%E7%BC%93%E5%AD%98.webp)]

CPU Cache

CPU Cache 是由很多个 Cache Line 组成的,Cache Line 是 CPU 从内存读取数据的基本单位(例如一次载入 64Byte),由各种标志(Tag)+ 数据块(Data Block)组成。

直接映射

  • 通过取模运算,计算内存块对应的 Cache Line 地址
  • 组标记 Tag: 记录是否是对应的内存块(因为多个内存块会映射到同一个 Cache Line)
  • 有效位 Valid Bit:标记数据是否还有效
  • 偏移量 Offset:定位 CPU 读取 Cache Line 中哪个 Word 字

因此,一个内存的访问地址由 组标记、Cache Line 索引、偏移量 三者共同定位。其它映射例如全相联、组相联等类似。

提升缓存命中率

提升缓存命中率,也就可以提升程序执行速度,优化方法例如:

  • 按内存布局顺序访问
  • 有规律的条件分支语句可以充分利用 CPU 的分支预测器
  • 当有多个同时执行的「计算密集型」线程,可以把线程绑定在某一个 CPU 核心上,避免线程在不同核心来回切换,影响缓存命中率。

写入数据

  1. 写直达 Write Through:把数据同时写入内存和Cache。每次写操作都会写回内存,消耗性能
  2. 写回 Write Back:将新数据写入 Cache Block 里,只有当修改过的 Cache Block「被替换」时才需要写到内存中。

缓存一致性问题

由于 L1/L2 Cache 是多个核心各自独有的,因此可能带来多核心的缓存一致性问题。因此需要一种同步机制,能够实现:

  1. 写传播:某个 CPU 核心里的 Cache 数据更新时,必须要传播到其他核心的 Cache。
    • 实现方法:总线嗅探,每个 CPU 核心监听总线上的广播事件,检查是否有相同的数据在自己的 L1 Cache 里,如果有事件就更新。会加重总线负载,且不能保证事务串行化
  2. 事务串行化:某个 CPU 核心里对数据的操作顺序,必须在其他核心看起来顺序是一样的
    • 实现方法:MESI协议,标记 Cache Line 的四种不同状态
    • Modified:已修改。Cache 数据和内存中数据不一致,可以自由写入,被替换时需要写回内存。
    • Exclusive:独占。仅一个核心存储该 Cache Line,可以自由写入,不需要通知其它核心。如果其它核心从内存读取了该 Cache Line,那么将转为共享状态
    • Shared:共享。修改时需要向所有其它核心广播请求,要求把该 Cache Line 标记为无效,然后再更新
    • Invalidated:已失效。数据不一致,不可以读取该状态数据。

伪共享

由于多个线程同时读写同一个 Cache Line 的不同变量,而导致 CPU Cache 失效的现象。

解决方案:

  • Cache Line 大小字节对齐(空间换时间)
  • 字节填充,例如 Disruptor 中的 RingBuffer 类数据前后填充 long,使得无论怎么加载 Cache Line,这整个 Cache Line 里都没有会发生更新操作的数据

CPU 调度

Linux 内核中,无论是进程还是线程,调度的都是 task_struct 结构体,区别在于线程的task_struct部分资源是共享了进程已创建的资源,如内存地址空间、代码段、文件描述符等。

调度器

  • Deadline:对应 dl_rq 运行队列
  • Realtime:对应 rt_rq。
  • Fair: 对应 cfs_rq。完全公平调度,优先选择 vruntime 少的任务,用于普通任务,内部组织成红黑树结构

调度优先级从上到下,dl_rq -> rt_rq -> cfs_rq,也即实时任务总是先于普通任务被执行。

进程优先级可以通过 nice | renice 设置/更改,范围 -20~19,是一个修正值,nice 值越小优先级越高。

软中断

中断是系统用来响应硬件设备请求的一种机制,操作系统收到硬件的中断请求,会打断正在执行的进程,然后调用内核中的中断处理程序来响应请求。中断是一种异步的事件处理机制,可以提高系统的并发处理能力。

Linux 为了解决中断处理程序执行过长和中断丢失的问题,将中断处理程序分成了两个阶段:

  • 上半部:直接处理硬件请求,也就是硬中断。
    • 负责耗时短的工作,特点是快速执行,一般会暂时关闭中断请求。例如处理跟硬件相关或时间敏感的事情。
  • 下半部:由内核触发,也就是软中断。
    • 负责上半部未完成的工作,特点是延迟执行,通常耗时较长。

另外,硬中断会打断 CPU 正在执行的任

你可能感兴趣的:(java)