2016-2017年のサービス障害を振り返る

最近全然ブログとか書けてないなーと思いつつ 2018 年を迎えてしまいました。本年もよろしくお願いいたします。

以前、DC/クラウド/通信事業者サービスの障害事例よせあつめ という記事を書いたところ意外と反響があったので、続きを書こうかなと年末考えていたのですが、結局 2017 年中は書けませんでしたね。いろいろあったんですよ。個人的な話なんで別にどうでもいいんですけど。そんなわけで年明けに書きます。

この記事は 2016 年アタマの GMO の障害とか github のサービス障害をきっかけに書いたものでした。その後、世の中的にはどんなサービス障害が起きているのかをざっとおさらいしてみたいと思います。いまシステムやサービスを作っていく中で、こういう原因で死ぬのか…というのを見ていくことは、ひいては「そこまで予見できなかった」あるいは「そこからは回復させられなかった」ってことを考えることなんですよね。落ちた = ダメじゃん、という話でおわるのはなくて、ここまでやられて初めて落ちるんか…とか、こういう可能性まで見込んで何か考えないとイカンのか…とか、こういう状況でもうまく逃げ切るための方法って何なのか…とか、発展的な話を考えるための材料だと思っていただければ。

挙げる事例については私がウォッチして見つけているものなので当然偏りがあります。その点はご承知おきください。他にもこういう事例があるよってのがあったら是非教えていただきたく。

参考資料

ニュースソース

ツイッターとかでも拾っていますがこの辺を見ることが多いですね。いろいろ時事ネタや速報だしてくれています。ありがたや。

参考記事

2016年の事例

2017年の事例

おわりに

個人的な所感としてはこんな感じです。

  • 相変わらず DC 設備系のトラブルはおきる : 停電・ケーブル切断などファシリティ・設備レベルの話はやっぱりゼロにはならない。
  • パブリッククラウドクラウド上のサービス(XaaS)ではソフトウェアで自動化されることによって障害が増幅される : 自動化してレバレッジをかける……一度に大量のサーバを操作したり処理を実行できる。ただ、これは誤った手順・オペミスのリスクを拡大する方向にも働く。実行するツールの選択ミス・パラメタ設定ミスなどをどう防ぐか → オペレーションの妥当性・正当性をどう保証するか、というのは課題になるだろう。それと大規模にやらかしたときにどうやって復旧するか、という話。両面での対策検討が必要になると思われる。
    • 複数のサイト(リージョン)やサービスをまたがるような障害にどう対処するか?
  • ネットワークエンジニア的には、この 1-2 年は BGP 操作による大規模障害が目立つのが気になるところ。とはいえこれ、upstream でやられちゃうと、エッジにいる側からはなかなか対処ができないんだよな。せめて問題検知や切り分け・状態の把握を早期にやれるようにするくらいか?

ネットワークの自動化、何つかう? 〜自動化ツール紹介〜 #APC勉強会 #30(2回目) 参加メモ

ネットワークの自動化、何つかう?〜自動化ツール紹介〜 APC勉強会#30(2回目) - connpass に参加してきたのでいつものメモ。1回目のときはぼんやりしていたらあっという間に満席になってしまったので2回目で滑り込みです。

資料は1回目の時に公開されているのでそちらを参照してください。

ネットワークの自動化、何つかう?〜自動化ツール紹介〜

はじめに
  • NW機器もAPIに対応して、自動化フレンドリーなものが増えてきた
  • そういう機械でなくても自動化できるツールやライブラリを紹介
    • netmiko
    • napalm
    • ansible
    • salt
全体像
  • 業務フロー : 作業, 実際に config 流し込むところの自動化
  • ツール依存イメージ
    • 構成管理ツール : ansible, salt
    • python ライブラリ : napalm, netmiko
  • 機能概要
    • netmiko, napalm : ライブラリ。抽象化の仕方が違う。
      • netmiko...直接コマンドを指定, napalm...ひとつのメソッドで複数のベンダのコマンドに相当
    • ansible, salt : ツール。抽象化の仕方が違う。
      • saltはnapalmの中で使っているのでベンダをお意識しなくても使えるようになっている
      • ansibleはモジュールによるけど、コマンドを直接呼ぶタイプのモジュールが多い
