tsalakh ain sus noam Huyah ol guf

勉強会のメモ。その他備忘録。参考にさせて頂いたサイトや資料はリンクさせて頂いていますが不都合があればご連絡ください。

【技術メモ】Elasticsearch/LuceneのDocValuesについて調べる

公式サイトより

www.elastic.co

Doc Values

Inverted IndexとDoc Values

  • ElasticsearchはInverted Index(転置インデックス)を採用している
  • が、ソート時は転置じゃない方が効率的(カラムストアと呼ばれる)
  • Elasticsearchでは、カラムストアを"doc values"として実装
  • DocValuesはデフォルトで有効
  • DocValuesは、fieldがインデックスされるときに生成される

Inverted Index

  • 転置インデックスは、certaion operationsのとき"のみ"有利
  • だからDoc Valuesが存在する
  • 転置インデックスは、termを含むドキュメントを探すのは得意
  • 一つのドキュメントに存在するtermを決定するのは苦手
GET /my_index/_search
{
  "query" : {
    "match" : {
      "body" : "brown"
    }
  },
  "aggs" : {
    "popular_terms": {
      "terms" : {
        "field" : "body"
      }
    }
  }
}
  • クエリの部分

    • 簡単で効率的だ
    • 転置インデックスは、termsでソートされてる
    • "brown"をterms listで見つけ、それを含むドキュメントを得るのは超早い
  • アグリゲーション部分

    • 一意のtermをドキュメントから探す必要がある
    • 転置インデックスでこれをやろうとするとvery expensive
    • インデックスのすべてのtermをiterateして当て込む必要がある
    • これは遅いしScale poorlyだ
  • DocValuesはこれに対して、inverting the relationshipで対処する

つまり、

Search finds documents by using the inverted index.
Aggregations collect and aggregate values from doc values.

Deep Dive on Doc Values

  • DocValuesはセグメント毎ベースで生成されて、かつ、immutableだ
  • DocValuesはDiskをシリアライズする、これはパフォーマンスとスケーラビリティ的に重要

  • 永続データ構造をディスクにシリアライズすることで、

  • JVMのヒープ上に保持するのではなく、
  • OSのファイルシステムキャッシュを利用してメモリを管理することができる

  • データの「ワーキングセット」が利用可能なメモリよりも小さい場合、OSはドキュメントの値をメモリに常駐させる。

  • これにより、ヒープに載せた時と同じパフォーマンスが得られる。
  • データの「ワーキングセット」が利用可能なメモリより大きい場合、OSは必要に応じてページングを開始する。
  • これらを純粋にヒープに載せると、OutOfMemoryが発生するのは避けられない

  • DocValuesの導入によって、ヒープは小さい設定でよくなる

  • 従来は、マシンのメモリの50%をJVMヒープに割り当てることが推奨されていました。
  • DocValuesの導入により、過去に推奨されたfull32gbの代わりに、おそらく64GBのマシンで4〜16GBのヒープを検討すること

Heap:Sizing and Swapping

  • Elasticsearchのデフォルトヒープ設定は1GB、通常は増やした方がいい
  • Luceneは、インメモリのデータ構造をキャッシュするためにOSを活用する。
  • Luceneセグメントは個々のファイルに格納され、セグメントは不変なので、これらのファイルは決して変更されません。
  • これにより、それらは非常にキャッシュに適しています。

Luceneのパフォーマンスは、OSとのこの相互作用に依存しています。 しかし、Elasticsearchのヒープに使用可能なすべてのメモリを与えた場合、Luceneのために残されることはありません。 これはパフォーマンスに重大な影響を与えます。

基本的な推奨は、ElasticsearchのJVMに50%、Lucene用に50% もしanalyzed string dataをaggregationgしないなら、JVMを減らした方が、GCも軽くなるしLucene用のメモリが増えるのでパフォーマンスは上がる

ヒープは32GBを超えないように。 JVMは圧縮したポインタを使用することができず、GCが非常に遅くなります。

32GBの話は相当重要。もっと大きいメモリを積んだサーバだったら?1TBとか。 まず、そんな大きなサーバじゃないことをおすすめする。 既にサーバがある場合には、以下の方針。 ・主に全文検索→4-32GBをヒープに。and letting Lucene use the rest of memory via the OS filesystem cache. ・主にソート/集計で、not_analyzedデータが多い→4-32GBをヒープに。and leave the rest for the OS to cache doc values in memory. ・主にソート/集計で、analyzed stringsが多い→32GBのノードを複数たてる。fielddataのためにヒープ領域が必要、だが1つのJVMで32GB以上のヒープはだめ


DocValues解説記事

blog.yoslab.com

DocValues とは?

  • 元々は、Lucene の機能
  • これを Elasticsearch でも使えるように v1.0 で実装していたよう
  • 今回のリリースでは、この DocValues の高速化が図られています
  • データをヒープで管理せず、OSレベルのディスクキャッシュ用のメモリ上で管理
  • 安定性が増す形
  • v1.4.0 では、このメモリをより効率的に使えるようになった、ということでしょう。

大谷さんによるDocValues記事翻訳

blog.johtani.info

