Skip to content

日活/并发量

  • 蝉管家日活:1-2K
  • 蝉镜直播:70 个直播间
    • 互动
    • 话术衍生 TTS
  • 蝉镜日活:1W+
    • PC 端 4.8K+
    • App 端 6.7K+
  • 蝉镜作品数:3W+
  • Jogg 日活:6K+
  • Jogg 作品数:7K+

  • 小型互联网产品
    • 日活/流量:1k-10k 日活用户
    • 并发量:100–500 并发请求/秒
    • 技术需求:单机 + Nginx 反向代理 + MySQL/Redis,偶尔加个水平扩展就够
    • 举例
      • 一个小型在线投票网站,高峰期几百人同时投票,单台机器+缓存能轻松承载
      • 某地方社区电商,每天几千订单,分布式集群完全没必要
      • 内部工具(如考勤系统),并发几十请求/秒,普通数据库就能撑住
  • 中型互联网产品
    • 日活/流量:1w–100w 日活用户
    • 并发量:500–5000 并发请求/秒
    • 技术需求:
      • 数据库读写分离
      • Redis/Memcached 缓存
      • 负载均衡 + 多机房部署
    • 举例
      • 一款区域电商活动秒杀,峰值 1,000 并发,缓存热点商品、用消息队列异步下单就能稳住
      • 中型移动游戏登录/匹配系统,峰值并发 2,000,单机 MySQL+Redis + Nginx 就够,没必要微服务全套
      • 企业级 SaaS 产品,某功能偶尔高峰并发 3,000,水平扩展数据库节点就能解决
  • 大型互联网产品
    • 日活/流量:100w+ 日活,峰值流量上亿请求/秒
    • 并发量:几十万甚至上百万并发请求/秒
    • 技术需求:
      • 完全分布式架构
      • 微服务 + API 网关
      • 多级缓存(Redis、CDN、热点缓存)
      • 消息队列 + 流量削峰(Kafka、RabbitMQ)
      • 数据库分库分表 + 异地多活
    • 举例
      • 双 11 秒杀活动,峰值 200,000 并发,缓存、队列、降级策略必须到位
      • 抖音短视频同时播放上百万次,CDN + 流媒体分发是标配
      • 直播电商高峰并发 100,000+,微服务 + Redis + MQ + 数据库分库分表稳住整场

虾皮后端二面

TODO

数据流和控制流的分离

这玩儿可以写在简历上

为什么这样做?/有什么好处?

  1. 控制流主要做 CRUD。控制流炸了,会影响用户使用,但不影响用户的业务
  2. 数据流炸了的话会影响用户的业务

对于一个系统来说,影响用户业务是很严重的事情,而且我们日常变更最多的是控制流服务,控制流和数据流分离,使得我们发布变更控制流服务时,不会影响到数据流服务,即不会影响用户的业务

11 Labs 就是使用的这种架构。Jogg 使用 11Labs 的音色,经常遇到音色列表接口故障,但是 TTS 接口依然可以正常的使用,这就是数据流和控制流分离,因为对于用户来说,TTS 是核心业务逻辑

孔令飞推荐的高频 Go 面试题

  1. Go 语言中的并发和并行区别?
  • 并发:同一时间段内处理多个任务(逻辑上的同时)
  • 并行:同一时刻多个任务同时执行(物理上的同时)

使用 runtime.GOMAXPROCS(runtime.NumCPU()) 控制最大并行度,这样调度器就会让 goroutine 在多个 CPU 核上同时执行

Go 用 goroutine 实现并发,用多核调度实现并行

Go 调度器(GMP 模型)解决的问题:如何高效地在有限的线程(M)上调度成千上万个 goroutine(G)


  1. 进程、线程、协程的概念及区别;

进程,例如浏览器,微信,这些都是独立的进程,每个进程有独立的资源,例如内存、文件句柄等,通常不会相互影响。

线程,例如百度云网盘可以在下载文件的同时预览图片,对应多个线程在一个进程中。多个线程可以共享进程的资源,但也有自己独立的资源(例如栈)。线程是 CPU 调度的基本单元,上下文切换会产生开销(用户态->内核态)

上下文切换的开销:CPU 为了切换任务而保存/恢复执行现场、刷新缓存、重新调度所付出的时间与性能损失

协程不由操作系统调度,由语言运行时控制,例如 Go 的 GMP 调度器,用户态切换开销低


  1. Go 垃圾回收机制
  2. Go 的 GMP 调度原理

  1. Go Channel 通信原理
  • 是什么?类似管道,用来在 goroutine 之间传递数据
  • 有缓冲和无缓冲
  • select 可以监听多个 channel:多路复用
    • 阻塞 IO 和 IO 多路复用的区别

  1. Go 语言中, 接口是什么,为什么要使用接口

面向接口编程、多用组合少用继承

  • 代码解耦、可扩展。不同的模块之间依赖接口,而不是实现
  • 可测试。方便单元测试 mock 测试

  1. array 和 slice 区别和联系是什么,slice 的数据结构是什么,以及 slice 底层是如何扩容的
  2. Go 中 map 的实现原理是什么,map 是如何扩容的,如何解决 hash 冲突
  3. Go 语言参数传递时值传递还是引用传递?
  4. Go 语言中哪些是引用类型?

  1. defer 关键字的作用和用法
  • 延迟执行函数,一般用于资源释放、日志处理、锁释放、事务回滚
  • 坑点 1:多个 defer 的执行顺序:defer 会把函数调用 压入栈中,后进先出(LIFO)顺序执行
  • 坑点 2:不管中途函数怎么退出(函数中间 return 或 panic),defer 都会执行
  • 坑点 3:defer 调用时的参数会立即计算,函数本身延迟执行

  1. Go 语言的错误处理机制是什么?

函数显式返回错误,而不是抛出异常 try...catch

调用者必须主动检查,通过返回值让错误成为“普通控制流的一部分”,避免隐藏逻辑,也让程序行为更可预测

go
type error interface {
    Error() string
}
  • errors.Join 合并错误
  • errors.Is/As
  • panic + recover

  1. 什么是类型断言?如何在 Go 语言中进行类型断言?
  • 类型断言就是接口“拆箱”的工具
    • 换个描述 1:这个接口值底层到底是什么类型,我要用它真实的类型来操作
    • 换个描述 2:接口是类型+值的组合,类型断言能把接口“解包”为具体类型”
  • 两种类型断言
    • 单指断言。类型不匹配的话会 panic
    • 安全断言。通过 ok 来确认断言成功/失败
  • 类型断言和类型转换的区别

  1. Go 语言中如何实现读写锁?
  • 读写锁:允许多个读并发执行,但是写操作时必须 独占
  • 并行读;串行写;写时,不可读
  • 适用场景:读多写少
  • 举三个应用场景
    • 缓存读取:例如蝉管家新手引导管理器,每 5 分钟从数据库同步一次配置到内存缓存,每个用户请求都会读取

拓展:Copy-on-Write(简称 COW,写时复制)

  • 怎么做:复制新对象再替换
  • 新旧版本覆盖、不会有脏读,没有锁竞争(无锁)
  • 适用场景:读多写少
  • 举三个应用场景
    • 缓存读取:小数据结构直接 CoW,大数据结构使用读写锁