netmiko

netmiko

  • シンプルで薄い抽象化ライブラリ。
  • login, モード移行, commit などを共通メソッドとして抽象化。
    • "conf term" とかは抽象化されてる
    • 表示・設定コマンドはコマンドを直接指定する
  • netmiko 対応機種
    • けっこうある

コード例

  • 状態表示
    • enable メソッドで抽象化されてる
    • send_command で直接コマンドを送る
      • コマンド実行結果がそのままとれる (特に parse とかしない)
  • 設定変更
    • 設定コマンドも直接指定
    • send_config_set でコマンド文字列(リスト)を渡して実行

まとめ

  • シンプルで薄い
  • teraterm マクロよりは楽かな
    • waitとかプロンプトとか気にしなくていいので設定に注力
    • 対応機種は限られるので注意
napalm

napalm

  • 多機能で厚い抽象化ライブラリ
    • 一部だけど表示コマンド・設定コマンドまで抽象化
  • 対応機種
    • netmikoよりはすくない
  • 対応メソッド
    • サイトにある…使いたい嬉々とやりたい操作の対応をチェックすべし。

コード例

  • 状態表示
    • get_interfaces メソッド→IOSの場合は"show interface" : 抽象化されてる
    • コマンド実行結果も parse されて構造化されたデータとして取得
    • 違うOSでも共通のデータ構造で取得できる
  • 設定変更
    • load_template メソッド。テンプレートを呼び出して、パラメータを渡して、設定実行。

まとめ

  • 多機能で厚い
    • 一部設定と表示に関しても抽象化…対応していないものについては直接コマンド指定して実行することもできる。
Ansible

ansible

  • シンプルな構成管理ツール
  • 抽象化というアプローチは特にとっていない。
    • ベンダごとにモジュールがあるのでそれを使い分ける
    • netconf 対応などは今後注目
  • 特徴
    • agentless
    • yaml で構成定義 (playbook)...なってほしい状態を定義する
      • プログラムを書くわけではない
  • 対応機種
    • v2.3, napalm よりちょっと多い

playbook例(cisco ios module)

  • 状態表示
    • コマンドを直接指定して実行
    • 特に parse されるわけじゃない
  • 設定変更
    • コマンドを直接指定して実行
    • "changed=1", 既に設定が入っていれば "changed=0"

まとめ

  • シンプル
    • インストールも pip で一発。必要なファイルも最低二つ。
salt

salt

  • 多機能な構成管理ツール
    • 中で napalm を使っている……抽象化するアプローチ
    • ベンダごとのモジュールも出てきているけど主要なのは napalm を使う方法
  • 概要
    • master/agent 型
    • yaml で構成定義
    • 高機能 : イベントドリブン, スケジューラ, WebAPI
    • v2016.11.0 で napalm 統合 (NW機器対応)

Saltの主な用語

  • Master : 指示を出す
  • Minion : いわゆる Agent, master の指示を受ける
    • Master-Minion 間は MQ
    • NW機器対応をどうするか…Proxy Minion
    • Master → Proxy Minion → NW機器 (ssh等)
  • Grains : ホスト名、シリアル番号、バージョン番号などの基本的な情報を保存
  • Pillars : 任意のデータを保存できる

対応機種

  • 基本的には napalm と同じ

設定がちょっとややこしい

  • バイスID → IPや認証情報は別ファイルで管理(proxy minion)

状態表示例

  • Grains から情報を引っ張ってくる
    • 内部で napalm キックして情報をとってくる
    • 構造化された情報がとれる

設定変更例

  • 定義ファイル実行
    • "changed=1"

デモ

  • 定義ファイルが更新されたら自動的に設定投入 : イベントドリブン
    • daemon で動いているのでファイル監視とかができる

まとめ

  • 多機能な構成管理ツール
各ツールの比較
  • ライブラリか、構成管理ツールか
  • 抽象化のアプローチ
  • メリット・デメリット
    • netmiko: 対応機種が多い。その分抽象化レベルは低い。
    • napalm: マルチベンダ環境の情報取得に強い…parseしてくれる。一方、設定系のメソッドがまだ少ない。足りないところは直接コマンド入力
    • ansible: シンプル! アプローチが違うので機種ごとにモジュールを使い分け。情報量が多い。開発が盛ん。
    • Salt: 高機能…イベントドリブンとかWebAPIとか。内部では napalm を使っているので、マルチベンダ情報取得に強いという特徴を。日本語情報は少ない。調べるときは公式ドキュメント頼み。

