本作品采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可。
本作品 (李兆龙 博文, 由 李兆龙 创作),由 李兆龙 确认,转载请注明版权。
引言
最近闲来无事,机缘巧合下在FAST’20 Research Track(USENIX Conference on File and Storage Techniques (FAST),CCF A类会议,存储领域顶会)中看到了熟悉的名字:欢神,朱爷,飞刀。还能说什么呢,YYDS!!
这篇paper的名称是《HotRing: A Hotspot-Aware In-Memory Key-Value Store》,介绍了一种在热点情况下大幅增加访问效率的数据结构HotRing
,看了其设计以后不禁感叹到现代的工业代码设计与我们平时的玩具已经不是一个层面上的东西了。
一般情况下提起热点,绝大多数人想的可能还是缓存击穿,分片等等,殊不知真正的工业界已经开始玩热点散列+RCU+自研数据结构了。
这篇文章主要讨论下对于HotRing的理解,主要是对[1]的学习和思考。我花了两天时间撸了一个单机版的轮子,实际上就是完成了3.1和3.2的设计。没写成支持并发的原因就是无锁代码确实有点难,RCU配合CAS的代码不仅是没写过,连见过的都很少,都只是了解原理罢了,有时间把《Lock-Free Linked List Using Compare-and-Swap》和《A Pragmatic Implementation of Non-Blocking Linked-Lists》拜读下再动手写吧,不过从单机的性能测试来看性能确实是很高的。
从自己实现来看,这篇文章中最难的地方其实是无锁操作的设计(包括rehash部分),一般人连线程并发都玩不明白,更别提设计无锁数据结构了。
我最疑惑的地方有两点:其一在于用户态RCU操作的实现,不过在网上找到了描述这个机制的文章[7]。疑惑的原因是因为低版本内核RCU的实现中采用每个核经历一次上下文来判断宽限期,因为读操作中是会关开中断,保证读操作执行过程不会被中断,这样只要每个核都经历了至少一次上下文切换,自然宽限期就结束了,但是用户态的RCU该如何做到这一点呢?
还有一点疑惑就是paper中的CAS操作是以一种怎样形式使用的呢?最直观的想法就是基于Occupied实现自旋锁,比如[1]3.8图8(a),在update和insert操作并发执行的时候,显然只有一个线程可以抢夺到B的Occupied位,如果是update操作的话,原子地将要更新的数据项B的“下一个数据项地址”设置为已占用,另一个线程只能重试了。如果是insert的话,其会修改前一个数据项的“下一个数据项地址”,这样更新操作就只能重试了,这不就是自旋锁吗。
内容
我认为想理解这个数据结构最好的方法还是看论文,虽然有很多博客都描述了这个奇巧无比的数据结构,但是都宽泛有余,精细不足,比如[2]。
我自己撸的的hotring-s
玩具,和这篇文章的大多数文字一样,都是两个月前的事情了[9]。网上应该还没人这么搞,现在的话在github上可以找到一个大哥写的hotring-r
[10],但是指针的处理比较粗糙。
再者我很清楚加了readme可能项目的可能看的人也会更多(因为看起来就牛b了不少),但是我懒得加。
总结
阿里云在存储领域还是令人敬佩的,FAST20上Key Value Storage领域阿里就贡献了两篇文章,在整个FAST20上贡献了五篇文章,可以说是非常有牌面了。
天行健,君子以自强不息。希望未来可以投身于此领域深耕,为中国存储事业贡献自己的微薄之力。
真总结
这篇文章其实是两个月以前写的,当时打算找时间补了那两篇论文以后搞个无锁的代码再发这篇文章,但是实习以来确实比较忙,估计三五个月之内是不可能去看了,今天刚好忙里偷闲,索性就把这篇文章再审一审发出来了。
再看看当时的感叹,只能说那时少年意气风发,心中所想皆为梦想,现在看来,还是恰????最为实在。
参考: