Skip to content

Latest commit

 

History

History
1397 lines (817 loc) · 48.1 KB

File metadata and controls

1397 lines (817 loc) · 48.1 KB

面试题

无法跳转到题目请在右侧目录索引中输入对应题目的序号点击即可

1. Java三大特性

Java 的三大特性是:

  1. 封装(Encapsulation) 👉 把数据和操作封装到类中,对外只暴露必要接口,隐藏内部实现。 👉 比如用 private 修饰属性,提供 get/set 方法。

  2. 继承(Inheritance) 👉 子类自动拥有父类的属性和方法,提高代码复用性。 👉 Java 是单继承,多实现(类只能继承一个类,但可以实现多个接口)。

  3. 多态(Polymorphism) 👉 同一个方法在不同对象上表现不同的行为。 👉 常见形式有方法重载(编译时)和方法重写(运行时)。

一句话总结:

封装保证安全,继承提高复用,多态提升灵活性,是面向对象的三大核心。

2. Java的基本数据类型和占用大小 (8种)

Java 一共有 8 种基本数据类型:

类型 占用空间 默认值 描述
byte 1 字节 0 整型,范围 -128 ~ 127
short 2 字节 0 整型
int 4 字节 0 默认整型
long 8 字节 0L 大整数
float 4 字节 0.0f 单精度小数
double 8 字节 0.0d 双精度小数,默认浮点型
char 2 字节 '\u0000' 单个字符
boolean ~1 字节* false 只有 true/false

注:boolean 在 JVM 中并没有明确规定大小,一般按一个字节处理。

一句话记忆法:

“4整(byte、short、int、long),2浮(float、double),1字(char),1布(boolean)”

3. SpringBoot最重要的注解 其他常用注解

Spring Boot 最重要的注解是:

** @SpringBootApplication**

它是 Spring Boot 的入口注解,相当于三个注解的组合

@SpringBootApplication = 
    @SpringBootConfiguration +
    @EnableAutoConfiguration +
    @ComponentScan

📌作用总结一句话:

“它表示这是一个 Spring Boot 应用的入口,能开启自动配置和组件扫描。”

其他常用注解(按功能分类):

  1. 组件类注解(用于创建 Bean):
  • @Component:通用组件
  • @Service:业务逻辑层
  • @Repository:持久层(自动处理异常转换)
  • @Controller / @RestController:控制层(前端接口)
  1. 依赖注入
  • @Autowired:自动注入 Bean(按类型)
  • @Value:注入配置值(如 application.yml)
  1. 配置和自动化相关
  • @Configuration:定义配置类
  • @Bean:在配置类中手动注册 Bean
  • @EnableAutoConfiguration:开启自动配置(Spring Boot 核心)
  • @ConditionalOnXXX:条件装配(Spring Boot 特有)
  1. Web 开发相关
  • @RequestMapping / @GetMapping / @PostMapping:映射 HTTP 请求
  • @RequestParam / @PathVariable / @RequestBody:绑定请求参数
  1. 其他常见注解
  • @Slf4j:自动引入日志对象(Lombok)
  • @Transactional:声明式事务管理
  • @Entity@Table@Id:JPA 注解(用于 ORM)

一句话总结:

“Spring Boot 最核心的是 @SpringBootApplication,其他常用注解分为组件、注入、配置、Web 等几类,配合自动装配机制,极大简化了开发流程。”

4. Mysql当中主从复制是怎么实现的

MySQL 主从复制是怎么实现的?

MySQL 主从复制本质是**基于二进制日志(binlog)**的异步复制机制,主要步骤:

  1. 主库(Master)写操作产生 binlog 所有对数据库的写操作(insert、update、delete)都会记录到主库的二进制日志中。

  2. 从库(Slave)通过 IO 线程读取主库 binlog 从库启动一个 IO 线程,连接主库,实时拉取 binlog 并保存到本地的中继日志(relay log)中。

  3. 从库 SQL 线程执行中继日志 从库启动 SQL 线程,读取中继日志内容,执行写操作,实现数据同步。

  4. 复制过程异步进行 主库不等待从库完成复制,写操作性能影响小,但可能有短暂延迟。

一句话总结:

MySQL 主从复制通过主库写二进制日志,从库拉取并执行日志,保持数据同步,是异步复制机制。

补充点:

  • 复制模式:异步、半同步、组复制等,主流是异步复制;
  • 复制延迟:从库滞后于主库,可能导致读数据不一致;
  • 主从切换:备份与容灾方案关键。

5. Mysql中隔离级别 怎么解决幻读

MySQL 的隔离级别有哪些?

MySQL 支持四个标准的隔离级别:

  1. 读未提交(Read Uncommitted) — 会发生脏读、不可重复读和幻读;
  2. 读已提交(Read Committed) — 解决脏读,但仍可能出现不可重复读和幻读;
  3. 可重复读(Repeatable Read) — 解决脏读和不可重复读,MySQL 默认级别;
  4. 可串行化(Serializable) — 最高级别,防止所有并发问题,包括幻读。

幻读怎么解决?

  • MySQL 在默认的 Repeatable Read 级别下,通过 间隙锁(Gap Lock)临键锁(Next-Key Lock) 实现对范围的锁定,防止其他事务在范围内插入新行,从而避免幻读问题。

  • 所以,MySQL 的 Repeatable Read 实际上解决了幻读,这和标准 SQL 理论有一点不同。

一句话总结:

MySQL 默认的 Repeatable Read 隔离级别通过间隙锁机制避免了幻读。

6. Mysql中四大特性, 原子性是怎么实现的,持久性是什么实现的

MySQL 四大事务特性(ACID):

  1. 原子性(Atomicity) 事务中的操作要么全部完成,要么全部不做,不会停留在中间状态。

  2. 一致性(Consistency) 事务执行前后,数据库都保持合法状态,数据规则不被破坏。

  3. 隔离性(Isolation) 多个事务并发执行时,互不干扰,仿佛是串行执行。

  4. 持久性(Durability) 一旦事务提交,结果永久保存,即使系统崩溃也不会丢失。

