移転のお知らせ

最近まったく更新していないのになんですが、自分でブログをいろいろカスタマイズしてみるのも面白そうかなと思い、自分の環境に移転することにしました。飽きたら戻ってくるかもしれませんが…

そんなわけで、今後の更新は以下のサイトで行っています。
http://blog.nicetrip.org/

よろしくお願いします。

ミャンマーについて

9月に二週間ほどミャンマーという国に行ってきました。このブログの内容にそぐいませんが、ニュースでついに流血の事態が報じられており個人的にとても悲しいので、旅行したときに私が持った印象を簡単に箇条書きにしておきます。読み捨ててください。でも、少しでもあの国に興味を持ってくださる方がいればうれしく思います。

  • マンダレーヤンゴンはイギリス植民地の面影(碁盤目状に整備された道路・ビクトリア調の建物)を残しており、その下の喧騒の様子が南インドの都市にそっくりだった。
  • ヤンゴンにはインド系が多いように感じた。歴史的な経緯があるらしい。
  • でも華僑もいっぱい。
  • 噛みタバコ文化圏。歩道の隅は真っ赤っ赤。
  • バガン遺跡に行ったが、個人的に遺跡は飽きが早い。
  • 遺跡がいまだ信仰の場になっているのは、あまり日本にない感覚だと思う。
  • ファッションの流行は(日本より当然遅れているが)どこでも一緒だなと思った。
  • インターネットは日本とアメリカへの直接の通信は遮断されていた。ただし、ドイツには制限がされていないので、プロキシ経由で実質的に何でも見れる。
  • 僧がネットしてるらしい。
  • 日本語学校が流行っているらしい(遊びに行きました)。
  • ツーリストはその国が観光地化しているとツーリストずれしていると嫌がり、ツーリストの施設がまったくないとそんなところにはそもそも行かない。
  • ミャンマーでもサッカーは大人気。サイカーのにいちゃんでもマンUチェルシーの選手を全部知ってた。サッカーはワールドワイドなスポーツだと再確認した。
  • 村でも衛星のアンテナを持っている家が必ずあって、そこから海外の情報を仕入れているらしい。NHKリビアなんとか放送とかも設定すれば見れた。
  • コンピュータの学校を卒業したという女の子(ニュースに出てくるシュエダゴン・パゴダの受付をしていました)はLinuxとかjavaとか知ってた!

ただ旅行しているだけだとミャンマーはとても平和に見えます(私がそうでした)。旅行人の特集を見ると、意外な影の部分がわかって面白いです。
旅行人156号ビルマ東西南北ミャンマーへの旅

malloc(1)

第1章から第4章まではUNIXの基礎知識、Cの基礎知識やソースの概要なので、第5章から読み進めていくことにします。

まず、straceをしているときに見かけたことがある気がするmallocとmfreeです。メモリの取得や開放のための関数です。
いきなり疑問点がひとつ。p297に「coremapとswapmapのそれぞれは、2515行で宣言されているmap型の構造体の配列である」と書かれてあるのですが、どこにその宣言がされているのか分かりませんでした。


203 : int coremap[CMAPSIZ];
204 : int swapmap[SMAPSIZ];

2515: struct map
2516: {
2517: char *m_size;
2518: char *m_addr;
2519: }
intの配列が宣言されていることは分かるんですけど…とりあえず、どこかでmap構造体の配列であることが宣言されていることを前提として読み進めるとします。map構造体は、アドレスのサイズ(charのポインタ)とアドレスの始点(charのポインタ)を要素としているようです。要素にはアドレスの終点はないようです。サイズと始点があれば計算できるものなので、余計なデータでメモリを消費しないということでしょうか。
さて、malloc関数のソースは以下の通り。

