Split-Ordered lists: lock-free hash tables

1.7K Views

April 12, 23

スライド概要

profile-image

分散システムとかデータベースとかロックフリーとかが好きです。

シェア

またはPlayer版

埋め込む »CMSなどでJSが使えない場合

関連スライド

各ページのテキスト
1.

Split-ordered lists: lock-free extensible hash tables O.Shalev and N.Shavit. In Journal of the ACM, 53(3):379-405,NY,USA,2006, ACM Press 論文紹介 M1 熊崎宏樹

2.

概要 複数のスレッドから並列にアクセスしても構造 が破壊されないハッシュテーブル  ロックを用いず高いスケーラビリティを実現  テーブルの拡張にもロックを用いない 

3.

既存研究  細粒度ロックハッシュテーブル ◦ DougLea氏によるバケット単位でのロックによる 並列ハッシュテーブル  Java6ではgetを楽観的ロック(成功時非ロック)にて行う 改良版をjava.util.ConcurrentHashMapとしてサポート ◦ 広く実用されている並列ハッシュとして比較対象  リニアハッシュテーブル ◦ ハッシュサイズを変更した際の影響範囲を最小 限に抑えるハッシュテーブル ◦ ハッシュテーブルアルゴリズムとしては比較的古 いけれどこれから紹介するものの先祖

4.

細粒度ロックハッシュテーブル  バケット単位でロックを行うハッシュマップ ◦ ロック対象バケットをハッシュで決定 ◦ リサイズは再帰的(?)にロックを獲得しながら行う  2003年発表Rev1.3, in JSR-166, the proposed Java Concurrency Package. ◦ 下図はストライプドロックハッシュテーブルの例 0 1 2 3 4 5 6 7

5.

細粒度ロックハッシュテーブル  バケット単位でロックを行うハッシュマップ ◦ ロック対象バケットをハッシュで決定 ◦ リサイズは再帰的(?)にロックを獲得しながら行う  2003年発表Rev1.3, in JSR-166, the proposed Java Concurrency Package. ◦ 下図はストライプドロックハッシュテーブルの例 赤い鍵をロックした場合 0, 3, 6番のバケットがロック 0 1 2 3 4 5 6 7 黄色い鍵をロックした場合 1, 4, 7番のバケットがロック 青い鍵をロックした場合 2, 5番のバケットがロック

6.

細粒度ロックハッシュテーブル  同一のロックを持つスレッドは一度に一つしか存在し ない ◦ スレッドは同時に一つのロックしか持たないのでデッド ロックもしない ◦ データ保持量に対してロック数を増やす実装もありうる 赤い鍵をロックした場合 0, 3, 6番のバケットがロック 0 1 2 3 4 5 6 7 黄色い鍵をロックした場合 1, 4, 7番のバケットがロック 青い鍵をロックした場合 2, 5番のバケットがロック

7.

リニアハッシュテーブル ハッシュのリサイズ時に移動するアイテムを 最少に抑えるハッシュテーブル  これ自身は特に並列性への配慮は無し   並列化は可能だけどそれが主眼ではない  1997年発表  Sorted Linear Hash Table Thomas Wang, March 1997last update July 1997 Hash(x) mod 4 == 0 0 1 2 3 Hash(x) mod 4 == 1 Hash(x) mod 4 == 2 Hash(x) mod 4 == 3

8.

リニアハッシュテーブル  例)ハッシュをリサイズして1だけ拡大する ◦ Modの係数を倍々で増やしていく ◦ 計算後の値が存在しないバケットを指すなら Modを1減らして計算した値を採用する Hash(x) mod 8 == 0 0 1 2 3 4 追加 Hash(x) mod 4 == 1 Hash(x) mod 4 == 2 Hash(x) mod 4 == 3

9.

リニアハッシュテーブル  下の例では、新しく追加されたバケットに既存 のバケットからアイテムを移動させた Hash(x) mod 8 == 0 0 1 2 3 4 Hash(x) mod 8 == 1 or 5 Hash(x) mod 8 == 2 or 6 Hash(x) mod 8 == 3 or 7 Hash(x) mod 8 == 4

10.

リニアハッシュテーブル  下の例では、新しく追加されたバケットに既存 のバケットからアイテムを移動させた ◦ Mod 8に変わる事によって移動する必要が 生じたのはMod 4 == 0だったバケットのみ 移動不要 Hash(x) mod 8 == 0 0 1 2 3 4 Hash(x) mod 8 == 1 or 5 Hash(x) mod 8 == 2 or 6 Hash(x) mod 8 == 3 or 7 Hash(x) mod 8 == 4

