双六工場日誌

平凡な日常を淡々と綴ります。

今更ながらの #isucon 3 参加報告:「isuconに勝てる銀の弾丸などなかった」

isucon参加ブログ書こうと思いつつ、転職・引っ越しとバタバタした日々が続いて、すでにisucon3から1ヶ月経ってしまいました。。。

今更感もありますが、遅ればせながら自分なりの反省エントリを書いておきます。

予選トップで通過したのに、本戦では惨敗...orz

 まず結果ですが、僕たちのチーム「勝浦タンタンメン」は、本戦は最終計測でスコアが出ずFAILし、あえなく惨敗いたしました…orz 負けた原因も完全に実力不足で、なんの言い分できないほど、完膚なきまでの敗北です。

 どのようにしたら勝てたのかは、@ 氏のエントリや公式の関連エントリまとめを見てみてください。また、isucon 3を体験できるAMIも公開されているので、問題自体はそちらを見てみてくださいませ。

 僕たちのチームは、予選ではフロントで捌く戦術がうまくハマって、スコアトップで予選通過することができましたが、本戦は小手先の技だけではどうにもできない良問*1で、自分たちの道具立てでは、ベンチマークのスコアも伸ばすことができないまま時間切れ。

 ちなみに、本戦は予選突破した25チームのうち、7チーム以外はベンチマークを完走することもできないという、死屍累々のハードコアなイベントでした。

 せめて動くようにできればよかったのですが、最後の方は浮足立ってしまって、動かすことすらかないませんでした…

反省点

 このような結果となった理由は、細かく上げればいろいろあるのですが、自分としての大きな反省点は、以下の2つです。

制限事項の理解と適切なアーキテクチャの選定ミス

 結果として、isucon 3で勝負を決めたのは、初期段階でのアーキテクチャ選定だったと思います。

 優勝チームは、フロント側のネットワーク帯域に100Mbps制限がかかっていることから、フロント4台、バックエンド1台構成にすることを、午後の早い段階で決めたと言っていました。

 チューニングでは、「推測するな計測せよ」が基本的な心構えだと言われることが多いですが、アーキテクチャから考えないといけない状況では、

  • 与えられた環境からどこがボトルネックになりやすいのか
  • どの程度のレスポンスタイム/スループットを出しうるのか

といったことを与えられた環境から割り出して、それを踏まえて動き出すことが重要でした。

 優勝チームの結果を見ると、以下の2つが今回の課題のボトルネックでした。

  • 画像変換のCPUボトルネック
  • フロントのネットワーク帯域のボトルネック

 特に自分では、フロントの100 Mbps制限がどれだけのものか肌感覚でわかっておらず、逆にディスクIOボトルネックの発生を気にしてしまって、考えのとっかかりとしてデータの分散配置を考える方に考えが向いてしまい、失敗しました。

 経験不足から、この辺りのことを肌感覚でわかっていなかったために、初動のところでコケてしまうことになりました。

チーム力の課題

 もう一つの反省点は、チーム力です。

 もし正しいアーキテクチャを考えられたとしても、それを実装しきるためのチーム力が必要がなければ勝つことはできません。特に、今回は課題のアプリが高度だったため、方針が決まっても、それをチームで分担して実装しなければ時間内に必要な修正を行い切ることは難しくなっていました。

 正直なところ、初動が正しかったとしても、自分たちのチームではそれを実装しきることはできなかったと思います。

 自分たちのチームは、会社もバラバラの混成チームで、ここは開催当初から課題でした。そのため、一度、isucon 2の問題を一緒に解く一旦合宿までやったのですが、当日の課題からすると、この程度の付け焼き刃のチームワークでは太刀打ちできませんでした。

 これまでの優勝チームの話を聞くと、チームメンバーが実際に何をやったのかはお互いに確認せずに作業していたとのこと。このぐらいの阿吽の呼吸ができれば理想でしたね。。。

自分がやろうとしたこと

 ということで、反省の多い本戦でしたが、自分がやろうとして失敗したことも書いて起きます。僕は、フロント2〜3台、アプリ・バックエンド2〜3台の構成で、以下のようなことをやろうとしました。

  • フロントは、Nginxをリバースプロキシとして置いて、バックエンドを "hash $request_uri;" で振り分ける
  • (結果としては動くところまで行きませんでしたが)動くところまで言ったら、フロントとアプリ・バックエンドの数を調整する

 この構成の利点は、バックエンドへの振り分けをURIごとに固定できるため、フロントのNginx複数台おいてもURIごとに決まったバックエンドを向くようにできることです。バックエンド2台ならば、配信対象コンテンツをメモリ上に載せることができるとの読みからです。

 ただ、この構成は最後まで動かし切ることができませんでした。この構成でアプリの初期状態だと、あとからPOSTされてくる画像は、一つのバックエンドに集中してしまう問題がありました。

 だんだん終了時間が迫ってきたので、見切り発車でこの変更を開始して、インフラだけ入れ替えたものの、対応するためのアプリの改修が間に合わずアウト。。。

 結果を見ると、これでディスクIOを減らしたところで影響はそれほど大きくなかったと思いますが、せめて動くようにはしたかったです。これは自分との闘いの部分なので、非常に悔しい。

 あとは、予選の印象からNginx側で捌くという発想が抜けず、冷静にレギュレーションを読んでアーキテクチャを検討できなかったのも、反省点です。変なところにこだわって、トリッキーなことをするよりは、可能な限りシンプルに済ませる方に頭をつかうべきでした。

