收集的一些问题?

发布于:2025-03-30 ⋅ 阅读:(46) ⋅ 点赞:(0)

红黑树和AVL树的区别? 

AVL(平衡二叉树) 红黑树
平衡标准 严格(左右子树高度差≤1) 宽松(最长路径≤2倍最短路径)
查找效率 更优(树更矮) 稍逊
插入/删除效率 调整代价高 调整代价低
适用场景 读多写少 写多读少,比如C++ STL的map
存储开销 平衡因子/高度(稍大) 颜色标记(更小)
  1. ​平衡严格性

    平衡二叉树(如AVL树)要求每个节点的左右子树高度差绝对值不超过1,属于严格平衡。而红黑树通过颜色规则(如红色节点不能连续、路径黑色节点数相等)实现大致平衡,允许局部不平衡,但最长路径不超过最短路径的2倍。

  2. ​旋转与变色机制

    平衡二叉树每次插入/删除都可能触发多次旋转(如左左、右右情况),维护成本较高。红黑树通过变色(如父节点和叔节点变黑、祖父节点变红)和最多三次旋转即可恢复平衡,实现更高效。

  3. ​适用场景

    红黑树适合频繁插入/删除的场景(如Java HashMap、Linux进程调度),平衡二叉树适合读多写少的场景(如数据库索引早期实现)。

MySQL索引的数据结构,为什么选择B+树?

  • 方便范围查询:叶子节点之间形成有序链表,支持范围查询和排序操作。
  • 减少磁盘IO次数:B+树相比于B树,非叶子节点只存放索引,存放了更多条目,树高度更矮,减少了fetch page,减少了磁盘IO次数。
  • 哈希索引:仅支持等值查询,无法范围查询)

MySQL事务出现死锁怎么办?除了顺序分配资源以外?

  • 设置超时:通过innodb_lock_wait_timeout参数自动回滚长时间等待的事务
  • 优化事务逻辑:减少事务粒度,长事务拆分为小事务;按固定顺序访问表或行
  • 重试机制:捕获死锁异常后自动重试(需业务层配合)

HTTP POST幂等性实现方案

  1. Token机制
    客户端首次请求生成唯一Token(如UUID),服务端通过Redis检查Token是否存在。若存在则拒绝重复请求,否则执行业务并存储Token

  2. 唯一业务标识
    利用数据库唯一约束(如订单号+状态字段),插入前校验是否已处理

  3. 乐观锁

    通过版本号(Version字段)控制更新操作,仅当版本匹配时才执行更新

过多出现time_wait的原因?如何处理?

  1. 主动关闭连接:服务端频繁关闭短连接(如HTTP请求未复用连接)。
  2. 高并发短连接:如Nginx反向代理默认使用短连接与后端交互。
  3. 高并发场景:
    在高并发短连接场景下(如爬虫、压测),短时间产生大量连接关闭操作,超出端口回收速度(默认 6.5 万端口上限),导致 address already in use 错误。

推荐方案 适用场景 风险提示
若是设置问题 开启Http长连接
系统层调优 调整 tcp_tw_reuse (开启端口复用)和端口范围 临时缓解端口耗尽
应用层优化 HTTP 长连接,连接池,确保服务端不主动关闭连接(调整服务器配置) 高并发业务
架构升级 负载均衡(请求发送到多台服务器) + 协议升级(使用支持服用的连接如http2/gRPC) 大规模分布式系统

如何处理?

  • 连接池管理
    在代码中引入连接池(如数据库、Redis 客户端),复用 TCP 连接,避免频繁创建/销毁

  • 避免服务端主动关闭
    确保服务端不主动关闭连接(如调整 HTTP 服务器配置),由客户端发起关闭

CLOSE_WAIT 过多原因与处理

  1. 应用未正确关闭Socket:被动关闭方未调用close()释放连接。
  2. 代码逻辑缺陷:如异常分支未关闭连接、线程阻塞未处理FIN报文。

解决方案:

  1. 检查代码:确保所有accept()返回的Socket最终调用close()。
  2. 设置超时

Reactor模型 vs Proactor模型

特性 Reactor Proactor
I/O模式 同步非阻塞(应用层处理I/O) 异步(操作系统处理I/O,应用处理回调)
核心组件 事件多路分离器(如epoll)、事件处理器 异步I/O接口(如IOCP)、完成事件队列
适用场景 高并发连接,I/O操作轻量(如Redis、Nginx) 高吞吐量,I/O密集型操作(如文件传输)
代码复杂度 较低(需自行管理读写缓冲区) 较高(依赖操作系统支持,linux往往不支持)

- reactor对象:监听和分发事件
- acceptor对象:获取连接
- handler对象:回调函数,处理业务

非阻塞同步网络模式:
非阻塞是指当前线程或进程发出read()请求后不会阻塞,而是会直接返回,可以进行下一步处理;此时应用程序不断轮询内核,直到内核将数据准备好;最后一次read()调用是一次同步的过程,等待内核将数据从内核拷贝到应用程序的缓冲区(用户空间)中。