11.

Split-ordered Hashtable  リニアハッシュの概念から拡張し、ハッ シュサイズが変わっても一切のノード移 動が無いよう工夫  「バケットの間をアイテムが移動するので はなく、アイテムの間をバケットが移動す る」という文章が印象的  順を追って説明します

12.

Split-ordered list      すべてのアイテムを一つの線形リストに投入 線形リスト内はhash値で昇順に並んでいる バケットの先頭を表すSentinel ノードも同一の 線形リストに投入 Sentinelノードへのショートカットをテーブルとし て保持 ListはLockfreeListを使うため並列に操作して も壊れない ◦ 更に操作失敗時にiteratorが先頭に飛ぶ欠点を最寄 りのSentinelノードへ飛ぶように改善

13.

概念図  一本の線形リストにデータとSentinelノードが両方入る ◦ 水色がデータ、緑色がハッシュ値 リストの中身はハッシュに沿って昇順  Sentinelノードはバケットの値をビット逆転した物を使う  ◦ 説明のためhash最大値は1byteにします 00000010 ↓ 01000000 00 0 1 2 3 02 40 48 00000001 ↓ 10000000 6d 7f 80 00000011 ↓ 11000000 8a c0 74

14.

データの挿入 1. 2. 対象となるデータのハッシュ値を算出 ハッシュ値に対応するテーブルにアクセス 図左の縦長のテーブル  3. テーブルにSentinelノードへのポインタが書いてあるため 対応するノードへジャンプ 図中の赤い線  4. Sentinelノードの指すポインタを手繰っていけばハッシュの 昇順にデータが並んでいるため、対応する場所に挿入 00 69 0 1 2 3 02 40 48 6d 7f 80 8a c0 74

15.

テーブルの拡張  Sentinelノードの間に挟まるアイテムの数が一定数を 超えた場合にテーブルを拡張する ◦ リニアハッシュと違い必ず倍々オーダー  あらかじめテーブルはそれなりの広さが用意してあり、 コピー無しで拡張可能,そのためロック不要 ◦ それ以上の拡大は後述します 00 0 1 2 3 4 5 6 7 02 40 48 6d 69 7f 80 8a c0 74

16.

テーブルの拡張 1. 2. テーブル拡張後は新規探索は新しいテーブル上で行う テーブル上に無かったらその一個左のSentinelノードを探索 ◦ もしそこにも無かったら更にもう一個左 3. 4. Sentinelノードが挿入されているべき個所を見つけ次第、 Sentinelノードを挿入する 目的の場所を見つけたら挿入 00 0 1 2 3 4 5 6 7 02 40 48 6d 69 7f 80 8a c0 74

17.

テーブルの拡張 テーブル拡張後は新規探索は新しいテーブル上で行う テーブル上に無かったらその一個左のSentinelノードを探索 1. 2. ◦ もしそこにも無かったら更にもう一個左 3. 4. 00 62 0 1 2 3 4 5 6 7 Sentinelノードが挿入されているべき個所を見つけ次第、 Sentinelノードを挿入する 目的の場所を見つけたら挿入 02 40 48 60 6d 69 7f 80 8a c0 74

18.

なぜリサイズがLockfreeなのか  検索中のスレッドが他のスレッドに追い抜かれ ても処理が続行可能 ◦ 新しいアイテムが挿入されようと ◦ Sentinelノードが挟まろうと ◦ ハッシュテーブルが拡張されようと ◦ ハッシュ値が一つの線形リスト上で昇順に並んでいる事 に変わりは無い 00 0 1 2 3 02 40 48 6d 7f 80 8a c0 74

19.

テーブルのリサイズ  もし確保しておいたテーブルサイズで足りなくなったら ◦ 必要なだけ新しい配列を確保してアサイン  左の配列は充分大きい  2段階間接参照のためオーバーヘッドはある 00 0 1 2 3 4 5 6 7 0 02 1 40 2 3 48 4 6d 5 6 7f 7 80 8 8a c0 74 9 10 11 12 13 14 16 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 21 22 23 24 25 26 27 28 29 30 31 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31

20.

