Glide Note

glidenote's blog

Octopressをアップデートした

2011年から使っているOctopressですが、導入時から全然アップデートしてなくて、jekyllが古いままだったので、

を参考にアップデートしてみたので作業メモ。

作業前にバックアップ

git管理しているので、作業前にcommitしておく。

1
2
git add .
git commit -m "commit before update"

remoteの確認

octopressというのがoctopress自体のソースだと確認出来る。

1
2
3
4
5
6
7
git remote -v
bitbucket       [email protected]:glidenote/octopress.git (fetch)
bitbucket       [email protected]:glidenote/octopress.git (push)
octopress       git://github.com/imathis/octopress.git (fetch)
octopress       git://github.com/imathis/octopress.git (push)
origin  [email protected]:glidenote/glidenote.github.com.git (fetch)
origin  [email protected]:glidenote/glidenote.github.com.git (push)

Octopressのmasterをfetch

1
git fetch octopress

mergeする前に差分を確認

1
git diff source...octopress/master

mergeする

1
git merge octopress/master

カスタムしているせいか、結構conflictしていたので、手動で1個ずつ修正。

gemの更新

1
bundle install

で各種gemの更新。

amazon pluginの変更

今まで、Amazon Plugin for Octopress - Zanshin.netのamazon pluginを使っていたんですが、 中で使用する{}が2個続く構文が原因で、Liquidがエラーを吐いて、rake generateが走らなくなっていたので、下記プラグインを利用するように変更。

octoeditor.vimをbundle execに対応してバージョンアップ

rakeが新しくなり、bundle execが必須になっていて、拙作のglidenote/octoeditor.vimで 記事の:OctopressGenerate:OctopressDeployが走らなくなっていたので、budle execを利用する

1
let g:octopress_bundle_exec = 1

というオプションを作って対応。

Octoprssのアップデート後から記事の生成(bundle exec rake generate)が体感的に 2/3くらいの時間になってちょっと感動した。(早くなると思ってなかったからベンチを取ってなかった…)

TAI64N形式のタイムスタンプをparseするFluentdのプラグインfluent-plugin-tai64n_parserを作った

追記 2014年2月19日 本記事の初投稿後に修正がかなり入っているので、最新の利用方法についてはglidenote/fluent-plugin-tai64n_parserを参照ください。

TAI64N好きですか!!qmailのログとかでよく見る下記みたいなやつ。

1
2
3
4
5
6
7
@4000000052fafd8d3298434c new msg 3890
@4000000052fafd8d32984b1c info msg 3890: bytes 372 from <root@**********.pb> qp 31835 uid 0
@4000000052fafd8d373b5dbc starting delivery 9: msg 3890 to remote glidenote@********.co.jp
@4000000052fafd8d373b6974 status: local 0/120 remote 1/60
@4000000052fafd8d38754cec delivery 9: success: ***.***.***.***_accepted_message./Remote_host_said:_250_ok_1392180611_qp_10394/
@4000000052fafd8d387554bc status: local 0/120 remote 0/60
@4000000052fafd8d387554bc end msg 3890

私は大嫌いで見たくないです。見たくないけど残念ながら結構見かけるし、Fluentdにただ流してもナノ秒が処理が出来ないので TAI64N形式のタイムスタンプをparseするfluent-plugin-tai64n_parserというものを作った。 既に本番サーバに投入して毎分30000メッセージくらい処理させてるけど、負荷もなく安定して動いてる。

設定例

1
2
3
4
5
6
7
<match test.**>
  type             tai64n_parser

  key              tai64n
  output_key       parsed_time
  add_tag_prefix   parsed.
</match>

下記みたいなメッセージが流れてくると

1
2
3
"test" => {
  "tai64n"      => "@4000000052f88ea32489532c"
}

下記のようにtai64nlocalかけたときと同じようにparseされる。

1
2
3
4
"parsed.test" => {
  "tai64n"      => "@4000000052f88ea32489532c"
  "parsed_time" => "2014-02-10 17:32:25.612979500",
}

qmailの送信ログを処理してみる

たとえばqmailの送信ログを処理する場合は、下記のような感じで設定

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<match raw.qmail.sent>
  type             parser
  remove_prefix    raw
  format           /^(?<tai64n>[^ ]+) (?<message>(((?:new|end) msg (?<key>[0-9]+)|info msg (?<key>[0-9]+): bytes (?:\d+) from <(?<address>[^>]*)> |starting delivery (?<delivery_id>[0-9]+): msg (?<key>[0-9]+) to (?:local|remote) (?<address>.+)|delivery (?<delivery_id>[0-9]+))?.*))$/
  key_name         message
  suppress_parse_error_log true
</match>

<match qmail.sent>
  type             tai64n_parser

  key              tai64n
  output_key       parsed_time
  add_tag_prefix   parsed.
</match>

