AWKのススメ

2009年10月23日

はじめまして。インフラチームの菅原といいます。

今年の7月に入社してから、コンソールとにらめっこする毎日を過ごしています。クックパッドのようにアクセスの多いサイトのサーバを扱うことが今まで無かったので、いろいろと勉強になることが多いです。

さて、インフラチームではサーバの状況をモニタリングして、サーバに問題がないかを常に把握するようにしています。そのため日常的にtailでログを追いかけているのですが、そんなときはAWKが非常に便利なことに気付き、最近はかなりAWKにハマっています。

今回は絶賛マイブーム中のAWKの活用例をご紹介したいと思います。

なぜAWKなのか?

残念ながらAWKの知名度はあまり高くないようで、社内でも「なぜRubyでやらないのか?」と聞かれることがありました。僕も入社するまではcutの代わりぐらいにしか使っていなかったのですが、あるときログ出力の整形に使って以来、AWKのおもしろさにすっかりハマってしまいました。

AWKの魅力はいろいろとあるのですが、ひとつあげるとすれば「ワンライナーの書きやすさ」です。もちろんRubyでもPerlでもワンライナーは書けるのですが、AWKはさらにワンライナーが書きやすい言語です。

仕事での活用例

普段、僕が仕事で使っているAWKスクリプトをいくつかご紹介します。AWKの文法についてはGNU Awk User’s Guideなどを参照してください。

Railsの500msec以上かかっている処理を追いかける

後からRailsのログを集計してもよいのですが、その場で状況を知りたいときは tail -f と AWK の組み合わせが強力です。次の簡単なAWKスクリプトは、遅くなっている処理をさくっと把握したいときに使っています。

$ tail -f log/production.log | ¥
 awk '/^Completed/{if($3 > 0.5) print }'
Completed in 0.56046 (1 reqs/sec) | Rendering: 0.23351 (41%) ...
Completed in 0.59227 (1 reqs/sec) | Rendering: 0.00010 (0%) ...
Completed in 1.90438 (0 reqs/sec) | Rendering: 1.87990 (98%) ...
...

Apacheの平均応答時間を追いかける

アクセスが多くなると tail -f でaccess_logを追いかけようとしても、流れが速すぎて状況を把握できません。そこでAWKで100リクエストごとの平均応答時間を計算して、現在の応答時間がどのくらいなのかを把握しています。

$ tail -f access_log | awk '
{i++; t+=$4}
i > 100 {
  print strftime("%H:%M:%S"), "|", t / i / 1000, "ms"
  i=t=0
}'
18:58:34 | 97.1538 ms
18:58:38 | 80.6553 ms
18:58:42 | 75.4794 ms

ちなみにクックパッドのaccess_logは以下のようなフォーマットで出力されます。

# ステータス, 時間, 処理時間(マイクロ秒), リクエストuri, パラメータ...
LogFormat "%>s\t%{%Y-%m-%d %H:%M:%S}t\t%D\t%U\t%q..."

上記のスクリプトを少し修正して、単位時間あたりのリクエスト数を出力するようにすると、サービスへどのくらいアクセスがあるのかを把握できるようになります。

[...]$ tail -f access_log | awk '
BEGIN{st=systime()}
{i++}
i > 200 {
  et=systime()
  printf("%s | %.1f req/sec\n",
    strftime("%H:%M:%S"),  i / (et - st))
  i=0; st=et
}'
19:10:45 | 16.8 req/sec
19:10:55 | 20.1 req/sec
19:11:06 | 18.3 req/sec

slow-query.logを追いかける

mysqldumpslowというスロークエリログ用のツールがありますが、その場で状況を知りたいときには tail -f で追いかけるのが手軽です。しかし、そのままでは少々見にくいので、次のようなAWKスクリプトで整形します。