まとめ

 isucon 3は、インフラ、アプリの総合力に加え、チーム力が問われる非常にいい大会でした。負けて非常に悔しい思いをしましたが、実力不足だったと言うしかないです。これだけの問題を用意してきた藤原さんにも完敗です。

 最後は、トリッキーなことをしてでも何とかしようとあがきましたが、状況を打開できるような「銀の弾丸」などなく、基本的なことをちゃんとやり切ったLINE選抜が圧倒的な強さで優勝しました。

 ただ、負け惜しみみたいになってしまいますが、本戦に参加できただけでも十分楽しかったです。負けたこと自体は、今でも悔しくて仕方ないですが、そう思えるのもisuconだからこそだと思います。

 こんな風にガチで技術勝負をして、出来上がったシステムの速い順に順番をつける誰から見てもわかりやすい勝負はいいですね。エンジニアの力は、普段はなかなか表に出てこないので、世の中にエンジニアの価値を知ってもらう上でもいい影響が出ているようにも思います。

 来年はまだどこがどうやるのか決まっていませんが、歴代優勝者が参加者として参加する頂上決戦があるとの噂もあり、非常に楽しみです。

 最後になりますが、主催のカヤックのみなさま、LINEのみなさま、DATAHOTELのみなさま、そして、予選・本戦とともに素晴らしい出題をしてくださった出題チームのみなさまに感謝を。ありがとうございました!

 反省点を噛み締めて、来年は、本戦でももう少しいい勝負ができるよう、この一年精進したいと思います。

 それでは、この辺で。

*1:予選の問題が悪いということを言っているわけではなく、予選は参加者の選抜という目的では非常によく出来た問題だったと思っています。本戦の問題は、本戦にふさわしい良問だったということです。念のため。

#isucon 2013 予選をトップ通過してきた(はず)。

あとに回すと、ブログを書くハードルが上がってしまいそうなので、取り急ぎ。*1

さて、10月5日、6日と2日間の日程で開催された、isucon(いい感じにスピードアップコンテスト)の予選に参加して、なんと、総合トップで通過いたしました!!!!!

今回は、まずは予選突破を目指して参加したのですが、いろいろな幸運が重なり、現時点で予選総合トップ! 現時点では、運営の方のAMI審査で問題がなければ、という条件付きではありますが。

すでに、参加チームの幾つかからブログ報告が出ていますが、ほかのチームがかなりアプリ側のコードに手を入れているのとは、対照的にスコアの大半はインフラ側チューニングです。

特に、フロントにおいたnginxで以下にリクエストを捌くかがスコアアップの決め手になっています。

また、アプリの言語はPythonを選びました。Python 3.3が使われていたのにはちょっと戸惑いましたが、結果的にはいい方向に倒れたと思います。

アプリ側で行った主な変更は、ほかのチームに比べて対してものはなく、

という、開始すぐにできるような類のものです。そのほかにも、ほかのチームがやっているようなキャッシュやレンダリングの削減など、いろいろと試行錯誤はしましたが、それほど大きな改善はなく、アプリのチューニングだけでは大きなブレイクスルーを起こすのは難しいと、途中で見切って、インフラ寄りのチューニングに舵を切りました。

今回の課題では、ベンチマークツールとアプリが同じサーバで動いており、かつ、レンダリングの負荷が高かったので、CPU資源があっという間に枯渇してしまうことが問題でした。 そのほとんどをまずNginx側で裁いて、アプリケーションにCPUを使わせないことが、今回のチューニングのポイントになっています。

その結果、フロントでできるだけリクエスト捌き、アプリにアクセスさせないようなNginxのチューニングを行って、30000点弱のスコアを出せたので、あとはその調整という感じですね。

また、isucon2でよく使われていたプリレンダリングは、ページ数が多かったり、ユーザログインの情報があったり、イニシャライズスクリプトに60秒の時間制限があったりと、なかなか効果的なものが入れにくかったので、これも見切って、Nginxのキャッシュの制御だけとしました。

ただ、そのバーターとして、多少のFailが出るのは許容しています。これに倒したのは、今回は、Failに重みが付けられていて、ある程度は妥協できるFailがあったということが大きいです。*2

ということで、結果だけ見ると、僕たちの勝因の多くは非常にシンプルはインフラチューニングによっています。そのほかに挙げるとしたら、制限時間内に効果的な施策を打つための時間管理ですかねー。 こういうインフラチューニングでも、レギュレーションを理解して、大きな観点でボトルネックを潰していけば、スコアが出るように問題が作られていたのかなーと思いますが、それは主催者のみ知るところです。