reactor可以理解为,来了事件通知应用进程,应用进程来处理;proactor则是,来了事件操作系统进行处理,处理完再通知进程。

线程池实现逻辑与参数

核心参数:
  1. 核心线程数(corePoolSize)​:常驻线程数量。
  2. 最大线程数(maximumPoolSize)​:临时线程上限。
  3. 任务队列(workQueue)​:存储未执行任务(如无界队列LinkedBlockingQueue)。
  4. 拒绝策略(RejectedExecutionHandler)​:队列满时的处理逻辑(如丢弃、抛异常)。
关键函数:
  1. submit(Runnable task):提交任务到线程池。
  2. shutdown():平滑关闭(等待任务完成)。
  3. shutdownNow():强制终止所有线程。

进程创建过多线程的问题

  1. 内存耗尽:每个线程默认占用栈空间(如8MB),数万线程消耗数百GB内存。
  2. 上下文切换开销:频繁切换线程导致CPU利用率下降。
  3. 系统资源限制:超过ulimit -u的线程数上限(默认约几千)。

解决方案

  • 使用线程池限制线程数量。
  • 采用协程(如Go的Goroutine)替代线程。

TCP报文格式?

源端口、目标端口:16位,最大65535

序列号:32位

确认应答:32位

标志位(控制位):9位

窗口大小:16位

线程与进程的区别

维度 进程 线程
资源隔离性 独立内存空间,崩溃不影响其他进程 共享进程内存,线程错误可能导致整个进程崩溃
调度开销 上下文切换需保存内存、寄存器等,开销大 仅保存寄存器+栈指针,切换速度快
通信方式 需通过IPC(管道、共享内存等) 直接读写共享变量(需同步机制)
创建成本 高(需分配独立资源) 低(共享进程资源)
应用场景 高隔离性需求(如微服务) 高并发需求(如Web服务器处理请求)

每个线程独有的部分有哪些?(主要是栈、寄存器)

  1. 线程ID:操作系统用于标识线程的唯一编号
  2. 寄存器状态:包括程序计数器、栈指针等执行上下文
  3. 私有栈空间:存储局部变量和函数调用链(如递归深度)
  4. 线程优先级:调度器根据优先级分配CPU时间片

进程的切换,还包括虚拟内存

binlog的主从复制

流程:

  1. 主库写入Binlog:事务提交时,主库将数据变更记录到Binlog。
  2. 从库拉取Binlog:从库的IO线程连接主库,获取增量Binlog日志,写入Relay Log。
  3. 从库重放日志:从库的SQL线程解析Binlog,重放SQL或行数据变更。

主库用来写,从库用来读。

用户态和内核态的区别,为什么要区分用户态和内核态?

用户态(User Mode)​

  1. 权限限制

    • 应用程序运行在用户态,​无法直接访问硬件资源​(如磁盘、网络设备)或执行特权指令(如修改内存管理配置)。

内核态(Kernel Mode)​

  1. 最高权限

    • 操作系统内核运行在内核态,​可直接控制硬件​(如CPU、内存、I/O设备)。
    • 能执行所有特权指令(如修改页表、中断处理、进程调度)。

通过用户态和内核态的隔离,操作系统可以限制应用程序的权限,只有内核有最高权限,这样能更好地管理系统资源。

发送消息到接收消息的系统调用过程?

假设用户通过浏览器(如PDD面试平台)发送文本消息到服务器,再从服务器传送到接收方,以下是核心步骤及涉及的系统调用


1. 客户端发送消息
  • ​**(1) 用户输入消息到浏览器**:

    • 浏览器将文本存入内存缓冲区,无直接系统调用(用户态操作)。
  • ​**(2) 建立TCP连接(若尚未建立)​**:

    • 系统调用:socket()(创建套接字)、connect()(发起连接请求)。
    • 若需DNS解析:getaddrinfo()(解析域名到IP)。
  • ​**(3) 发送数据**:

    • 系统调用:send() 或 write()(将数据从用户缓冲区写入内核网络协议栈)。
    • 内核将数据封装为TCP包,通过网卡发送。

2. 服务器接收消息
  • ​**(1) 监听连接(若首次)​**:

    • 系统调用:socket()bind()(绑定端口)、listen()(开始监听)、accept()(接受连接)。
  • ​**(2) 读取数据**:

    • 系统调用:recv() 或 read()(从内核缓冲区读取数据到用户空间)。
    • 内核处理TCP/IP协议栈,解包数据。
  • ​**(3) 处理并转发消息**:

    • 应用逻辑处理(如消息存储或转发),无直接系统调用。

3. 接收方客户端接收消息
  • ​**(1) 接收数据**:

    • 系统调用:recv() 或 read()(从内核缓冲区读取数据)。
    • 内核处理TCP/IP协议栈。
  • ​**(2) 浏览器渲染消息**:

    • 无直接系统调用(用户态渲染页面)。

系统调用次数估计
  • 客户端发送:约 3-5次socketconnectsend等)。
  • 服务器处理:约 4-6次acceptrecvsend等)。
  • 接收方接收:约 2-3次recvread等)。