2528: malloc(mp, size)
2529: struct map *mp;
2530: {
2531: register int a;
2532: resister struct map *bp;
2533:
2534: for (bp =mp; bp->m_size; bp++){
2535: if(bp->m_size >= size){
2536: a = bp->m_addr;
2537: bp->m_addr =+ size;
2538: if ((bp->m_size =- size) == 0)
2539: do {
2540: bp++;
2541: (bp-1)->m_addr = bp->m_addr;
2542: } while((bp-1)->m_size = bp->m_size);
2543: return(a);
2544: }
2545: }
2546 return(0);
2547 }
想像よりも遥かに短いです。

2528: malloc(mp, size)
2529: struct map *mp;
2530: {
...
2547: }
さっそく見慣れない書き方がでてきました。古い文法なのかなと調べてみたところ、第2章のp271に解説されていました。なんとなく想像できるように、関数の第1引数のmpがmap構造体へのポインタであることを宣言しているということのようです。宣言されていないsizeは「デフォルトとして整数であるとみなされる」ということらしいです。
2534行からはmallocの第2引数に渡されたsizeに十分なメモリをmap構造体の配列から取り除くという処理(リソースマップの管理)をしています。

2534: for (bp =mp; bp->m_size; bp++){
条件判定部の「 bp->m_size」は「 bp->m_size > 0」という意味らしいです。そして、ゼロサイズのエントリは最後の要素(見張りのエントリ)として存在しているようです。要するにエントリの最後まできたら、リソースマップに適当なエントリがないということで偽になって、

2546 return(0);
を返すようです。

2535: if(bp->m_size >= size){
2536: a = bp->m_addr;
2537: bp->m_addr =+ size;
2538: if ((bp->m_size =- size) == 0)
2539: do {
2540: bp++;
2541: (bp-1)->m_addr = bp->m_addr;
2542: } while((bp-1)->m_size = bp->m_size);
2543: return(a);
2544: }
2545: }
ここはそのまま読み進めるとつらいので、具体的な例を挙げながら読んでいくことにします。次のようなエントリを持ったリソースマップがあるとします。

エントリ サイズ アドレス
0 10 20
1 15 50
2 5 80

  • 例1 サイズが5のリクエストを受け取ったとき

エントリ0から検査していった場合、エントリ0のサイズ(10)は求めるサイズ(5)以上ですので、2535行目のif文は真になります。if文内ではaにエントリ0の始点のアドレス(20)を代入して(2536行目)、エントリ0の始点のアドレス(20)に求めるサイズ(5)を足します(2537行目)。さらにエントリのサイズ(10)から求めるサイズ(5)を引けば(2538行目)、以下のようになります。


エントリ サイズ アドレス
0 5 25
1 15 50
2 5 80
エントリ0のサイズが0になったときに2538行目のif文が真になってdo〜while文の処理を行いますが、ここでは偽なので2543行目で変更前のエントリ0の始点のアドレス(20)をreturnします。

  • 例2 サイズが10のリクエストを受け取ったとき

2538行目までは例1と同じです。


エントリ サイズ アドレス
0 0 30
1 15 50
2 5 80
ここでエントリ0のサイズが0になりますので、2538行目のif文が真になります。do〜while文ではリソースマップのエントリを繰り下げています。結果以下のようになります。

エントリ サイズ アドレス
0 15 50
1 5 80
ところで、2542行目のwhileの条件文は「==」で比較しているのではなく、「=」で代入しているだけなんですね。

2542: } while((bp-1)->m_size = bp->m_size);
どうやらbpがmap構造体へのポインタを示さなくなったときにこの条件文は偽になるようです。

Lions' Commentary on UNIX

最近C言語をまた少しずつ勉強しはじめてます。
インターネットの仕事をしていると、普段お世話になっているLinuxカーネルやら Apacheやらが動いている仕組みについてどうしても興味を持ってしまいます。そのソースは大概Cで書かれているのですが、私はCの理解が浅いのでなかなか手をつけることができませんでした。でもいつまでもそんなこと言ってられないので、興味ある題材で地道に勉強していこうかなと思って「Lions’ Commentary on UNIX (Ascii books)」を読んでいくことにしました。初期のシンプルなUNIXカーネルのソースの解説書です。
この本で扱っているカーネルと比較すると現在のLinuxカーネルは遥かに膨大らしいので、この本を読んだからといってLinuxカーネルをハックできるようになるわけではないと思うのですが、千里の道も一歩からということで。とりあえず今のレベルは「独習C」を一年前に一通り読んで、ポインタがよくわからないので「C言語ポインタ完全制覇 (標準プログラマーズライブラリ)」を途中まで読んでいるというところです。