とにかく、当初目的であった予選通過は達成できそうなので、本戦楽しんできます!

最後ですが、参加してみて、isuconは多大な運営の方の努力によって作られていることを実感しました。2日間、本当にお疲れさまです。 無事に本戦に参加できたら、よろしくお願いします!

*1:また、裏側の考え方など詳しく書くかもしれませんが、これで終わる可能性も高いです。。。

*2:そもそも、最初はスループット30000だけど、スコア3000みたいな結果が出ていました

メイドカフェが気になっている人におすすめの薄い本、『メイドカフェ批評』

f:id:sechiro:20130831160152j:plain:right:w240 僕の周りを見ていると、メイド喫茶に興味があるけど、最初に一歩が踏み出せない人が一定数います。

そういう人をメイド喫茶を紹介すると、かなりの確率でお店が気に入ってリピーターになってくれるのですが、そういう紹介なしだと、今から一人でメイド喫茶に行き始めてみるのはなかなかハードルが高いことのように思われているようです。

また、一言でメイド喫茶と言っても千差万別で、最初に入ったお店がその人が期待していたものと違うと、それ以降、「メイド喫茶」というジャンルごと興味がなくなってしまうということもあります。

そんな中、今年のコミックマーケット『メイドカフェ批評』という評論本が出ました。この本は、メイド喫茶という存在についてを徹底的に掘り下げた、おそらく史上初のメイドカフェの批評集です。

この本は、これからメイド喫茶に行ってみたいと思っている人、行ってみたいと思っていたけど手が出せなかった人、行ってみたものの幻滅して行かなくなってしまった人、そして、メイド喫茶について熱く語りたい人などに特のおすすめできる薄い本*1です。

この本の内容を押さえていれば、メイド喫茶に行ってはみたものの期待はずれとなってしまうことも少なくなると思います。

また、一冊の本として内容もバランスよく、構成もよく考えられていて非常に丁寧に編集されていて、メイド喫茶に興味がない人でも読み物として楽しめると思います。

可愛い表紙ですが、文字びっしりの硬派な内容なので、そこはご注意ください(笑)。

初版はすでに完売してしまったようですが、増刷がかかって、Comic ZINなどの各種同人ショップでも再び手に入るようになったので、僭越ながら僕から簡単に本の内容を紹介したいと思います。

内容紹介

さて気になる内容ですが、この本は「状況編」、「論考編」、「エッセイ」の3パートで書かれています。以下のそれぞれの簡単に内容を紹介します。

1.状況編

「状況編」とまとめられた最初の3編は、メイド喫茶に行ったことがない人や今のメイド喫茶の状況を俯瞰したい人に特におすすめです。膨大な資料や取材した内容が非常にコンパクトにまとめれていて、今のメイド喫茶の全体像をつかむことができます。これだけのものを調べるのは、相当大変だったと苦労が忍ばれます。

具体的なメイド喫茶の紹介やレビューではないので、これで全体像を掴んだあとに、気になる店舗のことを調べたり、実際に行ってみたりするのがいいと思います。

ここには以下のような記事が載っています。

  • メイド喫茶、はじめての選び方ーーメイド喫茶ポジショニングマップ
    • 秋葉原におけるメイド喫茶の歴史や位置づけ、それぞれの店舗を俯瞰したポジショニングマップが掲載されています。メイド喫茶にこれから行ってみようという人は、読んでおいて損しない内容だと思います。
  • THE HISTORY OF MAID CAFE
    • メイド喫茶の過去が年表と時々の転機となったトピックとともにまとめられています。
  • メディアが伝えるメイドイメージ
    • 英国メイド研究をしている筆者さんが、メイド喫茶がメディアを通じてどのように伝えられているのかを、大量の雑誌記事やドラマや報道での露出等の資料から調査されている労作です。

2.論考編

論考編では、思想誌顔負けのガチ批評が並びます。読み終わってみると、かなり固い論考が並びますが、共通するのは結局のところ、みんな、メイド喫茶が好きなんだなと思いました(笑) 「メイド喫茶が好き」ということを伝えるためだけに、これだけの文字数と情熱が投下されていることに胸が熱くなります。

  • メイド喫茶の条件
    • ハンナ・アレントの「人間の条件」を援用しつつ、メイド喫茶における人間性の獲得と感情労働のパロティ化を論じていると思ったら、結局、一人の魔女さんに捧げられた論考だったと本人がTwitterで告白していた3万字の大作です。

  • 二・五次元性をめぐって
    • 「なぜ喫茶店にメイドがいるのか」という問いから始まり、メイド喫茶の魅力を二・五次元性という観点で分析した論考です。メイド喫茶という虚構の世界がどのような位相にあるかを、某夢の国との対比から論じ、現実の直接の延長線上にありながら、虚構と現実の同時に持つことによるメイド喫茶とそこにいるメイドの魅力が論じられています。
  • メイド文化と音声学
    • 音声学の観点から、前半はメイドの名前の音声学的分析からメイドの持っている自己像を分析し、後半ではメイドの声の特徴を分析しています。意外な結論とともに、音声学の方法論も知ることができる論考です。

