ISUCON8 反省
:thinking_face: 学生枠参加。本戦14位/30
SNSシェアをしなかった中ではそれなりの順位っぽいですね。
https://github.com/wass88/isucon8-final/issues/2
// の後ろが事後反省。
- /infoの改善
-まともな時系列DBを使うほうが早そう // 時間内に無理
- キャッシュする→定期的に生成するとかを思いつくべきだった
- たぶんここがかなり効くんだと思う
- 取引測度の改善
- ISULOGGER の send_bulk を使う。
- sendをまとめて1リクエストにしてくれるやつ。非同期にログを流す。
- // Logサーバーを立てて実装した。
- // +200点ぐらいにはなってくれた気がする。
- /signinのBAN
- // 実装間に合わず
- // SNSをONにしたときに効くらしい。
- isucon-3のインスタンスが速いらしい
- setting DBは完全に不要。
- // redisに置いてもらった。
- // SNSにはほとんど手を付けていなかった、最後30分でONにしてFailして終わりだった。
- // 確率的にONにするのは思いつかないな…
SQLの改善はutgwさんに、インフラは全部nonyleneさんにやってもらった。
僕は全体を見て最初の2時間で戦略を練っていた。
/infoの真面目な改善について話し合うべきだった。
問題はすごく良かったと思います。まだまだ手を付けられるところが多い。
Pythonで非同期な処理を書くの非常に面倒なので、次からはGoでやりたい…
毎年要求されるレベルが線形に増えていくので、それに追いつかない感じがある。頑張り。
Rubyのtrace命令の話を確かめる
過去のblogから移動しました 元公開日時 2017-12-31 06:10:19
こんばんは。
この記事はKMCアドベントカレンダー23日目の記事です。大遅刻です。
前日の記事はprimeさんの
ビット演算マニアのためのAVX512入門 【KMCアドベントカレンダー 22日目】 - prime's diaryです
明日の記事はtetsutalowさんの
3つの事件で振り返る「何をやったらウイルス罪で捕まるか2017」 - Tetsu=TaLowの雑記(はてブロ版)です
本題
インターンの講義でお世話になった笹田さんの上の記事を読みました。
その記述を確かめながら小ネタにしようと思います。
次の素朴なコードのベンチマークを見てください。
require 'benchmark'
Benchmark.bmbm 10 do |r|
r.report "Normal" do
1000000.times {
a = 0
b = 1
100.times {
c = a + b
a = b
b = c
}
}
end
r.report "Boost" do
boost %q(
1000000.times {
a = 0
b = 1
100.times {
c = a + b
a = b
b = c
}
}
)
end
//省略
end
user system total real
Normal 9.510000 0.130000 9.640000 ( 10.713862)
Boost 8.590000 0.090000 8.680000 ( 9.021931)
Boost
のほうが速いようです。
boost %q()
で囲むだけでちょっと速くなっているようにみえます。
ねたばらし
boostの実装は以下のとおりです。
def boost src
eval src.gsub("\n", ";")
end
引数の文字列の改行全てをセミコロンに置き換えて実行するだけです。
すなわち次のコードより
a = 1 + 2
b = 3 + a
このコードの方がちょっと速くなるということです
a = 1 + 2;b = 3 + a
なんでだろう?
結論としては, trace命令が減ったからです。
RubyのVM
YARV
VMコードを見るには
puts RubyVM::InstructionSequence.compile("1+1").disasm
のようにすれば"1+1"のVM命令が読めます。
== disasm: #<ISeq:<compiled>@<compiled>>================================
0000 trace 1 ( 1)
0002 putobject_OP_INT2FIX_O_1_C_
0003 putobject_OP_INT2FIX_O_1_C_
0004 opt_plus <callinfo!mid:+, argc:1, ARGS_SIMPLE>, <callcache>
0007 leave
細かいところは説明しません。行番号と命令が1行ずつかかれています。
雰囲気で1と1をスタックに積んで足し合わせている様子を感じ取ってください。
rubyのコードは実行するときに, このようにVM命令を一度挟んでいます。
命令の説明は
insns.def
にあるので興味があれば読んでください。
trace命令
笹田さんの記事によると, trace命令はRubyコードの各行に挟まれるようです。
実際, ベンチマークで使ったコードのVM命令を見るとtrace命令はたくさんあります。
1000000.times {
a = 0
b = 1
100.times {
c = a + b
a = b
b = c
}
}
== disasm: #<ISeq:<compiled>@<compiled>>================================
== catch table
| catch type: break st: 0002 ed: 0008 sp: 0000 cont: 0008
|------------------------------------------------------------------------
0000 trace 1 ( 1)
0002 putobject 1000000
0004 send <callinfo!mid:times, argc:0>, <callcache>, block in <compiled>
0008 leave
== disasm: #<ISeq:block in <compiled>@<compiled>>=======================
== catch table
| catch type: break st: 0014 ed: 0020 sp: 0000 cont: 0020
| catch type: redo st: 0002 ed: 0020 sp: 0000 cont: 0002
| catch type: next st: 0002 ed: 0020 sp: 0000 cont: 0020
|------------------------------------------------------------------------
local table (size: 2, argc: 0 [opts: 0, rest: -1, post: 0, block: -1, kw: -1@-1, kwrest: -1])
[ 2] a [ 1] b
0000 trace 256 ( 1)
0002 trace 1 ( 2)
0004 putobject_OP_INT2FIX_O_0_C_
0005 setlocal_OP__WC__0 4
0007 trace 1 ( 3)
0009 putobject_OP_INT2FIX_O_1_C_
0010 setlocal_OP__WC__0 3
0012 trace 1 ( 4)
0014 putobject 100
0016 send <callinfo!mid:times, argc:0>, <callcache>, block (2 levels) in <compiled>
0020 trace 512 ( 9)
0022 leave ( 4)
== disasm: #<ISeq:block (2 levels) in <compiled>@<compiled>>============
== catch table
| catch type: redo st: 0002 ed: 0026 sp: 0000 cont: 0002
| catch type: next st: 0002 ed: 0026 sp: 0000 cont: 0026
|------------------------------------------------------------------------
local table (size: 1, argc: 0 [opts: 0, rest: -1, post: 0, block: -1, kw: -1@-1, kwrest: -1])
[ 1] c
0000 trace 256 ( 4)
0002 trace 1 ( 5)
0004 getlocal_OP__WC__1 4
0006 getlocal_OP__WC__1 3
0008 opt_plus <callinfo!mid:+, argc:1, ARGS_SIMPLE>, <callcache>
0011 setlocal_OP__WC__0 3
0013 trace 1 ( 6)
0015 getlocal_OP__WC__1 3
0017 setlocal_OP__WC__1 4
0019 trace 1 ( 7)
0021 getlocal_OP__WC__0 3
0023 dup
0024 setlocal_OP__WC__1 3
0026 trace 512 ( 8)
0028 leave
trace 1
というのがコードの行ごとに挟まるVM命令です。
この命令が7回も現れているのがわかります。
これに対して, コードの改行を削除して以下のように(広義の)ワンライナーにした場合, VM命令はこうなります。
1000000.times {; a = 0; b = 1; 100.times {; c = a + b; a = b; b = c; };};
== disasm: #<ISeq:<compiled>@<compiled>>================================
== catch table
| catch type: break st: 0002 ed: 0008 sp: 0000 cont: 0008
|------------------------------------------------------------------------
0000 trace 1 ( 1)
0002 putobject 1000000
0004 send <callinfo!mid:times, argc:0>, <callcache>, block in <compiled>
0008 leave
== disasm: #<ISeq:block in <compiled>@<compiled>>=======================
== catch table
| catch type: break st: 0010 ed: 0016 sp: 0000 cont: 0016
| catch type: redo st: 0002 ed: 0016 sp: 0000 cont: 0002
| catch type: next st: 0002 ed: 0016 sp: 0000 cont: 0016
|------------------------------------------------------------------------
local table (size: 2, argc: 0 [opts: 0, rest: -1, post: 0, block: -1, kw: -1@-1, kwrest: -1])
[ 2] a [ 1] b
0000 trace 256 ( 1)
0002 trace 1
0004 putobject_OP_INT2FIX_O_0_C_
0005 setlocal_OP__WC__0 4
0007 putobject_OP_INT2FIX_O_1_C_
0008 setlocal_OP__WC__0 3
0010 putobject 100
0012 send <callinfo!mid:times, argc:0>, <callcache>, block (2 levels) in <compiled>
0016 trace 512
0018 leave
== disasm: #<ISeq:block (2 levels) in <compiled>@<compiled>>============
== catch table
| catch type: redo st: 0002 ed: 0022 sp: 0000 cont: 0002
| catch type: next st: 0002 ed: 0022 sp: 0000 cont: 0022
|------------------------------------------------------------------------
local table (size: 1, argc: 0 [opts: 0, rest: -1, post: 0, block: -1, kw: -1@-1, kwrest: -1])
[ 1] c
0000 trace 256 ( 1)
0002 trace 1
0004 getlocal_OP__WC__1 4
0006 getlocal_OP__WC__1 3
0008 opt_plus <callinfo!mid:+, argc:1, ARGS_SIMPLE>, <callcache>
0011 setlocal_OP__WC__0 3
0013 getlocal_OP__WC__1 3
0015 setlocal_OP__WC__1 4
0017 getlocal_OP__WC__0 3
0019 dup
0020 setlocal_OP__WC__1 3
0022 trace 512
0024 leave
わかりにくいと思いますが, 行trace命令は7つから2つになり, 5つも減っています。
このため, 実行がすこし速くなったわけです。
trace命令の定義
trace命令の定義はinsns.defにあります。
nopほど単純ではない処理が行われているのがわかります。
記事に説明されていたとおり, TracePointという機能で使われているようです。
もうちょっと検証
最初のベンチマークの時にもう少し検証をしています。
boost
の定義とほとんど同じですが,
セミコロンではなく元の改行のままにするnonboost
を定義しました。
def nonboost src
eval src.gsub("\n", "\n")
end
boost
とnonboost
の違いは";"
と"\n"
だけです。
このベンチマークは以下のようになりました。
Rehearsal ----------------------------------------------
Normal 10.420000 0.210000 10.630000 ( 13.289735)
Boost 10.280000 0.190000 10.470000 ( 12.934161)
NonBoost 10.750000 0.200000 10.950000 ( 13.520492)
------------------------------------ total: 32.050000sec
user system total real
Normal 10.260000 0.160000 10.420000 ( 11.629897)
Boost 8.970000 0.120000 9.090000 ( 9.784410)
NonBoost 9.820000 0.140000 9.960000 ( 11.012133)
何度か実行してみると, Boost
<<< NonBoost
< Normal
の順に遅い感じがしました。
明らかにNonBoost
は余計な処理を行っているのにも関わらず, 遅くならないのは不思議です。
ruby2.5の場合
このベンチマークは以下のruby2.4で実行しましたが,
ruby 2.4.3p205 (2017-12-14 revision 61247) [x86_64-darwin16]
次のruby2.5では続く結果のように, どれもほとんど差がありません。
ruby 2.5.0p0 (2017-12-25 revision 61468) [x86_64-darwin16]
Rehearsal ----------------------------------------------
Normal 12.007801 0.255304 12.263105 ( 15.818664)
Boost 12.588323 0.237480 12.825803 ( 15.782480)
NonBoost 12.292849 0.235013 12.527862 ( 14.568634)
------------------------------------ total: 37.616770sec
user system total real
Normal 11.921363 0.238929 12.160292 ( 13.990406)
Boost 11.551764 0.235187 11.786951 ( 13.314673)
NonBoost 11.725629 0.180515 11.906144 ( 13.135241)
これは最初の記事で紹介されている通り, trace命令が抑制される最適化が施されたためです。
実際の命令を見てみると, 1つもtrace命令が存在しません。
== disasm: #<ISeq:<compiled>@<compiled>:1 (1,0)-(9,5)>==================
== catch table
| catch type: break st: 0000 ed: 0006 sp: 0000 cont: 0006
== disasm: #<ISeq:block in <compiled>@<compiled>:1 (1,14)-(9,5)>========
== catch table
| catch type: break st: 0007 ed: 0013 sp: 0000 cont: 0013
== disasm: #<ISeq:block (2 levels) in <compiled>@<compiled>:4 (4,16)-(8,7)>
== catch table
| catch type: redo st: 0001 ed: 0019 sp: 0000 cont: 0001
| catch type: next st: 0001 ed: 0019 sp: 0000 cont: 0019
|------------------------------------------------------------------------
local table (size: 1, argc: 0 [opts: 0, rest: -1, post: 0, block: -1, kw: -1@-1, kwrest: -1])
[ 1] c
0000 nop ( 4)[Bc]
0001 getlocal_OP__WC__1 a ( 5)[Li]
0003 getlocal_OP__WC__1 b
0005 opt_plus <callinfo!mid:+, argc:1, ARGS_SIMPLE>, <callcache>
0008 setlocal_OP__WC__0 c
0010 getlocal_OP__WC__1 b ( 6)[Li]
0012 setlocal_OP__WC__1 a
0014 getlocal_OP__WC__0 c ( 7)[Li]
0016 dup
0017 setlocal_OP__WC__1 b
0019 leave ( 8)[Br]
| catch type: redo st: 0001 ed: 0013 sp: 0000 cont: 0001
| catch type: next st: 0001 ed: 0013 sp: 0000 cont: 0013
|------------------------------------------------------------------------
local table (size: 2, argc: 0 [opts: 0, rest: -1, post: 0, block: -1, kw: -1@-1, kwrest: -1])
[ 2] a [ 1] b
0000 nop ( 1)[Bc]
0001 putobject_OP_INT2FIX_O_0_C_ ( 2)[Li]
0002 setlocal_OP__WC__0 a
0004 putobject_OP_INT2FIX_O_1_C_ ( 3)[Li]
0005 setlocal_OP__WC__0 b
0007 putobject 100 ( 4)[Li]
0009 send <callinfo!mid:times, argc:0>, <callcache>, block (2 levels) in <compiled>
0013 leave ( 9)[Br]
|------------------------------------------------------------------------
0000 putobject 1000000 ( 1)[Li]
0002 send <callinfo!mid:times, argc:0>, <callcache>, block in <compiled>
0006 leave
これによってほぼ任意のRubyのコードが数%速くなったのだと思います。すごい。
注意
記事にあるように, Ruby2.5以前でこの最適化を施したければ,
RubyVM::InstructionSequence.compile_option = {trace_instruction: false}
を使うべきです。
Cookpadインターン参加記 または 東京観光
過去のblogから移動しました 元公開日時 2017-09-01 15:30:00
Cookpadインターン2017に参加していました。
その時の行動ログを写真とともに残しておきます。
Cookpadには社食というものはなく, 代わりにキッチンがあります。インターン前半の講義フェイズでは, お昼ごはんは人事さんが作ってくださいました。どれも美味しかったです。
特にこのキーマカレーはとても美味しかったです。残ったカレーを講義終わってから温め直して食べました。講義中はこの事以外考えてなかった気がします。
インターンの初週が終わると, はじめてのコミケがありました。初日だけ参加しました。KMCのブースと辺りの技術系ブースを眺め, ボカロCDを何枚か買いあさりました。
とあるボドゲ会にお邪魔することができました。東京に来てしばらくボドゲができていませんでした。そのため, 11時間連続でボドゲしたこの日はとても満足しました。
翌日, KMCの仲間とともに謎の大会に参加しました。ボドゲの筆記テストあり, キャプテンリノを高く積み上げ, よくあるジレンマ問題をやり, 交渉のゲームでは無になりました。こういう気楽な遊びは神経を使わなくて本当に楽しいです。
スカイツリーを下から眺めました。京都タワーとそれほど変わらない気もしました。しかし, 京都駅に帰ったところ京都タワーはめちゃくちゃ低いことに気づきました。
一番恋しかったのはハイライトのチキンカツですね。代わりになるものを探して一番近かったのは浜勝のチキンカツでした。
Cookpadのキッチンで唐揚げを作りました。唐揚げはKMCでも作ったことがあるので余裕ですね。オフィスの冷蔵庫にはお世話になりました。
最終週の休みに上野のクレーンゲームでラッキービーストを手に入れました。その流れでけものフレンズ展にも足を運びました。かばんにボスを入れているとかばんちゃんの気持ちになれます。このボスは実物大でめちゃくちゃでかいので, 僕のかばんのメインスペースを専有しました。最終的にその状態で京都に帰ることになりました。
恵比寿のビルの最上階から見える恵比寿駅です。複々線を眺めるのは楽しいです。後半のお仕事フェイズでは, 外の風景に癒やされていました。
インターン最終日の肉です。おいしい。
インターンの内容を何も書いてない気がしてきました。
やりたいことを見つけられたらいいなと言う気持ちでインターンに参加していました。インターンでやった事自体は自分にとってそれほど大きな価値はなかった気がします。結局やりたいことを見つけられれば, すぐに手に入るものばかりだった気がします。
やりたいことって見つかるものなんですかね…。
とりあえずもっと手を動かさないと何も始まらないと思うので, 夏休みの後半はどうにかします。どうにかしたい。
2年ぶりにエンジニアのコミュニティーに属せて, やる気がでてきたつもりになったので頑張ります。
バイトをやめた
過去のblogから移動しました 元公開日時 2017-08-06 12:37:34
いわゆる退職エントリです。
大学でRとbashで遺伝子データの解析を1年超やってました。
辞めた理由は1ヶ月のインターンに行くためです。
インターンの後も学部3,4回生はそれなりに忙しいのもあります。
学部生は大学で働いても専門性が加味されず,
あんまりお金にならない。
遺伝子学の分野は実験(WET)と解析(DRY)の混合になります。WETとDRY両方に精通している人間は多くないようです。僕はもちろんDRY。実験室は一度見たきり。
マウスやヒトのリファレンスゲノムってかんたんにダウンロードできるんです。ヒトの実際のAやらGやらCやらTやらを眺めるのは面白かったです。自分もこれとほとんど同じなの不思議に感じます。あと, 誰の遺伝子なんだろう。リファレンスゲノムは時々アップデートされるので, 誰か1人のというわけではなさそう。
辛かったのはR言語。Rを使う必要が何故あるのかというと, 生物系のRのライブラリリポジトリがあり, そこのライブラリにはたいてい論文がついています。代わりが効きにくいのです。
Rに触れた最初はかなり苦痛でした。言語仕様と標準ライブラリはもれなくクソです。tidyverseライブラリ群にはかなり救われました。tidyverseとforeach使ってればRはマスターしたと言っていいと思います。(あといくつかの統計的モデルのライブラリが必要)
tidyverseを使う中でRはメタプログラミング言語という事に気づきました。Rの文法は流行らなかったと言われるLispのM式なのです。なので, ifも関数です。ということはRは数少ない遅延評価言語なのです。
実際に一番苦労させられたのはコマンドラインで走る雑多なDRYツール群です。Bashで長大な実験パイプラインを作るのに苦労しました。前任者の悲惨なコードを目の当たりにしていたので, かなり気を使いました。DRYの実験でgitで管理してる人間は存在するのだろうかみたいな世界観です。大変気を張ります。
雑多なツール群でめんどくさいのは, コマンドラインの引数のパーサが色とりどりすぎる点です。ハイフンが1個だったり2個だったり。引数の数が5を超えると覚えてられずにすぐに忘れます。必須なオプションって矛盾してると思うんですがどうなんでしょう。コマンドラインオプションを間違えると1,2日走らせていた実験が失敗するのも悲しいですね。シェルスクリプトの強いLinterがほしい。
色々愚痴りましたが, 別の世界観を垣間見れたのは悪いことでなかったと思います。明日から普通の情報系のコミュニティーに戻ります。インターン頑張ります。
欲しいものリストをおいておきます
http://amzn.asia/8P20UKl
ICPC国内予選2017参加記
過去のblogから移動しました 元公開日時 2017-07-19 17:07:17
こんにちは。3回生のwassです。
ICPCに参加したのでそのログを残しておきます。
僕は競プロから1年以上退いて,
活動としては部内のプロコンに月に1回程度参加するぐらいでした。
そのため実装はチームメイトに任せることにしました。
A: やってもらった。
B: やってもらった。焦って誤読しあってしまったのは良くなかった。みんなで同じ問題読む大事さを忘れていた。
C: やるだけ。やってもらった。
D: 困った。全探索解法部分はわかるが, bitDP部分でつまずく。半嘘解法を思いつき実装しているチームメイトを眺めた。オーダーがnだけ余計にかかる解法のため実行に時間がかかっていたらしい。
E: Dを実行しながらEを僕が実装することになった。構文木の全列挙で間に合うことがわかる。構文木のデータ構造を作らずに探索する方法は気づかなかった。構文木を素直に全列挙し, 恒等式判定をする実装をした。実行がコンテスト終了に間に合わなかった。あとで確認すると実装は合ってたっぽい。Dではついてた-O3
を忘れていたのは事故。
G: 右手法で探索をすれば行けるやろという気分ではいた。だけ。フローは賢いなあ。。
Dは奇跡的に間に合ったので結果は4完。4完内ではビリ近くの55位。くやしい。
競プロ楽しいですね。活動を再燃させる。
悪いものを食べて判断力が鈍っているときに,
楽しそうな提案をすると乗ってくれることがわかるブログです→
http://kyp.hatenadiary.com/entry/2017/07/19/024104
部室に温度センサーとかつけて監視する
(過去のblogから移動しました 元公開日時 2016-12-22 05:45:44)
こんにちは, KMC2回生のwass80です。
この記事はKMC Advent Calendar 2016 21日目の記事です.
昨日の記事はtronくんの「Neutron 買ってみたのは いいけれど……」でした。記事タイトルが575ですね。
明日の記事はbase64くんの「いい感じのメドレーを自動生成したい」です。自分がもやりたかったことやられたので, 後でいい感じコミットぜったいしたる。
今回はRaspberryPi3 ModelBを買ったので, 使って部室の監視をしたいと思います。
概略図
Raspberryにつながった温度センサーの値をfluentdでinfluxDBに送りつける。
grafanaでグラフを表示。
用意するもの
- Amazon
- 秋月
- 部室に落ちていたもの
- ブレッドボード
- オス-オスジャンプワイヤー
- microUSBケーブル
- 買い忘れたもの
- オス-メスのジャンプワイヤー
RasberryPi3はArduinoと違って, オス-メスのジャンプワイヤーが必要になるので注意しましょう。買い忘れました。
RasberryPi3
センサーをつなげて値を読み取りましょう。
セットアップ
Raspberry Pi 3を買ってMacを使ってWiFi接続とSSHの接続するまで
SDカードにRaspbianを焼いてRasberryPi3に差し込みます。
USBで電源を供給すれば起動します。HDMIで画面を見ます。
初期パスワードはuser:pi/pass:raspberryです。速やかに変更しましょう。
sshがデフォルトで無効になっているので有効化する必要があります。
Wifiでつながると便利なのでその設定もします。
温度センサー
第39回「ラズベリーパイで温度・湿度・気圧をまとめて取得!AE-BME280でIC2通信」
このセンサーにははんだ付けが必要です。
I²C方式シリアル通信をします。
上の記事通りに接続したら, I²Cを有効化します。
Github: SWITCHSCIENCE/BME280のコードを借りて(少し改変して)データを表示してみます。
t, p, h = readData()
print("気温:%f\t大気圧:%f\t湿度:%f" % (t, p, h))
pi@raspberrypi:~ $ python bme280/bme280.py
気温:19.729584 大気圧:1005.779496 湿度:56.260745
動いてそうです。
このデータを10秒おきに次のfluentdに送りつけましょう。
from fluent import sender
import time
logger = sender.FluentSender('raspi', host='sharp')
if __name__ == '__main__':
while True:
t, p, h = readData()
print("気温:%f\t大気圧:%f\t湿度:%f" % (t, p, h))
logger.emit('climate', {'temperature': t, 'pressure': p, 'humidity': h})
time.sleep(10)
systemd用のunitファイルを書きましょう。
#/etc/systemd/system/bme280.service
[Unit]
Description = bme280 climate sensor
[Service]
ExecStart = /home/pi/bme280/bme280.py
Restart = always
Type = simple
[Install]
WantedBy = multi-user.targe
$ sudo systemctl enable bme280
$ sudo systemctl start bme280
fluentd
ログの受け渡しをするサービス。
fluentdは Input → Filter → Output の経路でJSONのログ(event)を流します。
例えば, 以下のことができます。
- あるログファイルの書き込みを感知して(Input)
- それがErrorのログならば(Filter)
- Slackへ通知する(Output)
今回は以下の構成になります。
- TCPでログを受け取る(Input)
- そのすべてを(Filterなし)
- influxDBに送りつける(Output)
InputとFilterとOutputを結びつけるのは, ログに紐づくタグです。
Inputでログにタグを付け, 対応するFilter, Outputが動きます。
fluentdはすでに部室で動いていたので間借りします。
fluentdはデフォルトでTCPで受け取る以下のForward Inputが動いています。
#不要なコード
<source>
type forward
port 24224
bind 0.0.0.0
</source>
RaspberryPIからraspi.climate
タグをつけてfluentdに送っています。
#前述抜粋
logger = sender.FluentSender('raspi', host='sharp') #sharpはfluentdのあるサーバ名
logger.emit('climate', {'temperature': t, 'pressure': p, 'humidity': h})
なので以下の設定を追加します。
<match raspi.climate> #このタグであれば
@type copy #次のOutputそれぞれに受け渡す
<store> #ファイルに保存
@type file
path /var/log/td-agent/raspi/climate.log
</store>
<store> #influxdbに送りつける
@type influxdb
host 192.168.220.31
port 8086
dbname climate
user root
password root
use_ssl false
time_precision s
</store>
</match>
# matchは上からマッチし, マッチしたものがあればそれ以上マッチしない。
<match raspi.**> #上にマッチしなければ, 別のファイルに保存。
@type file
path /var/log/td-agent/raspi/raspi.log
</match>
今回はinfluxDBに送るついでにファイルにも保存していますが, DBを真面目に運用するなら必要ないでしょう。
influxDB
field/tagキーに値を時系列で突っ込んで行くデータベース。
「性別(∋男,女)」のように値の種類(=カーディナリティ)が少ないものはtagキー。
「気温=実数」のようにカーディナリティが高いものはfieldキーに指定します。
influxDBの準備にはdocker-composeを用いました。
参考: nicolargo/docker-influxdb-grafana
# docker-compose.yml
version: '2'
services:
influxdb:
image: influxdb:latest
ports:
- "8083:8083"
- "8086:8086"
env_file:
- 'env.influxdb'
volumes:
- influxdb-storage:/var/lib/influxdb
grafana:
image: grafana/grafana:latest
ports:
- "13000:3000"
links:
- influxdb
volumes:
- grafana-storage:/var/lib/grafana
environment:
- GF_SERVER_ROOT_URL=%(protocol)s://example.jp/~wass80/app/grafana
- GF_AUTH_ANONYMOUS_ENABLED=true
- GF_AUTH_ANONYMOUS_ORG_ROLE=Admin
volumes:
influxdb-storage:
driver: local
grafana-storage:
driver: local
起動する。
$ docker-compose up -d
InfluxDB と fluentd を組み合わせを試してみた
データベースを作ればデータを受け取る準備が完了します。
influxDBのWebインターフェースはdeprecatedのようなので, 今回はCLIを用いました。
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
791734f2cf3a grafana/grafana:latest "/run.sh" 8 hours ago Up 8 hours 0.0.0.0:13000->3000/tcp dockerinfluxdbgrafana_grafana_1
d39bac4136e8 influxdb:latest "/entrypoint.sh influ" 8 hours ago Up 8 hours 0.0.0.0:8083->8083/tcp, 0.0.0.0:8086->8086/tcp dockerinfluxdbgrafana_influxdb_1
$ docker exec -it d39 influx
Visit https://enterprise.influxdata.com to register for updates, InfluxDB server management, and monitoring.
Connected to http://localhost:8086 version 1.1.1
InfluxDB shell version: 1.1.1
> CREATE DATABASE climate
> SHOW databases
name: databases
name
----
_internal
climate
#fluentdの設定 前述抜粋
<store> #influxdbに送りつける
@type influxdb
host 192.168.220.31 # influxDBの動くサーバ
port 8086
dbname climate #データベース名
user root
password root
use_ssl false
time_precision s
</store>
これで{'temperature': t, 'pressure': p, 'humidity': h}
というfleid:値がinfluxdbに流れます。
Grafana
influxDBの内容をめっちゃかっこよく表示してくれるいい子。
先程のdocker-composeで一緒に起動していました。
今回はBasic認証がすでにかかっているところで動かすため, Grafanaの認証を無効化しています。
リバースプロキシ用の設定を環境変数に追加しています。
# docker-compose.yml (前述抜粋)
grafana:
image: grafana/grafana:latest
ports:
- "13000:3000"
links:
- influxdb
volumes:
- grafana-storage:/var/lib/grafana
environment:
- GF_SERVER_ROOT_URL=%(protocol)s://example.jp/~wass80/app/grafana
- GF_AUTH_ANONYMOUS_ENABLED=true
- GF_AUTH_ANONYMOUS_ORG_ROLE=Admin
influxDBを登録しましょう。
GUIで設定できます。
あとはめっちゃいい感じGUIでグラフの設定をします。
いいですね。
できました。
凡例の色付き横線を押すと色の変更と軸の左右の変更ができます。
他にも色々センサーを買いましたが, RaspberryPIがアナログ入出力が出来ないことを知りませんでした。A-D変換を買ってきます。
明日の記事をお楽しみに。
ISUCON6本戦を復習して勉強する
(過去のblogから移動しました 元公開日時 2016-10-24 13:08:12)
ISUCON6お疲れ様でした。とても楽しかったです。
:innocent:チームは順位表で😇と表示されていました。 これは運営の方がわざわざ実装をしてくださったらしいです。 絵文字のチームが増えると 🍣と🍺問題 http://blog.kamipo.net/entry/2015/03/23/093052 が起こりうるのでやめましょう。 競技中のポータルサイトの右上に現れる"Hello, 😇"は面白かったです。 ぜひこの絵文字を結果発表で前に大きく出したかった。
:innocent:チームは与えられた実装よりスコアを下げてしまいました。 全くもって付け焼き刃が通らないという様子で作問者の思惑通りに手のひらの上で転がされた感じになりました。チームの3人の知識を合わせて0.01人の量に満たないことがわかったので, これから勉強していきたいと思います。
docker上で実行されているrackアプリにrack-lineprofileを仕込むという戦略を最初に予定していたのですが, 実行したところ一切のログが残らず混乱をしてしまいました。プロファイルを取る方法を失い, nodeでのボトルネック具合もよくわからないので, 問題点を追求できなかったです。 その場合でもCPU時間を参考にすればよかったです。
今回はチーム内での分担も行うことが出来ず, 問題に取り組む効率が最悪だったと思います。 全体の構成図を最初に書いておけば方針の決定に役立ったと思いました。 本番中はreactやらSSEやらSSLやらでかなり打ちのめされていました‥。
やることがたくさんあるとてもいい問題だったので, KMC内で本戦に出ていないチームともう一度解き直す会を行いたいです。
チームメイトutgwの様子 http://utgwkk.hateblo.jp/entry/2016/10/23/233114