题目重点:先定义复合操作不变量,再用争用与锁持有时间评价分片锁、锁顺序、CAS及内存回收成本。
题意与假设
这道练习题保留了面经中值得训练的核心约束,并将需要澄清的条件单独列出。现场拿到变体时,先和面试官确认这些条件。
- 训练讨论一个共享key-value索引,put/get及跨key操作需分别定义;不把实际Azure Storage实现代入。
- 正确性合同包括读到完整版本、写入不丢失、跨key约束是否原子,不能只以线程安全一词概括。
- lock-free指系统整体持续进展,不等于每线程等待有界;wait-free是更强合同。
解题路线
- 先列受保护状态与操作不变量,读写需要怎样观察版本。全局mutex最易证明,先作为正确基线测锁等待、持锁时间和争用,而非假定一定慢。
- 热点来自独立key时用分片锁或节点锁减少竞争。跨分片操作按固定顺序取锁,resize/删除/迭代需要独立生命周期协议;锁变多不能自动保证复合操作原子。
- 缩短临界区把网络I/O与昂贵计算移出锁,但读取后执行再提交必须校验版本,避免过期状态写回。读写锁适用于真实读占比与读持锁成本条件,写饥饿/管理开销可能抵消收益。
- CAS/乐观更新要说明失败重试、ABA、内存回收和重排可见性。单个原子指针不等于整个结构lock-free;hazard/epoch等回收机制的正确性与成本需能解释。
- 用相同负载/语义比较throughput、p99、CPU重试、内存与公平性,覆盖热点key和长尾操作。若global lock已经满足SLO,细粒度复杂度可能不值得;这是实测取舍而非口号。
手动走一遍
训练例两个key之间转余额,按key分片后分别锁住更新不足以防读者看到中间状态。可按一致顺序同时持两锁并保证读合同,或把操作放事务/版本协议;只说每个key线程安全无法推出跨key金额守恒。
规模与取舍
单key锁查找可O(1),但实际等待取决于争用与临界区。lock-free重试次数不必每线程有界,不能简单宣称O(1)延迟。性能比较同时计元数据和内存回收成本。
易错点与追问
容易失分的边界
- 细锁越多必定越快。
- 把atomic与完整事务等同。
- CAS忽略ABA与被回收节点。
- benchmark没有热点或尾延迟。
继续深挖
- 全局resize如何和分片更新协调?
- 读多写少却写者饥饿怎么办?
- 一个线程持锁后阻塞I/O会怎样?
- lock-free结构如何安全释放节点?