3.エッセイ

  • 秋葉原のメイドカフェが文化になるには 再考
    • 秋葉原文化を作る上で、メイド喫茶をその中にどう根付かせるかを論じたエッセイです。最近の課題などにも触れつつ、秋葉原の街づくりの観点からメイド喫茶の将来を論じています。
  • 世界最先端の現場の知恵
  • キモオタによるメイド喫茶恋愛論ーー地獄の門の向こうに
    • この2つは、メイド喫茶という2.5次元に囚われてしまった男たちの生きざまについてのエッセイです。若干、上級者向けのニオイがするので、この2つはメイド喫茶に何回か行ってみてから、ここだけ見直してニヤニヤするのが正しい読み方かなと思っています(笑)

以上のような非常に濃い内容で、ざっくり内容を紹介するだけでも一苦労です(笑)

最初にも触れましたが、こちらの本はComic ZIN等の同人ショップにて手に入れることができます。

また具体的なメイド喫茶紹介としては、このブログでもインフラエンジニアのためのメイド喫茶紹介と称して「キュアメイドカフェ」や「シャッツキステ」などを紹介したこともあるので、興味がある方がいたらこちらも合わせてご覧ください。

また、購入の際は「汝はエンジニアのような名状しがたい何かなりや?」と、合わせてご検討いただけると幸いです。*2

それでは、長くなったのでこの辺で。

これからメイド喫茶に行く人、メイド喫茶やアキバ文化を語る上では必携の一冊だと思いますので、興味がある方には是非おすすめしたい一冊でした。


<追記> 書誌情報や執筆者の情報は、執筆&編集をされたたかとらさんのブログをご参照くださいm(__)m

<追記2 9/1 7:01>

『メイドカフェ批評』での執筆者の立ち位置について、たかとらさん、岸井さんがTwitterで補足のコメントをされていたので、紹介させてもらいたいと思います。筆者ごとに微妙な距離感で批評をされているところも、この本の見所の一つだと思っています。

*1:ただし、136ページ

*2:宣伝乙

エンジニアのための料理教室通いのすすめ

f:id:sechiro:20130407120531j:plain:right:w250 僕は、4年前から思い立って「ベターホーム」の料理教室に通っています。

今ちょうど、11月開始の教室の申し込み時期で、体験教室が開かれていて、Twitterでも紹介したので、それをブログにもまとめておきます。

ツイートした内容はこちら。

料理教室を特にエンジニアに勧める理由は、以下の通りです。

  • 料理をすることに集中できる環境が整えられている。

    • 料理教室だと、時間内にある程度の凝った料理ができるようにいい材料を必要分量だけ揃えてくれているため、手間が少ないし、自炊するときのような材料のやりくりに困らない。
    • 仕事が忙しい時期は、料理をする時間が取れなかったり、材料を買っても料理する時間が取れずにダメにしてしまったりすると思いますが、料理教室に通っていれば、少なくともその時は料理に集中することができます。
  • 料理の基本的なところはできる人に習った方が早い。

    • レシピでは「さっとゆでる」、「ひとつまみ」、「ツノが立つぐらい」、「7,8分」などなど、実際に作っているのをみた経験がないとどの程度か判断できない表現が多用されるので、文章だけから完全に料理を再現するのは難しい。そこでトライ・アンド・エラーをするのは非常に非効率だと思います。
    • 料理教室では、できるだけレシピを普遍化して話すような工夫がされているので、その点もおすすめ。一般的に料理ができる人でも、それを他人に伝えられるかは別問題。
  • 休日を有効活用することができる。(休日クラスの場合)

    • 僕の場合は、日曜午前のクラスに通いました。教室は10時開始で12時半ごろ終了なので、料理教室で作ったものを昼ごはんとして食べて、午後からほかのことができます。*1
  • エンジニア以外との接点ができる。

    • 料理教室に限りませんが、習い事をすると仕事上では会わないような人と会う機会を得ることができます。
    • 料理教室は基本的には黙々と作業をして、終わったら、各自帰る感じなので、それほど会話があるわけではありませんが、教室という枠が設定された中で人と話す訓練にもなると思います。

男性が料理教室などの習い事をするというのは、ハードルが高いことのように思うかもしれませんが、エンジニアに限らず、なかなか料理の時間が取れないサラリーマンなら、行ってみる価値はあると思っています。

補足:国内のメジャーな料理教室

料理教室は、小さいところ、大きいところ、いろいろなものがありますが、全体的な傾向としては、小さな料理教室は美容や健康、特別な材料、シェフ直伝など、それぞれのテーマに特化したところが多く、大きいところは家庭料理の基本を体系立てて教えることを中心にしているように思います。

