看到一个很好的面经 忍不住刷一下

幻想中最理想的goer面试 写一下

2.除了Go,有用过其他语言吗?相比这些,Go有什么特点?

Go的特点包括:

  • 简洁性:语法简单,无继承的组合式面向对象设计
  • 高效的并发模型:goroutines和channels使并发编程变得简单
  • 快速编译:比Java和C++编译速度更快
  • 内置垃圾回收:不需要手动内存管理,但比Java GC更轻量单一可执行文件:易于部署,无外部依赖跨平台:良好的跨平台兼容性

3. Go并发模型?为什么要这样设计?

Go的并发模型基于CSP(通信顺序进程)理念,主要通过goroutines和channels实现:

  • Goroutines:轻量级线程,由Go运行时管理,初始栈只有几KB
  • Channels:用于goroutines间通信的管道,遵循"通过通信共享内存,而不是通过共享内存通信"这样设计的原因:
  • 线程模型在处理高并发场景时成本高(每个线程需要MB级栈空间)
  • 共享内存并发容易导致竞态条件、死锁等问题 通过goroutines和channels,Go能在有限资源下运行成千上万并发任务,同时保持代码的可读性和简洁性。 需要注意 go并发不一定要协程池 只需要一个计数器控制协程数量就ok

4.陷入内核态具体发生了什么?什么情况下会陷入内核态?为什么要陷入内核态?弊端是什么?如何避免陷入内核态? 陷入内核态发生的过程: - 用户程序执行系统调用指令

- CPU保存当前上下文(寄存器值、程序计数器等) - CPU特权级从用户态切换到内核态 - 执行内核中对应的系统调用处理程序 - 操作完成后,恢复用户态上下文,返回用户程序

(这md编辑器也太难用了) 陷入内核态的情况: 系统调用(文件IO、网络IO、进程创建等) 硬件中断(时钟中断、IO设备中断等) 程序异常(段错误、除零错误等) 为什么要陷入内核态: 保护系统资源,限制普通程序访问硬件和关键资源 提供统一接口访问硬件资源 实现资源共享和进程调度 弊端: 上下文切换开销大(保存、恢复寄存器状态) CPU缓存和TLB失效,影响性能 系统调用比普通函数调用慢10-100倍 避免内核态切换的方法: 批处理系统调用,减少切换次数 使用用户态实现的库(如无锁数据结构) 内存映射文件代替读写调用 使用epoll/io_uring等高效IO模型减少切换

5.Go垃圾回收机制?对比Java、C++,有什么独特的地方? Go采用三色标记并发清除垃圾回收算法: 三色标记: 白色:未访问对象 灰色:已访问但引用未扫描完的对象 黑色:已访问且引用扫描完的对象 主要特点: 并发:大部分GC工作与用户程序并发执行 写屏障:确保并发标记正确性 STW(Stop-The-World)短暂:现代Go版本STW时间通常<1ms 对比其他语言: 盲区 不懂 有没有兄弟补充一下

6.这个过程中写屏障解决什么问题?没有写屏障会导致什么问题? 写屏障解决的问题: 解决并发GC中的对象丢失问题 确保三色不变性,防止黑色对象引用新创建的白色对象而导致误回收 没有写屏障会导致: 黑色对象(已扫描完)可能引用新分配的白色对象 由于黑色对象不会再被扫描,这些新白色对象可能被错误回收 引用关系变化无法被GC感知,导致内存泄漏或悬空指针 Go使用混合写屏障(Hybrid Write Barrier)

  1. 插入写屏障:当黑色对象引用白色对象时,将白色对象标记为灰色
  2. 删除写屏障:当灰色对象对白色对象的引用被删除时,将该白色对象标记为灰色 通过写屏障,Go确保了并发垃圾回收的正确性,同时保持了较低的STW时间。

7.讲讲你对channel的理解,原理是什么? Channel是Go并发模型的核心,提供goroutines间的通信机制: 基本概念: 类型化消息通道,遵循FIFO(先入先出) 可以是有缓冲或无缓冲的 支持发送、接收和关闭操作 内部实现原理: channel在运行时由hchan结构体表示 主要组成:环形缓冲区、互斥锁、发送/接收等待队列、关闭标志等 无缓冲channel:发送方阻塞直到有接收方,实现同步 有缓冲channel:缓冲区满时发送阻塞,空时接收阻塞 运行机制: 发送数据: 如有接收者等待,直接交给接收者 否则,缓冲区未满时存入缓冲区 缓冲区满/无缓冲时,发送者阻塞并加入sendq队列 接收数据: 如有发送者等待,直接从发送者获取 否则,缓冲区非空时从缓冲区取 缓冲区空/无缓冲时,接收者阻塞并加入recvq队列 关闭channel: 设置关闭标志 唤醒所有等待的goroutines 通过这种机制,channel实现了CSP模型中通信顺序进程的思想,使并发编程更安全。

