抓了面试一些常见的八股文,让DS回答了一下简短的回答,适合三年以内的后端吧。大家看一乐,真要理解还是要看书深入思考
一、Golang
-
对比Go协程和正常线程的区别
- 协程:用户态轻量线程,由Go运行时调度,栈动态扩缩(初始2KB),创建/切换开销极小,支持百万级并发。
- 线程:内核态线程,由操作系统调度,固定栈(MB级),创建/切换开销大,并发数受限。
-
值类型和引用类型的区别
- 值类型:直接存储数据(如
int、struct),赋值时复制整个值。 - 引用类型:存储数据地址(如
slice、map),赋值时共享底层数据。
- 值类型:直接存储数据(如
-
channel死锁的场景
- 无缓冲channel:发送端无接收者或接收端无发送者。
- 有缓冲channel:缓冲区满时发送或空时接收,且无其他协程配合。
-
slice如何扩容
- 容量不足时,新容量通常翻倍(旧容量<1024),否则按1.25倍增长,最终对齐内存分配。
-
Go中哪些变量不能比较
- 不可比较类型:
slice、map、函数、含不可比较字段的结构体或接口。
- 不可比较类型:
-
new与make的区别
new:返回类型指针,初始化为零值。make:初始化slice、map、channel的底层结构并返回引用。
-
读写锁(RWMutex)的实现原理
- 写锁:互斥锁,持有时禁止其他读写。
- 读锁:计数实现,允许多个读共享,写锁优先。
-
高吞吐数据处理方案
- 使用工作池(Worker Pool)+缓冲Channel,异步处理+批量提交,分布式分流。
-
死锁及解决
- 条件:互斥、请求保持、不可剥夺、环路等待。
- 解决:超时机制、固定锁顺序、死锁检测。
-
反射(reflect)核心用途
- 运行时动态获取类型信息、修改变量值(如JSON序列化、ORM映射)。
-
Golang的GC机制
- 三色标记法+混合写屏障,并发标记-清除,非分代、非紧缩。
-
map并发安全方案
- 使用
sync.Map(读多写少场景)或Mutex包裹普通map。
- 使用
-
外层协程捕获子协程panic
- 不能,需在子协程内部通过
defer+recover捕获。
- 不能,需在子协程内部通过
-
panic捕获限制
- 未
recover的panic会导致程序退出,已崩溃的协程无法恢复。
- 未
-
slice和数组区别
- 数组:值类型,固定长度。
- Slice:引用类型,动态长度,底层引用数组(含指针、长度、容量)。
-
内置并发安全类型
- 仅
sync包结构(如Mutex、Map)和channel,其他需自行加锁。
- 仅
-
结构体嵌套组合
- 支持匿名嵌套,可直接访问嵌套结构体的字段和方法。
-
结构体等值比较
- 若所有字段可比较且值相等,则结构体相等。
-
interface类型理解
- 动态类型系统核心,包含类型和值的二元组,用于多态和抽象。
-
Go 1.18后的interface增强
- 支持泛型(类型参数),允许定义带类型约束的接口。
-
interface等值比较
- 动态类型和值均相等时,接口相等。
-
逃逸分析
- 编译器决定变量分配在栈还是堆,避免内存泄漏。
-
channel缓冲区别
- 无缓冲:同步操作(发送需等待接收)。
- 有缓冲:异步操作,缓冲区满时阻塞。
-
map并发访问问题
- 触发
concurrent map read/writepanic,无法捕获,必须加锁。
- 触发
-
GMP模型
- G(Goroutine)、M(内核线程)、P(调度上下文)。
-
G放入全局队列的时机
- P的本地队列已满或G需被其他P窃取时。
-
Go的GC原理
- 三色标记法,并发标记阶段仅两次短暂停(STW)。
-
GC扫描是否并发
- 标记阶段并发,清除阶段并行。
-
GC根对象
- 全局变量、栈上的指针、寄存器中的指针。
-
堆和栈区别
- 栈:函数调用自动分配/释放,存局部变量。
- 堆:手动或GC管理,存长期数据。
-
进程空间
- 用户空间(代码、堆、栈)+内核空间(系统调用)。
-
进程、线程、协程区别
- 进程:资源隔离单位;线程:CPU调度单位;协程:用户态轻量线程。
-
链表与线性表
- 线性表:连续存储(如数组);链表:非连续存储,指针链接。
-
有序双向链表高效查询
- 二分查找优化(跳表思想)或转换为平衡树结构。
-
gRPC优势
- 基于HTTP/2多路复用,支持流式通信,高效二进制编码(Protobuf)。
-
空结构体用途
- 节省内存(零大小),用于信号传递(如
chan struct{})。
- 节省内存(零大小),用于信号传递(如
-
defer执行顺序
- 后进先出(LIFO),类似栈。
-
Protobuf
- 二进制序列化协议,高效紧凑,跨语言支持。
-
gRPC与HTTP/2
- gRPC基于HTTP/2,支持流式、头部压缩、多路复用。
-
sync.Pool场景
- 缓存临时对象,减少GC压力(如频繁创建/销毁的结构体)。
-
sync.Map原理
- 通过
read和dirty两map分离读写,原子操作保证并发安全。
- 通过
-
map扩容机制
- 负载因子>6.5或溢出桶过多时,渐进式扩容(新旧桶并存)。
-
协程池作用
- 控制并发量,减少协程创建/销毁开销。
-
GC触发条件
- 内存分配达阈值(默认100%增长率)或手动调用
runtime.GC()。
- 内存分配达阈值(默认100%增长率)或手动调用
-
channel关闭后读取
- 关闭后读取返回零值,需通过
v, ok := <-ch判断是否关闭。
- 关闭后读取返回零值,需通过
-
切片注意事项
- 避免共享底层数组导致意外修改,注意扩容性能影响。
-
参数传递方式
- 值传递:所有类型均传值(引用类型传递指针拷贝)。
-
defer原理
- 编译器插入延迟执行代码,通过链表记录调用顺序。
-
map底层结构
- 哈希表,桶数组+链表(Go 1.18后可能引入红黑树优化冲突)。
-
hash冲突解决
- 链表法(拉链法),极端情况可能转为红黑树。
-
性能调优案例
- 使用
pprof分析CPU/内存,优化热点代码(如减少锁竞争)。
- 使用
-
线程日志分析
- 通过
GODEBUG=schedtrace=1000查看调度状态,分析阻塞原因。
- 通过
二、Mysql
-
索引的优缺点
- 优点:加速查询、保证唯一性
- 缺点:占用存储、降低写性能
-
聚簇索引和非聚簇索引与回表查询
- 聚簇索引:数据与索引一起存储(如主键索引),叶子节点存数据行。
- 非聚簇索引:叶子节点存主键值,需回表查询聚簇索引获取完整数据。
-
MySQL事务隔离级别
- 读未提交、读已提交、可重复读(默认)、串行化。
-
治理大表方案
- 分库分表、归档历史数据、使用分区表、优化索引。
-
千万级表读取优化
- 读写分离、覆盖索引、缓存(Redis)、垂直拆分。
-
索引创建原则
- 高频字段优先、高区分度字段、联合索引最左匹配、避免过多索引。
-
联合索引最左匹配原则
- 索引
(a,b,c)生效场景:WHERE a=1、WHERE a=1 AND b=2,但WHERE b=2不生效。
- 索引
-
优化SQL方案
- 避免
SELECT *、用EXPLAIN分析、优化子查询为JOIN、减少全表扫描。
- 避免
-
分页优化
- 使用
WHERE id > N替代OFFSET、覆盖索引、缓存总数。
- 使用
-
不同隔离级别区别
- 读未提交:可能脏读;读已提交:避免脏读但不可重复读;
- 可重复读:避免不可重复读;串行化:完全串行。
-
接口性能优化
- 异步处理、缓存结果、批量操作、压缩传输数据。
-
全表扫描场景
- 未使用索引、
LIKE '%xx%'、非索引字段排序/分组。
- 未使用索引、
-
主从同步原理与日志文件
- 原理:主库写Binlog,从库IO线程拉取,SQL线程重放。
- 日志文件:Binlog、Redo Log、Undo Log。
-
可重复读
- 事务内多次读取同一数据结果一致,通过MVCC实现。
-
MySQL事务实现
- InnoDB通过Undo Log回滚、Redo Log持久化、MVCC和锁机制实现ACID。
-
索引使用场景
- 走索引:字段独立使用、符合最左匹配、范围查询。
- 不走索引:字段运算(如
WHERE a+1=2)、隐式类型转换、联合索引跳过前缀。
-
联合索引前缀匹配
- 索引按字段顺序排序,跳过前缀会导致后续字段无序,无法利用索引。
-
内存溢出解决与GoPool作用
- 解决:检查内存泄漏、优化数据结构、限制并发。
- GoPool:控制协程数量,避免无限制创建协程导致OOM。
-
延迟双删策略
- 更新前删缓存 → 2. 更新数据库 → 3. 延迟再删缓存(防止旧数据回填)。
-
缓存击穿/穿透/雪崩
- 击穿:热点数据失效 → 互斥锁或永不过期。
- 穿透:查询不存在数据 → 布隆过滤器。
- 雪崩:大量缓存同时失效 → 随机过期时间、多级缓存。
-
MySQL架构
- 连接层 → 服务层(解析/优化) → 引擎层(InnoDB/MyISAM)。
-
查询流程
- 连接器 → 分析器 → 优化器 → 执行器 → 存储引擎 → 返回结果。
-
存储引擎区别
- InnoDB:支持事务、行锁、外键。
- MyISAM:不支持事务、表锁、全文索引。
-
字符串类型
- CHAR、VARCHAR、TINYTEXT、TEXT、MEDIUMTEXT、LONGTEXT。
-
BLOB和TEXT区别
- BLOB:存二进制数据(如文件),无字符集;
- TEXT:存文本,有字符集,支持全文索引。
-
MySQL索引理解
- 基于B+树,加速查询、排序和分组;包含聚簇/非聚簇索引,支持覆盖索引。
-
数据库索引原理及B+树优势
- 原理:B+树是多路平衡树,叶子节点形成有序链表。
- 为何不用二叉树:二叉树高度高(IO多),B+树多路分支减少磁盘访问。
- 为何不用Hash:Hash不支持范围查询,B+树叶子链表支持高效范围扫描。
-
聚集索引与非聚集索引区别
- 聚集索引:数据按索引顺序存储(如InnoDB主键),叶子节点存数据行。
- 非聚集索引:叶子节点存主键值(需回表),如MyISAM索引。
-
InnoDB索引策略
- 覆盖索引、索引下推(ICP)、自适应哈希索引、最左前缀匹配。
-
创建索引方式
CREATE INDEX index_name ON table(column);ALTER TABLE table ADD INDEX index_name(column);- 唯一索引:
UNIQUE KEY。
-
聚簇/非聚簇索引及注意事项
- 底层实现:B+树;不用B-Tree:B+树叶子链表更适合范围查询。
- 不用Hash:无法范围查询。
- 叶子节点:聚簇索引存数据,非聚簇存主键值。
- 注意事项:避免过多索引、最左匹配、区分度低的字段不建索引。
-
整型自增主键 vs UUID
- 整型自增:存储小、插入有序(减少页分裂)、范围查询快。
- UUID:无序、存储大、插入性能差。
-
非主键索引存主键值
- 保证数据一致性(数据行移动时无需修改非主键索引),节省存储空间。
-
创建索引的场景
- 需要:高频查询字段、WHERE/JOIN/ORDER BY/GROUP BY涉及的列。
- 不需要:频繁更新的字段、区分度低的列(如性别)、小表。
-
count(*)、count(1)、count(列名)
count(*)和count(1):统计所有行,性能相同。count(列名):忽略NULL值。
-
IN vs EXISTS
- IN:子查询结果集小,外层表大时高效。
- EXISTS:外层表小,子查询能利用索引时高效。
-
UNION vs UNION ALL
- UNION:去重并排序,性能低。
- UNION ALL:不去重,直接合并结果,性能高。
-
连接类型区别
- 内连接(INNER JOIN):仅返回匹配的行。
- 左连接(LEFT JOIN):返回左表全部+右表匹配的行。
- 右连接(RIGHT JOIN):返回右表全部+左表匹配的行。
-
连接类型定义
- 内连接:匹配的行。
- 外连接:左/右/全外连接(保留未匹配的行)。
- 交叉连接(笛卡尔积):两表所有行组合。
-
事务隔离级别及默认
- 读未提交、读已提交、可重复读(MySQL默认)、串行化。
-
并发问题
- 脏读:读到未提交的数据。
- 不可重复读:同一事务内多次读结果不同。
- 幻读:同一事务内读到新增/删除的行。
-
事务四大特性(ACID)与实现
- 原子性:Undo Log回滚。
- 持久性:Redo Log写盘。
- 隔离性:锁+MVCC。
- 一致性:前三者共同保证。
-
MVCC原理
- 通过版本链(事务ID、回滚指针)和ReadView判断数据可见性,实现非阻塞读。
-
乐观锁 vs 悲观锁
- 乐观锁:版本号/CAS,适合读多写少。
- 悲观锁:
SELECT ... FOR UPDATE,适合写多。
-
MySQL锁类型
- 行锁、表锁、意向锁、间隙锁、临键锁、自增锁。
-
InnoDB行锁实现
- 对索引项加锁,若查询无索引则退化为表锁。
-
间隙锁与死锁
- 间隙锁:锁定索引范围,防止幻读。
- 死锁示例:
- sqlCopy Code
-- 事务1UPDATE t SET v=1 WHERE id=1; `` UPDATE t SET v=2 WHERE id=2;-- 事务2UPDATE t SET v=3 WHERE id=2; ``UPDATE t SET v=4 WHERE id=1;- 解决:设置超时(
innodb_lock_wait_timeout)、死锁检测(自动回滚)。
-
死锁解决经验
- 重试事务、调整SQL顺序、拆解事务、监控死锁日志。
-
SQL优化日常方法
- 分析慢查询、使用EXPLAIN、优化索引、避免全表扫描、减少JOIN复杂度。
-
SQL优化步骤与EXPLAIN
-
步骤:定位慢SQL → 分析执行计划 → 优化索引/改写SQL。
-
EXPLAIN字段:
- `type`:访问类型(const > ref > range > index > ALL)。- `key`:实际使用的索引。 - `rows`:预估扫描行数。 - `Extra`:`Using index`(覆盖索引)、`Using filesort`(需优化)。 -
-
有效使用复合索引
- 确保查询条件包含最左列,且避免中断(如范围查询后列失效)。
-
长耗时SQL优化方向
- 检查索引是否失效、优化表结构、分批处理、读写分离、缓存结果。
-
最左前缀原则
- 联合索引
(a,b,c),查询必须从a开始连续使用(如a、a,b、a,b,c)。
- 联合索引
-
不走索引的情况
- 对索引列使用函数/运算(如
WHERE YEAR(date))、隐式类型转换、OR条件非全覆盖、LIKE '%xx'。
- 对索引列使用函数/运算(如
-
分库分表设计
- 分库:垂直拆分(按业务)、水平拆分(按数据分布),减少单点压力。
- 分表:解决单表数据过大(如按时间或哈希)。
-
三个范式
- 1NF:列不可再分(原子性)。
- 2NF:消除部分依赖(所有非主属性完全依赖主键)。
- 3NF:消除传递依赖(非主属性直接依赖主键)。
-
百万级别或以上的数据如何删除
- 删除索引策略:删除前先移除索引,完成数据删除后重建索引,可提升删除效率14。
- 分批删除:使用LIMIT分批次删除,避免长时间锁表,例如每次删除1万条并加入延迟78。
- 临时表法:将需保留数据存入临时表,删除原表后重命名临时表,适用于全表清理场景27。
- 分区表优化:对表进行分区设计,直接TRUNCATE分区实现快速删除5。
- 禁用约束:删除前临时关闭外键检查,加快删除速度7。
-
MySQL的binlog有几种录入格式?分别有什么区别
- Statement:记录原始SQL语句,日志量小但可能主从不一致。
- Row:记录每行数据变化,精度高但日志量大。
- Mixed:混合模式,根据场景自动选择Statement或Row。
-
主键索引与唯一索引的区别
- 非空约束:主键不允许NULL值,唯一索引允许单个NULL值。
- 数量限制:每表仅一个主键,可存在多个唯一索引。
- 聚簇索引:InnoDB中主键默认是聚簇索引,唯一索引为非聚簇。
-
索引有哪几种类型
- B+树索引:默认索引类型,支持范围查询和排序67。
- Hash索引:仅支持等值查询,内存表默认类型67。
- 全文索引:用于文本内容的全文搜索。
- 空间索引:支持地理数据类型(如R-Tree)。
-
Hash索引和B+树索引有什么区别
- 查询效率:Hash索引等值查询O(1),但不支持范围查询;B+树范围查询效率高67。
- 排序支持:B+树天然有序,Hash索引无法排序67。
- 适用场景:Hash适合精确查找,B+树适合范围查询及排序需求67。
-
使用B+树的好处
- 减少IO次数:多层级结构减少磁盘访问67。
- 范围查询高效:叶子节点链表结构便于范围扫描67。
- 数据有序性:天然排序支持ORDER BY等操作67。
- 高扇出度:单节点存储更多键,降低树高度67。
三、Redis
-
Redis用途
- 缓存、分布式锁、消息队列、会话共享、实时排行榜。
-
用户信息存储与缓存策略
- 敏感信息存数据库,高频访问数据(如昵称)走缓存;非全量缓存,需防击穿(加互斥锁/布隆过滤器)。
-
Redis过期淘汰策略
- 定期删除:随机检查并删除过期键。
- 惰性删除:访问时检查过期并删除。
- 内存淘汰策略:LRU、LFU、随机淘汰等(
maxmemory-policy配置)。
-
缓存击穿/雪崩/穿透
- 击穿:热点数据失效 → 互斥锁/永不过期。
- 雪崩:大量缓存同时失效 → 随机过期时间/多级缓存。
- 穿透:查询不存在数据 → 布隆过滤器/缓存空值。
-
单例模式场景
- 饿汉模式:启动时初始化,适合资源占用少、高频调用。
- 懒汉模式:首次调用初始化,适合资源占用大、延迟加载。
-
Redis过期删除策略
- 定期删除(间隔扫描) + 惰性删除(访问时检查)。
-
Redis常用数据结构
- String、Hash、List、Set、ZSet、Stream、Bitmaps、HyperLogLog。
-
分布式缓存实现
- Redis Cluster分片、主从复制(Sentinel高可用)、Codis代理分片。
-
引入Redis优化服务器
- 缓存热点数据、读写分离(主写从读)、数据分片存储、异步队列削峰填谷。
-
缓存与数据库一致性
- 延迟双删:更新后删缓存 → 延迟再删一次。
- 旁路缓存:读时更新缓存,写时淘汰缓存。
-
保证一致性方案
- 先更新数据库 → 再删缓存(失败则重试队列补偿)。
-
写缓存成功但数据库失败
- 缓存成脏数据 → 需回滚缓存(如监听数据库事务状态)。
-
缓存更新失败处理
- 异步重试(消息队列)、补偿任务(定时比对数据库同步缓存)。
-
缓存过期机制
- 可设置过期时间(如30分钟);部分数据永不过期(需主动更新)。
-
缓存同时过期问题
- 雪崩效应 → 随机过期时间(基础时间+随机偏移量)。
-
分布式锁应用挂掉
- 锁自动过期(
EXPIRE),或使用Redlock算法(多节点互斥)。
- 锁自动过期(
-
Redis持久化机制
- RDB:定时快照,恢复快但可能丢数据。
- AOF:记录写操作,数据更安全但文件大。
-
fork子进程原因
- 避免阻塞主进程(利用Copy-On-Write机制减少内存拷贝)。
-
Redis高性能原因
- 基于内存、单线程多路复用、高效数据结构(如跳跃表、哈希表)。
-
Redis vs Memcached
- Redis支持更多数据类型、持久化、集群;Memcached纯内存、多线程。
-
SQL与NoSQL区别
- SQL:强一致性、事务、结构化查询;NoSQL:高扩展性、灵活模型(键值/文档等)。
-
Redis持久化(同84)
- RDB(快照) + AOF(日志追加)。
-
Key失效机制
- 主动过期(定时删除) + 被动过期(访问时检查)。
-
持久化优缺点
- RDB:优点恢复快,缺点数据丢失风险。
- AOF:优点数据安全,缺点文件大、恢复慢。
-
持久化方式选择
- 高安全性选AOF,高性能选RDB,或混合使用(Redis 4.0+)。
-
持久化数据扩容
- 水平分片(Cluster)、数据迁移工具(如
redis-trib),AOF/RDB文件拆分。
- 水平分片(Cluster)、数据迁移工具(如
-
过期键删除策略
- 惰性删除(访问时检查) + 定期删除(随机扫描部分键)。
-
处理过期数据方法
- 惰性删除:访问时检查过期并删除。
- 定期删除:周期性随机扫描过期键并删除。
-
保证Redis数据为热点
- 设置内存淘汰策略为
allkeys-lru或volatile-lru,结合高频访问数据设置合理TTL。
- 设置内存淘汰策略为
-
内存淘汰策略
v
noeviction(不淘汰)、allkeys-lru、volatile-lru、allkeys-random、volatile-random、volatile-ttl、allkeys-lfu、volatile-lfu。 -
内存用完后果
- 若配置
noeviction,写操作返回错误;其他策略按规则淘汰数据腾出空间。
- 若配置
-
内存优化手段
- 使用高效数据结构(如Hash代替多个String)、配置
ziplist压缩小集合、设置过期时间、分片存储。
- 使用高效数据结构(如Hash代替多个String)、配置
-
主从复制模型
- 主节点处理写操作,异步复制数据到从节点;从节点可读,主节点故障时自动切换。
-
生产环境部署
- Redis Cluster分片集群 + Sentinel高可用,主从节点跨机器部署,开启RDB和AOF持久化。
-
哈希槽概念
- 集群将数据分为16384个槽,每个节点负责部分槽,通过
CRC16(key) % 16384分配位置。
- 集群将数据分为16384个槽,每个节点负责部分槽,通过
-
写操作丢失风险
- 可能丢失,因主从复制是异步的(主节点写入后未同步即宕机);可通过
min-slaves-to-write配置降低风险。
- 可能丢失,因主从复制是异步的(主节点写入后未同步即宕机);可通过
-
集群复制方式
- 主节点异步推送写命令到从节点,从节点重放命令保持数据同步。
-
集群最大节点数
- 理论支持16384节点(每个槽可单独分配),但实际受网络和管理限制。
-
提高多核利用率
- 单机多实例部署(不同端口),或使用集群模式分散节点到多机器。
-
Redis分区目的
- 扩展内存和吞吐量,分散数据压力,提升性能。
-
分区实现方案
- 客户端分片(一致性哈希)、代理分片(Codis)、Redis Cluster自动分片。
-
分区缺点
- 跨节点事务/多键操作不支持,扩容复杂,维护成本高。
-
分布式锁实现
SET key value NX PX 30000(原子操作);或使用RedLock算法(多节点互斥)。
-
并发竞争Key解决
- 分布式锁控制写入顺序,或结合WATCH/MULTI乐观锁,或串行化处理(Lua脚本)。
-
RedLock定义
- 分布式锁算法,需半数以上Redis节点成功获取锁,避免单点故障。
-
缓存预热
- 系统启动时主动加载热点数据到缓存,避免首请求击穿数据库。
-
缓存降级
- 高并发时关闭非核心缓存,返回默认数据或错误,保障核心服务可用。
-
查找固定前缀Key
- 使用
SCAN命令迭代遍历(如SCAN 0 MATCH prefix*),避免阻塞的KEYS命令。
- 使用
-
字符串最大容量
- 512MB(由
proto-max-bulk-len配置限制)。
- 512MB(由
-
延时队列实现
- 使用
ZSET,消息到期时间设为score,消费者轮询ZRANGEBYSCORE获取到期消息。
- 使用
-
异步队列实现
- 列表结构:生产者
LPUSH,消费者BRPOP阻塞获取;或使用Pub/Sub(无持久化)。
- 列表结构:生产者
-
回收进程工作方式
- 内存不足时按淘汰策略删除键;过期键通过惰性删除(访问触发)和定期删除(定时扫描)回收。
四、Kafka
-
为什么要使用消息队列?
- 系统解耦,异步通信,流量削峰,数据持久化。
-
保证消息有序,一个Topic只能有一个Partition吗?
- 否,同一业务消息需哈希到同一Partition,单Partition内有序。
-
业务突增导致消息积压怎么办?
- 扩容消费者,优化消费逻辑,增加Partition数量。
-
生产者收到成功响应后消息一定不会丢失吗?
- 不一定,需配置
acks=all和副本同步机制。
- 不一定,需配置
-
高并发下如何避免重复消费?
- 幂等性设计,全局消息ID去重。
-
如何保证消息可靠性?
- 生产者
acks=all,Broker多副本,消费者手动提交Offset。
- 生产者
-
消息队列中间件对比及场景
- Kafka(高吞吐),RabbitMQ(复杂路由),RocketMQ(事务消息)。
-
Kafka如何实现高吞吐?
- 顺序I/O,批量发送,零拷贝技术。
-
消息队列是什么?
- 异步通信中间件,解耦生产者和消费者。
-
其他消息队列了解吗?
- RabbitMQ(AMQP协议),RocketMQ(阿里开源),ActiveMQ(JMS协议)。
-
Kafka部署方式
- 多Broker集群,分区多副本,依赖ZooKeeper协调。
-
DevOps使用实践
- CI/CD流水线,Prometheus监控,ELK日志管理。
-
不用Kafka可以吗?
- 可替代,如RabbitMQ适用于低吞吐场景。
-
分布式锁原理
- Redis的
SETNX,ZooKeeper的临时顺序节点。
- Redis的
-
Kafka消息丢失和重复消费
- 丢失:生产者未确认或副本丢失;重复:Offset提交失败重试。
-
Kafka和RabbitMQ区别
- Kafka拉模式(日志存储),RabbitMQ推模式(队列路由)。
-
拉模式的好处
- 消费者按能力拉取,避免Broker过载。
-
Kafka核心概念
- Producer(生产者),Broker(服务节点),Consumer(消费者),Topic(消息分类)。
-
Kafka保证消息顺序性
- 同一Partition内顺序写入和消费,按Key路由。
-
Kafka消息存储方式
- 分段日志文件,按时间追加,索引快速定位。
-
Kafka高可用与分区机制
- 分区多副本,Leader选举,ISR同步副本集合。
-
高可用Kafka集群设计
- 跨机房副本,多Broker分散负载,监控自动故障转移。
-
Kafka副本机制
- Leader处理读写,Follower同步数据,ISR保证一致性。
-
Kafka消息传递语义
- At-Least-Once,At-Most-Once,Exactly-Once(事务支持)。
-
消息持久化与缓存策略
- 磁盘日志持久化,Page Cache加速读写。
-
消费者组作用
- 组内消费者共享Topic,每条消息仅被一个消费者处理。
-
生产者可靠性配置
acks=all,retries重试,幂等性启用。
-
Offset管理区别
- 自动提交(可能重复),手动提交(业务成功后提交)。
-
Exactly-Once实现
- 生产者幂等性,跨分区事务。
-
Kafka性能调优
- 调整
batch.size,linger.ms,使用SSD,优化网络。
- 调整
-
批处理机制影响
- 减少网络请求,提升吞吐,但增加延迟。
-
消息积压处理
- 扩容消费者,临时Topic分流,丢弃非关键数据。
-
延时问题解决
- 优化消费者逻辑,减少拉取间隔,提升硬件性能。
-
Broker宕机恢复
- 切换Leader,副本同步数据,重启节点。
-
监控与诊断
- 监控吞吐量、延迟、Offset滞后,日志分析异常。
-
Kafka安全特性
- SSL/TLS加密,SASL身份认证,ACL权限控制。
-
Consumer推还是拉?
- 拉模式(消费者主动拉取)。
-
消费状态跟踪
- Offset存储于Broker或外部系统(如Kafka内部主题)。
-
Kafka主从同步
- Follower从Leader拉取数据,ISR维护同步副本列表。
-
ZooKeeper作用
- 管理集群元数据,协调Leader选举,监控节点状态。
-
Kafka判断节点存活的两种条件
- Broker与ZooKeeper保持心跳连接。
- Leader副本能正常响应副本同步请求(ISR机制)。
-
分布式下保证消息顺序消费
- 消息按Key哈希到同一Partition,单Partition内严格有序。
- 消费者组内每个Partition仅由一个消费者处理。
-
控制消费位置
- 手动提交Offset(
commitSync/commitAsync)。 - 使用
seek()方法重置Offset到指定位置。
- 手动提交Offset(
-
Kafka高可用机制
- 多副本(Replica)机制,每个Partition有多个副本。
- Leader故障后,从ISR列表选举新Leader。
-
减少数据丢失
- 生产者:
acks=all,确保所有副本写入成功。 - Broker:配置
min.insync.replicas保证最小同步副本数。 - 消费者:手动提交Offset,避免消费后未提交导致消息丢失。
- 生产者:
-
避免重复消费(如扣款场景)
- 业务层幂等性设计(如数据库唯一约束)。
- 消息携带唯一ID,消费端记录已处理ID。
-
Kafka定义与场景
- 定义:分布式流处理平台,支持高吞吐、持久化消息队列。
- 场景:日志聚合、实时数据处理、事件溯源。
-
Kafka的优势
- 高吞吐量(百万级TPS)。
- 水平扩展性(分区机制)。
- 持久化存储(支持长时间保留消息)。
-
队列模型与Kafka消息模型
- 队列模型:点对点,消息被单个消费者消费。
- Kafka模型:发布-订阅,支持消费者组并行消费。
-
多副本机制及好处
- 机制:每个Partition有Leader和Follower副本。
- 好处:数据冗余、故障自动恢复、高可用性。
-
保证消息不丢失
- 生产者:
acks=all和重试机制。 - Broker:多副本同步(ISR)。
- 消费者:手动提交Offset,确保消费完成再提交。
- 生产者:
-
高效存储设计原理
- 顺序写入磁盘,接近内存访问速度。
- 分段日志(Segment),按时间或大小切分。
- 稀疏索引(
.index文件)快速定位消息。
-
性能高原因
- 零拷贝技术(
sendfile)。 - 批处理(生产者和消费者批量操作)。
- 分区并行读写。
- 零拷贝技术(
-
Kafka优缺点
- 优点:高吞吐、持久化、扩展性强。
- 缺点:延迟较高、运维复杂度高。
-
分区(Partition)概念
- 逻辑划分:每个Topic被分为多个Partition,分散存储和负载。
-
分区原则
- 默认轮询分配(无Key时)。
- 指定Key时按哈希值分配到特定Partition。
-
消息分区的目的
- 水平扩展Topic的吞吐量。
- 允许并发消费,提升处理效率。
-
ACK机制
acks=0:不等待确认(可能丢失)。acks=1:Leader写入成功即确认。acks=all:所有ISR副本写入成功才确认。
-
日志分段与刷新策略
- 分段策略:按时间(
log.roll.hours)或大小(log.segment.bytes)。 - 刷新策略:异步刷盘(
log.flush.interval.messages控制频率)。
- 分段策略:按时间(
-
消息丢失/不一致的场景
- 生产者:
acks=0或1时Leader故障未同步副本。 - Broker:磁盘故障且无足够副本。
- 消费者:自动提交Offset后业务处理失败。
- 生产者:
五、ES
- ES是干什么的?
- 分布式搜索和分析引擎,支持全文检索、结构化查询、日志分析和实时数据分析。
- ES集群架构及调优
- 集群架构:3个主节点(避免脑裂),10个数据节点,索引按日期分治。
- 数据规模:单索引百亿级文档,分片数按数据量分配(建议单分片20-50GB)。 -
- 调优手段:分片数预计算、冷热数据分层、JVM堆内存(≤32GB)、
refresh_interval调大减少写入压力。
- Elasticsearch搜索过程
- 客户端发送查询请求到协调节点。
- 协调节点将请求转发到相关分片(主/副本)。
- 分片执行查询并返回结果(打分、排序)。
- 协调节点聚合结果,返回最终排名列表。
- 单个Node分片分配
- 通常每个节点分配10-20个分片,避免过多导致资源争用,结合硬件资源(CPU/内存/磁盘)调整。
- 大数据量聚合实现
- 使用
composite聚合分批次处理。 - 启用
doc_values提升聚合性能。 - 分片策略优化(如按时间范围分片)。
- 使用
- 数据写入原理
- 写入请求先到协调节点。
- 路由到目标分片的主副本。
- 主副本写入后同步到副本分片
- 客户端收到写入成功响应。
- 写入调优方法
- 增大
refresh_interval(默认1s调至30s)。 - 使用
bulk批量写入,调整batch_size。 - 关闭副本(写入完成后再启用)。
- 增大
- Master选举机制
- 基于Zen Discovery协议,节点通过Ping检测存活,过半节点投票选举Master。
- 配置
discovery.zen.minimum_master_nodes防止脑裂。
- 主分片数量后期更改
- 不能直接修改,需通过
reindex或新建索引调整。原因:分片数影响路由和存储分布,更改会导致数据重分布混乱。
- 不能直接修改,需通过
- 集群状态监控
- 使用
_cluster/health、_catAPI。 - 集成Prometheus+Grafana监控指标(节点状态、索引性能、JVM)。
- 商业工具:Elastic Stack的Monitoring模块。
- 使用
- Master节点与候选Master节点区别
- Master节点:当前负责集群元数据管理。
- 候选Master节点:配置为
node.master=true,可参与选举但非当前Master。
- 并发读写一致性
- 使用版本号(
version)实现乐观锁。 - 写操作指定
seq_no和primary_term保证时序一致。
- 使用版本号(
- 倒排索引
- 词项(Term)到文档ID的映射,记录词项出现的位置和频率,用于快速全文检索。
- 拼写纠错实现
- 使用
term_suggester或phrase_suggester基于编辑距离和词频推荐候选词。 - 结合N-Gram分词和统计模型优化。
- 使用
- 电商搜索技术架构
- 前端:商品数据通过Kafka同步到ES。
- 检索:ES实现商品搜索、过滤、排序。
- 优化:同义词扩展、聚合统计、性能分级(先召回后排序)。
- 避免脑裂方法
- 配置
discovery.zen.minimum_master_nodes=(master候选节点数/2)+1。 - 使用7.x+版本,默认启用
cluster.initial_master_nodes。
- 配置