Help us understand the problem. What is going on with this article?

Riak docs の LevelDB を意訳してみた

More than 5 years have passed since last update.

後半疲れて、適当になりまくった意訳です・・・(本当に酷い
http://docs.basho.com/riak/1.3.1/tutorials/choosing-a-backend/LevelDB/

Overview

eLevelDB は LevelDB の Erlang バインディングです
LevelDB は相対的に新しい Key-Value データベースのライブラリです
LebelDB のストレージアーキテクチャは BigTable の memtable/sstable に似ています
この設計と実装は、Bitcask の RAM 制限を解消したストレージエンジンになる可能性があります

Strengths

LevelDB と eLevelDB のライセンスは New BSD License と the Apache 2.0 License です
LevelDB は初期設定で Google Snappy によるデータ圧縮を行います
これにより CPU の負荷が高くなるが、サイズを小さくできます
圧縮効率はテキストデータ (raw text, Base64, JSON …etc) で特に良くなります

Weaknesses

LevelDB は読み込む為に少数のシークが行われるかもしれません

TODO: 後で読む

Installing eLevelDB

eLevelDB はディストリビューションに含まれている為、個別にインストールする必要はありません
しかしながら、Riak の初期設定では Bitcask ストレージエンジンが使用されます
eLevelDB を使用するには、設定ファイル app.config の storage_backend variable を riak_kv_eleveldb_backend に変更します
eLevelDB を設定すると、Riak は初期状態で下記のように格納します。

erlang %% LevelDB Config {eleveldb, [ {data_root, "/var/lib/riak/leveldb"} ]},

Configuring eLevelDB

eLevelDB の初期状態の振る舞いは、app.config の eleveldb セクションのパラメータを追加または変更することで修正できます
eLevelDB の古い舞を修正するために使用するパラメータを、後述する Key Parameters セクションに記載します
また、アプリケーション要件に基づいたパラメータをどのように設定するかを、後述する Parameter Planning セクションに記載します

Key Parameters

eLevelDB の振る舞いを修正するパラメータを下記に記載します

Write Buffer Size

全ての v-node が同じサイズの write buffer を持つことは望ましくありません
同じ時間に write buffer の圧縮が起こることによって、パフォーマンスに影響を与えます
従って、初期状態では、eLevelDB は各 v-node の write buffer をランダムで生成します

write buffer の生成される範囲は、the write_buffer_size_min と write_buffer_size_max パラメータで指定します
もし app.config で指定しなかった場合は、the write_buffer_size_min を 30MB、write_buffer_size_max を 60MB となります
下記のように設定した場合 write buffer の平均サイズは 45MB になるでしょう

{eleveldb, [
        ...,

        {write_buffer_size_min, 31457280 }, %% 30 MB in bytes
            {write_buffer_size_max, 62914560}, %% 60 MB in bytes
        ...
]}

write buffers を変更する場合、write_buffer_size_min は少なくても 30MB 以上で、
write_buffer_size_max のおよそ半分のサイズが write_buffer_size_min で指定されるべきです

もし write buffers を全て同じサイズに設定したい場合は write_buffer_size を使用します
write_buffer_size を使用すると write_buffer_size_min と write_buffer_size_max を無視します
しかしながら、前述した通り write buffer を全て同じサイズに設定することは推奨されません

より大きな write buffer は、特にバルクロード中のパフォーマンスを増やします
Up to two write buffers may be held in memory at the same time,
so you may wish to adjust this parameter to control memory usage.

Max Open Files

DB によって開くことができるファイル数です
もし DB に大きな warking set がある場合、この値を増加させる必要があるかもしれません
TODO: budget one open file per 2MB of working set divided by ring_creation_size

max_open_files の最小値は 20 で、初期状態は 20 となります

{eleveldb, [
        ...,
            {max_open_files, 20}, %% Maximum number of files open at once per partition
        ...
]}

もし Riak 1.2 より前のバージョンで max_open_files を設定した場合は Riak 1.2 以上のバージョンでは半分に減らす必要があります
例えば Riak 1.1 で 250 を設定していた場合は Riak 1.2 にて 125 に設定します

ストレージエンジンに利用される open file に大きな値を設定する為には、システムの open files limits の設定を調べなければいけません
もし emfile を含むエラーが出力された場合は、システムの open files limit を超過しているでしょう
より詳細な情報は Tips & Tricks セクションを参照してください

Block Size

ブロックは user data packed のサイズに近い値を設定します
非常に大きなデータベースでは、block size を 256k (または他の 2 の累乗) に増やすように、より大きな block size がパフォーマンスを増加させる良い方法です

LevelDB の初期状態では、internal block cache は 8MB であることに注意してください
従って、block size を増やした場合、同様に cache_size サイズを変更したいと思いでしょう

block size の初期状態では 4K です

{eleveldb, [
        ...,
            {block_size, 4096}, %% 4K blocks
        ...
]}

Riak 1.2 においては初期状態の 4K から変更することは推奨されません
Riak 1.2 においては 4K より大きな block size がパフォーマンスを妨げる場合があります

Block Restart Interval

キーを delta エンコードする為の restart points 間のキーの数ってよくわかんねーけど、
ほとんどのクライアントは、このパラメータをそのままにしておくべきです
block_restart_interval の初期値は 16 です

{eleveldb, [
        ...,
            {block_restart_interval, 16}, %% # of keys before restarting delta encoding
        ...
]}

Cache Size

cache_size はどれだけのデータを LevelDB がメモリーに格納するかを設定します
データセットの多くをメモリーに載せることで、パフォーマンスが向上します
LevelDB のキャッシュは、OS とファイルシステムのキャッシュと一緒に動作します
それらを無効または under-size にしないでください

もし 64-bit の Erlang VM 上であれば、仮に十分な利用メモリーがある場合は 2GB を超えた値を設定できます
Bitcask と異なり、LevelDB は keys と values を block cache に格納します
これは利用可能なメモリーより大きな key space の管理を考慮に入れるためです

eLevelDB は cluster の各パーティションごとに LevelDB のインスタンスを作成します
したがって、各パーティションは自分のキャッシュを持つでしょう

利用可能なメモリーの 20-30% を cache_size に設定することを推奨します
利用可能とは、物理的に搭載されているメモリーから、ファイルシステムキャッシュのオーバーヘッドを含んだ他サービスで承知されるメモリーを取り除いた後のメモリーです

例えば、それぞれ 16GB のフリーなメモリーを備えた 4 台の物理ノードで 64 個のパーティションで構築されたクラスタを想定してください
最前のシナリオは、各ノード上の予想される active な v-node 数で、利用可能なメモリー の半分 (8GB) を割ったサイズを設定します
従って、予想される v-node 数は 16 (64 / 4) で、利用可能なメモリーの半分 8GB を割った値 512MB (8GB / 16) を設定します

     (Number of free GBs / 2) * (1024 ^ 3)
    ---------------------------------------- = Cache Size
    (Number of partitions / Number of nodes)

しかし、実際にはいくつかのノードが落ちるかもしれません
物理ノードが落ちた時に、このクラスターで何が起こるでしょうか
その落ちたノードによって管理されていた 16 台の v-node は、このクラスタの active なノード (今回の場合は 3 node) で処理されます
16 台の v-node ではなく、各ノードはおおよそ 22 台の v-node を処理します
16 台を超えるノードは fallback v-node で、落ちたノードの代わりとして管理する為に動作します

このケースにおける cache サイズは、さきほど予想した 16 * 512MB = 8GB に代わって、22 * 512MB = 11GB がキャッシュの合計となります
The total available memory is now too heavily weighted towards cache.
いくつかキャッシュに余裕を持たせたくなるでしょう

        (Number of free GBs / 2) * (1024 ^ 3)
    ---------------------------------------------- = Cache Size
    (Number of partitions / (Number of nodes - F))

    F = Number of nodes that can fail before impacting cache use of memory on remaining systems

もし 1 台の物理ノードが落ちてもキャッシュメモリーに影響を与えないようにする為には F = 1 を使用します
利用可能なメモリーの半分 8GB を 22 (64 / (4-1)) で割った値 372MB を指定します
これにより各物理ノードはメモリーを 50% で 22 台の v-node にキャッシュを有効に利用できます
If a second node went down, this cluster would feel that.

もしかしたら、なぜ利用可能なメモリーの 50% だけなのか疑問に思うかもしれません
それは、他の物理メモリーは OS や Erlang VM や OS のファイルシステムのキャッシュ (linux 上の buffer pool) によって使用されるからです
ファイルシステムのキャッシュは、クラスタの read/write にかかる時間を速くするでしょう
もう一つの理由としてはディスクへのページングを避けることにあります

仮想メモリーは OOM を防ぐのをサポートします
しかし、ディスクをページングするコストを高くし、クラスタのパフォーマンスに著しい影響を与えます

cache_size の初期値は 8MB です

{eleveldb, [
        ...,
            {cache_size, 8388608}, %% 8MB default cache size per-partition
        ...
]}

Sync

true にすると、書込みが完了する前に OS の buffer cache からフラッシュされます
これにより書込み速度は遅くなりますが、データの永続性をより正確にできます

false にすると、HW がクラッシュするといくつかの最近の書込みが失われるかもしれません
クラッシュしたのが単にプロセスであれば、sync が false でも書込みは失われません

言い換えれば、DB が同期しない書込みの意味合いは write() システムコールと同じ耐障害性を持っています
また、DB が同期する書込みの意味合いは fsync() に続いた write() システムコールと同じ耐障害性を持っています

もう一つの考えは、ハードディスクは自身のメモリーに書込みをバッファしているかもしれないので、プラッタに書き込む前に書き込み結果を返しているかもしれないということです
ハードディスクが停電の場合においてメモリー上のデータを保存できるかなので、安全かもしれないが、全然でないかもしれません
データの耐久性が絶対に必要な場合は、ディスクの buffer を無効にするか、バッテリーの冗長化を行い、適切に shutdown を行うようにしてください

sync の初期値は false です

{eleveldb, [
        ...,
            {sync, true}, %% do the write()/fsync() every time
        ...
]}

Verify Checksums

true にすると、基盤ストレージからの全てのデータ読み込みは、checksums が一致するか確認されるでしょう
verify_checksums の初期値は false です

{eleveldb, [
        ...,
            {verify_checksums, true}, %% make sure data is what we expected it to be
        ...
]}

Parameter Planning

次のステップは、パラメータを設定することによって、LevelDB の実装がどれだけメモリーを必要とするかを評価します

Step 1: Calculate Available Working Memory

現在の Unix-like なシステム (Linux / Solaris / SmartOS) は、ディスクオペレーションのためのバファ領域に、プログラマによって割り当てられなかった物理メモリーを使用します
Riak 1.2 では、LevelDB は OS のバッファリングに依存する為にモデル化されます
そのため、OS の為に利用可能な物理メモリーを 25-50% 残さなければいけません
ハードディスクの場合は 35-50%、SSD の場合は 25-35% 必要です

LevelDB のメモリーは、OS に予約されないメモリーとして計算されます

leveldb_working_memory = server_physical_memory * (1 - percent_reserved_for_os)

例えば、物理サーバが 32GB のメモリーを搭載し、そのうち 50% が予約されている場合は下記のようになります

leveldb_working_memory = 32G * (1 - .50) = 16G

Step 2: Calculate Working Memory per vnode

Riak 1.2 では、v-node に割り与えるメモリーを設定します
v-node の作業メモリーを計算するには、LevelDB の合計作業メモリーを vnode の数で割ります

vnode_working_memory = leveldb_working_memory / vnode_count

例えば、1 台の物理サーバが 64 台の vnode を含む場合は下記のようになります

bash vnode_working_memory = 16G / 64 = 268,435,456 Bytes per vnode

Step 3: Estimate Memory Used by Open Files

開かなければいけないファイルを与えられた際の正確なメモリーを決める変数があります
下記の定式は、適度に大きな LevelDB の実装において、誤差 10% 以内に近い値を求めます

open_file_memory = (max_open_files-10) * (184 + (average_sst_filesize/2048) * (8 + ((average_key_size+average_value_size)/2048 +1) * 0.6)

もし物理サーバが 64 台の v-node を含み、テーブルに示すパラメータの場合は以下のようになります

Parameter Value
max_open_files 150
average_sst_filesize 314,572,800 Bytes = 300MB
average_key_size 28 Bytes
average_value_size 1,024 Bytes = 1MB
Total 191,587,760 Bytes = 182MB
bash open_file_memory = (150-10)* (184 + (314,572,800/2048) * (8+((28+1024)/2048 +1)*0.6 = 191,587,760 Bytes 

Step 4: Calculate Average Write Buffer

write_buffer_size_min と write_buffer_size_max の平均を計算してください
初期状態はそれぞれ 30MB および 60MB です。
したがって、初期状態の平均は 45MB です。

Step 5: Calculate vnode Memory Used

v-node によって使用されるメモリーの憶測の量は、下記に占める項目の合計です

  • average_write_buffer_size (from Step 4)
  • cache_size (from app.config)
  • open_file_memory (from step 3)
  • 20 MB (for management files)

例えば、テーブルに示すパラメータの場合は、下記のようになります

Paramater Byte
average write buffer size 47,185,920 = 45MB
cache size 8,388,608 = 8MB
open files 191,587,760 = 182MB
management files 20,971,520
Total 268,133,808 (~255 MB)

Step 6: Compare Step 2 and Step 5 and Adjust Variables

例えば、ステップ 2 で、1 つの v-node あたりに 268,435,456 Byte = 256MB を作業メモリーに設定することを計算しました
ステップ 5 で、v-node は約 268,133,808 Byte = 255MB を消費するだろうと憶測しました
ステップ 2 とステップ 5 の違いは 301,648 Bytes (~300 kB) 以内にあります
これは例外的に近い値になっていますが、but happens to be more precise than really needed.
この間の誤差が 5% 以内であれば、十分に良い状態です

上記の計算は、この memory model spreadsheet の中で自動化されます

Tuning LevelDB

eLevelDB は、どのようにチューニングするかによってパフォーマンスは極端に変動します
All the configuration is exposed via application variables in the eleveldb application scope.

Tips & Tricks:

Be aware of file handle limits

eLevelDB は max_open_files を使用することでファイルディスクリプタの数を制御できます
eLevelDB は、一つのパーティションごとに初期状態の最小値である 20 が設定されます
したがって、64 個のパーティションがある場合、最大 1280 (20*64) 個のファイルディスクリプタを持つでしょう

これは、いくつかのプラットフォーム (例えば OS X の場合初期状態の上限は 256 です) で問題が発生します
その解決法は、利用できるファイルディスクリプタ数を増やすことです
open files limitations や Open-File-Limits の情報を調査してください

Avoid extra disk head seeks by turning off noatime

eLevelDB はファイルの読み書きを積極的に行います
そのため、/etc/fastab のマウントオプションに noatime を追加することで大幅な速度の向上を得ることができます
これは、全てのファイルの最終アクセス時間に記録を無効にします
If you need last access times but you'd like some of the benefits of this optimization you can try relatime.

/dev/sda5    /data           ext3    noatime  1 1
/dev/sdb1    /data/inno-log  ext3    noatime  1 2

Recommended Settings

Linux ディストリビューションにおける推奨される一般的な設定を下記に示します
本番環境においては、/etc/syscfg.conf を次のように設定することを推奨します

net.core.wmem_default=8388608
net.core.rmem_default=8388608
net.core.wmem_max=8388608
net.core.rmem_max=8388608
net.core.netdev_max_backlog=10000
net.core.somaxconn=4000
net.ipv4.tcp_max_syn_backlog=40000
net.ipv4.tcp_fin_timeout=15
net.ipv4.tcp_tw_reuse=1

Block Device Scheduler

カーネル 2.6 から、Linux は 4 つの I/O elevator モデルの選択肢を与えました
そのうち、NOOP elevator モデルを選択することを推奨します
Linux の boot line に evevator=noop を設定することで変更できます

ext4 Options

ext4 ファイルシステムはデータの保全性を増加させるが、パフォーマンス劣化を引き起こす 2 つのオプションを含んでいます
Riak の保全性は、同じデータを複数のノードで格納することに基づいています
これらの 2 つのオプションは LevelDB のパフォーマンスを向上させる為に変更できます
したがって、barrier=0 と data=writeback に設定することを推奨します

CPU Throttling

CPU のスロットリングがある場合、無効にすることで LevelDB のパフォーマンスを向上できる場合があります

No Entropy

HTTP プロトコルを使用していれば、カーネル 2.6 の SSL entropy bits によってプログラムが停止することがよく知られています
HTTPS を使用する場合は、疑似乱数の生成の為に HAVEGE パッケージのインストールを推奨します

swappiness

/etc/sysctl.conf に vm.swappiness=0 を設定することを推奨します
The vm.swappiness default is 60, which is aimed toward laptop users with application windows.
This was a key change for mysql servers and is often referenced on db performance.

FAQ

Riak 1.0 においてセカンダリインデックスを使用するには eLevelDB でバケットのインデックスが設定されていることを必要とします

LevelDB Implementation Details

LevelDB は Google の支援を受けたオープンソースプロジェクトです
LevelDB は Erlang アプリケーションに組み入れられ、Riak で key/value データをディスクに格納するストレージとなりました
LevelDB の実装は、BigTable をインスパイアしています

How “Levels” Are Managed

LevelDB は memtable/sstable デザインです
ソートされたテーブルへの Set は、レベルのシーケンスに整理されます
各レベルは、前のレベルのおよそ 10 倍程のデータを格納します
フラッシュによって生成されたソートされたテーブルは、特に若いレベル (level-0 と呼ばれる) に置かれます
若いファイル数がある閾値 (現在 4) を超えた場合、新しい level-1 ファイルのシーケンスを作成する為に、全ての若いファイルは level-1 のファイルとマージされます
新しい level-1 のファイルは、2MB ごとのデータに作成されます

若い level のファイルは、重複したキーを含んでいるかもしれません
しかしながら、他の levels は重複しない key ranges があります
1 よりも大きい場合の level の数 'L' を考えます
Level-L のファイルを結合したサイズが 10^L MB (例えば Level-1 は 10MB, Level-2 は 20
MB… のように) を超える場合、Level-L の一つのファイルと 全ての Level-(L+1) のファイルをマージし、新しい Level-(L+1) のファイルセットを作成します
これらのマージは、bukl reads と writes を使用するだけで、若い Level を最大の Level に徐々に移行する効果があります

Level-L のサイズが上限を超える度に、LevelDB はバックグランドのスレッドでそれらを圧縮するでしょう
Compaction は、Level-L からファイルを取り、次の Level-L+1 から重複するファイルを全て取り除きます
Level-L のファイルが、Lebel-L+1 のファイルの一部だけを重複している場合は注意してください
Level-L+1 のファイル全体が Compaction の入力として使用され、Compaction 後に破棄されるでしょう

Level-0 は特別 (Level-0 のファイルは重複しているかもしれない) なので、Level-0 から Level-1 への Compaction は特別に扱われます
Level-0 のファイルのうちいくつかが互いに重複した場合、Level-0 の Compaction は一つより多くの Level-0 のファイルを取り除くかもしれません

Compaction は、Level-L+1 ファイルのシーケンスを生成する為に、取ったファイルの内容をマージします
LevelDB は、現在の output ファイルが対象のファイルサイズ (2MB) に達した後に、新しい Level-L+1 ファイルを生成するよう切り替わります
現在の出力ファイルのキー範囲が、ten 'level-(L+2)' ファイルより十分に増えた場合に、LevelDB は新しい出力ファイルに切り返えます
この最後のルールは、Level-L+1 で行った Compaction の後では、Level-L+2 からデータをあまり取り除かないでしょう

各 Level への Compaction は、キー空間を通して回転します
より詳細を述べると、各 Level-L において、最後に Level-L で実施した Compaction が終了したキーを記録しています
Level-L に対する次の Compaction では、この記録したキーの後に最初にはじまるファイルを取るでしょう
もしファイルが無い場合、キー空間の最初に戻ります

Level-0 の Compaction は、Level-0 から 4 個の 1MB のファイルを読むでしょう
さらに最悪のケースで Level-1 の全てのファイル (10MB) を読みます
つまり、この場合は LevelDB は 14MB 読み込み、14MB 書き込むでしょう

Level-0 の特別な Compaction 以外においては、LevelDB は Level-L から2MB のファイルを 1個とるでしょう
最悪のケースにおいては、Level-L+1 から、およそ 12 個のファイルを重複しているでしょう
(10 because level-(L+1) is ten times the size of level-L, and another two at the boundaries since the file ranges at level-L will usually not be aligned with the file ranges at level-L+1).
従って、Compaction は 26MB (= 2MB *1 + 2MB * 12) 読み込み、26MB 書き込むでしょう
仮に 100MB/s のディスク I/O レートと仮定すると、最悪のケースにおける Compaction コストはおよそ 0.5 秒になるでしょう

意図的に遅くした場合についてなので省略:
If we throttle the background writing to a reasonably slow rate, for instance 10% of the full 100MB/s speed, a compaction may take up to 5 seconds. If the user is writing at 10MB/s, LevelDB might build up lots of level-0 files (~50 to hold the 5*10MB). This may significantly increase the cost of reads due to the overhead of merging more files together on every read.

Compaction

Levels are compacted into ordered data files over time.
Compaction first computes a score for each level as the ratio of bytes in that level to desired bytes.
For level 0, it computes files / desired files instead.
最も高いスコアのレベルが Compaction されます

Level-0 を Compaction する場合に考慮するただ一つの特別なケースは、that after picking the primary L0 file to compact, it will check other L0 files to determine the degree to which they overlap.
これは、いくつかの I/O を回避する試みで、we can expect L0 compactions to usually if not always be “all L0 files”.
See the PickCompaction routine in 1 for all the details.

Comparison of eLevelDB and Bitcask

LevelDB は持続的に順序づけられた Map です
Bitcask は持続的な Hash テーブルで、順序づけられていません
Bitcask はメモリーにキーを格納します
従って、多数のキーがある DB においては、利用可能なメモリーを使い果たし、仮想メモリを使用することでパフォーマンス劣化を引き起こすかもしれません

Bitcask は 一つの検索にかかるディスクシークは 1 回であることを保証します
LevelDB は少数のディスクシークが必要とするかもしれません
例えば、読み込みはレベル毎に一回のディスクシークが必要となります
もしメモリーにデータベースの 10% が格納されている場合、LevelDB は一回のディスクシークが必要になるでしょう
(for the last level since all of the earlier levels should end up cached in the OS buffer cache)
メモリーにデータベースの 1% が格納されている場合、LevelDB は二回のディスクシークが必要になるでしょう

Recovery

LevelDB never writes in place:
LevelDB は常にログファイルに追記するか、または新しいログファイルを生成する為に既存のファイルとマージします
したがって OS がクラッシュすると、不十分な書込みがログに記録されるでしょう
LevelDB のリカバリー処理は、checksums を使用して不完全なレコードを検知し、それをスキップするでしょう

eLevelDB Database Files

Below there are two directory listings showing what you would expect to find on disk when using eLevelDB.
この例の場合、64 個のパーティションリングを 64 個のディレクトリで表します

leveldb/
|-- 0
|   |-- 000003.log
|   |-- CURRENT
|   |-- LOCK
|   |-- LOG
|   `-- MANIFEST-000002
|-- 1004782375664995756265033322492444576013453623296
|   |-- 000005.log
|   |-- CURRENT
|   |-- LOCK
|   |-- LOG
|   |-- LOG.old
|   `-- MANIFEST-000004
|-- 1027618338748291114361965898003636498195577569280
|   |-- 000005.log
|   |-- CURRENT
|   |-- LOCK
|   |-- LOG
|   |-- LOG.old
|   `-- MANIFEST-000004

... etc ...

`-- 981946412581700398168100746981252653831329677312
    |-- 000005.log
    |-- CURRENT
    |-- LOCK
    |-- LOG
    |-- LOG.old
    `-- MANIFEST-000004

64 directories, 378 files

多数の put (write) オペレーションを行うと、eLevelDB で動作している Riak クラスタは次のように見えるでしょう

gburd@toe:~/Projects/riak/dev/dev1/data$ tree leveldb/
leveldb/
|-- 0
|   |-- 000118.sst
|   |-- 000119.sst
|   |-- 000120.sst
|   |-- 000121.sst
|   |-- 000123.sst
|   |-- 000126.sst
|   |-- 000127.log
|   |-- CURRENT
|   |-- LOCK
|   |-- LOG
|   |-- LOG.old
|   `-- MANIFEST-000125
|-- 1004782375664995756265033322492444576013453623296
|   |-- 000120.sst
|   |-- 000121.sst
|   |-- 000122.sst
|   |-- 000123.sst
|   |-- 000125.sst
|   |-- 000128.sst
|   |-- 000129.log
|   |-- CURRENT
|   |-- LOCK
|   |-- LOG
|   |-- LOG.old
|   `-- MANIFEST-000127
|-- 1027618338748291114361965898003636498195577569280
|   |-- 000003.log
|   |-- CURRENT
|   |-- LOCK
|   |-- LOG
|   `-- MANIFEST-000002

... etc ...

`-- 981946412581700398168100746981252653831329677312
    |-- 000003.log
    |-- CURRENT
    |-- LOCK
    |-- LOG
    `-- MANIFEST-000002

64 directories, 433 files

関連

http://dayafterneet.blogspot.jp/2011/05/google-snappy.html

na_ga
{ "twitter": https://twitter.com/na_ga, "facebook": https://www.facebook.com/katsutoshi.nagaoka }
cyberagent
サイバーエージェントは「21世紀を代表する会社を創る」をビジョンに掲げ、インターネットテレビ局「AbemaTV」の運営や国内トップシェアを誇るインターネット広告事業を展開しています。インターネット産業の変化に合わせ新規事業を生み出しながら事業拡大を続けています。
http://www.cyberagent.co.jp/
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away