总计10-15次系统调用(具体次数依赖实现和网络状态)。


问题扩展:发送文件的差异?

如果发送的是文件而非文本,主要区别在文件读取和数据传输方式


1. 客户端发送文件的额外步骤
  • ​**(1) 读取文件内容**:

    • 系统调用:open()(打开文件)、read()(读取文件到用户缓冲区)、close()
    • 大文件可能分多次读取。
  • ​**(2) 数据处理**:

    • 可能需计算哈希值(如MD5):read()读取数据,多次调用加密相关函数。
    • 分块传输:多次调用send()发送文件块。

2. 服务器接收文件的额外步骤
  • ​**(1) 写入文件**:

    • 系统调用:open()(创建文件)、write()(写入接收的数据)、close()
    • 大文件分多次写入。
  • ​**(2) 完整性校验**:

    • 计算哈希值:多次read()读取已接收文件内容。

关键差异总结
步骤 文本消息 文件传输
数据来源 内存缓冲区(直接输入) 磁盘文件(需open/read
数据传输 单次或少量send() 多次read()和分块send()
数据存储 直接存入内存或数据库 write()到磁盘文件
完整性校验 通常无需 可能需计算哈希值(额外read调用)

总结

  • 文本消息:系统调用集中在网络通信(send/recv)。
  • 文件传输:额外涉及文件I/O(open/read/write)、分块处理和校验,系统调用次数显著增加(约 20-30次)。

有了mysql为什么还需要redis,redis用来解决什么问题?

Redis 主要用于解决 ​高性能、低延迟、高并发场景下的数据访问问题。

Redis 和 MySQL 协作的模式:

在实际应用中,Redis 和 MySQL 的结合往往是为了优化性能,尤其是在数据查询速度、读写压力大的情况下。

2.1 缓存层 + 数据库层
  • 使用 Redis 缓存数据:

    • Redis 作为缓存层,MySQL 作为持久化存储。Redis 缓存一些热点数据,减少数据库的访问压力,提高响应速度。

    • 典型应用场景:例如,电商系统中商品信息、用户信息等,可以缓存到 Redis 中。这样,频繁的查询直接从 Redis 中读取数据,避免了每次都查询 MySQL。

  • 实现方式:

    1. 在应用读取数据时,首先查询 Redis,如果缓存中有数据,直接返回;如果没有,查询 MySQL 数据库,并将结果写入 Redis 缓存中。

    2. 数据修改时,首先更新 MySQL 中的数据,然后删除或更新 Redis 缓存。

  • 优点:

    • 降低 MySQL 的查询压力,提高系统的响应速度。

    • 通过 Redis 提供的低延迟,减少对数据库的访问次数。

  • 缺点:

    • 需要处理缓存与数据库的一致性问题。

    • 如果缓存穿透或缓存雪崩没有处理好,可能会给 MySQL 带来过大的压力。

2.2 异步写入和队列机制
  • 使用 Redis 作为消息队列:

    • Redis 可以作为消息队列,将高并发的请求异步地写入 MySQL。例如,在某些高并发场景下,写操作可以通过 Redis 队列缓存,并异步地将这些操作批量写入 MySQL 数据库

    • 典型应用场景:例如,订单系统中,当用户下单时,可以将订单信息写入 Redis 队列,后台异步处理订单数据并持久化到 MySQL 中。

  • 优点:

    • 将高并发写操作异步化,避免对数据库造成过大压力。

    • 利用 Redis 的高吞吐量和低延迟,减少请求的等待时间。

  • 缺点:

    • 需要保证队列的可靠性,防止数据丢失。

    • 需要处理队列的堆积,避免消息处理过慢。

阻塞、非阻塞、同步和异步之间的关系?

        阻塞(Blocking)非阻塞(Non-blocking)是描述操作是否会使当前执行的线程或进程被挂起的概念。而同步(Synchronous)异步(Asynchronous)**则涉及操作如何协调执行时的等待行为和控制流。

概念 描述 例子
阻塞 操作会等待直到完成,当前线程被挂起。 同步文件读取,网络请求等待响应。
非阻塞 操作立即返回,当前线程不会被挂起。 异步文件读取,网络请求立刻返回。
同步 操作按顺序进行,后续操作需要等待当前操作完成。 顺序执行的函数调用,文件操作。
异步 操作可以在后台执行,不会阻塞当前线程。 网络请求、文件操作通过回调或事件完成。

算法

1.手撕LRU

2.Leetcode16 最接近的三数之和

3.对折链表

4.小于n的最大数

5.

题目:给定一个数n如23121;给定一组数字a如[2 4 9],求由a中元素组成的小于n的最大数(做了十分钟没做出来要求换题)
    题目:输入两颗二叉树,判断B是否是A的子结构约定空树不是任意树的子结构(eazy题)
链接:字节生活服务后端开发日常实习一二三面经_牛客网
6.

算法:三数之和去重;最长公共子序列;

7.

算法题:至少有 K 个重复字符的最长子串;接雨水


网站公告

今日签到

点亮在社区的每一天
去签到