<match parsed.qmail.sent>
  type file
  path /var/log/td-agent/qmail_tai64n_parsed.log
</match>

すると下記みたいな感じでパースされて、ナノ秒単位でparsed_timeに変換された時間が入ってくる。

1
2
3
4
5
6
7
2014-02-12T13:50:11+09:00       parsed.qmail.sent       {"tai64n":"@4000000052fafd8d3298434c","message":"new msg 3890","key":"3890","parsed_time":"2014-02-12 13:50:11.848839500"}
2014-02-12T13:50:11+09:00       parsed.qmail.sent       {"tai64n":"@4000000052fafd8d32984b1c","message":"info msg 3890: bytes 372 from <root@**********.pb> qp 31835 uid 0","key":"3890","address":"root@**********.pb","parsed_time":"2014-02-12 13:50:11.848841500"}
2014-02-12T13:50:11+09:00       parsed.qmail.sent       {"tai64n":"@4000000052fafd8d373b5dbc","message":"starting delivery 9: msg 3890 to remote glidenote@**********.co.jp","key":"3890","address":"glidenote@**********.co.jp","delivery_id":"9","parsed_time":"2014-02-12 13:50:11.926637500"}
2014-02-12T13:50:11+09:00       parsed.qmail.sent       {"tai64n":"@4000000052fafd8d373b6974","message":"status: local 0/120 remote 1/60","parsed_time":"2014-02-12 13:50:11.926640500"}
2014-02-12T13:50:11+09:00       parsed.qmail.sent       {"tai64n":"@4000000052fafd8d38754cec","message":"delivery 9: success: ***.***.***.***_accepted_message./Remote_host_said:_250_ok_1392180611_qp_10394/","delivery_id":"9","parsed_time":"2014-02-12 13:50:11.947211500"}
2014-02-12T13:50:11+09:00       parsed.qmail.sent       {"tai64n":"@4000000052fafd8d387554bc","message":"status: local 0/120 remote 0/60","parsed_time":"2014-02-12 13:50:11.947213500"}
2014-02-12T13:50:11+09:00       parsed.qmail.sent       {"tai64n":"@4000000052fafd8d387554bc","message":"end msg 3890","key":"3890","parsed_time":"2014-02-12 13:50:11.947213500"}

上の例だとfluent-plugin-tai64n_parserでparse後に、sonots/fluent-plugin-record-reformerのようなプラグインを使って tai64n自体のキーを消して、DBに入れればTAI64N形式のタイムスタンプを二度と見なくて良くなる。

参考

1時間1円でSSDなVPS(Digital Ocean)にシンガポール リージョンが来ていた

以前紹介した1時間1円でSSDなVPS(DigitalOcean)にシンガポール リージョンが来ていた。

早速インスタンスを立てて、自分の環境から、どのくらいのレスポンスなのか計測

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
[akira@dev001] $ ping -c 10 128.199.***.***
PING 128.199.***.*** (128.199.***.***) 56(84) bytes of data.
64 bytes from 128.199.***.***: icmp_seq=1 ttl=53 time=76.7 ms
64 bytes from 128.199.***.***: icmp_seq=2 ttl=53 time=75.7 ms
64 bytes from 128.199.***.***: icmp_seq=3 ttl=53 time=73.8 ms
64 bytes from 128.199.***.***: icmp_seq=4 ttl=53 time=73.7 ms
64 bytes from 128.199.***.***: icmp_seq=5 ttl=53 time=74.1 ms
64 bytes from 128.199.***.***: icmp_seq=6 ttl=53 time=76.1 ms
64 bytes from 128.199.***.***: icmp_seq=7 ttl=53 time=75.8 ms
64 bytes from 128.199.***.***: icmp_seq=8 ttl=53 time=75.7 ms
64 bytes from 128.199.***.***: icmp_seq=9 ttl=53 time=76.1 ms
64 bytes from 128.199.***.***: icmp_seq=10 ttl=53 time=78.0 ms

--- 128.199.***.*** ping statistics ---
10 packets transmitted, 10 received, 0% packet loss, time 9096ms
rtt min/avg/max/mdev = 73.738/75.623/78.060/1.290 ms

今まで日本から一番レスポンスの良かったSan Francisco1へのping応答が105msくらいなので、30msくらい早くなった。

さくらVPSが11msとかなので、比較するとまだまだですが、sshログインして半日触った感じだと レスポンスの遅延とか特に感じなくて快適。(たぶんまだあんまり使われてないからだと思うけど)

とりあえずVagrant+DigitalOceanな使い捨てサーバ環境はシンガポールリージョンに移行した。

重要なメールが届いたらIRCにメールの件名を通知するようにした

自分がTO,CC,BCCに入ってたり、本文に自分の名前が入ってるメールはちゃんとメーラで振り分けしてチェックしているんですが、 自分が参加しているML宛てに重要なメールが届いたときにを見逃してしまう事が多い。

