华顺信安-后端日常实习-一面面经

华顺信安-后端日常实习-一面面经
最新回答
任凭阻碍

2026-01-22 22:36:52

华顺信安后端日常实习一面面经总结如下:

1. MySQL 聚簇索引和非聚簇索引
  • 聚簇索引:数据行实际存储在索引的叶子节点中,主键索引即为聚簇索引。

    特点:数据物理排序与索引一致,查询效率高,但插入、更新、删除操作可能因页分裂导致性能下降。

    适用场景:主键查询或范围查询。

  • 非聚簇索引:叶子节点存储的是主键值而非数据行,需回表查询。

    特点:索引与数据分离,适合辅助索引,但多次查询可能引发回表开销。

    适用场景:非主键字段的查询优化。

2. Redis 过期 key 的删除策略
  • 定时删除:为每个过期 key 设置定时器,到期立即删除(内存友好但 CPU 开销大)。
  • 惰性删除:访问 key 时检查是否过期,过期则删除(CPU 友好但可能内存泄漏)。
  • 定期删除:周期性随机抽查部分 key 并删除过期项(平衡 CPU 和内存的开销)。
  • 实际实现:Redis 结合惰性删除和定期删除策略,避免单一策略的极端问题。
3. Redis 单线程模型
  • 核心机制:Redis 使用单线程处理所有命令请求,通过事件循环(Event Loop)实现高并发。
  • 优势:

    避免多线程的锁竞争和上下文切换开销。

    数据结构操作原子性,无需额外同步机制。

  • 适用场景:高吞吐、低延迟的键值存储,如缓存、计数器、排行榜等。
4. Redis 单线程模型满足的业务需求
  • 原子性操作:单线程确保命令的原子性,适合计数器、分布式锁等场景。
  • 低延迟响应:避免线程切换和锁等待,适合实时性要求高的业务。
  • 简化开发:无需处理多线程并发问题,降低代码复杂度。
5. MySQL 的乐观锁和悲观锁
  • 乐观锁:

    机制:通过版本号或时间戳实现,更新时检查数据是否被修改。

    适用场景:读多写少,冲突概率低的场景(如库存扣减)。

  • 悲观锁:

    机制:通过 SELECT ... FOR UPDATE 加锁,确保独占访问。

    适用场景:写多读少,冲突概率高的场景(如转账操作)。

6. Context 上下文
  • 定义:Go 语言中用于传递请求作用域的数据(如请求 ID、用户信息等)。
  • 特点:

    基于协程的键值存储,生命周期与协程绑定。

    通过 context.WithValue 添加数据,context.Value 读取数据。

  • 应用场景:超时控制、取消信号传递、分布式追踪等。
7. GMP 模型(Go 调度器)
  • 组成:

    G(Goroutine):用户级轻量线程。

    M(Thread):操作系统线程。

    P(Processor):逻辑处理器,绑定 M 和 G 的调度上下文。

  • 调度机制:M 从 P 的本地队列获取 G 执行,实现高并发和低延迟。
8. Defer 关键字
  • 作用:延迟执行函数调用,通常用于资源释放(如文件关闭、锁释放)。
  • 执行顺序:后进先出(LIFO),在函数返回前执行。
  • 与 return 的关系:defer 在 return 返回值赋值后执行,但可能修改命名返回值。
9. Redis 多次查询优化(Pipeline)
  • 问题:多次网络往返导致延迟高。
  • 解决方案:使用 Pipeline 将多个命令打包发送,减少 RTT(Round-Trip Time)。
  • 适用场景:批量插入、批量查询等非事务性操作。
10. Redis 排行榜实现(ZSET)
  • 数据结构:有序集合(ZSET),通过 ZADD 添加成员和分数,ZRANGE 查询排名。
  • 优势:

    支持按分数排序和范围查询。

    原子性操作,适合高并发场景。

11. 协程阻塞的原因
  • I/O 操作:如网络请求、文件读写等。
  • 系统调用:如 time.Sleep、锁等待等。
  • CGO 调用:进入 C 代码时可能阻塞整个 M。
  • 解决方案:通过异步 I/O、协程池或调整调度策略减少阻塞。
12. Map 并发安全性
  • 默认不安全:Go 的 map 非线程安全,并发读写会引发 panic。
  • 解决方案:

    使用 sync.Mutex 或 sync.RWMutex 加锁。

    使用并发安全的 sync.Map(适合读多写少场景)。

13. Map 数据有序性
  • 默认无序:map 的键值对存储顺序不确定。
  • 有序方案:

    使用切片存储键,排序后遍历(如 sort.Strings)。

    通过 for 循环切片索引访问 map 值。

14. 内存溢出与内存泄漏
  • 内存溢出(OOM):程序申请内存超过系统限制,导致崩溃。
  • 内存泄漏:程序未释放不再使用的内存,逐渐耗尽资源。
  • 常见原因:

    未关闭的资源(如文件、连接)。

    缓存未设置过期策略。

    循环引用导致 GC 无法回收。

15. 切片扩容原理
  • 初始容量:切片创建时容量为 0,首次追加时分配初始容量(通常为 1)。
  • 扩容规则:

    当容量不足时,按 2 倍或 1.25 倍(根据元素类型大小)扩容。

    扩容会触发内存重新分配和数据拷贝,可能引发性能问题。

  • 优化建议:预分配足够容量(如 make([]T, 0, N))减少扩容次数。