ツールつかいどころ選択

  • 管理したい危機に対応しているかどうか
  • コードを書くかどうか
    • コードにすると運用城南があるのであれば構成管理ツール系へ
  • シンプル or 高機能
    • 高機能 → 学習コストが高い
  • どの程度抽象化したいか
    • ターゲットが一つ二つであればそんなに抽象化気にしないのでは
  • 管理対象機器の種類・ベンダ数
    • 種類が多いほど、抽象化レベルが低いとベンダごとのコマンド使い分け・パターンが増える。
  • 既存で導入している構成管理ツールがあるならあわせる

まとめ

  • 特徴を把握して適材適所で
これから
  • 自動化を進めるにあたって: ツール・人・仕様
    • 人: 自動化するための設計・実装スキル、文化
    • ツール: 今回の話はここ
    • 仕様: api拡充、標準化
QA
  • dry-run/diff 表示
    • ansible, salt は dry-run できる。netmiko, napalm は自前で dry-run 動作を実装しないといけない。
  • ツールによる設定変更・管理のメリット
    • 設定要件→定義ファイルのexportなど、中間加工のしやすさ。デメリットとしてはyaml知らないといけないというのはある
  • excelからデータとれる?
    • 標準ではなさそう。やろうとおもえばやれる
  • commit の自動化って大丈夫?
    • 変なことすると途中で止まるとかはある。検証・dry-runしてチェックしたうえで実行とか、そのあとのテストなどでリスクヘッジしていく。アプリ開発の自動化とはこういった点で性質が異なる。
  • 表示コマンドの抽象化は必要か?
    • ケースバイケースではあるが、あると便利だと思う。自前で parse するのは大変。
  • 既存の自動化スクリプト+構成管理ツールでサーバとNWの一括管理というのがメリットがあるのでは
    • サーバ側を含めて、というのはメリットがあるだろう
  • 機器が対応していない場合のアプローチ?
    • paramiko (netmiko内部のssh module) ベースで自作, ansible module 自作、あたりか。
  • Ansible導入どうやってる?
    • 最初のハードル。インベントリファイルどう作るかとか。別なスクリプトかませないといけないかもしれない。最初の対応はちょっと泥臭い対応が必要になりそう。
  • 失敗時ロールバック?
    • 実装すれば全部可能。モジュールについては試していないが、junosのケースでは失敗時commitしないようになっているのでは?

所感

懇親会でも他の方と話をしたんですが、この辺のツールで気になるところはある程度共通だなあと。

  • エラー処理・例外処理
  • dry-run など実行前のチェックの可否

何かしらのカタチでコマンドを投げる、というところだけだとやっぱり実際動かしていシステムで使うのはちょっとねー、という話になる。あと、エラー処理とか例外処理とか、運用している側からすると、やりたいことそのものではないというのもあるかな。エラー処理とか対応手順とかはあるんだけど、CLIベースの機材に対してそれを自動化するための仕掛けそのものを作るのってハードル(手間的な)が高いんだよね…。ツールにあるエラーハンドリングの仕掛けの上でやりたいこと(やりたいエラー処理)に集中できるようにならないかな、と言う話とかね。

D3.js v4 の Hierarchical Edge Bundling を理解する(3)

Sample Code

サンプルコードはこれ

こういう図ができる。


データの準備

leaf 間のリンクデータを追加します。

    var link_data = [
        {"source" : "Azura", "target" : "Enoch"},
        {"source" : "Enoch", "target" : "Abel"},
        {"source" : "Enoch", "target" : "Noam"},
        {"source" : "Azura", "target" : "Noam"},
        {"source" : "Abel", "target" : "Enos"},
        {"source" : "Abel", "target" : "Noam"},
        {"source" : "Noam", "target" : "Enos"},
        {"source" : "Enos", "target" : "Cain"}
    ];

変わらないところ