原子性是怎么实现的?

  • MySQL 通过**日志机制(Undo Log + Redo Log)**保证原子性。
  • Undo Log 用于事务回滚,能撤销未完成的修改,保证“全做或全不做”。
  • 事务提交时,Redo Log 确认写入磁盘,保证修改持久。

持久性是怎么实现的?

  • 通过 Redo Log(重做日志) 实现。
  • 数据修改先写入Redo Log,并刷盘,确保即使数据库崩溃,也能通过重做日志恢复数据。
  • 另外,MySQL 还定期将内存中的数据页刷新到磁盘(刷脏页),保证数据持久。

一句话总结:

原子性靠 Undo Log 支持回滚,持久性靠 Redo Log 保证数据即使崩溃也能恢复。

7. 服务端渲染和客户端渲染的区别

服务端渲染(SSR)和客户端渲染(CSR)的区别:

特点 服务端渲染(SSR) 客户端渲染(CSR)
页面生成位置 服务器生成完整 HTML 页面 浏览器用 JavaScript 渲染页面
首屏加载速度 快,页面直接返回完整内容 慢,先加载空白页面再执行 JS 渲染
SEO 友好度 好,搜索引擎能直接抓取内容 差,需额外配置 SSR 或预渲染
交互响应性 依赖服务器,用户操作需更多请求 快,交互大多在客户端完成
开发复杂度 相对复杂,需服务器支持 简单,纯前端开发

一句话总结:

服务端渲染页面由服务器生成,首屏快且 SEO 好;客户端渲染页面由浏览器生成,交互更流畅但首屏较慢。

8. 网页完整的渲染过程

网页完整的渲染过程:

  1. 浏览器发送请求 浏览器向服务器发送 HTTP 请求,获取网页资源(HTML、CSS、JS 等)。

  2. 服务器响应 服务器返回 HTML 文档。

  3. HTML 解析生成 DOM 树 浏览器开始解析 HTML,生成 DOM(文档对象模型)树。

  4. CSS 解析生成 CSSOM 树 浏览器解析 CSS 文件和内联样式,生成 CSSOM(CSS 对象模型)树。

  5. 构建渲染树(Render Tree) 浏览器将 DOM 树和 CSSOM 树结合,生成渲染树,只包含需要显示的节点。

  6. 布局(Layout 或 Reflow) 浏览器计算渲染树中每个节点的几何信息(大小、位置)。

  7. 绘制(Paint) 浏览器将布局信息转换成屏幕上的像素,绘制到屏幕。

  8. 执行 JavaScript 浏览器解析并执行 JS 脚本,可能会修改 DOM 或 CSSOM,触发重绘或回流。

一句话总结:

浏览器请求资源,解析 HTML 和 CSS 生成渲染树,计算布局并绘制页面,同时执行 JavaScript 动态修改页面。

9. 进程和线程的区别

进程和线程的区别:

特点 进程(Process) 线程(Thread)
定义 操作系统资源分配的基本单位 CPU 调度的基本单位
资源拥有 拥有独立的内存空间和系统资源 共享所属进程的内存和资源
创建销毁 创建销毁开销较大 创建销毁开销较小
通信方式 进程间通信(IPC)较复杂 线程间通信直接访问共享内存
调度 由操作系统调度 由进程内的调度器管理
稳定性 一个进程崩溃不影响其他进程 一个线程异常可能影响整个进程

一句话总结:

进程是资源分配的独立单位,线程是执行调度的最小单位,线程共享进程资源,通信更高效。

10. 进程间的通讯方式

进程间通信的常见方式:

  1. 管道(Pipe)

    • 只能在有亲缘关系的进程间通信(如父子进程)。
    • 数据以字节流形式单向传输。
  2. 命名管道(Named Pipe / FIFO)

    • 支持无亲缘关系进程间通信。
    • 通过名字访问,依然是字节流。
  3. 消息队列(Message Queue)

    • 以消息为单位传递,支持异步通信。
    • 操作系统维护队列,进程读写消息。
  4. 共享内存(Shared Memory)

    • 不同进程共享一块内存区域,速度最快。
    • 需要同步机制(如信号量)保证数据一致。
  5. 信号量(Semaphore)

    • 主要用于进程同步,控制访问共享资源的数量。
    • 常与共享内存结合使用。
  6. 套接字(Socket)

    • 适用于网络通信,也可用于本地进程通信。
    • 支持跨机器通信。

一句话总结:

进程间通信方式多样,管道和消息队列适合简单传输,共享内存速度快但需同步,套接字适合网络通信。

11. 线程间的通讯方式,多个服务,单服务

线程间通信的方式

  1. 单服务(同一进程内多线程)
  • 共享内存 线程共享进程的内存空间,直接读写共享变量是最常见的通信方式。

  • 同步机制 为避免竞态条件,常用锁机制保证线程安全,比如:

    • synchronized(Java)
    • Lock 接口(如 ReentrantLock)
    • 信号量(Semaphore)
    • 监视器(wait/notify)
  • 线程间消息队列 如 Java 中的 BlockingQueue,线程通过队列安全传递数据。

  1. 多服务(跨进程或分布式服务间通信)
  • 网络通信

    • HTTP/REST API
    • RPC(如 gRPC、Thrift)
    • WebSocket
  • 消息中间件

    • Kafka、RabbitMQ、ActiveMQ 等消息队列
    • 用于异步解耦和流量削峰
  • 共享存储

    • Redis、数据库等作为通信介质

一句话总结:

同一进程内线程通信靠共享内存和同步机制,多服务间通信靠网络协议和消息中间件。

12. Linux常见命令 ,搜索等

Linux 常用命令(重点是搜索相关)