IRCは基本的に常時起動していて、キーワードには反応するようにしているので、参加しているML宛てにメールが届いたらメールのsubjectをIRCに通知して気づけるようにした。

これをやる前置きとして、弊社ではIkachanが導入されてるので、 curl叩けばIRC通知されるようになっており、IRCへの通知は大変手軽に出来るようになってる。

仕組み

  • サーバ上でfetchmailをcronで回して、メールを定期受信
  • procmailで条件に一致する場合を判定し、コマンド(curl)を叩いてIRCに通知する

たとえば、特定の人(From)からメールが届いたらIRCに通知するよう場合の .procmailrcの内容は下記のような感じ

1
2
3
4
5
6
7
8
9
10
11
12
13
SUBJECT=`formail -c -xSubject:`
IRC_POST_SUBJECT=`echo $SUBJECT | nkf -w`

:0
* ^(From).*[email protected]
{

  :0 c
  | /usr/bin/curl -F channel='#maeda_test' http://ikachan.hogemoge.com:4979/privmsg -F message="メールが届いてるよ!  件名:${IRC_POST_SUBJECT}"

  :0
  ~/Maildir/
}

「2014年にfetchmailとかprocmailなんて…」という感じかもしれないけど、 軽量だし、技術的には枯れてて非常に安定しているので、こういうことをやるのには適してると思う。

td-agentでqueue size exceeds limit

昨年構築してからずっと安定稼働していたfluend(td-agent)が年明けくらいから下記のエラーが出て連日停止してしまって、 ちょっとハマったのでメモしておく。(ハッキリとした原因は掴めてないですが)

利用しているtd-agentのバージョンはtd-agent-1.1.18-0.x86_64

現象

fluent.logには下記が出ていて、機能が停止している。

1
2
3
4
5
6
2014-01-09T20:28:59+09:00       fluent.error    {"error":"#<Fluent::BufferQueueLimitError: queue size exceeds limit>","error_class":"Fluent::BufferQueueLimitError","message":"forward error"}
2014-01-09T20:28:59+09:00       fluent.warn     {"error_class":"Fluent::BufferQueueLimitError","error":"#<Fluent::BufferQueueLimitError: queue size exceeds limit>","message":"emit transaction failed "}
2014-01-09T20:28:59+09:00       fluent.warn     {"error_class":"Fluent::BufferQueueLimitError","error":"#<Fluent::BufferQueueLimitError: queue size exceeds limit>","message":"emit transaction failed "}
2014-01-09T20:28:59+09:00       fluent.warn     {"error_class":"Fluent::BufferQueueLimitError","error":"#<Fluent::BufferQueueLimitError: queue size exceeds limit>","message":"emit transaction failed "}
2014-01-09T20:28:59+09:00       fluent.warn     {"error_class":"Fluent::BufferQueueLimitError","error":"#<Fluent::BufferQueueLimitError: queue size exceeds limit>","message":"emit transaction failed "}
2014-01-09T20:28:59+09:00       fluent.warn     {"error_class":"Fluent::BufferQueueLimitError","error":"#<Fluent::BufferQueueLimitError: queue size exceeds limit>","message":"emit transaction failed "}

dmesgには下記が延々と出続けている。possible SYN flooding on port 24224はtd-agentがポート開いてるけどaccept(2)してないから出ていると@hiboma先生がサクッと検証用のコードを書いて調査してくれた。

1
2
3
possible SYN flooding on port 24224. Sending cookies.
possible SYN flooding on port 24224. Sending cookies.
possible SYN flooding on port 24224. Sending cookies.

構成は以前書いたもののまま。

対処方法

いろいろ調査して、試してみたんですが、先に対処内容を書いておくと、@hiboma先生が調べてくれた fluentdで死の宣告queue size exceeds limit - boku no blog を参考に、buffer_typememoryからfileに変更して現象は収まって復旧。

変更内容は下記のような感じ

buffer_chunk_limitbuffer_queue_limitの値は結構気をつけてたんですが、 メモリ64GB+SSDのサーバで、盲目的にbuffer_type memoryにしていたのが災いした模様。

調査でやったこと

  • buffer_chunk_limit,buffer_queue_limitの調整
  • strace、gdbでバックトレース
  • monitoring agentを利用して詳細リソースの監視
  • kill -USR1 飛ばしてみる

など、@hibomaと@hfmに協力してもらってかなりいろいろなことを試してみたけど、症状も改善せず。

調査で分かったのはqueue size exceeds limitが出て、いきなり止まるんじゃなくて、logrotateのタイミングで死んでるような挙動。 logrotate内で実行しているkill -USR1を実行してみると旧プロセスが残ったままになったりして、調査している問題と別の問題と思われる謎の挙動が発生して 訳が分からない状態に…

参考