doc values

  • メモリの利用の最も大きなものの1つはfielddataです。
  • aggregation、ソート、スクリプトがフィールドの値に素早くアクセスするために、フィールドの値をメモリにロードして保持します。
  • ヒープは貴重なため、1ビットも無駄にしないためにメモリ内のデータは高度な圧縮と最適化を行っています。
  • これは、ヒープスペース以上のデータをもつまでは、非常によく動作します。 これは、多くのノードを追加することによって常に解決できる問題です。
  • しかし、CPUやI/Oが限界に達してしまうずっと前に、ヒープ空間の容量に到達します。

  • 最近のリリースは、doc valuesによるサポートがあります。

  • 基本的に、doc valuesはin-memory fielddataと同じ機能を提供します。
  • doc valuesの提供する利点は、それらが、非常に少量のヒープ空間しか使用しない点です。 doc valuesはメモリからではなく、ディスクから読み込まれます。
  • ディスクアクセスは遅いですが、doc valuesはカーネルファイルシステムキャッシュの利点を得られます。
  • ファイルシステムキャッシュはJVMヒープとはことなり、32GBの制限による束縛がありません。
  • ヒープからファイルシステムキャッシュにfielddataを移行することによって、より小さなヒープを使うことができます。
  • これは、GCがより早くなり、ノードが更に安定することを意味します。

Linuxカーネルの基礎知識

pekopeko1.tumblr.com

ハード・ディスクと主メモリーの間にもアクセス速度の大きな差があります。 そこで,プロセッサのキャッシュと同じように,一度利用したハード・ディスクのデータをそのままメモリー内に保持しておくことで高速化が図れます。 メモリー内にデータがあれば,次回以降のアクセスの際にそれを高速に利用できます。この仕組みをディスク・キャッシュと呼びます。

ディスク・キャッシュの種類

Linuxでは,用途にあわせて複数のディスク・キャッシュを用意

  • バッファ・キャッシュ
    • バッファ単位でのキャッシュ
    • ブロック入出力(=ファイル入出力)はすべてバッファ経由
    • 処理終了後もバッファを解放せずにキャッシュとして利用
  • ページ・キャッシュ
    • ページ単位でのキャッシュ
    • Linuxでは基本的に,"ページ"という単位でメモリーを扱う
    • 一度使用したページを残すことで,再利用時の処理速度向上
    • ただし、ページ単位で入出力を行うデータにしか利用できない
    • このようなデータの代表:ファイルの中身のデータ

統合された2つのキャッシュ

  • ブロック入出力処理は,すべてバッファ経由
  • そのため,ページ・キャッシュに入るデータも必ずバッファ・キャッシュを利用
  • これは,キャッシュを重複使用することになる

  • カーネル2.2

    • ファイル読込はページ・キャッシュ、書込はバッファ・キャッシュ
    • 2種類のキャッシュの整合性を取るために面倒な操作が必要
  • カーネル2.4
    • ページ・キャッシュとバッファ・キャッシュが一部統合
    • バッファ・キャッシュとページ・キャッシュの間の同期問題を劇的に改善
  • カーネル2.6
    • バッファ・キャッシュを完全に廃止
    • ディスク・キャッシュは,すべてページ・キャッシュに統合
    • これに伴って,ディスク入出力の単位はブロックではなくページに変更

f:id:chamc:20170113215642p:plain


キャッシュの種類

linuxcommand2007.seesaa.net

ディスクキャッシュ

  • ディスクキャッシュ = ファイルキャッシュ+メタデータキャッシュ
  • メタデータ = i-Node,Directory Entry
  • メタデータキャッシュ = スラブキャッシュ
  • スラブキャッシュ = ページサイズより小さなデータをキャッシュする仕組み

freeコマンド

  • 実使用メモリー量:Totalメモリ - ( free + buffers + cached )

cached:ファイルキャッシュに使用しているメモリ量 buffers:メタデータキャッシュに使用しているメモリ量


カーネルレベルの解説込み

d.hatena.ne.jp

Linux のページキャッシュ

Linux (に限らず他の OS もそうですが) にはディスクの内容を一度読んだらそれはカーネルがキャッシュして、二度目以降はメモリから読む機構 = ページキャッシュがあります。

Linux のディスクキャッシュが「ページキャッシュ」と呼ばれるのは、キャッシュの単位がページだからです。 ページというのは Linux仮想メモリの最小単位。 つまり何かしらのデータがメモリに存在するとき、そのメモリ領域をカーネルが扱うときの最小単位です。 ディスクの内容をキャッシュする場合、ファイルを丸ごとキャッシュしたりするのではなくiノード番号とファイルのオフセットをキーにしてページ単位でキャッシュします。

ページキャッシュの処理はどこで実装されているか、を知ろうのコーナーです。

read(2) の処理を実装しているであろう箇所、つまりファイルシステム周りのコードを見ればいいわけです が、ファイルシステム関連は幾つかのレイヤに分かれた構造になっているのでなかなか複雑です。

肝になるのは仮想ファイルシステムです。

Linuxext3、tmpfs、reiserfs、xfs、vfat ... と多数のファイルシステムを扱うことができます。 そこでファイルシステムの実装を隠蔽するのが仮想ファイルシステムです。 またその抽象化されたファイルシステムはブロック型デバイスを抽象化したものと言えます。

すべてのファイルシステムへの命令は VFS を経由してそれぞれの実装へ到達します。 VFS はインタフェースを抽象化するだけでなく、各ファイルシステムに共通の手続きを提供したり、ページキャッシュのような性能を向上させる機能などを提供します。


http://goungoun.dip.jp/app/fswiki/wiki.cgi/devnotebook?page=Linux%A1%A2%C9%E9%B2%D9%A4%DE%A4%EF%A4%EA%A4%CE%CF%C3

ページキャッシュ(/proc/meminfo:Buffers + Cached)

ページキャッシュ経由でデータがやり取りされる。

+------------------------------------------+
| ファイルシステム、mmap、スワップ処理など |
+------------------------------------------+
         read↑          ↓write
+------------------------------------------+
|  ページキャッシュ (Buffers + Cached)     |
+------------------------------------------+
         read↑          ↓write
+------------------------------------------+
|        外部記憶装置(HDDなど)           |
+------------------------------------------+