12.9 学习笔记

1. Redis 和 MySQL 之间的数据同步与一致性如何保证?

数据同步方案

核心采用「更新数据库 → 消息队列通知 → 更新缓存」的流程:

  1. 数据更新时优先写入 MySQL,确保数据持久化落地;
  2. 通过 RabbitMQ/Kafka 等消息队列发送缓存更新通知(替代 Redis Pub/Sub 的不可靠方案);
  3. Redis 订阅节点接收通知后,主动从 MySQL 拉取最新数据更新缓存,保证缓存数据来源可靠。
一致性保障策略
  • 弱一致性(非核心数据):允许缓存与数据库短时间不一致,依赖缓存过期机制(设置合理 TTL)最终达成数据一致,实现成本低、性能影响小;
  • 强一致性(核心数据)
    ① 分布式事务:引入 Seata TCC 模式,将「更新数据库」和「更新缓存」纳入事务,保证操作原子性;
    ② 缓存操作策略:采用「先删缓存 → 更新数据库 → 延迟双删缓存」,避免并发场景下的缓存脏数据;
    ③ 兜底校验:定时任务对比缓存与数据库数据,发现不一致时自动修复。

2. Go 数组和切片的区别?

特性 数组 切片
长度特性 固定长度,声明时指定且不可修改 动态长度,随元素增删自动变化
底层结构 单一连续内存块,直接存元素 引用类型(指针+len+cap),指向底层数组
扩容机制 无扩容能力,需手动复制到新数组 自动扩容:<256 倍扩容,≥256 按 1.25 倍扩容,生成新底层数组
传参特性 值传递,拷贝整个数组,效率低 引用传递,仅拷贝 3 个底层字段,效率高

3. 如何排查 Goroutine 导致的 CPU 占用过高?

步骤 1:定位高 CPU 进程

Linux 环境下执行 top 命令,筛选出 CPU 占比高的 Go 进程,记录 PID。

步骤 2:采集性能数据
  • CPU 采样:go tool pprof -seconds 10 http://<进程地址>:<端口>/debug/pprof/profile
  • 协程栈信息:go tool pprof http://<进程地址>:<端口>/debug/pprof/goroutine
步骤 3:分析核心问题
  • 在 pprof 交互界面,通过 top 查看高 CPU 函数、list 定位具体代码行、web 生成调用图;
  • 重点排查死循环、高频计算、无阻塞的循环逻辑等异常。
步骤 4:进阶可视化分析
  • go-torch 生成火焰图,直观展示 CPU 占用分布;
  • 通过 trace 工具(go tool trace)分析协程调度轨迹,确认是否存在频繁切换、锁竞争等问题。

4. RESTful API 设计规范 & HTTPS 原理

RESTful API 设计规范
  1. 资源命名:用名词(复数)表示资源,如 /users/projects,禁用动词;
  2. HTTP 方法语义:GET(查询)、POST(创建)、PUT(全量更新)、PATCH(部分更新)、DELETE(删除);
  3. 状态码:遵循语义,如 200(成功)、201(创建成功)、400(参数错误)、401(未授权)、500(服务端错误);
  4. 版本控制:URL 中加版本(/v1/users)或请求头传版本号;
  5. 过滤分页:通过查询参数实现,如 /users?page=1&size=10&role=admin
HTTPS 原理

HTTPS = HTTP + TLS/SSL,核心通过「加密+认证+验完整性」保障通信安全:

  1. TLS 握手阶段
    • 客户端:发送随机数 + 支持的加密套件;
    • 服务端:返回随机数 + 数字证书(含公钥);
    • 客户端:验证证书合法性,生成预主密钥,用服务端公钥加密后发送;
    • 双方:基于 3 个随机数生成会话密钥(对称加密密钥);
  2. 数据传输阶段:HTTP 数据通过会话密钥对称加密传输,同时用消息摘要验完整性、数字证书验身份,防止窃听/篡改/伪造。

5. 脏读与幻读概念

  • 脏读:事务 A 读取了事务 B 未提交的更新数据,若 B 回滚,A 读取的是无效"脏数据",仅发生在「读未提交」隔离级别;
  • 幻读:事务 A 两次查询同一范围数据时,事务 B 插入/删除该范围数据,导致两次查询行数不一致("幻觉");与不可重复读的区别:不可重复读是数据内容修改,幻读是行数变化。