[...]$ tail -f slow-query.log | awk '
/^# Time/ {
  q=substr(q,0,64)
  printf("%s %s %-17s %2d %s\n", d, t, h, s, q)
  d=$3; t=$4
}
/User/ {h=$5}
/Query_time/ {s=$3}
/^[^ ]/ {q=$0}'
091010 17:46:45 [192.168.xxx.xxx]   2 SELECT foo, bar, zoo FROM...
091010 17:55:29 [192.168.xxx.xxx]   3 SELECT foo FROM...
091010 17:56:08 [192.168.xxx.xxx]   3 SELECT foo FROM...

ANSIエスケープシーケンスを使えば、10秒以上かかったクエリだけ赤く表示することもできます。

awk '
/^# Time/ {
  if (s > 9) {
    printf("33[0;31m")
  } else {
    q=substr(q,0,64)
  }
  printf("%s %s %-17s %2d %s\n", d, t, h, s, q)
  printf("33[0m")
  d=$3; t=$4
}
/User/ {h=$5}
/Query_time/ {s=$3}
/^[^ ]/ {q=$0}'

まとめ

今回は、仕事で使っているAWKスクリプトをいくつかご紹介させていただきました。僕もまだAWK初心者なのでお世辞にも洗練されたコードとはいえませんが、それでも非常に役に立っています。
ちなみに、AWKのワンライナーには何か癖になるものがあり、最近はワンライナーばかり書いているので、historyがスクリプトの保存先と化しつつあります。

みなさんもAWKで一行野郎を使いこなしましょう!

おまけ

GNU Awkはソケットが使えるので、カレントディレクトリをDocumentRootとするWebサーバを、ワンライナーで書いてみました。

awk 'BEGIN{s="/inet/tcp/80/0/0";"pwd" |& getline;r=$0;while((s |& getline) >; 0){gsub(/[\r\n]/,"");if($0 ~ /^\s*$/){c="cat " r path;printf "HTTP/1.0 200 OK\r\n\r\n" |& s;while((c |& getline) > 0){print |& s}close(c);close(s)}else if($0 ~ /HTTP/){print;path=$2}}}'

きちんと改行をいれるとこんな感じになります。

awk '
BEGIN {
  s = "/inet/tcp/80/0/0"
  "pwd" |& getline
  r = $0

  while ((s |& getline) > 0) {
    gsub(/[\r\n]/, "")

    if ($0 ~ /^\s*$/) {
      c = "cat " r path
      printf "HTTP/1.0 200 OK\r\n\r\n" |& s

      while ((c |& getline) > 0) {
        print |& s
      }

      close(c)
      close(s)
    } else if ($0 ~ /HTTP/){
      print
      path = $2
    }
  }
}'

AWKを使ったことがなくても、わかりやすいコードではないでしょうか?

GNU Awkのネットワーク機能はとても面白いです。AWKを始めた人には、ネットワーク機能のマニュアルを一読することをお薦めします。

クックパッドとHadoop

2009年9月16日

はじめまして。今年の5月に入社した勝間@さがすチームです。

入社してからは、なかなか大変なことも多いですが、最近はお酒好きが集まって月曜から飲み合う 「勝間会」なるものも発足して、仕事面でも仕事以外の面でも密度の高い毎日を過ごしています!

さて、僕は「さがす」チーム所属ということで、普段はレシピを「さがす」ユーザの満足度を上げるために、 クックパッドの検索まわりについて、いろいろな開発を行っています。 一方で、ユーザの「さがす欲求」について深く知るために、大規模なデータ解析を行い、欲求の分析を行う機会も増えてきました。

ところが、クックパッドのログは膨大な数があるので、一口のデータ解析と言っても通常のバッチ処理だと間に合わないため、 分散処理環境の必要性が高まってきました。 そこで、まずは手軽に試せる分散処理の王道ということで、最近ではHadoopを使ったデータ解析環境を整備しています。

