プログラマは人間のことって注釈が必要な時代

ロケットガールの誕生〜コンピューターになった女性たち」って本を読んでいて、ふと思い立ったので久しぶりに書いてみる。なんと4年振り!

NASAマーキュリー計画の裏方で活躍した黒人女性らを描いた「ドリーム(Hidden Figures)」って映画のヒットも記憶に新しいが、もともとコンピュータは数値計算をする人間のことを指していた。なので、機械式やデジタル式のコンピュータが登場したころは、Automatic ComputerとかDigital Computerと呼ばれた*1。下記に、Wikipediaからコンピュータの語源を引用する。

英語の 「Computer(コンピューター)」は算術演算(数値計算)を行う主体を指す語であるが、元々は主体として人を指していた。この用法は(英語圏では非常に稀になりつつあるが)今でも有効である。オックスフォード英語辞典第2版では、この語が主体として機械をも指すようになった最初の年を1897年と記している。同辞典では、1946年までに、異なる方式の計算機を区別するための、「Computer」に付く修飾語句がいくつか導入されている。これらの修飾語の中には「Analogue(アナログ)」、「Digital(ディジタル, デジタル)」「Electronic(エレクトロニック)」といった語が含まれている。様々な引用文から、1946年以前にこれらの語が既に使われていたことは明らかである。

エントリの更新をサボっていた間に、コンピュータ界隈では、深層学習に代表される人工知能技術が大盛り上がりである。深層学習は非常にざっくり言って、今まで職人技であった特徴量の設計を、大量のデータを用いて自動化する技術である。最初は画像識別の分野で注目されていたが、徐々に機械翻訳やゲームなど様々な応用が可能なことが明らかになってきた。人間がルール(コード)を書くのがこれまでのソフトウェアだったとすると、機械がデータからルールを見つけるのがこれからのソフトウェアであるってことで、Andrej Karpathy氏はこの潮流を「Software 2.0」と呼んでいる。もちろんSoftware 1.0的なプログラミングがまったく不要にはならないだろうが、昔は人間がプログラミングしてたんだよとか、プログラマって職業があってね、という注釈が必要な時代はいつ頃やってくるのだろうか?

ロケットガールの誕生: コンピューターになった女性たち

ロケットガールの誕生: コンピューターになった女性たち

*1:最近Analogue Computerが再び脚光を浴びつつあるので、区別する上でDigitalと修飾語を付ける必要がまた出てきたかも。

AIST Super Green CloudにおけるCloudStack運用話

本エントリはCloudStack Advent Calendar 2014の22日目のエントリとして書きました。

はじめに

今年の7月からApache CloudStackを用いてプライベートクラウドを運用しています。オープンソース版のCloudStackを155台(プロセッサ数3100)の計算機で運用するというのは、それなりの規模だと自負しています。InfiniBand + PCIパススルーでHPC用途でも使える性能を持った仮想クラスタを提供するという点が目玉です。詳細は次の2つのスライドを参照してもらうとして、本エントリでは、現在に至るまで遭遇したCloudStackの問題をまとめてみました。

プライマリストレージがローカルディスク、セカンダリストレージがS3互換のCephオブジェクトストレージという具合に、一般的な構成とはちょっと違っているのでコーナーケースをいろいろ踏んでいる模様です。通常はプライマリストレージとしてNFSなどの共有ストレージが使われます。CloudStackでは、スケジューラが選んだホストにVMをデプロイし、何か問題があると、VMマイグレーションで別ホストに動かすという処理を行うことがあります。共有ストレージの場合はまったく問題ないのですが、ローカルストレージだとマイグレーションできず、そこでジ・エンドです。例えば、以下のリストには挙げてませんが、仮想クラスタを作成するとき、複数のVMを同時並行にデプロイします。この際、タイミングによっては、スケジューラは同じホストを選択することがあります。しかし、PCIパススルーを使う場合はホストに1 VMしか実行できないので、後続のVMはリソース不足でデプロイに失敗します。すると、そのVMを次の候補のホストにマイグレーションしようとするのですが、前述のようにプライマリストレージがローカルストレージだとマイグレーションに失敗し、デプロイもエラーになります。(補足:PCIパススルー拡張の有無に関わらず、デプロイに失敗した場合にこの問題は起きえます。)