命令 作用 简要说明
ls 列出目录内容 ls -l 查看详细信息
cd 切换目录 cd .. 返回上级目录
pwd 显示当前路径
cp 复制文件或目录
mv 移动或重命名文件
rm 删除文件或目录 rm -r 删除目录及内容
cat 查看文件内容
more/less 分页查看文件 less 支持上下翻页
grep 文件内容搜索 grep "关键词" 文件名
find 查找文件 find /path -name "file.txt"
locate 快速查找文件 依赖数据库,先更新 updatedb
ps 查看进程 ps aux 查看所有进程
top 实时查看系统资源
chmod 修改文件权限
chown 修改文件所有者
tar 打包/解包 tar -zxvf 解压 tar.gz 文件

搜索相关重点命令:

  • grep:按内容搜索,常用配合管道符,例如 ps aux | grep java 查找 java 进程
  • find:按文件名查找,支持复杂条件,如时间、大小等
  • locate:速度快,基于索引数据库,但不适合实时文件变化

一句话总结:

Linux 搜索文件用 findlocate,搜索内容用 grep,结合管道能高效定位。

13. Linux通讯命令,通讯原理是什么

Linux 通讯常用命令:

命令 作用 简要说明
ping 测试网络连通性 通过 ICMP 协议检测目标是否可达
traceroute 跟踪路由路径 显示数据包经过的路由节点
netstat 显示网络连接状态 查看端口、连接、路由等
ss 替代 netstat,显示套接字 显示 TCP、UDP 连接
ifconfig / ip 配置或查看网络接口 ip 是新命令,功能更强大
telnet 测试端口连通性 连接到远程端口,调试服务
nc (netcat) 读写网络连接,端口监听 简易的 TCP/UDP 客户端和服务器
curl 网络请求工具 测试 HTTP、FTP 等协议
wget 命令行下载工具 支持 HTTP、FTP

Linux 通讯原理简述:

  • 基于 TCP/IP 协议栈 Linux 网络通信遵循 TCP/IP 协议族,主要负责数据的传输和路由。

  • 套接字(Socket)通信机制 网络通信核心是套接字,应用程序通过套接字接口进行数据发送和接收。

  • 数据包在内核中传递 应用层的数据经过传输层(TCP/UDP)、网络层(IP)、链路层处理,封装成数据包发送。

  • 网络设备驱动负责物理传输 包括以太网卡、无线网卡等硬件,完成实际的信号传输。

一句话总结:

Linux 网络通信依赖 TCP/IP 协议和套接字机制,常用命令如 ping、netstat 和 nc 用于测试和调试网络连接。

14. tcp三次握手,为什么必须要三次

TCP 三次握手是什么?

TCP 三次握手是建立一个可靠连接的过程,目的是双方确认彼此的发送和接收能力,确保连接可靠。

为什么必须要三次?

  1. 第一次握手(SYN):客户端发送 SYN 包(请求连接),告诉服务器客户端的初始序列号(Seq)。

  2. 第二次握手(SYN-ACK):服务器收到后,回复 SYN-ACK 包,确认客户端的序列号(Ack = Seq + 1),并发送自己的序列号。

  3. 第三次握手(ACK):客户端收到后,发送确认包 ACK,确认服务器的序列号(Ack = 服务器 Seq + 1)。

为什么不能少于三次?

  • 第一次握手只确认客户端请求连接,服务器不知道客户端是否准备好接收数据。

  • 第二次握手确认了客户端请求,并且告诉客户端服务器也准备好,但客户端还没确认服务器的状态。

  • 第三次握手确保客户端和服务器双方都已确认对方的接收能力,连接正式建立。

一句话总结:

三次握手确保双方收发能力互相确认,保证连接建立时双方都准备好可靠通信。

15. hashmap底层原理,有哪些线程安全的map

HashMap 底层原理:

  • 结构:基于数组 + 链表(JDK7)/数组 + 链表 + 红黑树(JDK8 及以后)实现。
  • 存储:通过 key 的 hashCode() 计算哈希值,定位数组索引。
  • 冲突处理:哈希冲突时,链表存储相同索引的多个元素,元素多到一定阈值会转成红黑树,提升查找效率。
  • 扩容机制:当负载因子超过 0.75 时,HashMap 会自动扩容,容量翻倍,并重新计算元素位置。
  • 线程安全:HashMap 本身 非线程安全,多线程并发访问可能导致数据不一致或死循环。

线程安全的 Map 实现:

  1. Hashtable

    • 早期线程安全的实现,所有方法都加了 synchronized,性能较低。
  2. Collections.synchronizedMap(Map<K,V>)

    • 通过包装普通 Map,方法加同步,适合低并发场景。
  3. ConcurrentHashMap

    • 高性能线程安全实现,采用分段锁(JDK7)和 CAS + 锁结合(JDK8),支持高并发。
  4. ConcurrentSkipListMap

    • 线程安全的有序 Map,基于跳表实现,支持并发访问。

一句话总结:

HashMap 用数组加链表/红黑树存储元素,非线程安全;线程安全的有 Hashtable、同步包装的 Map 和高性能的 ConcurrentHashMap。

16. springboot启动注解是什么,内部的三个实际注解讲一下

Spring Boot 启动注解是什么?

@SpringBootApplication 是启动注解,标记主程序入口。

它内部包含的三个主要注解:

  1. @SpringBootConfiguration

    • 标明这是一个配置类,继承自 @Configuration,告诉 Spring 这是一个配置文件。
  2. @EnableAutoConfiguration

    • 启用自动配置,根据类路径和配置自动装配相关的 Bean,减少手动配置。
  3. @ComponentScan

    • 开启组件扫描,自动发现和注册 @Component@Service@Controller 等 Bean。

补充说明

  • 这三个注解组合起来,实现了 Spring Boot 应用的“约定优于配置”理念。
  • @SpringBootApplication 让你只需要写一个注解就能完成配置和扫描。

一句话总结:

@SpringBootApplication 是启动注解,包含配置声明、自动配置和组件扫描三大功能,简化 Spring Boot 项目启动流程。