料理教室最大手は、私が通っている「ベターホーム」と「ABCクッキングスタジオ」でしょう。どちらも全国に教室があります。

ABCクッキングスタジオ」には行ったことがないので、その内容は紹介しかねますが、「ベターホーム」は設立50年を迎えた老舗で、雰囲気はおばちゃん先生の家庭科の授業みたいな感じで、非常に緩い雰囲気です。

料理教室のカリキュラムは1年コースが基本で、ベターホームは5月/11月始まりです。クラスの時間は「第4日曜午前」と固定されていますが、都合がつかない日は他の教室・曜日に振替可能で、振替の期限は3年以内と調整がしやすくなっています。「ABCクッキングスタジオ」は1日だけのクラスもあるようなので、ちょっと試してみたい人には向いてそうです。

また、「ベターホーム」には「男性向け」というクラスもありますが、「男性向け」クラスが設定されているのは、主に平日の昼間。講師の方に聞いたところ、「男性向け」クラスは、リタイヤされたお年寄りの方で、女性に混じって勉強するのに抵抗がある人向けで、そうでない人には普通のクラスをおすすめしているとのことでした。クラスは、女性が圧倒的に多いですが、女性が9割を超えてくると逆に気になりません。*2

日々SAN値を削って仕事をしている方も多いと思いますが、気晴らしに通ってみてはいかがでしょうか。

*1:また、ブリキュアを観てから出発できます。

*2:逆に5対5みたいな方がお互い意識してしまう気がします

エクスポートしたZabbixのテンプレートのサイズが2Mを超えてしまい、インポートができなくなった人向けメモ

自宅のZabbix設定の整理をしていて、複数のテンプレートをまとめてエクスポートしたのち、インポートで戻そうとしてハマったのでメモ。

ハマった原因は非常に単純で、「エクスポートしたテンプレートファイルのサイズが2MBを超えていたから」でした。 今回は、エクスポートしたテンプレートをそのまま戻すだけだったので、特に問題なく行くと思ってエクスポートされたXMLファイルを指定して、インポートしようとしたところ、以下のエラーが発生。

f:id:sechiro:20130827040457p:plain

メッセージは次の通り。「エラー: インポートに失敗しました ファイルサイズが大きすぎます。アップロードファイルサイズの最大値は2097152バイトです」

それで、ファイルのサイズを確認してみたところ、確かに1つのXMLファイルで2.5MB。アイテム数が多いテンプレートをまとめてエクスポートしてしまったばっかりに、これだけ大きいファイルになってしまっていました…。

手元のCentOS 6に入っているPHP 5.3では、ファイルアップロードの最大サイズをデフォルトで「upload_max_filesize」で制限している様子。そこで、まずは/etc/php.iniを開いて、以下のように編集。

upload_max_filesize = 2M

  ↓

upload_max_filesize = 4M

これで大丈夫だと思って再チャレンジするも、結局表示は変わらず…。どうやら、ZabbixはPHP全体の設定とは別にアップロード制限をしている様子。

仕方ないので、問題切り分けのため、「/usr/share/zabbix/info.php」に以下の内容のファイルを配置して、ブラウザから「http://<zabbix-serverのIP>/zabbix/info.php」にアクセスしてZabbixのPHP設定を確認。

$ vi 
<?php
phpinfo();

「upload_max_filesize」を確認してみると、やはり、/zabbix にはローカルの値が設定されていることがわかりました。

Directive Local Value Master Value
upload_max_filesize 2M 4M

/zabbixのローカルの設定は、httpd設定や.htaccessにあるはずなので、Zabbix Webの設定ファイル「/etc/httpd/conf.d/zabbix.conf」を調べたところ、案の上、以下のようなPHP設定が書かれていました。

<Directory "/usr/share/zabbix">
    Options FollowSymLinks
    AllowOverride None
    Order allow,deny
    Allow from all

    php_value max_execution_time 300
    php_value memory_limit 128M
    php_value post_max_size 16M
    php_value upload_max_filesize 2M
    php_value max_input_time 300
    # php_value date.timezone Europe/Riga
</Directory>

こちらをエクスポートしたファイルサイズよりも大きい値に書き換えて、httpdを再起動したところ、無事にインポート成功。

f:id:sechiro:20130827040452p:plain

この制限さえ通過してしまえば、特に問題は起こりませんでした。ただ、今回の作業対象が運用中のサーバではないので、大きいファイルのインポートによる負荷を考えなくていいという条件があってのことですが。

運用中のサーバに適用しているテンプレートをインポートにて一括で更新すると、各ホストの設定変更が一斉に走ってしまうため、かなり重い処理になります。 今回はそういうことがなかったので、この回避策を使いましたが、そういう点を考えてもテンプレートはあまりファイルサイズが大きくならない範囲でエクスポートするのがよいようです。

Zabbix 2.0 のグラフの文字化けを直す、「alternatives」での日本語フォント設定方法

今更感がありますが、Zabbix 2.0 を入れる度にフォントの名前、パス、alternativesの書式を毎回忘れるのでメモ。環境はCentOS 6です。

