[kernel] カーネル/VM Advent Calendar 2011 2日目 #kernelvm
この記事はhttp://atnd.org/events/21910のために書かれたものです。
今回の記事では TranscendentMemory, frontswap, zcacheを紹介します。
TranscendentMemory とは
簡単に言えばLinuxカーネルの新しいメモリ管理システムです。TranscendentMemoryは
- サイズが不定で知ることができない
- 特殊なput/getの関数でページ単位で「ハンドラ」を使って読み書きする
- 設定によっては書いたものが消えてしまうこともある
抽象的なメモリになっています。こんなにいかにも使いにくいのに一体どんなメリットがあるんでしょうか?
このようにメモリを抽象化することで、このシステムの裏側でいろいろと面白いことができるようになります。たとえば
- メモリデータを圧縮 (zcache) (2.6.39でstagingにマージ)
- 高速な回線を使ってP2Pでメモリデータをやりとり (RAMster)
- あるいはメモリサーバに送信
- SSDやNVRAMを「拡張メモリ」として活用
- VMのメモリをHypervisorで圧縮・dedup
などの操作が抽象化されていることによってやりやすくなります。
さて、以上のように TranscendentMemoryの裏側の例を紹介してきましたが、逆に表側、 TranscendentMemory にput/getする側はどうなっているのでしょうか。
put/getするfrontend側は
- ファイルシステムのcleanなファイルキャッシュを扱う cleancache (3.0にマージ)
- メモリがたりなくなれば TranscendentMemory から捨てられる
- swapをフックして TranscendentMemory に送る frontswap
とがあります。これをカーネルでONにしてbackend driverを適切に設定してやれば、あとはカーネルで適当にメモリ圧縮してくれるわけですね。
Frontswap+cleancache+zcacheを使ってみる
さて、せっかくなのでfrontswapなどを使ってみましょう。
当然みなさんgitでLinuxカーネルを取ってきてるでしょうから
$ git remote add tmem git://oss.oracle.com/git/djm/tmem.git $ git fetch tmem $ git merge tmem/frontswap-v11
このようにしてpatchをとりこんでください。mm/swapfile.cがconflictしますが
<<<<<<< HEAD err = try_to_unuse(type); compare_swap_oom_score_adj(OOM_SCORE_ADJ_MAX, oom_score_adj); ======= err = try_to_unuse(type, false, 0); /* force all pages to be unused */ test_set_oom_score_adj(oom_score_adj); >>>>>>> tmem/frontswap-v11
を
err = try_to_unuse(type, false, 0); /* force all pages to be unused */ test_set_oom_score_adj(oom_score_adj);
こんな感じに直せば大丈夫です。zcache,frontswap,cleancacheをカーネルに組み込むようにして、あとはいつものようにコンパイルしてください。
ですが…再起動する前に! zcacheはカーネルの起動パラメータに"zcache"が入っていないと有効にはなりません。忘れずに追加しておいてください。
…ということで再起動します。
Nov 23 06:36:56 [kernel] [ 3.769848] zcache: cleancache enabled using kernel transcendent memory and compression buddies Nov 23 06:36:56 [kernel] [ 3.799276] zcache: frontswap enabled using kernel transcendent memory and xvmalloc Nov 23 06:36:57 [kernel] [ 5.288799] zcache: created ephemeral tmem pool, id=0, client=65535 Nov 23 06:36:57 [kernel] [ 5.289425] EXT4-fs (sda5): mounted filesystem with ordered data mode. Opts: (null) Nov 23 06:36:57 [kernel] [ 5.289583] VFS: Mounted root (ext4 filesystem) readonly on device 259:655360. Nov 23 06:36:57 [kernel] [ 22.366606] Btrfs loaded Nov 23 06:36:57 [kernel] [ 22.395155] device fsid 5c08bf87-f564-4b2d-8a63-68e38f525614 devid 1 transid 1092270 /dev/sda3 Nov 23 06:36:57 [kernel] [ 22.397151] btrfs: enabling auto defrag Nov 23 06:36:57 [kernel] [ 22.397161] btrfs: use lzo compression Nov 23 06:36:57 [kernel] [ 22.397170] btrfs: disk space caching is enabled Nov 23 06:36:57 [kernel] [ 23.640003] zcache: created ephemeral tmem pool, id=1, client=65535 Nov 23 06:36:57 [kernel] [ 27.638328] zcache: created ephemeral tmem pool, id=2, client=65535 Nov 23 06:36:57 [kernel] [ 27.638337] EXT4-fs (sda5): re-mounted. Opts: (null) Nov 23 06:36:57 [kernel] [ 27.874058] zcache: created persistent tmem pool, id=3, client=65535 Nov 23 06:36:57 [kernel] [ 27.874065] Adding 4953084k swap on /dev/sda4. Priority:-1 extents:1 across:4953084k FS
うまくいけばこのようにファイルシステムのmountやswaponごとにzcacheが TranscendentMemory のpoolを作っているのがカーネルログに出てくるかと思います。
実際動いているの?
$ ls /sys/kernel/debug/cleancache/ failed_gets invalidates puts succ_gets $ cat /sys/kernel/debug/cleancache/* 24871401 46104226 491298 14126 $ ls /sys/kernel/debug/frontswap failed_puts gets invalidates succ_puts $ cat /sys/kernel/debug/frontswap/* 315690 634050 958144 1155149 $ ls /sys/kernel/mm/zcache/ compress_poor evicted_unbuddied_pages flush_found zbud_cumul_zbytes zv_curr_dist_counts curr_obj_count failed_alloc flush_total zbud_cumul_zpages zv_max_mean_zsize curr_obj_count_max failed_eph_puts mean_compress_poor zbud_curr_raw_pages zv_max_zsize curr_objnode_count failed_get_free_pages put_to_flush zbud_curr_zbytes zv_page_count_policy_percent curr_objnode_count_max failed_pers_puts zbpg_unused_list_count zbud_curr_zpages evicted_buddied_pages flobj_found zbud_buddied_count zbud_unbuddied_list_counts evicted_raw_pages flobj_total zbud_cumul_chunk_counts zv_cumul_dist_counts $ cat /sys/kernel/mm/zcache/curr_obj_count 201104 $ cat /sys/kernel/mm/zcache/compress_poor 32430
このようにcleancache, frontswapの動作状況が記録されています。
ところで cleancacheの方には failed_getsが、frontswapの方には failed_putsがありますね。上で書いた通り、cleancacheの方はいつでもbackend側でデータを削除してしまってもいいのでfailed_getsがあるわけですね。一方で、frontswapの方は、swapの中身が途中で消えてしまっては大変ですからfailed_getsはありません。その代わりにfailed_getsがあります。 frontswapはbackendにデータを渡しますが、この時にbackendは受け渡し拒否することができます。具体的ははzcacheの場合、メモリデータをあまり圧縮できない時(/sys/kernel/mm/zcache/zv_page_count_policy_percentの設定値 デフォルトで75%)には、受け渡しを拒否して普通のswap deviceに管理するようにしてもらいます。
おまけ
TranscendentMemoryについてはこんなPDFがあっていろいろ載っています。
http://www.linux-kvm.org/wiki/images/d/d7/TmemNotVirt-Linuxcon2011-Final.pdf