OpenVZの使い道

OpenVZのようなパーティショニングの技術はどういった場面に役に立つのだろう、とちょっと考えてみました。


まず、HSP各社がサービスしているようなホスティングサービスが思い浮かびます。VEのroot権限を直で渡してVPS・VDSと呼ばれるサービスをするのもよし、その上にいろいろアプリケーションをのせて共用ホスティングとして提供するのもよし。ただこれは安直すぎるので、他に使える場面を考えてみます。


OpenVZの高機能なリソース制限機能を使うなら、アプリケーションサーバをVE内に閉じ込める、というのは結構いい案だと思います。設定が適切ならVE内でいくら暴れてもHNはへっちゃらなので、高負荷でサーバが重すぎてsshでログインしても何もできずにリブート、ということがなくなるかもしれません。1台のサーバで複数サービスを提供しているなら、1アプリケーションごとVE内に閉じ込めてしまえば、特定のアプリケーションの暴走のあおりを他のサービスがうけることはありません。こちらのサイトでも同じことを指摘してらっしゃいます。


あと、ライブマイグレーション機能がHAに役立たないのかなあ、とも思います。
もちろんサーバの突然死はロードバランサに任せておくしかないとして、ハード交換やハードの更新の場面ではVZカーネルをインストールしているサーバでライブマイグレーションすれば、サーバに入っていたデータもしっかり移行できます。まあ、しっかり構築済みのサーバと入れ替えればいいことですし、ロードバランサにぶら下げているノードに大事なデータをおいておくこともあまりないかもしれませんが、オプションとして持っておけばちょっと役立つこともあるかと思います。


高い収容率を考えると、社内の検証用サーバや研修用に役立ちます。これが一番手軽な利用方法ですかね。OSの仮想化なので、カーネルファイルシステムの検証などコアなことはできませんが、Webアプリケーションの開発とかアプリケーションの動作確認とかには十分使えます。VEの再構築も一瞬で終わります。

Puppetを導入してみました

仕事でサーバの初期構築や運用方法を見直す機会があったので、Puppetというシステム自動管理ツールを導入してみました。

これまでのシステム管理というと、初期構築時はサービス・サーバごとに構築用スクリプトを作成し、運用時に設定ファイルの変更があればexpectの使い捨てスクリプトで全サーバに設定を反映させていました。
この方法では初期構築スクリプトがサービスごとにばらばらで担当者が代わったときに解読が困難だったり、設定ファイルの変更を初期構築に反映していなかったりと、メンテナンスに難がありました。


Puppetを一ヶ月使用してみた感想を以下に箇条書きにしてみます。マニュアルを精読してないので、勘違いがたくさんありそうですが…

  • tagが便利
  • puppetrunが便利。
  • puppetdを特定のIPにbindできない?(0.0.0.0でListenしてしまう)
  • Componentsにエイリアスが使えないような気がする。
  • Componetnsに依存関係を持たせられないような気がする。
  • Rubyで書かれていることをよく耳にするけど、フレームワークを直接いじることがなければあまり関係ない。定義ファイル(Resource)はPuppet文法で記述する。facterを使うときはRubyで記述する。
  • Resourceのpackageを使ってrpmをインストールするとき依存関係がめんどくさい。いらないパッケージをアンインストールするときもめんどくさい。
  • Resourceのpackageでproviderにyumを指定してアンインストールするときに依存関係にあるパッケージをアンインストールしてくれない。(おそらく意図しないパッケージをアンインストールしないためにこう実装されているのだと思うが初期構築するときにめんどくさいので、結局execに頼ってしまう)
  • 確かにひとつひとつのResourceは簡潔にかけるが、定義ファイルの依存関係が複雑化していってしまう。ドキュメントは必要そう。