「alternatives」を使ってZabbix 2.0 の文字化けを直す

Zabbix SIAのパッケージを使って、Zabbix 2.0 (zabbix-web)をインストールした直後は、「DejaVuSans」がグラフ描画用のフォントに指定されていて、Web画面を日本語化した場合、グラフ内の日本語が文字化けして「□」のような文字となってしまいます。これはグラフ描画用のフォントに日本語フォントが指定されていないためです。

f:id:sechiro:20130827025219p:plain

Zabbix SIAのパッケージを使って、Zabbix 2.0のインストールを行った場合、このグラフ表示用のフォントは「alternatives」という設定切替ツールで管理されています。インストール直後の設定を確認すると、以下のようになっており、日本語フォントが設定されていません。

$ alternatives --display zabbix-web-font
zabbix-web-font -ステータスは自動です。
リンクは現在 /usr/share/fonts/dejavu/DejaVuSans.ttf を指しています。
/usr/share/fonts/dejavu/DejaVuSans.ttf - 優先項目 10
現在の「最適」バージョンは /usr/share/fonts/dejavu/DejaVuSans.ttf です。

これに「IPA Pゴシック」を追加して、それに設定を切り替えることでグラフを日本語表示させることができるようになります。そのためには、以下のコマンドを実行します。

$ sudo yum install ipa-pgothic-fonts
$ sudo alternatives --install /usr/share/zabbix/fonts/graphfont.ttf zabbix-web-font /usr/share/fonts/ipa-pgothic/ipagp.ttf 1000

最後の引数の「1000」は優先度。「DejaVuSans」の優先度「10」より大きければ構いませんが、作業者が意図的に変更していることがあとからわかるようにここでは大きい値を設定しました。

以下のように、設定が変更されたことを確認します。

$ alternatives --display zabbix-web-font
zabbix-web-font -ステータスは自動です。
リンクは現在 /usr/share/fonts/ipa-pgothic/ipagp.ttf を指しています。
/usr/share/fonts/dejavu/DejaVuSans.ttf - 優先項目 10
/usr/share/fonts/ipa-pgothic/ipagp.ttf - 優先項目 1000

設定変更は、これで完了です。Webブラウザからグラフを確認してみてください。「□」のところが、日本語表示となっているはずです。

f:id:sechiro:20130827025240p:plain

「alternatives」の仕組み

ここまでで設定変更としては十分ですが、せっかくなので「alternatives」コマンドのことも補足として書きたいと思います。

「alternatives」は、複数の設定を都度入れ替えて使えるようにする仕組みです。内部では、設定された内容でシンボリックリンクの張替えを行う。今回の設定の後、変更されたシンボリックリンクの内容を確認すると以下の通りとなっていました。*1

$ ll /usr/share/zabbix/fonts/graphfont.ttf
lrwxrwxrwx 1 root root 33  827 02:15 2013 /usr/share/zabbix/fonts/graphfont.ttf -> /etc/alternatives/zabbix-web-font
$ ll /etc/alternatives/zabbix-web-font
lrwxrwxrwx 1 root root 38  827 02:15 2013 /etc/alternatives/zabbix-web-font -> /usr/share/fonts/ipa-pgothic/ipagp.ttf

「alternatives」が書き換えているシンボリックリンクを直接「ln」コマンドを使って書き換えても同等の設定は可能です。ネットを検索した限りだとその手順も多いですが、パッケージが「alternatives」を使っているので、その流儀に従う方がベターだと思います。

ちなみに、ターミナルで「alternatives」とだけ打つと、以下のように新規設定の方法が表示されますが、かなり直感的ではありません…。

alternatives --install <リンク> <名前> <パス> <優先度>

ここで表示されているそれぞれの引数の意味は以下の通りです

  • <リンク>は、管理したい設定ファイルのパスです。今回はZabbixグラフ描画用フォントファイル「/usr/share/zabbix/fonts/graphfont.ttf」です。
  • <名前>は、alternatives上での設定管理名で、今回は「zabbix-web-font」*2
  • <パス>は、追加する設定ファイルへのパスで、今回は新たにインストールした「/usr/share/fonts/ipa-pgothic/ipagp.ttf」です。
  • <優先度>は、複数の<パス>が設定されている場合の優先度。値が大きいほうが優先的に使用される。今回はもともとの「DejaVuSans」に「10」が設定されていたので、追加した「IPA Pゴシック」に「1000」を指定して、そちらが優先的に使われるようにしました。ただし、優先度にかかわらず、以下に紹介する方法で、直接使用する<パス>を設定することもできます。

また、今回行った設定を元に戻したい場合は、以下のコマンドを使います。コマンドを実行すると、対話的に設定を選ぶことができます。追加設定時は面倒ですが、その後の切替は楽ですね。

$ sudo alternatives --config zabbix-web-font

設定の際の参考になれば。それでは。

追記: 「zabbix-web-japanese」 をインストールすればよいとの情報をいただきました。