性能評価  Java実装のDougLea式の並列Hashmapを C++に移植して比較 ◦ ロックは64に固定(それ以上増やしてもパフォーマン スが改善しなかったため  Split-ordered listもC++で実装  計算機 ◦ 30-processor Sun Enterprise 6000, a cache-coherent NUMA machine formed from 15 boards of two 300 MHz UltraSPARC® II processors and 2 GB of RAM on each.  コンパイラ ◦ a Sun cc compiler 5.3, -xO5 and -xarch=v8plusa

21.

DougLea式ハッシュテーブル ロックを64以上増やしても性能が伸びなかったというグラフ

22.

二つのハッシュテーブルの比較

23.

二つのハッシュテーブルの比較 •DougLea式は24スレッドでピーク •新アルゴリズムは44スレッドでピーク •8スレッド以下の環境ではDougLea式のほうが高速 •新アルゴリズムはスケーラビリティに優れる •多スレッド時の速度がばらつくのはネットワークや並列マシン上で のスレッド配置が影響を与えるようになったから

24.

利用パターンによる性能差

25.

利用パターンによる性能差 左から右にかけて、検索の割合が減ってい き削除の割合が増えていくテストケース  スレッド数が少ない場合を除く全ての場面 で新アルゴリズムが倍以上高速 

26.

まとめ Split-orderedなLockfreeListによる並列ハッ シュマップを提案  一般に使われている物よりスケーラビリティに 優れる  8コアまでならDougLea式の方が高速 

27.

感想     DougLea式はJavaのメモリモデルを上手く利用していたのでそれ をどのようにC++に移植したのか興味深い(愚直にやると Segmentation Faultしてしまう 大規模計算機上でのみ真価を発揮するアルゴリズムかっこいい Lock-freeの利点は進行保証やリアルタイム性にも有るので価値 のあるアルゴリズムだと思った この論文を引用している論文を探したけれど比較対象として挙げ ている論文は見つからなかった。(実装が大変だから…?)

28.

他に読んだ論文  "A Pragmatic Implementation of Non-Blocking Linked-Lists" Timothy L. Harris ◦ CASベースのLock-freeな線形リスト  "Lock-Free Linked Lists and Skip Lists" Mikhail Fomitchev, Eric Ruppert ◦ 1本目の論文の改良版。CAS失敗時に線形リストの先頭まで 戻ってしまう欠点を補うため、削除操作をマーキング→削除の2 段階ではなくマーキング→直前ノードのポインタアサイン→削 除の3段階に分割したもの ◦ LockfreeSkipListはそれを利用して構成するようだけど差がよ く分からなかった ◦ 性能評価が無かったため紹介せず

29.

他に読んだ論文  "Simple, Fast, and Practical Non-Blocking and Blocking Concurrent Queue Algorithms“ Philippas Tsigas, Yi Zhang. 2001 ◦ Lockfree queueの論文。Enque操作を「末尾に繋げる」「tailポ インタを更新する」の2ステップに分割し、末尾に繋げる瞬間を 線形化ポイントとして定義し、2ステップ目を他のスレッドや Deque操作側で手伝うようにした画期的なQueue。同一の実 装がBoost.lockfree.fifoとして提案され現在レビュー中。  Software transactional memory for dynamic-sized data structures Maurice Herlihy, Victor Luchangco, Mark Moir, William N. Scherer 2003 ◦ HTMの生みの親であるMaurice氏がSTMについて書いた初め の論文。トランザクションマネージャーやグローバルロックが出 てきた辺りで中断。

30.

他に読んだ論文  Transactional Memory Today: A Status Report Maurice Herlihy Conference: International Conference On Principles Of DIstributed Systems - OPODIS 2009 ◦ Maurice氏が自分へのCitationの増加も含め HTM,STMの最近のトピックをおさらいしている  Hazard Pointers: Safe Memory Reclamation for Lock-Free Objects Maged M. Michael IEEE TRANSACTIONS 2004 ◦ CASベースのLockfreeデータ構造で常に問題にな るABA問題に対して、GCの考え方を取り入れて、 ハードウェア機能を利用したタグによるABA回避並 に効率的かつそれ以上に安全にオブジェクトの寿命 を管理する方法。実装でポインタ群を配列に入れて 2分探索する辺りから追えなくなった。

31.

他に読んだ論文  Lock-Free Data Structures Andrei Alexandrescu ,2007 ◦ WRRM(Write Rarely Read Many)な使用パターン においてはstd::mapなどの非並列データ構造を動 的に確保し、それへのポインタを経由して参照し、 データを追加・削除する際には全てコピーした上で 変更を加えた新しいポインタへCASすると良いよ、と いう論文(?) ◦ Segmentation Faultしないためにはオブジェクトの 寿命管理にはGCが妥当で、GCを用いた場合削除 や上書きの操作の線形一貫性は保たれないだろう けれど、これで充分な場面に適用するならとても簡 単に実装できるのでお勧め、という主張。