そんな中、ちょうどtech lunchで発表の順番が僕に回ってきたので、いい機会なので 「そもそもHadoopって何?」ということや「Map & Reduceを行っているとき、各プロセスは何をしているの?」な話をデモを含めながら発表してみました。 今回は、そのときの内容の資料と質疑応答の内容を共有したいと思います。

発表資料はこのようなものを利用しました。

その後は、このような質疑応答が行われました。

HDFSのNameNodeがボトルネックにはなりえないのか?

NameNodeは障害が起こると、HDFSのクラスタ全体が利用不能になるので、SPOFという観点で考えると、構成上どうしてもボトルネックになり得ます。
ただし、NameNodeが扱うメタデータを保護できれば、NameNodeに障害が起きても復旧できるため、次のような方法が提唱されています。

  • メタデータについては、RAIDを組んで多重にディスクに書き込む。
  • または、NFSマウントされた領域にメタデータを書き込む。
  • SecondaryNameNodeはNameNodeのメタデータのバックアップを定期的にとっているため、NameNodeとSecondaryNameNodeを物理的に別ノードに分けて運用する。

また、NagiosやGangliaでモニタリングを行うことも可能で、ここから障害を検知することも可能です。

Hadoop MapReduceの処理コードはmasterにだけ置いておけば配布されるのか?

処理コードはMap&Reduce実行時にmasterからslaveに配布することができます。もちろんあらかじめrsyncなどで配布しておく方法も取ることが出来ます。

HDFSの安定性は?

レプリケーションの数を増やすことで安定稼働されます。 バックアップ失敗を想定して、レプリケーション数は3以上が推奨されています。また、HDFSに対してファイルシステムチェックを行うことも可能です。

Hadoop MapReduceとHDFSを分けた方がリソースを効率的に使えるのでは?

そういう発想もありかと思いますが、Hadoop開発陣の方針として、基本的には標準的な設定の使用を推奨しているようです。
標準的な設定は、YahooやFacebookなど大規模に利用されているケースをベースにして設定されたものなので、これに習うのが結果的に一番安定して動作するのでしょう。

Taskを割り振るのに優先度が付けられるのか?

複数Jobを与えるときに、優先度を付けることができます。

UU測定のサンプルコードで、複数プロセス存在するはずのReduceがハッシュマップのようなオブジェクトをどうして持てるの?

ハッシュマップのようなキーごとに処理を行うオブジェクトを持つためには、Reducerはキーごとに同じノードが処理を行っている必要があります。このとき、Mapの出力を同じキーごとに同じグループに属するように分割できれば、Reduceは分割可能となります。

ここでの、「Mapの出力を、ソートし、Reduceに渡す」フェーズは「Shuffle」、「Reduceへの入力をキーに基づいてグループ化してまとめる」フェーズを「Sort」フェーズと呼びます。 HadoopではShuffleやSortは完全に隠蔽されているので開発者がこれらのコードを書くケースはありません。

つまり、今回のようなMapの出力がkeyごとに分割されている場合は、Shuffle, SortによってMapの出力を分割、グループ化してReduceが処理できるようになるのでうまく扱うことができます。

HDFSを画像サーバなどに利用できるのか?

HDFSからのレスポンスは特に速いわけではなく、転送速度がボトルネックになるので、画像サーバには向いていません。HDFSは、データの行き来がそれほど起こらない、ログデータのようなものの保存が最も適していると思います。 画像サーバを分散ストレージで検討する場合は、他のプロダクトを利用したほうがよさそうです。

HadoopはHDFSに特化してるのか?

Hadoopを利用する場合は、必ずしもHDFSしか使えないわけではないです。他にもAmazon S3, CloudStoreなんかの選択肢があります。実際は、HDFSが一番ポピュラーで標準的に利用されているので、今回はこれを試してみました。

Hiveたのしそうですね

試してみましたが、なかなかたのしいです。 RDBと親和性高く、Joinなんかもできるのは魅力的なので、導入を検討しています。

クックパッドではHadoopはどのように使われるの?