@ さんから、以下の情報をいただきました。

このパッケージは、Zabbix SIAのリポジトリに含まれているファイルで、中身を確認したところ、以下のコマンドで「alternatives」の設定を追加して、日本語フォントを設定してくれるもののようです。

/usr/sbin/update-alternatives --install /usr/share/zabbix/fonts/graphfont.ttf zabbix-web-font /usr/share/fonts/vlgothic/VL-PGothic-Regular.ttf 20

以下のコマンドでインストールできます。

$ sudo yum -y install zabbix-web-japanese

インストールして、結果を見たところ、僕の環境では以下のような設定がなされました。

$ alternatives --display zabbix-web-font
zabbix-web-font -ステータスは自動です。
リンクは現在 /usr/share/fonts/ipa-pgothic/ipagp.ttf を指しています。
/usr/share/fonts/dejavu/DejaVuSans.ttf - 優先項目 10
/usr/share/fonts/ipa-pgothic/ipagp.ttf - 優先項目 1000
/usr/share/fonts/vlgothic/VL-PGothic-Regular.ttf - 優先項目 20
現在の「最適」バージョンは /usr/share/fonts/ipa-pgothic/ipagp.ttf です。

優先度「20」で「VL-PGothic-Regular」の設定が追加されていますね。ただ、手動で設定したものより優先度が低いので、そのままだと設定が変わらず。以下のコマンドを実行して、「3」を選ぶと追加でインストールした設定に切り替えることができました。

$ sudo alternatives --config zabbix-web-font

3 プログラムがあり 'zabbix-web-font' を提供します。

  選択       コマンド
-----------------------------------------------
   1           /usr/share/fonts/dejavu/DejaVuSans.ttf
*+ 2           /usr/share/fonts/ipa-pgothic/ipagp.ttf
   3           /usr/share/fonts/vlgothic/VL-PGothic-Regular.ttf

Enter を押して現在の選択 [+] を保持するか、選択番号を入力します:3

*1:/etc/alternatives以下にシンボリックリンクが貼られていれば、そのファイルはalternativesに管理されているファイルということになります。

*2:これが/etc/alternatives以下に作成されるシンボリックリンクの名前になっています。そのため、変更対象の設定名がわからない場合は、/etc/alternativesのシンボリックリンクファイル名から名前を調べることができます

bashのプロセス置換機能を活用して、シェル作業やスクリプト書きを効率化する

@ さんが「シェルスクリプトでハマった件→【募】ステキな回避方法」でお題を出されていて、それに回答してみました。

その内容はリンク先を見てもらうとして、回答の中で使ったbashのプロセス置換について書かれた記事をあまり見ないので、回答で使ったプロセス置換のことをエントリにしてみたいと思います。

最初に注意点ですが、プロセス置換の機能は、bashzsh*1の機能でPOSIX互換の機能ではありません。そのため、使用時には、対応していないシェルでは使えませんし、bashで使う場合も /bin/sh ではなく /bin/bash を明示的に指定する必要があります。たとえば、プロセス置換を使ったスクリプト「script.sh」に対して"$ bash script.sh" というコマンドは成功しますが、"$ sh script.sh" というコマンドは失敗します。この辺りの違いは「/bin/sh と /bin/bash の違い」を見てみてください。

さて、本題のプロセス置換ですが、"man bash” を見ると以下のように書かれています。

Process Substitution

Process substitution is supported on systems that support named pipes (FIFOs) or the /dev/fd method of naming open files. It takes the form of <(list) or >(list). The process list is run with its input or output connected to a FIFO or some file in /dev/fd. The name of this file is passed as an argument to the current command as the result of the expansion. If the >(list) form is used, writing to the file will provide input for list. If the <(list) form is used, the file passed as an argument should be read to obtain the output of list.

When available, process substitution is performed simultaneously with parameter and variable expansion, command substitution, and arith-metic expansion.

これだけではよくわからないと思うので、出力対象として使った場合、入力対象として使った場合の使用例をご紹介します。

出力対象としてプロセス置換を使う >(list)

出力対象にプロセス置換を指定すると、例えば以下のようなことができます。僕としては、一番最初の例をよく使います。

スクリプト出力のすべてをログに取る*2

#!/bin/bash
# 以降の出力はすべて画面に出力されるとともにログファイルにも記録される。
exec 1> >(tee -a stdout.log)
exec 2> >(tee -a stderr.log >&2)
(何か処理)

標準エラー出力の内容をフィルタする*3

#!/bin/bash
exec 2> >(grep -v "exclude" > &2)
(何か処理)

teeの分割先に指定

cat inputfile | tee >(grep -v exclude > outputfile)

入力対象としてプロセス置換を使う <(list)

こちら側の使い方では、処理済みテキストを渡したい場合に汎用的に使うことができます。いくつか例を挙げます。

diffの入力対象に処理済みテキストを渡す