当初はMLやJIRAにリポートしても反応が薄く(というか無反応)でかなり気持ちが萎えたのですが、年末に近づくにつれパッチも取り込まれ始め安堵しています。まだまだ抱えている問題は山積しているので、来年は開発コミュニティに対してもっとプレゼンスを上げていきたいと考えています。また、運用で得た知見も別途機会を設けて共有したいですね。

運用中に踏んだ地雷リスト

以下に、我々が遭遇した不具合を列挙します。なお、我々はバージョン4.3を使っており、独自に開発したSR-IOV対応パッチを取り込んでいます。以下でたびたび「sriov-43」というgitブランチ名が出てきますが、これはプライベートなgitリポジトリのブランチです。

1. cloudstack-agent jsvc gets too large virtual memory space. (JIRA #7951)

物理メモリの搭載量の大きいマシンで、cloudstack-agent が過剰に仮想メモリを確保するため、インスタンス作成時にQEMUがメモリを確保できず起動に失敗する場合がある。cloudstack-agent のメモリ使用量を制限するパッチを作成した。パッチは本家に報告して取り込まれた。

ホスト起動時は問題ないが、数日経つとVMのデプロイに失敗するという現象が発生する。メモリリーク等を疑ったが、結局cloudstack-agentの問題だった。cloudstack-agent(jsvcプロセス)が30GB超のメモリを確保していた。

2. listUsageRecords generates NPEs for expunging instances (JIRA #6472)

アカウンティング情報を取得する API を呼び出す際に、破棄されたリソースがあると NullPointerException が発生する不具合があった。修正パッチが既に本家に取り込まれていたが、この修正に不十分な部分があり、NullPointerException は発生しないものの必要な情報(virtualmachineid)が含まれない状態で結果が返ってきていた。取得情報に virtualmachineid も含める修正パッチを作成し、本家に報告して取り込まれた。

3. Duplicate usage records when listing large number of records (JIRA #2625)/Small page sizes return duplicate results (JIRA #3401)

アカウンティング情報を取得する際の SQL 文が適切ではなく、ページサイズ等の条件によっては内容の重複する結果が返ってくる場合があった。既知のバグでありパッチも存在したので、sriov-43 ブランチにcherry-pick した。

4. Public key content is overridden by template's meta data when you create a instance (JIRA #6869)

インスタンスの ROOT ボリュームからテンプレートを作成すると、そのインスタンスの下記の情報もテンプレートの属性情報として記録されていた。

そのテンプレートから新しいインスタンスを作成する際、user data 経由でSSH 公開鍵を渡そうとしても、強制的にテンプレート付属の SSH 公開鍵がインスタンスに渡されていた。本家に報告後、開発者(Harikrishna Patnala)により修正パッチが作成されたので、sriov-43ブランチにcherry-pickした。

5. Attaching a data disk created on local storage to a VM is failing (JIRA Migration of a VM with volumes in local storage to another host in the same cluster is failing #6802)/Migration of a VM with volumes in local storage to another host in the same cluster is failing (JIRA #6810)

プライマリストレージにローカルディスクを使用する構成での不具合である。特定の物理マシンの host id を指定してインスタンスを作成すると失敗する場合があった。storage poolallocator の処理に不具合があった。既存のバグであり、パッチも存在したので、sriov-43ブランチにcherry-pickした。

6. Negative ref_cnt of template(snapshot/volume)_store_ref results in out-of-range error in Mysql (JIRA #6236)

セカンダリストレージに S3 を使用する構成での不具合である。セカンダリステージングストア上に作成されるテンプレートのキャッシュの排他制御ができておらず、タイミングによってキャッシュの参照カウンタが -1になる場合があった。参照カウンタが -1 となったテンプレートはそれ以後使用できなくなる(ゴミとして残る)。本家に workaround する本パッチが報告されていたが、排他制御を行う根本的な対処ではなく、参照カウンタが 0 の時はそれ以上デクリメントしないという処理を追加するパッチであった。ただしこのパッチにもバグがあり、修正すべきメソッドとは別のメソッドに処理が追加されていたため、我々で修正した上でsriov-43ブランチに適用した。

7. [S3] Parallel deployment makes reference count of a cache in nfs secondary staging store negative(-1) (JIRA #7539)

上記のパッチ(CLOUDSTACK-6236)適用後も別の処理で参照カウンタが -1 になる現象が発生したため、根本対策としてキャッシュの処理部分に lock による排他制御を追加するパッチを作成した。本家に報告、パッチの送付を行ったが、未だに放置されている。

8. Can't create proper template from VM on S3 secondary storage environment (JIRA #7412)

セカンダリストレージに S3 を使用する構成での不具合である。インスタンスのボリュームからテンプレートを作成する際にも、セカンダリステージングストア上でボリュームがキャッシュされる不具合があった。同じインスタンスのボリュームから複数回テンプレートを作成すると、2回目以降はプライマリストレージ上のオリジナルのボリュームではなく、セカンダリステージングストア上のキャッシュされた古いボリュームからテンプレートが作成されていた。インスタンスのボリュームからテンプレートを作成する際は、セカンダリステージングストアでキャッシュしないパッチを作成した。パッチは本家に報告して取り込まれた。

9. Fails to attach a volume (is made from a snapshot) to a VM with using local storage as primary storage. (JIRA #8085)

これもプライマリストレージがローカルディスクの場合に起きる(マイグレーションを前提としていることに起因する)バグ。スナップショットから作成したボリュームがアタッチできない。バグ報告済み。

クラスタ管理ソフトウェアとの相性

ASGCのもう一つの特徴として、いわゆるスパコン上でクラウドを運用している点が挙げられます。ASGCのハードウェアは、Cray社製のスパコン(PCクラスタ)です。Crayのスパコンには標準のクラスタ管理ソフトウェアとしてACEが搭載されており、ASGCでも使っています。ACEはスパコンとして運用することを前提に作られたソフトウェアなので、CloudStackなどのクラウドミドルウェアを動かすことは念頭になく、ホストでcloudstack-agentが動作するまでに結構苦労しました。この手のクラスタ管理ソフトウェアとクラウドミドルウェアの親和性が高くなると、運用する側としてはとってもうれしいです。

ACEでは、ネットワークブートでディスクイメージを各ホストに展開しますが、/work以外のディレクトリはread onlyになります。一般的なスパコン運用であればこれで問題ないのですが、これではCloudStackは動きません。具体的には、次のような問題があり、地道に問題を潰していきました。ファイル一つの変更でもディスクイメージの作り直しが必要になります。。

  • /etc や /var/lib/libvirt 上のファイルが編集できない。/etc/cloudstack/agent/agent.properties などの cloudstack-agent が書き換える事を前提としているファイルを全て洗い出し、それらのファイルを /work に移しシンボリックリンクを貼る。
  • /etc/{cgconfig.conf,cgrules.conf} など、CloudStack 関連以外のファイルも cloudstack-agent が書き換えるため、/work に移してリンク

謝辞

上記の問題を解決し、日々ASGCの安定運用に尽力しているASGCサポートチームの面々(少数精鋭!)に感謝して、本エントリを閉じます。

Programming -- Principles and Practice Using C++

C++のお勉強に、Stroustrupの「Programming -- Principles and Practice Using C++」略してPPPを読み始めた。言語の学習は原典というか、作者の本をまず読むことにしているんだけど、「The C++ Programming Language」の方ではなく、こっちを選んだ。ちなみにTC++PL3の翻訳は持っているけど、全然読めてない。。

実行環境はMac OS X 10.10なのでclang。公式ページからstd_lib_facilities.hをダウンロードしておく。

以下、メモ。
2章から7章までプログラムを動かしながら読む。プログラミングの初心者向けの内容なので、特にC++どっぷりという内容ではない。Hello Worldから始まり、数式をパースして四則演算を行うプログラムを作ってみる。この内容で250ページも書くんだからなぁ。。

  • 3.9.2 unsafe conversions
    • narrowingの説明
    • C++11にはbrace-initializationってのがあって、narrowingをerrorにできる。
  • 4.3.1 constant expressions
    • const以外にconstexprってのがある。コンパイル時に定数とわかるものについてはconstexprと書ける。
  • 4.6 vector
  • 5.6 exceptions
    • 例外のさわりを紹介
  • 6. Writing a program
    • user-defined typeの実現としてclassを導入。structは出てこない。
    • expression()で再帰を導入。
  • 7. (6の拡張)
  • 8.
    • scopeとかpass-by-value、pass-by-(const-)reference。当然pointerはまだ出てこない。
    • 関数呼び出し時のスタックの挙動
    • だんだんstd_lib_facilities.hで隠蔽されていたことが明らかになってくる。

Programming: Principles and Practice Using C++ (English Edition)

Programming: Principles and Practice Using C++ (English Edition)

OSv雑感

次のスライドは@syuu1228さんの「OSvの概要と実装」。

  • ライブラリOSが流行っている感じもするので、そのうちまとめておきたい。USENIX ATCのOSvの発表を聞いて、タネンバウム教授がexokernelと何が違うみたいな質問をしてたそうな。
  • ユーザ空間がなくカーネル空間のみという割り切りはすごい。ハイパーバイザが最後の砦になるので、よいという判断。カーネルじゃなくてライブラリと考えればそんなものかとも思うが、カーネルとアプリが同じメモリプールからmallocするとなると、ちょっとしたオーバランでカーネルをぶっ壊してしまいそう。
  • アプリからPF filterやnet channelにフックを仕込んでパケットを奪って処理することが可能。実装の雰囲気としてはカーネルモジュール。
  • ttyないのでエディタを開発するのは難しい。REST APIを利用して外部からファイルを流し込むのがOSv流。
  • Dockerと狙いがかぶってそう。完全なisolationが一つの鍵か?
  • Virtual Appliance的な利用を想定しているようだ。
  • 元々ゲストOS上で動くことしか考えてなかったが、実はベアメタルで動きそうなぐらいレガシーデバイスがサポートされつつある。もう一息でベアメタルで動いてしまったり?
  • Huaweiがaarch64サポートを実装。

gitから任意のバージョンのLinuxカーネルのソースコードをチェックアウトするメモ

何はともあれgit clone。

$ git clone git://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable.git

Linuxカーネルでは、3.x.y系列ごとにブランチがあり、リリースバージョンにタグを付けることになっている。なので、ソースコードをチェックアウトする方法は2つ。ブランチ(linux-3.x.y)をチェックアウトする方法と、タグ(v3.x.y)でリリースバージョンをチェックアウトする方法。

まずはブランチから。git branch -aで本家のブランチがずらずらでてくるので、見たいバージョンを探す。

$ git branch -a

あとは任意のバージョンをチェックアウトするだけ。

$ git checkout -b linux-3.10.y origin/linux-3.10.y

続いてタグ。git tag -lでずらずらでてくる。

$ git tag -l

タグを指定して、チェックアウト。

$ git checkout -b v3.10 v3.10

ここではローカルリポジトリにブランチを作っているけど、もちろん「-b xxx」を指定しなくてもOK。

ソースコードリーディングのお供としてctagsをと思ったけど、CentOSvimだとcscopeがデフォルトっぽいので、cscopeのタグファイルを作っておく。

$ make cscope ARCH=x86

SimGrid

分散システムのシミュレータに仏INRIAが開発しているSimGridってのがある。メルボルン大のCloudSim(その前にGridSimってのもあった)とは別物。SimGridは大抵のUNIXシステムに対応しているので、OSXでも動くのだが、homebew用のformulaもあったので、サックリ動かすことができた。

ただ、ソースパッケージの中にはサンプルコードもいろいろあるので、ダウンロードしてそっちも眺めてみることを勧める。例えば、examples/msg/sendrecvってのは単純な2プロセス間でのメッセージ送信になる。

$ cmake CMakeLists.txt
$ make

sendrecvという実行ファイルが生成される。以下が実行結果。platform_sendrecv.xmlでホストやネットワークトポロジを定義し、deployment_sendrecv.xmlでプロセスをどのホストでデプロイするか定義する。

$ ./sendrecv platform_sendrecv.xml deployment_sendrecv.xml 
[0.000000] [msg_test/INFO] test_all
[Inmos:sender:(1) 0.000000] [msg_test/INFO] sender
[Inmos:sender:(1) 0.000000] [msg_test/INFO] host = Bellevue
[Inmos:sender:(1) 0.000000] [msg_test/INFO] task_la->data = 0.000000e+00
[Bellevue:receiver:(2) 0.000000] [msg_test/INFO] receiver
[Bellevue:receiver:(2) 1.301011] [msg_test/INFO] Task received : latency task
[Bellevue:receiver:(2) 1.301011] [msg_test/INFO] Communic. time 1.301011e+00
[Bellevue:receiver:(2) 1.301011] [msg_test/INFO] --- la 1.301011 ----
[Inmos:sender:(1) 1.301011] [msg_test/INFO] task_bw->data = 1.301011e+00
[Bellevue:receiver:(2) 1085.076238] [msg_test/INFO] Task received : bandwidth task
[Bellevue:receiver:(2) 1085.076238] [msg_test/INFO] Communic. time 1.083775e+03
[Bellevue:receiver:(2) 1085.076238] [msg_test/INFO] --- bw 922700.551985 ----
[1085.076238] [msg_test/INFO] Total simulation time: 1.085076e+03

platform_sendrecv.xmlの定義では、InmosとBellevueの間の遅延は100ミリ秒なのに、実行結果が1.3秒とはこれ以下に? platform_sendrecv.xmlの遅延を半減したり倍増して再実行してみたけど、やっぱり一桁結果が違う。バンド幅は100Mbpsという定義なので、ほぼあっているけど。

(追記)マニュアルによると、デフォルトのネットワークモデルLV08ではTCP slow startをモデル化するために、遅延が10.4倍になるとかある。うぅ、なぜそんなモデル化になるのか、よくわからん。

CentOS 7でOSvを動かすまで

OSvを動かしてみるぞ〜。

git clone https://github.com/cloudius-systems/osv.git

して、README.mdを眺める。scripts/setup.pyで必要なパッケージをインストールするみたいだけど、CentOS用の記述がないので、Fedoraをベースにコードを追加。versionがexact matchなので、マイナーバージョンアップしたらダメだな、これ。まぁ、いいや。

diff --git a/scripts/setup.py b/scripts/setup.py
index 8487c2a..c73891b 100755
--- a/scripts/setup.py
+++ b/scripts/setup.py
@@ -51,6 +51,30 @@ class Fedora(object):
 
     versions = [Fedora_20, Fedora_21]
 
+class CentOS(object):
+    name = 'CentOS Linux'
+    install = 'yum -y install'
+    packages = ['gcc-c++', 'gcc-c++-aarch64-linux-gnu', 'git', 'gdb', 'qemu-img',
+                'qemu-system-x86', 'libvirt', 'maven', 'java-1.7.0-openjdk',
+                'ant', 'autoconf', 'automake', 'boost-static', 'genromfs', 'libtool',
+                'flex', 'bison', 'maven-shade-plugin', 'python-dpkt', 'tcpdump', 'gdb',
+                'gnutls-utils', 'openssl', 'python-requests', 'p11-kit', 'patch', 'wget',
+                'unzip', 'ncurses', 'ncurses-devel', 'libstdc++-static', 'openssl-libs',
+                'openssl-devel'
+                ]
+    ec2_packages = standard_ec2_packages
+    test_packages = ['openssl-devel']
+    ec2_post_install = standard_ec2_post_install
+
+    class CentOS_7(object):
+        packages = []
+        ec2_packages = []
+        test_packages = []
+        ec2_post_install = None
+        version = '7.0.1406'
+
+    versions = [CentOS_7]
+
 class Debian(object):
     name = 'debian'
     install = 'apt-get -y install'
@@ -105,6 +129,7 @@ class Ubuntu(object):
 distros = [
            Debian(),
            Fedora(),
+           CentOS(),
            Ubuntu()
            ]

あとは、README.mdに従うだけだけど、makeで止まった。なにやら途中でqemuを起動しているのだが、CentOSにはqemu-system-x86_64コマンドがない(代わりに/usr/libexec/qemu-kvmがある)のが問題のようだ。次のようにworkaround。

$ sudo ln -s /usr/libexec/qemu-kvm /usr/bin/qemu-system-x86_64

scripts/run.pyを実行すると、驚くほどあっさりOSvが起動する。ちなみに-nオプションを付けると、ネットワークが有効になる。デフォルトでは192.168.122.0/24からDHCPIPアドレスが払い出される。-vオプションでvhostを使った高速化が有効になる。

$ sudo ./scripts/run.py -nv
OSv v0.13-53-ge31c3dd
DMI: error
eth0: 192.168.122.89
/# help
COMMAND DESCRIPTION
api     execute arbitrary OSv API operations as defined by the schema
cat     concatenate files and print on the standard output
cd      change the shell working directory
date    print the system date and time
df      report file system disk space usage
dmesg   print operating system boot log
echo    display a line of text
exit    close shell and exit
free    display amount of free and used memory in system
hello   a command example
help    list console available commands and show help
ls      list directory contents
mkdir   make directories
rm      remove files or directories
top     display OSv threads
/# 
/# hello
Hello, OSv!

/proc/self/mapsを見て、luaの共有ライブラリがリンクされているので気付いたのだけど、このシェルはluaで実装されているのね。

/# cat /cli/commands/hello.lua
--[[
Commands are expected to be Lua modules.
This file is an example of such a module.
For more on Lua modules, see: http://lua-users.org/wiki/ModulesTutorial
]]--

local cmd = {}

cmd.desc = [[a command example]]
cmd.hello = [[Usage: hello

A command example.]]

--- Called when the command is executed
-- @param args List of arguments from the command line
cmd.main = function(args)
	print("Hello, OSv!")
end

return cmd

dmesgを見えるとどんなデバイスが登録されているかわかる。

/# dmesg
dmesg
4 CPUs detected
Firmware vendor: Seabios
bsd: initializing - done
VFS: mounting ramfs at /
VFS: mounting devfs at /dev
RAM disk at 0x0xffff800002796040 (4096K bytes)
net: initializing - done
vga: Add VGA device instance
eth0: ethernet address: 52:54:00:12:34:56
virtio-blk: Add blk device instances 0 as vblk0, devsize=10842275840
random: virtio-rng registered as a source.
random: intel drng, rdrand registered as a source.
random: <Software, Yarrow> initialized
VFS: unmounting /dev
VFS: mounting zfs at /zfs
zfs: mounting osv/zfs from device /dev/vblk0.1
VFS: mounting devfs at /dev
VFS: mounting procfs at /proc
random: device unblocked.
program zpool.so returned 1
BSD shrinker: event handler list found: 0xffffa0000199e500
	BSD shrinker found: 1
BSD shrinker: unlocked, running
[I/43 dhcp]: Waiting for IP...
[I/246 dhcp]: Server acknowledged IP for interface eth0
[I/246 dhcp]: Configuring eth0: ip 192.168.122.89 subnet mask 255.255.255.0 gateway 192.168.122.1 MTU 1500
Running from /init/30-auto-00: /libhttpserver.so &!

シェルだとできることは限られているのだけど、REST API経由でいろいろ弄れるのが今っぽい。ブラウザでhttp://192.168.122.89:8000/を開く。あ、ブラウザ経由でリブートやシャットダウンもできちゃった。面白い。ちなみにコンソールからシャットダウンするときは、exit (or Ctrl-a x)でOK。