直近では、様々な条件下でのログ解析や、バックエンドのDB更新などに利用される予定です。

まとめ

クックパッドにおいてデータ解析の需要が高まってきたことで、Hadoopへの取り組みをまとめてみました。今後、本格導入していく際にはまた改めてエントリを上げたいと思います。

また、このような分散環境におけるデータ解析についてご興味ある方を、クックパッドでは募集しています!

こんにちはみなさん、とんかつってうまいですし目黒のとんきは哲学ですよね、8/1付けで商品部エンジニアになったnegipoです。すてきな上司とかわいい同僚に囲まれてとても幸せです!

さて、今回はクックパッドのバックエンドで動いているバッチシステムの紹介スライドを共有します。

大事なことは全部かいてあるので読んで下さい。
けっこう大胆な修正が入っていますが、なんとか趣旨をよみとってもらえるとうれしいです。

という訳で、クックパッドでは2週間に1度みんなでお昼ごはんを食べながら一人のエンジニアが何かをしゃべる、”tech lunch”というものを開始しました。技術部はもちろん、商品部や編集部のディレクターなど多岐にわたる人たちがクックパッドがどうやって動いているか、将来どうなっていくのかという話にふむふむと頷いています。
今後このtech lunchで共有された技術的な内容は、順次この開発者ブログに掲載していく予定です。皆様のお役に立つ情報がどんどん集まればよいなと思います。
今後ともクックパッド開発者ブログをよろしくお願いします。

こんにちは。クックパッドのインフラを担当している高田悟史です。入社してもう少しで1年になりますが、とても密度の濃い毎日をすごしています。

今回は、クックパッドで1年を通してアクセス数が1番多いバレンタインデーを無事のりきったお話をします。

1年を通してクックパッドのアクセス数(PC版)を見ると、日々順調に増えている中でもクリスマス前後とバレンタインデー前後が、特に多くなっています。例えば去年度では、2007年のピークが12/24の8,110,082PV、年をあけた2008年のピークが2/13の14,906,776PVだったので、バレンタインデーのピークはクリスマスのピークの1.8倍のアクセスがありました。

バレンタインデーにアクセスしてくれたユーザーに、いかに快適に使ってもらうかはとても重要となるので、インフラチームでは、去年の7月にリニューアルを終えてからずっと、バレンタインデーを意識した仕事をしていました。もはや「バレンタインデー」=「アクセスが多い日」と認識してしまっていて、直前になってそういえばチョコレートを贈る日だったんだ!と思い出したほどです。

さて、バレンタインデーのアクセス対策ですが、年があけてからはインフラチーム4人が、オフィスの奥にある和室部屋にこもり、システムのボトルネックの調査をし、キャッシュの実装、サーバーの増設、去年のクリスマスをもとにした負荷テスト、などをしていました。

その結果、無事バレンタインデーのアクセスをさばくことができたので、先週、技術部ではバレンタインのりきりを祝う会を開きました。当日は、ちょうどクックパッドのモバイル版「モバれぴ」が、docomo・au・SoftBankの3キャリア公式化を終えた日でもあったので、一緒に祝いました。

v_cake
女子社員がこっそり作ってくれたケーキです。どうもありがとうございました。

v_all
技術部の集合写真。

バレンタインデーのアクセス対策については、また改めて書こうと思います。

こんにちは、はじめまして。
クックパッドで社内システムの運営をしています、えいしょうです。
今日は、クックパッドの開発からは少し話題がそれますが、
弊社の社内システム、その中でも特に「Salesforce」というシステムについて、ちょっとお話しさせて頂こうかと思います。

 

今や企業には、実に様々なシステムがあります。
弊社のような業種の場合、システムがなければ何も仕事できないと言っても、過言ではありません。

ですが、どの企業でも、こと「営業」に関しては
比較的アナログが多いのではないでしょうか。
何故か?おそらく、一人一人の「経験」や「勘」に頼るところが多く、
機械的なプロセス分析やパフォーマンスチェックが、難しいからだと思います。