cluster layout を円周上に描画するところは 前回 と同じです。leaf 間のリンクだけ上書きしてます。path の書き分けのために class 指定して CSS で描き分けてるところくらいかな。

変わるところ

まず、leaf 間リンク情報を Node オブジェクトに変換します。d3.map() については d3/d3-collection: Handy data structures for elements keyed by string. を参照。leaf 一覧 (nodes.leaves()) を name attribute で引っ張れるようにしています。

    var nodes_name_map = d3.map(nodes.leaves(), function(d) { return d.data.name; });

leaf 間リンクのデータは name だけ持っているので、それをキーに Node オブジェクトを取ってきます。

    var interleaf_links = link_data.map(function(d) {
        return {
            "source" : nodes_name_map.get(d.source),
            "target" : nodes_name_map.get(d.target)
        };
    });
    console.log("interleaf_links");
    console.log(interleaf_links);


leaf 間 path の描画

d3.radialLine() はそのまま使います。ここで重要なのは node.path(target) です。

# node.path(target) <>

Returns the shortest path through the hierarchy from this node to the specified target node. The path starts at this node, ascends to the least common ancestor of this node and the target node, and then descends to the target node. This is particularly useful for hierarchical edge bundling.

GitHub - d3/d3-hierarchy: 2D layout algorithms for visualizing hierarchical data.

path は node と target の間に共通の parent がある場合に、そこを経由した曲線を作成してくれます。……というのもあって上の図はあえて cluster layout tree の上に上書きしてみました。この機能、d3.js v3 では d3.layout.bundle() が提供していたようです。

    // path
    svg.selectAll("path.interleaf")
        .data(interleaf_links)
        .enter()
        .append("path")
        .attr("class", "interleaf")
        .attr("d", function(d) {
            return line(d.source.path(d.target));
        });

Hierarchical Edge Bundling

leaf のみにして parent node を描画しないようにすればできあがりです。

コードはこれ。

--- d3-hierarchical-edge-bundling.js    2017-06-03 23:56:00.309974700 +0900
+++ d3-hierarchical-edge-bundling2.js   2017-06-04 00:26:54.340704000 +0900
@@ -51,9 +51,6 @@
     var node_size = 20;
     var cluster = d3.cluster().size([360, radius]);
     var nodes = cluster(root_node);
-    var parent2child_links = nodes.links();
-    console.log("parent2child_links");
-    console.log(parent2child_links);

     var nodes_name_map = d3.map(nodes.leaves(), function(d) { return d.data.name; });
     var interleaf_links = link_data.map(function(d) {
@@ -73,19 +70,6 @@
         .curve(d3.curveBundle.beta(0.85))
         .radius(function(d) { return d.y; })
         .angle(function(d) { return path_angle(d.x); });
-    svg.selectAll("path.parent2child")
-        .data(parent2child_links)
-        .enter()
-        .append("path")
-        .attr("class", "parent2child")
-        .attr("d", function(d) {
-                return line([
-                    d.source,
-                    { "x" : d.source.x, "y" : (d.source.y + d.target.y)/2 },
-                    { "x" : d.target.x, "y" : (d.source.y + d.target.y)/2 },
-                    d.target
-                ]);
-            });

     // path
     svg.selectAll("path.interleaf")
@@ -99,7 +83,7 @@

     // circle (overwrite path)
     svg.selectAll("circle")
-        .data(nodes.descendants())
+        .data(nodes.leaves())
         .enter()
         .append("circle")
         .attrs({
@@ -112,7 +96,7 @@

     // text
     svg.selectAll("text")
-        .data(nodes.descendants())
+        .data(nodes.leaves())
         .enter()
         .append("text")
         .attrs({

おわりに

3回に分けて、順を追いつつ Hierarchical Edge Bundling の話を見てきました。D3.js Gallery にあるのは凄くきれいで洗練されてるんだけど、何をやっているのか理解したいという目的で見るとちょっと難しいね。まああれは、D3.js でどんなことができるのか、"上" のイメージを見せるものだよね。本当はこの上で、CSSを組み合わせて動的にハイライトさせるとかそういう処理があったりするんですが、そのへんは発展課題で。最小限でやるとこんな感じじゃないかなあと思っていますが、それほど javascript とかやってるわけじゃないので、もうちょっといい方法もあるかもしれません。