つらつらと不満点も書きましたが、タグ機能は非常に便利なので活用しています。
タグは主に初期構築用のsetupと運用用maintenanceの2種類を用意して、運用上変更が生じそうなResourceにはこれら2種類のタグをつけています。実際に変更することになったら、maintenanceのタグを使ってpuppetrunします。このResourceにはsetupタグもついていますので、初期構築にも反映されます。これで「設定変更を初期構築スクリプトに反映してなかったので、今運用しているサーバとは設定が異なるサーバができちゃったよ!」ということはなくなると思います。


Puppetについての情報は以下のサイトにまとまっています。

http://gihyo.jp/admin/serial/01/puppet/0001
http://trac.mizzy.org/puppet

オプティミストはなぜ成功するか

オプティミストはなぜ成功するか」(マーティン・セリグマン)は先日の13項目の「情熱」(モチベーション)を保つのに役にたつ本です。
オプティミストはなぜ成功するか
著者セリグマンは高名な心理学者で学習性無力感という理論を発表しています。セリグマンの無力に関する実験は以下のページをご覧ください。
http://www.kyoto.zaq.ne.jp/dkaqw906/spopsy6.htm
最近ですと深海魚のカタルシスさんでも紹介されていました。
http://d.hatena.ne.jp/Agguy0c/20070502/1178084208
この実験の説明には少しだけ補足があって、電気ショックを与えられ続けられた犬のうち3分の1は無力状態に陥らなかった犬がいたそうです。この存在がセリグマンのオプティミストに関する研究のきっかけになります。オプティミストペシミストは不幸に遭遇したときの説明スタイルの違いから生じるそうです。説明スタイルには永続性、普遍性、個人度の三つがあり、オプティミストペシミストだと以下のように異なります。

■永続性
オプティミストは、不幸の原因は一時的なものだと信じている。ペシミストは、自分に起こった不幸は永続的であり、いつまでも自分の人生に影響を与えると考えている。

<悪い出来事の説明>

オプティミスト ペシミスト
私は疲れている 私はもう立ち直れない
君は私が部屋を片付けないとがみがみ言う 君はいつもがみがみ言う

良い出来事の説明の場合、悪い出来事のときと説明が逆になる。つまり、オプティミストは永続的な説明をし、ペシミストは一時的な説明をする。<良い出来事の説明>

オプティミスト ペシミスト
私はいつもついている 今日はついている
敵は能力がない 敵は疲れていたんだ

■普遍性
オプティミストは不幸の原因を特定の(限定的な)説明をする。ペシミストは普遍的な説明をする。

<悪い出来事の説明>

オプティミスト ペシミスト
この本は役に立たない 本は役に立たない
私はこの分野では役に立たない 私は役に立たない

良い出来事の場合は、やはり逆になる。つまり、オプティミストは普遍的な説明をし、ペシミストは限定的な説明をする。<良い出来事の説明>

オプティミスト ペシミスト
私は良くできる 私は数学が良くできる
私はうけがよかった 私は彼女にうけがよかった

■個人度
オプティミストは悪い出来事に対し外向的な説明をし、ペシミストは内向的な説明をする。<悪い出来事の説明>

オプティミスト ペシミスト
お前は馬鹿だ 私は馬鹿だ
私は貧乏な境遇で育った 私は安定性に欠ける人間だ

<良い出来事の説明>

オプティミスト ペシミスト
私は幸運をのがさない 偶然幸運にめぐまれた
私の技がさえていた チームメイトにめぐまれた

一般に「希望」と呼ばれるものは悪い出来事に対する永続性と普遍性の説明スタイルで成り立っているそうです。

原因が一時的と考えることによって無力状態を時間的に制限できるし、特定の原因によるものだと思えば無力さをその状況のときにだけ限定できる。

この本には自分の楽観度を計るテストもあります。テストを見てみると、入社のときにやったことがあるやつです。有名なテストなんでしょうね。このテストを試してみたところ、私は超ペシミストでした…