悲观锁与乐观锁:核心机制与实现方式
- 悲观锁:通过互斥锁、读写锁、自旋锁等方式显式加锁,实现资源独占。
- 乐观锁:采用原子操作、CAS、版本号、无锁数据结构等机制,检测并处理冲突,通常不直接加锁。
悲观锁类型与要点
- 互斥锁(Mutex)
- 语义:互斥访问,持锁线程独占资源。
- 实现方式:用户态先尝试 CAS,失败则进入内核等待队列(如 futex),被唤醒后重新竞争。
- 适用场景:临界区较长或可能阻塞的操作。
- 读写锁(Shared Mutex)
- 语义:允许多个读者并行访问,写者需独占。
- 适用场景:读远多于写的共享数据。
- 注意事项:需关注写者饥饿和优先级策略。
- 自旋锁(Spinlock)
- 语义:通过忙等(循环检查)获取互斥权,是互斥的一种等待策略。
- 适用场景:短临界区、不可阻塞上下文、多核系统。
- 注意事项:高争用或单核时会浪费 CPU,建议使用自适应策略(如 spin‑then‑park)。
乐观锁机制与要点
- 原子操作 / CAS
- 语义:基于原子读写和 compare_exchange,实现无阻塞更新,适合短小原子更新(如计数器、标志)。
- 注意事项:需退避策略,处理重试开销,警惕 ABA 问题。
- 版本号 / 乐观锁
- 语义:读-改-写过程中不加锁,提交时检查版本号或条件,失败则重试或回退。
- 适用场景:读多写少的场合。
- 无锁数据结构
- 语义:用 CAS 等原语实现队列、栈等,读写不加互斥。
- 注意事项:实现复杂,需安全回收(如 hazard pointers、epoch GC),并处理 ABA 问题。
Redis 分片方案对比
Redis 是一种内存键值存储(in‑memory key‑value store),广泛应用于分布式缓存、消息代理等场景,支持低延迟读写,并具备可选的持久化与复制功能。
分片方式及特点
- 服务器分片(Redis Cluster)
- 路由方式:集群节点通过 cluster 协议维护 hash slot,负责请求路由。
- 优点 :
- 自动分片
- 内置故障转移与在线重分片
- 缺点 :
- 客户端需支持 cluster
- 跨节点多键操作受限(需 hash tag 或重定向处理)
- 客户端分片(Client‑side)
- 路由方式:应用或客户端库按哈希/一致性哈希决定目标实例。
- 优点 :
- 实现简单
- 无额外中间层
- 延迟低
- 缺点 :
- 扩容/故障需客户端感知并更新映射
- 无自动故障转移
- 代理/中间件分片(Proxy)
- 路由方式:代理层(如 Twemproxy、Codis)统一路由请求到后端分片。
- 优点 :
- 客户端透明
- 便于集中管理与平滑扩容
- 缺点 :
- 代理可能成为瓶颈或单点
- 需做好高可用与性能规划
Spark Shuffle 机制简述
Spark 就是一个分布式的大数据计算引擎。我们通过写代码给它下达指令,让它帮我们在成百上千台服务器上,极速完成数据的清洗(ETL)、统计报表分析(SQL)、实时流监控以及机器学习预测。
Spark Shuffle 本质上就是跨节点的数据重排列。
当我们执行像 GroupBy(分组)或 Join(关联)这样的高级分析指令时,为了把具有相同属性的数据汇聚到一起计算结论,Spark 必须把原本散落在集群各个节点上的数据进行全局的打乱与重新分布。
因为这个过程需要海量的网络传输和磁盘读写,所以 Shuffle 一直是 Spark 计算中最耗时、最容易成为性能瓶颈(比如发生数据倾斜)的环节。