Norikraでそこそこ手軽にNetFlow解析
去年のJANOGで別の方が発表された内容とダダ被りではあるものの,折角なのでメモ程度に書いておく.
概要
- データセンタネットワークやバックボーンネットワークの運用をやっていると,インターネットに出入りするトラフィックの内訳 (どのISP向けのトラフィックが多いのか,どの回線にトラフィックが乗っているか,等) を見たいことがよくある
- NetFlowをNorikraで解析し,その結果をGrowthForecastに流し込むと,トラフィックの内訳をそこそこ手軽に見ることができる
- 定常的なモニタリング用途以外に,突発的なトラブルシューティングにも使えていろいろ便利
背景
自前でAS (Autonomous System) を運用している事業者では,トラフィックのコントロールの観点から,「どのAS向けのトラフィックがどのくらいあるのか」「このASとはどの回線を使って通信しているか」といった情報を知りたいケースがよくある (と思う). このような場面では,NetFlowに代表されるトラフィック統計情報を収集する機能が用いられる.NetFlowを使うと,ある機器を通過した通信フローに関する情報 (src/dst IP, src/dst ASなど) が取得できるので,これらの情報を解析すればトラフィックの内訳を知ることができる.
NetFlow解析を行う場合,一般的には次のような選択肢がある.
回線ごとのトラフィック集計を行いたいケースや複数ASを運用しているようなケースでは,柔軟性の観点から自前での構築を選びたくなる.が,一から全てやるのは結構大変なので,解析はNorikraに,結果のグラフ化はGlowthForecastにやってもらうことにする.
実現方法
構成はNorikra+Fluentd+GrowthForecast.NetFlowコレクタはfluent-plugin-netflowを使用する.
Fluentdの設定はこんな感じ.fluent-plugin-forest使ってるので、AS数や回線数によってはメモリの消費に注意.
## <- NetFlow <source> type netflow tag netflow.flow bind 0.0.0.0 port 2055 </source> ## -> Norikra <match netflow.*> type norikra norikra 127.0.0.1:26571 remove_tag_prefix netflow target_map_tag true </match> ## <- Norikra <source> type norikra norikra 127.0.0.1:26571 <fetch> method sweep tag_prefix norikra.query tag field _gf_key interval 1m </fetch> </source> ## -> GrowthForecast <match norikra.query.**> type forest subtype growthforecast remove_prefix norikra.query <template> gfapi_url http://127.0.0.1:5125/api/ graph_path netflow/as${tag_parts[0]}/${tag_parts[1]}_bps_${tag_parts[2]} name_keys traffic_bps </template> </match>
この構成でNorikraに下のようなクエリを登録した後NetFlowを流し込めば,ひとまずAS毎の集計結果がNorikraで出力されるはず (ただしこの時点では全ての回線の合計値が出力される).
select src_as, dst_as, (SUM(in_bytes * sampling_interval) * 8) / 60 as traffic_bps, from flow.win:time_batch(60 sec, 0L) group by src_as, dst_as
次は回線毎の集計.SNMP ifIndexと回線の対応関係やフローの向きのチェックを全てEPLで書くのは辛いので,簡単なUDFを作った.
norikra-udf-netflowでは,NetFlowのデータを扱い易い形式に変換するためのいくつかの関数を定義している.内容は下の表のような感じ.変換に必要な情報はインストール前にあらかじめdefinition.yamlに書いておく必要がある.
Function | Description |
---|---|
NFDirection(src_as, dst_as) | フローの向き ("in" or "out") |
NFOppositeASN(src_as, dst_as, ipv4_src_addr, ipv4_dst_addr) | 対向のAS番号 |
NFRouter(host_ipaddr) | NetFlowの生成元のルータの名称 |
NFCareer(host_ipaddr, ifindex_in, ifindex_out, flow_direction) | フローが通過した回線の名称 |
これらの関数を使って回線毎の集計をやる場合,こんな感じのクエリになる.
Query name: flow_aggregator, Group: LOOPBACK(aggregated_flow)
select NFOppositeASN(src_as, dst_as, ipv4_src_addr, ipv4_dst_addr) as opposite_as, NFCareer(host, input_snmp, output_snmp, NFDirection(src_as, dst_as)) as career, (SUM(in_bytes * sampling_interval) * 8) / 60 as _traffic_bps, NFDirection(src_as, dst_as) as flow_direction from flow.win:time_batch(60 sec, 0L) group by OppositeASN(src_as, dst_as, ipv4_src_addr, ipv4_dst_addr), NWPoPCareer(host,(code) input_snmp, output_snmp, FlowDirection(src_as, dst_as)), FlowDirection(src_as, dst_as)
Query name: traffic_as_per_career
select opposite_as, career, case LAST(_traffic_bps) when null then 0 else LAST(_traffic_bps) end as traffic_bps, (opposite_as || "." || career || "." || flow_direction) as _gf_key from aggregated_flow.win:time_batch(60 sec, 0L) group by opposite_as, career, (opposite_as || "." || career || "." || flow_direction)
一度LOOPBACKで集計済みデータを別target(上の例だとaggregated_flow)に流しているのは,後で突発的に解析用のクエリを投入する時にデータを再利用しやすくするため.NorikraのクエリでFluentdのタグを作ってる点がちょっとアレ. ここまで全て上手く動いていれば,GrowthForecastでグラフが作られているはず.
これまでの運用状況など
Norikra
去年末に投入後,約3ヶ月稼働中.単純な時間平均で 10000 event/sec (=10000 flow/sec) 弱程度のeventを流し込んでいる.JVMが数回突然死したり,CPUコアが多い環境で起動しないトラブルに遭遇した*1以外は概ね安定している.現在heapに30GB弱割り当てていて,GCのタイミングで結構な時間止まっているので何とかしたい.
Flow collector
fluent-plugin-netflowが手元の環境だと1プロセスあたり8000 flow/sec 近辺でsocket bufferが埋まる速度に追い付けなくなった.順当に行けばfluent-plugin-multiprosessでポートを分けて負荷を分散させる場面だと思われる.が,これをやるとルータによってNetFlowの送り先が変わってしまうので後々大変そう,ということになり*2,nfcollectという超簡易的なNetFlow collectorを書いて凌いだ.
nfcollectはフローの到着順を保持しない代わりにそこそこのスループットが出るようになっていて,flow-genで試したところ同じ環境で30000 flow/secぐらいまでは何事も無く捌いてくれた.こちらを使った場合でもある時点でfluent-plugin-netflowと同じ問題が発生することに変わりは無いものの,現状30000 flow/secを越えることをはまず無さそうということで一旦目を瞑っている.
その他諸々
当初は単純な集計用途だけを想定していたが,使い始めてから暫くすると,トラブルシューティング的な用途にも使えそうなことが分かった.例えば本来存在するはずの通信が見えない時や,特定ISPから特定アドレス帯への通信が上手くいかないといった時に,その問題に合わせたクエリをその場で書いてNorikraに投入してしばらく待てば,パケットキャプチャより手軽に調査ができる*3.ちょっとしたクエリのサンプル集のようなものを事前に書いておけば,大抵の人は問題無く扱えると思う.
まとめ
NetFlow解析,割と難しいもの扱いされているという噂を耳にしますが,やってみると色々便利なのでまずは試してみると良いと思います.