8.多个协程访问同一个map,要加锁吗?为什么channel不用? 多协程访问map: 是的,必须加锁。Go中的map不是并发安全的 sync.Map类型就不用了 Channel为什么不用锁: Channel实际上内部使用了锁(hchan结构体包含mutex),自带锁操作 本质区别: Map是数据结构,设计上未考虑并发 而channel是专门为并发设计的相当于一种原语

9.MySQL为什么需要索引?举个例子讲讲根据索引找到记录的过程? MySQL需要索引的原因: 无索引时需全表扫描,时间复杂度O(N) 索引降低时间复杂度至O(log N) 可实现排序、分组等操作优化 支持唯一性约束 索引查找过程(以InnoDB B+树索引为例): 假设有一个包含id、name、age字段的用户表,对id建立索引:

  1. 定位根节点:B+树从根节点开始查找
  2. 遍历非叶节点: 假设查找id=42的记录在根节点中找到合适的区间(如10-50)根据指针访问对应的子节点重复过程直到叶节点
  3. 在叶节点查找: 叶节点存储索引键值和对应的行记录指针顺序查找id=42的记录
  4. 获取完整记录: 如是聚集索引,叶节点直接包含完整记录如是二级索引,找到主键后再查一次聚集索引

10.联合索引a,b,c,使用a,c会用到索引吗? 对于联合索引(a,b,c): 遵循"最左前缀原则":联合索引只能从左到右使用 WHERE条件中有a但缺失b时,只能利用a部分 例如:对于INDEX idx_abc(a,b,c)索引:

  • WHERE a=1 AND b=2 AND c=3:完全用到索引
  • WHERE a=1 AND c=3:只用到a的索引部分
  • WHERE b=2 AND c=3:不使用此索引
  • WHERE a=1:只用到a部分 原因是B+树按(a,b,c)的顺序组织,缺少中间的b值会导致无法继续使用索引中的c部分。

11.幻读是怎么产生的?为了解决幻读用了什么手段? 幻读产生:

  • 事务A读取满足某条件的记录集合
  • 事务B插入或删除满足相同条件的记录并提交
  • 事务A再次读取时,发现记录集合变化("幻影记录") 幻读与不可重复读的区别:幻读关注新增/删除记录,不可重复读关注已有记录的修改。

解决幻读的手段:

  1. Next-Key Locks: InnoDB在RR隔离级别使用结合记录锁(Record Lock)和间隙锁(Gap Lock)锁定索引记录及记录间隙,防止插入
  2. Serializable隔离级别: 最高隔离级别,自动将读操作转换为共享锁完全避免幻读,但并发性能最差 InnoDB在REPEATABLE READ隔离级别下通过Next-Key Locks解决了大部分幻读问题,是MySQL默认隔离级别。

12.Redis为什么快? Redis速度快的原因:

  1. 内存数据存储: 数据存放在RAM中,避免磁盘IO瓶颈内存访问速度比磁盘快几个数量级
  2. 高效的数据结构: 专门设计的数据结构:字典、跳表、压缩列表等针对不同场景优化的数据类型
  3. 单线程模型(Redis 6.0前): 避免线程切换和锁开销使用IO多路复用处理并发连接
  4. 网络协议 Redis 使用名为 RESP(REdis Serialization Protocol)的协议进行客户端和服务器端的通信。RESP 协议设计简单、解析速度快且具有可读性,支持多种数据类型,如简单字符串、错误、整数、大容量字符串和数组 这些因素共同作用,使Redis即使在普通硬件上也能达到每秒数十万次操作的性能。

13.讲讲Redis主从复制?主从复制之间有差距怎么解决? Redis主从复制机制:

  1. 基本原理: 一主多从架构,主写从读主节点数据变更自动同步到从节点
  2. 复制过程: 从节点发送PSYNC命令全量同步:主节点生成RDB文件发送给从节点增量同步:通过复制偏移量和复制积压缓冲区同步命令 主从复制差距产生原因:
  • 从节点重启或暂时断连
  • 大量写入导致复制积压缓冲区溢出