一番よくある使い方はdiffと組み合わせて使う方法です。diffは、入力対象としてファイルのみを対象としているため、通常のパイプで処理済みテキストを渡すことができません。プロセス置換を使うことで、コマンドで処理した結果同士をdiffで比べることができます。

diff <(grep -v "exclude" inputfile) <(sed -e 's/a/b/' inputfile)

inputfileの中で、"exclude"という言葉が入っている行を除外してWhileループを回す

プロセス置換は、あたかもファイルであるかのように扱うことができるので、Whileループにも渡すことができます。たとえば、以下の2つは同等の内容になります。

  • プロセス置換を使わない方法
cat inputfile | grep -v "exclude" > newfile
while read line
do
    echo $line
done <newfile
  • プロセス置換を使う方法
while read line
do
    echo $line
done < <(cat inputfile | grep -v "exclude")

プロセス置換を使うとこのように一時ファイルへの書き出しを行う必要がなくなり、処理後に削除するなどといった扱いを気にする必要がなくなります。

bash プロセス置換」などのワードで検索するとほかにもいろいろ例が出てくると思います。どうしても一時ファイルを書きたくない、という場合以外は、必ず使わなければいけない機能ではないですが、覚えているとスクリプトをシンプルかつ見通しよく書ける場合があります。

僕も応用例にはあまり詳しくないので、ほかにいい活用例があれば教えてもらえると嬉しいです。

<追記>

プロセス置換を使ったタイムスタンプ付きフィルタの例として、OpenStack開発環境のDevStackにちょうどいい例があるので、そちらもご紹介。DevStackのスクリプトは、bashの便利機能を多用しているので非常にいいサンプルになります。 ただ、bash固有の機能を知らないとどこでログにタイムスタンプが付けられているのかを理解するのが難しい…。

以下は「stack.sh」の該当箇所のみの引用ですが、スクリプト本体にはコメントがないので、上記のサイトの解説から引っ張ってコメントにしています。

#Copy stdout to fd 3
    exec 3>&1
    if [[ "$VERBOSE" == "True" ]]; then

#Redirect stdout/stderr to tee to write the log file
        exec 1> >( awk '
                {
                    cmd ="date +\"%Y-%m-%d %H:%M:%S \""
                    cmd | getline now
                    close("date +\"%Y-%m-%d %H:%M:%S \"")
                    sub(/^/, now)
                    print
                    fflush()
                }' | tee "${LOGFILE}" ) 2>&1

#Set up a second fd for output
        exec 6> >( tee "${SUMFILE}" )
    else

#Set fd 1 and 2 to primary logfile
        exec 1> "${LOGFILE}" 2>&1

#Set fd 6 to summary logfile and stdout
        exec 6> >( tee "${SUMFILE}" /dev/fd/3 )
    fi

<さらに追記 8/18>

ブコメで以下のコメントをもらったので、ここで出しているwhileループの例について補足します。

whileループのところ、直接 cat inputfile | grep -v exclude | while read line ~~ すればいいのでは?

僕が出していた例は、確かにコメントでいただいたものでも結果は変わりません。ただ、もともとのお題がパイプに伴う変数の扱いの問題で、コメントでいただいたようにパイプでつないだ場合、「ループ内で変数を変更してもそれがメインシェルの変数に反映されない」*4という問題に引っかかります。なので、ここではパイプを使わない場合の例を書きました。

たとえば、以下のスクリプトを実行してみます。

#!/bin/bash
var="first"

cat inputfile | grep -v exclude | while read line
do
    # ループの中で変数書き換え
    var="second"
done
echo $var # whileループ内での変更が反映されて、"second"が出るはず・・・?

while read line
do
    # ループの中で変数書き換え
    var="second"
done < <(cat inputfile | grep -v exclude)

echo $var # 上と同様の結果???

2つのループの違いは、パイプかプロセス置換での擬似的なファイル入力かだけですが、こちらの出力結果は、以下のようになります。

first
second

前者の場合は、var="second"への変更がWhile内部だけでしか有効にならないため、その外にあるvar変数に反映されません。一方、後者ではwhileループの中で変数変更が反映されています。*5この辺りはお題のエントリの解答編に詳しく書かれているので、そちらをご参照ください。

*1:プロセス置換は、zshでも使えるようですが、僕自身はzsh使いではないので、ここでは触れません

*2:プロセス置換を使わなくてもファイルに標準出力と標準エラー出力をリダイレクトして、それをtailすることで実現できますが、そうすると別途tailのプロセスの扱いを考えたりする必要があって手間がかかります。

*3:これがhirose31さんの日記にコメントしたものです

*4:この原因は、サブシェルの起動によるものだと説明されることが多く、僕もこれまでそう思っていましたが、お題のブログへのコメントに「bash (や POSIX sh) は、コマンドパイプラインの変数値変更はそのコマンドラインローカルになるから」ということではないかということが書かれていました。自分の手元で実験した限りでは、確かに指摘の通りで、サブシェルを使わない場合でも同じ現象となりました。

*5:一時ファイルを使った場合もプロセス置換と同様の結果になります。