17. MySQL事务,事务特性

MySQL 事务是什么?

事务是一组要么全部执行成功、要么全部不执行的操作,保证数据的一致性和完整性。

事务的四大特性(ACID):

  1. 原子性(Atomicity) 事务中的操作是一个不可分割的整体,要么全部成功,要么全部失败。

  2. 一致性(Consistency) 事务执行前后,数据库的状态必须保持一致,不违反任何约束。

  3. 隔离性(Isolation) 并发执行的事务互不干扰,事务之间的操作彼此隔离。

  4. 持久性(Durability) 事务一旦提交,其结果是永久保存的,即使系统崩溃也不会丢失。

一句话总结:

MySQL 事务保证操作的原子性、一致性、隔离性和持久性,确保数据安全可靠。

18. HTTP/1.1 具体特点

  • 支持 持久连接(Connection: keep-alive),减少建立连接开销
  • 支持 管道化(Pipelining),但浏览器支持不完善
  • 支持 分块传输编码,服务器可以边生成边发送响应
  • 增加了更多的缓存控制和请求头字段
  • 请求和响应头部较大,文本格式,效率较低

19.. Promise 的特点

  • 用于解决异步操作的回调地狱
  • 状态不可变(pending → fulfilled/rejected)
  • 支持链式调用 .then()
  • 提供错误捕获 .catch()
  • 可以并发处理多个异步操作(Promise.all

20.. localStorage,sessionStorage,cookie 区别

存储类型 存储位置 生命周期 大小限制 作用域 是否随请求发送给服务器
localStorage 浏览器 永久保存(除非手动清除) 5-10MB 同源
sessionStorage 浏览器 会话结束即清除 5MB 同源,且窗口/标签独立
cookie 浏览器 可设置过期时间 4KB 同源,且路径可细分 是,随请求发送服务器

21. 反转链表

  • 通过迭代或递归将链表的 next 指针反转
  • 迭代思路:用三个指针 prevcurrnext 依次改变链接方向
  • 时间复杂度 O(n),空间复杂度 O(1)

22. useCallback,useMemo,memo

  • useCallback(fn, deps):缓存函数实例,避免不必要的函数重创建
  • useMemo(fn, deps):缓存函数的返回值,避免重复计算
  • memo(Component):高阶组件,缓存组件输出,防止不必要的重新渲染

23. memo 的原理(props变化时重新渲染)

  • memo 会浅比较前后 props
  • 如果 props 没变化,跳过渲染,复用上次结果
  • 如果 props 变化,重新渲染组件

24. CSS3 新特性

  • 弹性盒模型(Flexbox)
  • 动画和过渡(Animation & Transition)
  • 媒体查询(Media Queries)
  • 圆角(border-radius)
  • 阴影(box-shadow & text-shadow)
  • 渐变(linear-gradient、radial-gradient)
  • 多列布局(multi-column)

25. Flex 布局

  • 容器设置 display: flex
  • 方向:flex-direction (row, column)
  • 主轴对齐:justify-content
  • 交叉轴对齐:align-items
  • 子项可伸缩:flex-grow, flex-shrink, flex-basis

26. ES6 新特性

  • letconst 声明变量
  • 箭头函数 ()=>{}
  • 模板字符串 `text ${var}`
  • 解构赋值
  • 扩展运算符 ...
  • Promise
  • 模块化 import/export
  • 默认参数、剩余参数
  • 类和继承
  • Symbol 类型

27. 数组方法

  • 遍历类forEachmap
  • 过滤类filter
  • 归约类reduce
  • 查找类findfindIndex
  • 判断类someevery
  • 排序sort
  • 添加/删除pushpopshiftunshiftsplice
  • 复制slice
  • 扁平化flat

28. 为什么用 gRPC?

  • 高性能:基于 HTTP/2,支持多路复用、二进制传输,速度快、延迟低
  • 强类型接口:用 Protocol Buffers 定义接口,自动生成代码,类型安全
  • 多语言支持:支持多种编程语言,方便跨平台微服务通信
  • 双向流:支持客户端、服务器流式数据传输,灵活高效
  • 简单易用:接口定义明确,调用像本地函数一样简洁

29. 如果大量数据写入 MySQL 会发生什么?

  • 写性能压力大,可能导致延迟增加
  • 锁竞争加剧,特别是 InnoDB 表的行锁/表锁,可能引发阻塞
  • 主库负载上升,写多会影响主从复制效率
  • 磁盘 IO 增加,可能导致 IO 瓶颈
  • 二进制日志变大,影响复制和恢复速度

30. MySQL 主从复制怎么实现的?

  • 主库将所有写操作记录到 二进制日志(binlog)
  • 从库启动 IO 线程连接主库,拉取 binlog 并写入 中继日志(relay log)
  • 从库启动 SQL 线程,执行中继日志,完成数据同步
  • 这种复制是异步的,主库不等待从库确认

31. 主从复制延迟的原因?

  • 网络延迟,从库拉取 binlog 有延时
  • 从库负载高,执行中继日志慢
  • 大事务或慢查询导致执行阻塞
  • IO 瓶颈,磁盘写入速度限制
  • 复制线程阻塞,比如锁竞争或资源争用

32. Redis 预检成功,数据库扣减失败怎么办?

  • 这是分布式事务一致性问题,常用方案有:

    • 补偿机制:失败后回滚 Redis 预检的操作(比如增加库存)
    • 消息队列异步重试,确保数据库扣减最终完成
    • 分布式事务框架(如 Seata)保证跨系统事务原子性

33. 用过压测吗,有什么指标?

  • 压测指标常见的有

    • TPS/QPS(每秒事务/请求数)
    • 响应时间(平均、最大、百分位数,如P99)
    • 错误率(失败请求占比)
    • 系统资源利用率(CPU、内存、磁盘IO、网络带宽)
    • 并发数(同时在线用户数或请求数)

34. 分布式锁逻辑,底层原理

  • 基本逻辑:利用外部存储(Redis、Zookeeper等)作为锁的存储媒介,确保同一时刻只有一个客户端持有锁
  • Redis分布式锁实现:通过 SET key value NX PX timeout 命令原子性设置锁,使用唯一标识防止误释放
  • 原理:利用原子操作和过期时间防止死锁和锁遗失
  • Redlock 算法:多 Redis 实例实现更高可用和安全的分布式锁

35. 讲讲大模型相关

  • 大模型通常指参数量非常巨大的深度学习模型(如 GPT、BERT)
  • 优点:具备强大的泛化和理解能力,支持多任务
  • 挑战:训练成本高,推理慢,部署资源需求大
  • 主要技术包括:模型压缩、蒸馏、分布式训练、多模态融合

36. 抖音消息推送架构设计讨论

  • 瓶颈和压力点

    • 大量粉丝推送,消息并发量巨大,带宽和消息处理能力压力大
    • 单点发送或数据库瓶颈导致推送延迟或失败
  • 优化方案

    • 消息队列异步处理,削峰填谷
    • 推模式改拉模式,结合用户在线状态分批拉取消息
    • 分层缓存(Redis等)存储消息
    • 使用CDN和分布式服务减少延迟

37. 生产者-消息队列-消费者的瓶颈及消息积压问题

  • 瓶颈:消息生产速度远超消费速度导致积压

  • 解决措施

    • 扩容消费者,提高消费能力
    • 优化消费逻辑,减少处理时间
    • 限流或降级保护,防止流量暴涨
    • 使用高性能消息队列(Kafka、RocketMQ)

38. 数据库写入压力大怎么优化?

  • 分库分表:水平拆分减少单库压力
  • 读写分离:写主库,读从库
  • 缓存:用 Redis 缓存热点数据减少 DB 访问
  • 批量写入:减少单次写操作次数
  • 异步写入:通过消息队列缓冲写请求
  • 优化索引和 SQL:避免全表扫描

39. redis三大缓存问题和解决方案

Redis 三大缓存问题及解决方案

  1. 缓存穿透

    • 问题:查询一个数据库中不存在的数据,缓存和数据库都没有,导致请求直接穿透到数据库,造成压力。

    • 解决方案

      • 缓存空结果(比如缓存空对象,设置较短过期时间)
      • 使用布隆过滤器(Bloom Filter)提前过滤不存在的请求
  2. 缓存击穿

    • 问题:某个热点数据在缓存过期瞬间,大量请求同时到达数据库,造成数据库压力骤增。

    • 解决方案

      • 使用互斥锁(分布式锁)保证只有一个请求去加载数据,其他等待
      • 提前异步刷新热点数据,避免缓存失效瞬间大量请求
  3. 缓存雪崩

    • 问题:大量缓存同时过期,导致大量请求直接访问数据库,可能导致数据库崩溃。

    • 解决方案

      • 缓存过期时间加随机值,错开失效时间
      • 多级缓存(本地缓存 + Redis)
      • 采用降级策略或限流保护数据库

一句话总结:

缓存穿透防空结果或用布隆过滤器,缓存击穿用锁或提前加载,缓存雪崩用随机过期和多级缓存来解决。

40. 布隆原理

布隆过滤器原理:

  • 布隆过滤器是一种空间效率很高的概率型数据结构,用来判断一个元素是否可能存在于集合中。

  • 它由一个位数组和多个哈希函数组成。

  • 添加元素时:用多个哈希函数对元素进行哈希,得到多个数组下标,将对应位设为1。

  • 查询元素时:用相同的哈希函数计算元素位置,检查对应位是否都为1。

    • 如果有任意一位是0,说明元素一定不存在
    • 如果所有位都是1,说明元素可能存在(存在误判)。

特点

  • 优点:空间和查询时间都很高效。
  • 缺点:存在误判率(可能判断存在但实际不存在),但不会漏判(不存在判定为不存在)。

一句话总结:

布隆过滤器用多个哈希函数和位数组快速判断元素是否可能存在,牺牲少量准确性换取高效性能和低空间。

41. 屏障的原理

屏障的原理:

  • 屏障允许多个线程在某个点相互等待,直到所有线程都达到这个点,才一起继续执行。
  • 线程到达屏障时会阻塞,并增加计数器。
  • 当计数器达到预设的线程数,屏障触发,所有等待的线程同时被释放。
  • 这保证了所有线程在屏障点同步,防止部分线程提前执行。

常见实现:

  • Java 中的 CyclicBarrierCountDownLatch 都是屏障的典型实现。
  • CyclicBarrier 可以重复使用,支持线程达到屏障后执行一个回调动作。

一句话总结:

屏障通过计数等待所有线程达到同步点,确保线程集体同时继续执行。

42. 装饰器、列表表达式

  1. 装饰器(Decorator)
  • 装饰器是一种函数,用来包装另一个函数,增强或修改其行为,不改变原函数代码。
  • 通过**@语法糖**应用。
  • 本质上是一个高阶函数,接收函数作为参数并返回一个新函数。

示例

def decorator(func):
    def wrapper():
        print("Before call")
        func()
        print("After call")
    return wrapper

@decorator
def say_hello():
    print("Hello")

say_hello()
  1. 列表表达式(List Comprehension)
  • 用简洁语法创建列表,替代传统的 for 循环添加元素
  • 语法结构:[表达式 for 变量 in 可迭代对象 if 条件]

示例

squares = [x*x for x in range(10) if x % 2 == 0]
print(squares)  # 输出 [0, 4, 16, 36, 64]

一句话总结:

装饰器是包装函数,修改行为;列表表达式是快速生成列表的简洁语法。

43. HTTP 常见状态码

  • 200 OK:请求成功
  • 301 Moved Permanently:永久重定向
  • 302 Found:临时重定向
  • 400 Bad Request:请求参数错误
  • 401 Unauthorized:未授权
  • 403 Forbidden:禁止访问
  • 404 Not Found:资源未找到
  • 500 Internal Server Error:服务器内部错误
  • 503 Service Unavailable:服务不可用

44. GET, PUT, POST

  • GET:请求获取资源,不改变服务器状态,幂等。
  • POST:提交数据,可能创建资源或改变状态,不幂等。
  • PUT:更新或创建资源,幂等。

45. PUT 和 POST 最主要的区别

  • PUT 是幂等的,发送相同请求多次结果相同(通常更新资源)。
  • POST 不幂等,发送多次可能创建多个资源或有不同效果。

46. Nginx

  • 高性能的反向代理服务器和负载均衡器,常用做静态资源服务器和反向代理。

47. 负载均衡

  • 将请求分发到多个后端服务器,提升系统吞吐和可靠性。

48. 反向代理

  • 代理服务器接收客户端请求,将请求转发给后端服务器,隐藏真实服务器信息。

49. 如何修改 Nginx 配置

  • 编辑配置文件(如 /etc/nginx/nginx.confsites-enabled 下文件),修改后用命令 nginx -t 测试配置,最后执行 nginx -s reload 重载配置。

50. Git 查看历史提交记录

  • git log 查看详细提交历史
  • git log --oneline 简洁模式

51. Git 回退版本

  • git reset --hard <commit_id> 回退到指定版本(危险,慎用)
  • git revert <commit_id> 生成新提交,撤销某次提交

52. Postman 高级功能

  • 环境变量管理
  • 脚本测试(Pre-request Script、Tests)
  • Collection Runner 运行批量请求
  • Mock Server 模拟接口

53. JMeter 作用

  • 性能测试工具,用于压力测试、负载测试和功能测试,模拟多用户并发访问。

54. 怎么定义权限?

  • 权限是控制用户对系统资源访问的规则。

  • 通常通过**角色(Role)+ 权限(Permission)**模型管理。

  • 主要方式有:

    • 基于角色的访问控制(RBAC):用户绑定角色,角色有权限。
    • 基于属性的访问控制(ABAC):根据用户属性、资源属性、环境等动态判断。
  • 在系统中通过鉴权中间件或框架(如 Spring Security)实现权限校验。

55. @Transactional 注解的原理?

  • @Transactional 是 Spring 事务管理的声明式注解。
  • 通过**AOP(面向切面编程)**拦截标注方法,开启事务管理器管理的事务。
  • 运行时,切面在方法调用前开启事务,方法正常结束提交事务,出现异常回滚事务。
  • 底层依赖事务管理器(如 DataSourceTransactionManager)操作数据库连接和事务。

56. 为什么 Caffeine 做一级缓存,Redis 做二级缓存?

  • Caffeine 是本地缓存,存储在应用内存,访问速度快,适合频繁读写的热数据,减少网络开销。
  • Redis 是分布式缓存,跨进程共享,容量大,支持持久化和多实例,保证数据在多应用间一致。
  • 结合使用,Caffeine 缓存热点数据提升性能,Redis 保证多服务数据共享和一致性。

57. ES(Elasticsearch)相关使用

  • 用于全文搜索和分析,支持分布式、实时查询。
  • 主要操作:索引管理、文档增删改查、DSL 查询、聚合分析。
  • 常用场景:日志分析、电商搜索、推荐系统。

58. 如何排查 bug

  • 复现问题,查看日志和异常堆栈。
  • 使用调试工具(IDE调试器、断点)定位。
  • 打印关键信息,排除法定位。
  • 结合版本控制回退对比代码。
  • 使用监控系统查看系统指标。

59. Docker 相关使用

  • 容器化应用,镜像构建与管理。
  • 主要命令:docker builddocker rundocker psdocker logs
  • Dockerfile 编写定义镜像。
  • 容器编排(Docker Compose/Kubernetes)管理多容器应用。

60. 如何进行性能优化

  • 代码层面优化(算法、数据结构、避免重复计算)。
  • 数据库优化(索引、SQL调优、读写分离)。
  • 缓存使用(本地缓存、分布式缓存)。
  • 异步处理(消息队列、任务调度)。
  • 资源监控与瓶颈分析。

61. 项目中 LRU 算法是否还有优化空间?

  • 可以结合时间和频率,如 LFU 或者 LRU+LFU 混合策略。
  • 利用更高效的数据结构减少操作复杂度。
  • 结合应用场景动态调整缓存容量。

62. 有没有遇到性能调优的瓶颈?

  • 常见瓶颈有数据库 IO、网络延迟、锁竞争、CPU 限制。
  • 解决方法通常是拆分服务、分库分表、缓存、异步处理、水平扩展。

63. 对于 RabbitMQ 的使用

  • 可靠的消息中间件,支持多种交换机类型(direct、fanout、topic)。
  • 用于异步任务、削峰填谷、解耦服务。
  • 支持消息确认、持久化、死信队列。
  • 配合消费者限流和重试机制提高稳定性。

64. 网址到浏览器显示的全过程:

  1. 输入 URL 浏览器解析 URL,提取协议、域名、端口和路径。

  2. DNS 解析 查询域名对应的 IP 地址,可能有本地缓存、系统缓存或向 DNS 服务器请求。

  3. 建立 TCP 连接 通过三次握手与服务器建立 TCP 连接。

  4. 发送 HTTP 请求 浏览器向服务器发送 HTTP 请求报文。

  5. 服务器响应 服务器返回 HTTP 响应,包括状态码、响应头和响应体(HTML 等)。

  6. 浏览器解析 HTML 解析 HTML,构建 DOM 树。

  7. 下载资源 解析过程中遇到 CSS、JS、图片等资源,浏览器发起并发请求下载。

  8. 构建 CSSOM 解析 CSS,生成 CSSOM 树。

  9. 生成渲染树 DOM 和 CSSOM 合并生成渲染树(Render Tree)。

  10. 布局(回流) 计算每个节点的几何信息(大小和位置)。

  11. 绘制(重绘) 根据渲染树绘制像素,显示到屏幕。

65. 浏览器怎样把资源显示出来?

  • 通过构建 DOM 和 CSSOM,生成渲染树。
  • 计算布局信息,确定页面元素位置和尺寸。
  • 将内容绘制到屏幕的图层上,完成页面渲染。
  • JS 执行可能触发布局或重绘,动态更新页面。

66. Linux 的 readwrite

  • read 从文件或设备读取数据到用户空间缓冲区。
  • write 将用户空间数据写入文件或设备。
  • 这两个调用涉及内核态和用户态切换,数据一般会经过内核缓冲区。

67. 零拷贝 DMA

  • DMA(Direct Memory Access)允许硬件设备直接与内存交换数据,绕过 CPU,减少数据复制次数
  • 零拷贝技术利用 DMA 直接在用户缓冲区和设备间传输数据,提高效率,减少 CPU 负载。

68. 内核态和用户态切换

  • 用户态是运行应用程序的状态,内核态是运行操作系统核心代码的状态。
  • 切换时 CPU 需保存当前状态,切换权限级别,执行内核代码(系统调用或中断处理),切换代价较高。
  • 频繁切换会影响性能。

69. HTTP/3.0

  • 基于 QUIC 协议(UDP+多路复用+加密),替代 TCP,减少连接建立和传输延迟。
  • 支持更快的连接恢复和拥塞控制。
  • 更适合移动和不稳定网络环境。

70. 网络下载慢的原因

  • 带宽限制
  • 网络延迟和丢包
  • 服务器负载高或限速
  • TCP 慢启动或拥塞控制影响
  • DNS 解析慢
  • 客户端性能限制或防火墙影响

71. 技术栈有哪些?

  • 技术栈是完成项目所用的所有技术集合,包括编程语言、框架、数据库、服务器、中间件等。
  • 例如:前端(React)、后端(Spring Boot)、数据库(MySQL)、缓存(Redis)、消息队列(RabbitMQ)、容器(Docker)等。

72. 索引失效/没生效原因

  • SQL 写法不规范(如函数操作字段、类型不匹配)
  • 使用了范围查询后索引列右侧的索引失效
  • 多列索引没有按照最左前缀原则使用
  • 数据量太小导致全表扫描成本更低
  • 统计信息不准,优化器选择全表扫描

73. EXPLAIN 调优

  • 通过 EXPLAIN 查看查询执行计划,关注是否用到索引、扫描行数、连接方式等。
  • 根据结果优化索引、SQL 结构、减少全表扫描和不必要的排序。

74. 索引生效了还是很慢怎么办?

  • 检查查询是否返回大量数据,优化分页或过滤条件。
  • 复合索引设计是否合理。
  • 确认服务器资源瓶颈(CPU、IO)。
  • 可能需要优化表结构或分库分表。

75. Redis 分布式锁相关场景及更好方案

  • 场景:保证多个服务间对共享资源的互斥访问。
  • 方案:使用 Redis 的 SET key value NX PX timeout 实现原子加锁。
  • 更好方案:Redlock 算法,多个 Redis 实例保证高可用和安全。

76. K8s 相关

  • Kubernetes 是容器编排平台,实现容器自动部署、扩缩容、负载均衡和管理。
  • 核心组件有 Master(API Server、Scheduler)、Node(Kubelet、Container Runtime)等。
  • 主要概念:Pod、Service、Deployment、ConfigMap、Ingress。

77. Go 两个 slice 比较

  • Go 不支持直接比较两个 slice 是否相等。
  • 需要遍历元素逐一比较长度和内容。

78. Go 泛型

  • Go 1.18+ 支持泛型,允许函数和类型接受任意类型参数。
  • type parameters 声明,提升代码复用性和类型安全。

79. Go channel

  • 用于 goroutine 之间通信的管道,支持同步和异步消息传递。

80. Go context

  • 用于传递取消信号、超时和请求范围的数据,常用于控制并发和请求生命周期。

81. Go select

  • 用于监听多个 channel 的操作,支持超时和多路复用。

82. Go 最新特性

  • 泛型支持
  • Fuzzing 模糊测试内置支持
  • Go Workspaces 多模块管理
  • 性能和编译速度提升

83. GPU算子优化方法

  • 利用线程并行最大化计算单元利用率
  • 内存访问优化,减少全局内存访问,使用共享内存缓存数据
  • 减少分支,避免线程发散
  • 合理调度线程块和线程数量,充分利用硬件资源
  • 使用异步拷贝和流水线技术重叠计算与数据传输

84. GEMM(矩阵乘法)优化

  • 采用块状分割(blocking),分块加载数据进共享内存
  • 利用寄存器缓存共享内存减少内存访问延迟
  • 线程协同计算,每个线程负责计算子矩阵的一部分
  • 使用SIMD指令集和硬件加速特性
  • 减少内存Bank冲突

84. Bank Conflict优化

  • 共享内存分成多个bank,避免不同线程访问同一bank导致冲突
  • 通过数据重排(padding)、改变访问模式,确保访问bank不冲突
  • 设计合适的内存访问策略,使线程访问共享内存尽量均匀分布

85. Faster Transformer框架

  • NVIDIA开源的高性能Transformer推理库
  • 针对Transformer模型结构,做低精度计算(如FP16)、内存优化、并行化加速

86. Transformer具体的输出

  • 输入:通常是 (batch_size, seq_length, embed_dim)
  • 输出与输入shape相同 (batch_size, seq_length, embed_dim)
  • 每层经过自注意力和前馈网络,shape保持不变

87. QKV的计算过程

  • 输入向量通过三个线性变换(矩阵乘法)分别生成 Query (Q)、Key (K)、Value (V)
  • Q和K计算注意力权重,V加权求和得到输出
  • 公式:Attention(Q,K,V) = softmax(QK^T / sqrt(d_k)) * V

88. 算子核函数设计方法

  • 根据计算任务设计对应的CUDA核函数
  • 设计时关注线程分配、内存访问模式和同步
  • 优化计算密集度和内存带宽利用率
  • 保证核函数内无竞态条件和最小线程发散

89. Transfer-Encoding 响应头(重点是 chunked

  • Transfer-Encoding: chunked 表示服务器分块传输数据,不预先告知响应体长度。
  • 优点:可以边生成边发送,适合**流式传输、大文件或服务端渲染(SSR)**场景。
  • 每个数据块前标注块长度,最后一个为 0\r\n\r\n 表示结束。

90. 宏任务 / 微任务 / MessageChannel

宏任务(macro task):

  • 宿主环境调度的任务,如:setTimeoutsetIntervalsetImmediate、UI 渲染等。

微任务(micro task):

  • 当前宏任务执行完后立即执行的任务,如:Promise.thenMutationObserverqueueMicrotask

MessageChannel

  • 原生浏览器提供的消息通信机制,也可以用来实现微任务调度。
  • setTimeout 更快,常用于polyfill 中模拟 nextTick 或异步更新 DOM。

91. Vue.nextTick 源码逻辑简述(Vue 2.x)

  • 原理:在 DOM 更新后执行回调。

  • 内部用到了微任务优先调度机制,如:

    • Promise.then(现代浏览器)
    • MutationObserver(兼容性)
    • MessageChannel
    • 最后才是 setTimeout 兜底。
  • 主要作用:等 DOM 更新完之后再操作 DOM,避免拿到旧状态。

92. Webpack 解决了什么痛点?

  • 模块化管理:支持 import/export,解决 JS 依赖混乱问题
  • 打包优化:将多个资源(JS/CSS/图片等)打包成优化后的静态文件
  • 热更新(HMR):开发效率提升
  • Tree Shaking:去除无用代码,减小包体积
  • Loader & Plugin 系统:灵活扩展,适配各种资源编译(如 Babel、SASS)

93. C++ 编译过程(四个阶段)

  1. 预处理(Preprocessing):处理 #include#define 等宏指令
  2. 编译(Compiling):将 .cpp 编译成 .o,生成汇编或机器码
  3. 汇编(Assembling):生成目标文件 .o/.obj
  4. 链接(Linking):把多个 .o 和库文件合并成可执行文件

94. 编译、链接、重定位

  • 编译:生成目标文件,符号地址是相对的
  • 链接:把各目标文件的符号连接起来
  • 重定位:分配符号在最终可执行文件中的绝对地址

95. 除了 inline,还能怎么设置内联函数?

  • 使用 __attribute__((always_inline))(GCC/Clang)强制内联
  • 使用 #pragma inline(部分编译器支持)
  • 将函数定义写在类定义中(类内定义默认内联)

96. 头文件里可以放什么?

  • 函数声明、类定义、常量定义、模板定义、inline函数
  • 不能放函数的定义(除非是内联或模板),避免多重定义

97. explicit 的作用?

  • 禁止构造函数发生隐式类型转换
  • 用于防止错误的自动类型转换行为,提升类型安全性

98. C++ 四种强制类型转换

  1. static_cast:安全的基本类型转换或向上转型
  2. dynamic_cast:用于类之间安全转换(需有虚函数)
  3. const_cast:去除 const/volatile 修饰
  4. reinterpret_cast:危险的底层强转(按内存位处理)

99. double 转 int64 用 reinterpret_caststatic_cast 区别

  • static_cast<double>int64_t值转换,浮点变整数
  • reinterpret_cast地址转换,不改变内容,只改变解释方式,会出错!

100. 构造函数抛出异常的问题

  • 解决方法

    • 构造函数内使用智能指针(RAII)自动释放
    • 分阶段构造,用工厂函数包装构造过程
    • 捕获异常清理资源,避免内存泄漏

101. 智能指针常见问题

  • 循环引用(shared_ptr 互指) → 用 weak_ptr 解决
  • 使用不当导致双重释放、悬空引用
  • unique_ptr 不能复制,只能转移所有权
  • 不要用裸指针和智能指针混用

102. 为什么要内存对齐?

  • 性能优化:现代 CPU 访问内存通常按对齐地址读取(如按 4 字节、8 字节块),非对齐访问会降低性能甚至导致异常。
  • 硬件要求:某些平台不支持非对齐访问,可能会触发异常(如 ARM)。
  • 对齐后的访问更快、更安全、能最大限度利用总线带宽。

103. 处理大文件用进程还是线程?

  • 推荐多进程

    • 更好地隔离资源,每个进程处理一部分文件,互不干扰。
    • 能充分利用多核 CPU,并行读取多个文件块(结合 mmap / 分段读取)。
  • 线程适用于内存数据量大但共享性强的场景,线程共享地址空间更轻量,但要注意同步。

104. 多进程的稳定性 + 扩展性

  • 稳定性好:进程间隔离,一个崩溃不会影响其他进程,避免级联故障。
  • 扩展性强:天然支持横向扩展(加更多进程/节点),易于负载均衡。
  • 常用于守护进程 + worker 模型,适合大并发、高可用系统(如 nginx、redis cluster)。

105. 体系结构中的缓存(Cache)

  • CPU 有三级缓存(L1、L2、L3),层级越高,容量越大,访问速度越慢。
  • 缓存原理是局部性原理(时间局部性、空间局部性)。
  • 数据访问先查缓存,没命中则从主内存读取并写入缓存。

106. 多核 CPU 处理同一块数据时如何同步?

  • 缓存一致性问题:多个 CPU 各自有缓存,会导致缓存失效或数据不同步。

  • 解决方案

    • 总线锁/内存屏障:确保操作原子性与执行顺序
    • MESI 协议:硬件协议同步各核缓存状态,避免数据不一致
    • 软件层面使用锁(互斥锁、自旋锁、原子变量等)确保多核数据同步
    • 避免 false sharing:不同核操作相邻内存地址时引发 cache line 冲突