解决主从复制差距的方法:

  1. 调整复制缓冲区大小: 增加repl-backlog-size参数值防止短时断连后全量同步
  2. Redis 6.0+多线程IO: 加速网络数据读写减少复制阻塞
  3. 考虑使用Redis集群: 分片减轻单主节点负担提高整体复制效率

14.讲讲Redis哨兵机制? Redis哨兵(Sentinel)机制:

  1. 基本概念: 独立运行的进程,监控Redis主从节点自动故障检测和转移提供服务发现功能
  2. 主要功能: 监控:检查主从节点是否正常运行通知:异常时通知管理员自动故障转移:主节点故障时选举新主节点配置提供者:客户端连接时提供服务信息
  3. 工作原理: 多个哨兵共同监控Redis实例通过发布/订阅频道通信使用"主观下线"和"客观下线"机制判断故障使用Raft算法选举领导者哨兵执行故障转移
  4. 故障转移流程: 哨兵检测到主节点主观下线哨兵间确认客观下线选出领导者哨兵选择最优从节点作为新主节点通知其他从节点复制新主节点监控原主节点,恢复后设为从节点
  5. 配置要点: 至少3个哨兵实例确保高可用quorum参数决定客观下线票数down-after-milliseconds决定主观下线时间parallel-syncs控制同时切换的从节点数

15.Kafka适合什么场景?为什么适合? 没用过,有没有兄弟补充一下。

16.高考千分之五,你们省多少考生?是衡中的吗? 楼主好厉害

原文:https://www.nowcoder.com/feed/main/detail/7debd415f5bf42cd9edbde4af995a488?sourceSSR=users

#牛客创作赏金赛#
全部评论

相关推荐

一面:1.&nbsp;redis的过期删除策略2.&nbsp;rdb和aof3.&nbsp;aof重写和写时复制4.&nbsp;rocketmq和kafka架构设计区别5.&nbsp;他们各自的注册中心的实现有什么区别6.&nbsp;rocketmq的延时队列的是如何实现的7.&nbsp;innoDB&nbsp;b+树8.&nbsp;mysql的事务隔离级别9.&nbsp;hashmap原理10.&nbsp;手撕:判断链表是否有环二面:二面无八股,全讲的项目手撕:二叉树层序遍历找出每层最大值。&nbsp;问如果是二叉搜索数能否把空间复杂度优化一下三面:1.&nbsp;raft协议(详细)要具体的如何选举leader&nbsp;flower和candidate的交互2.&nbsp;现代计算机发展中,timewait状态的2msl是否是固定的3.&nbsp;tcp超时重传和确认应答机制(很详细)&nbsp;类似tcp的ack默认是accumulate的还是selectitve的,这个可以详细看一下小林coding写的那个介绍的文章,其实都包含了,但是有些点过于细节了之前其实没有太关注过。4.&nbsp;mysql三种日志是如何实现的数据库的acid5.&nbsp;持久性的实现体现的是日志的刷盘还是数据的刷盘。当时问的是,这个持久化的体现,是指的b+树的刷盘,还是redolog文件的刷盘。现在想起来应该是指的redolog的刷盘,b+树修改后的数据先暂存到buffer&nbsp;pool然后交由操作系统决定刷盘时机,这个也回答的不好。6.&nbsp;数据库崩溃恢复的过程(详尽)&nbsp;提问:如果mysql宕掉了,如果读取redolog恢复,那mysql具体是怎么做的,是有什么指针进行标记恢复的位置吗?是从上到下还是从下到上进行恢复。不会。7.&nbsp;mysql是怎么决定是否要按着undolog进行回滚呢8.&nbsp;levelDB是什么&nbsp;9.&nbsp;两阶段提交有什么问题&nbsp;(可用性上)10.&nbsp;三阶段提交和二阶段提交相比改进了什么11.&nbsp;最终一致性相当于在&nbsp;acid&nbsp;哪个级别上进行了宽松处理12.&nbsp;这相当于是哪种隔离级别呢?13.&nbsp;虚拟线程具体的实现14.&nbsp;zgc&nbsp;g1前两面都是秒过,最后三面挂了,部门leader面,问的问题确实很难很细,确实是技不如人了,hr说有更合适的人选了。看来就是和字节无缘啊#字节跳动##后端开发##Java##牛客创作赏金赛##暑期实习#
点赞 评论 收藏
分享
评论
3
14
分享

创作者周榜

更多
牛客网
牛客企业服务