6. Redis ZSet 为何用跳表?

Redis ZSet 选择跳表而非红黑树,核心原因:

  1. 实现复杂度低:跳表的增删查逻辑比红黑树简单,代码维护成本低;
  2. 查询性能相当:时间复杂度均为 O(logN),满足排序查询需求;
  3. 范围查询高效:红黑树范围查询需中序遍历,跳表可通过上层索引快速定位边界,适配 ZRANGE/ZREVRANGE 等高频场景;
  4. 并发友好:跳表更新仅涉及局部节点,锁粒度小;红黑树旋转调整涉及多节点,并发性能受限。

7. 跳表的插入、删除、修改操作(面试结构化回答)

前置:跳表核心特性

跳表是概率型有序数据结构,基于多层索引链表实现(Level 0 是完整有序链表,上层为稀疏索引),平均时间复杂度 O(logN),实现简单且支持高效范围查询。

1. 插入操作

核心:找各层前驱 + 随机生成层高 + 更新指针

① 定位前驱:从最高层向下遍历,用 update 数组记录每一层"值小于目标值"的最后一个节点;

② 校验重复:遍历到 Level 0,若目标值已存在则返回(业务可支持重复值,调整判断逻辑);

③ 随机层高:以 50% 概率停止层高增长,保证索引层稀疏性;

④ 插入节点:若新层高超过跳表最大层高,补充 update 数组高层前驱(指向头节点),将新节点插入各层前驱后继位置,更新跳表最大层高。

2. 删除操作

核心:定位待删节点 + 更新前驱指针 + 清理空索引层

① 定位前驱:同插入逻辑,用 update 数组记录各层前驱;

② 校验存在性:Level 0 确认节点存在,不存在则返回;

③ 移除节点:遍历各层,将前驱后继指针跳过待删节点;

④ 清理层高:若最高层索引无节点,降低跳表最大层高,避免无效遍历。

3. 修改操作

两种实现方式:

  • 高效方式:按查找逻辑定位目标节点,直接修改值(O(logN));
  • 兼容方式:先删除旧值,再插入新值(兼容旧值不存在场景,略增开销)。
关键细节补充

① 随机层高:避免层级退化,是跳表保持 O(logN) 复杂度的核心;

update 数组:一次性记录各层前驱,将多轮遍历合并为一轮,保证性能;

③ 重复值处理:遍历判断改为"值小于等于目标值",Level 0 处理重复节点。

应用场景

跳表因实现简单、并发友好,被用于 Redis ZSet、LevelDB 等存储系统,核心适配"有序+范围查询"场景。

相关推荐
1104.北光c°4 分钟前
滑动窗口HotKey探测机制:让你的缓存TTL更智能
java·开发语言·笔记·程序人生·算法·滑动窗口·hotkey
默默开发1 小时前
完整版:本地电脑 + WiFi 搭建 AI 自动炒股 + 自我学习系统
人工智能·学习·电脑
for_ever_love__1 小时前
Objective-C学习 NSSet 和 NSMutableSet 功能详解
开发语言·学习·ios·objective-c
盐水冰9 小时前
【烘焙坊项目】后端搭建(12) - 订单状态定时处理,来单提醒和顾客催单
java·后端·学习
Hello小赵9 小时前
视频压缩编码学习(一)—— 基础知识大集合
学习
左左右右左右摇晃9 小时前
计算机网络笔记整理
笔记·计算机网络
不吃西红柿的859 小时前
[职场] 内容运营求职简历范文 #笔记#职场发展
笔记·职场和发展·内容运营
似水明俊德10 小时前
02-C#.Net-反射-学习笔记
开发语言·笔记·学习·c#·.net
智者知已应修善业11 小时前
【51单片机独立按键控制数码管移动反向,2片74CH573/74CH273段和位,按键按下保持原状态】2023-3-25
经验分享·笔记·单片机·嵌入式硬件·算法·51单片机
adore.96811 小时前
3.18 复试学习
学习