しかし、経験や勘に頼っていては、いつまで経っても生産性の向上は望めませんし、
人数が増えるほど情報が錯綜し、却ってパフォーマンスが下がってしまいます。

 

そこで登場するのが「Salesforce」です。
今やSaaS(Software as a Service)の急先鋒と言われて様々なことができるシステムですが、
その機能のキモは、読んで字のごとく「営業の力」、つまり営業をサポートし、売上を上げるところにあります。

具体的には何をしているのか?
大きく分けると、以下の5つになるかと思います。

 

(1)受注情報の一元管理

誰がいつ、どこの企業から、何の商品をいくらで受注したか。
これが把握できなければ会社は成り立ちませんので、どの企業でも管理している情報でしょう。経理が主導して管理している企業が多いかと思います。

(2)ヨミ(売上見込み)情報の一元管理

(1)はすでに売上が確定した情報ですが、それだけでは会社としての見通しが立ちません。また、営業としても、何をどう頑張ったらいいのか分かりません。
これも、どの企業でもおおよそは把握しているでしょう。
営業事務やマネージャが主導になり、エクセルを使って管理している企業が多いんじゃないでしょうか。

(3)顧客情報の一元管理

ここからは、できていない企業も多いんじゃないでしょうか。
連絡先、業種、担当者の名前といったハードデータだけでなく、
(1)(2)の紐付けによる受注データやヨミデータ、
また、誰がいつ何をして(ex.訪問した・電話した)、その結果がどうだったか、といった行動データまで、すべてを一元管理します。
このような詳細な顧客情報を共有することで、以下2つのメリットを享受できます。
・引き継ぎがとても楽になります。
  営業活動の中でもかなり厄介な、顧客の引き継ぎ。
  ところが、これらの情報が共有されていれば、「よろしく」の一言で片付きます。
・既存顧客に対する適切な営業が可能になります。
  商材にもよりますが、リピートの提案には、適切なタイミングと確かな履歴情報が
  必要です。今までのお付き合いが詳細に把握でき、いいタイミングでアラートが
  上がってくれば、チャンスを逃さずにリピートの売上につなげることができます。

(4)営業マンのパフォーマンスの把握

ここまで来ると、たいていのシステムじゃあ難しいんじゃないでしょうか。Salesforceの真骨頂です。
(2)ヨミデータや(3)で出てきた行動データを、営業マンごとに集計すれば、
さまざまな切り口からの営業マンのパフォーマンスを知ることができます。
たとえば、1週間の行動量、受注率や失注率、案件の発生ペース、などなど。
ここで肝心なのは、『会社として重視すべき指標(KPI)を設定し、ぶれないこと』です。
見れるのであればと欲張って、いろんな指標を知りたくなるものですが、余りにたくさんあると大事なものを見失ってしまいます。
指標はシンプルにすること。これには、マネージャーや経営陣の協力が不可欠です。

(5)フレキシブルなデータの分析

以上の登録されたデータを、さまざまな切り口から分析できます。
たとえば、商材別の売上、販路別のヨミ、販売代理店のパフォーマンス、など。
この場合、「スピーディーさ」がとても重要になります。
さまざまな分析が柔軟にできることで、信憑性や価値が増し、よりアイディアを広げることができます。一つ分析するのに何日もかかっていたのでは、動きの速い営業の世界では役に立ちません。

 

ここまで書いていて、弊社はまだまだだなぁと、我ながら痛感してしまいました。。。
これらが全て活用された時、本来の価値が発揮され、売上への貢献という目的が達成するのだろうと思います。
そこで初めて導入プロジェクト(の”第1段階(!)” )が達成。道のりは長いです。

 

閑話休題。
ではなぜ「Salesforce」を選んだのか?

・・・かなり長くなってしまったので、続きはまた次回にさせて頂きます。
次回も長くなってしまうような気がしますが・・・お付き合いくださいませ。