サーバ「管理」ツールとしてのMackerelの起源

この記事は、SaaSのサーバ監視サービスMackerelを起源を遡り、そこから現在の姿に至った経緯をはてな社内のエンジニアに共有するためのものです。 なお、ここに書かれていることは、Mackerel開発チームの公式見解ではありません。

概要

Mackerelは、もともとは2007年ごろに開発されたはてなの社内のサーバ管理ツールであり、動的なインフラストラクチャに対応するために、現在でいうところのInfrastructure As Codeを目指したものです。 そこから2013年にSaaSのサービスとして開発され、コードベースとアーキテクチャは全く新しくなり、監視機能を備え、サーバ「監視」サービスと呼ばれるようになりました。 しかし、はてな社内では、プログラマブルなAPIを備えたサーバ「管理」サービスとして、Mackerelを中心にしたインフラストラクチャを構築しています。 Mackerelの起源は、サーバ「監視」というよりはむしろサーバ「管理」にあったということをここに書き残します。

社内Mackerelの誕生

社内Mackerelは、はてな前CTOのstanakaさんを中心に2007年ごろに開発が始まりました。 社内Mackerelのコードベースは、mackerel.ioのそれとは全く別のものであり、社内Mackerelにしかない機能もあれば、Mackerelにしかない機能もあります。 しかし、共通する思想はあり、その思想は現代のインフラストラクチャ管理にも通ずるものであると考えています。

はてなでは、2007年前後にXen Hypervisorによるサーバ仮想化技術が導入[1]され、物体としてのサーバに加えて、データとしてのサーバを管理し始め、人手による管理コストが増大しました。 具体的には、サーバの増減に合わせて、人がIPアドレス管理表を更新したり、ホスト名やIPアドレスが記載された各種設定ファイルを更新して回るとといった手間が増えたことを指します。

これらについて、全体のサーバ数が少ないかつ、個数の増減頻度が小さければ、人手による管理にもコストはかかりません。 一方で、クラウド環境のように、データとしてサーバを扱うのであれば、プログラマブルに管理するためのデータベースが必要です。 そこで、社内Mackerelが誕生しました。

このように、社内Mackerelはサーバ監視というより、プログラマブルなインフラストラクチャ管理を目指したツールでした。 実際、社内Mackerelのことをサーバ「監視」ツールではなく、サーバ「管理」ツールと呼んでいました。

社内Mackerelの特徴

構成レジストリ

社内Mackerelの主な管理単位は、「ホスト」であり、ホスト名やIPアドレスはもちろんOSの種別やCPU数、メモリ量などのソフトウェア、ハードウェア情報も含みます。 加えて、ホストは以下の属性情報を持ちます。

  • 「サービス」「ロール」
  • ホストステータス ('working', 'standby', 'maintenance', 'poweroff', 'destroyed')
  • 拠点、ラック、電源、ネットワークなど

これらはビューとして人が参照するだけでなく、REST APIにより各種ツールと連携し、インフラストラクチャ要素の情報を一元化しています。 具体的には、以下のように各種ツールのパラメータを、MackerelのAPI経由で動的取得し、ホスト名やIPアドレスの多重管理を防いでいます。

  • 1: 死活監視ツールの設定ファイルの自動生成[2]
  • 2: 内部DNSのゾーンファイルの自動生成
  • 3: デプロイツールからのデプロイ対象ホストの動的取得
  • 4: 構成管理ツール(Chef)の適用cookbookを対象ホスト名から動的解決

1について、サーバ監視のうち、死活監視についてはNagiosを利用します。同一ロールであれば、同じ監視設定を流用できることと、ホストステータスがworking以外に変更すれば監視を外すといった動的なプラットフォームに適した運用が可能になります。1 2について、ホスト単位のレコード以外に、ロール名ベースのDNSラウンドロビン用FQDNとVIP用FQDNがあり、サービスディスカバリに利用します。 3について、Capistranoでホスト名を静的に設定したところをAPIによりロール名だけ設定しておけば、対象にデプロイできます。ホストステータスをmaintenanceにしておけば、デプロイ対象から外れます。 4について、ホスト名を与えれば、ホストに紐付いたロールから適用するcookbookを自動解決できるようになります。

このようなツールは、CMDB[3]に似ていますが、資産管理機能は含みません。 どちらかといえば、書籍「Infrastructure As Code」[4] 3.4節 構成レジストリに近いものです。 構成レジストリは、インフラストラクチャ要素についての情報集積庫であり、書籍では、構成レジストリと例として、Zookeeper/Consul/etcdや、Chef Server/PuppetDB/Ansible Towerなどが挙げられています。

メトリックの時系列グラフ

社内Mackerelには、前述の構成レジストリ機能に加えて、メトリックのクローリングと、メトリックを時系列グラフ表示する機能があります。 メトリッククローリングはPrometheusなどと同様にPull型のアーキテクチャであり、クローラーがOSの基本メトリックはSNMP、MySQLなどのミドルウェアについてはミドルウェアのプロトコルでメトリックを取得し、RRDtoolに保存します。

社内Mackerelの時系列グラフ機能の実装については、過去の発表資料[5]で詳しく説明しています。

今から振り返ると、メトリックの収集、保存、可視化については、Repiarableにするために、専用のツールに任せ、ビューだけ統合したほうが良かったと考えています。 社内Mackerelの開発開始が2007年より、もう少し後であれば、Collectd[6]で収集し、Graphite[7]に保存するといった選択肢もありました。

メトリックに限らず、当時Nagiosには使いやすいAPIがなく強引な手段で統合している実装をみると、Infrastructure As Codeを志向しようには世の中が追いついていなかった様が伺えます。

SaaSとしてのMackerelへ

2013年にMackerelの開発が始まり、2014年に正式リリースされました。 SaaSとして提供するにあたって、グラフツールではないため、メトリックに着目するより、「ホスト」に着目するといった主要な思想は、社内Mackerelから引き継がれました。他にも以下の要素が引き継がれました。

  • サービス・ロールの概念
  • ホストステータスと監視のon/offとの連動
  • 統合されたホスト管理とメトリックグラフビュー

特にサービス・ロールはMackerelの中心概念であり、社内Mackerelとほとんど同じものです。 私見ですが、サービス・ロールは、人間が決定しなければいけないラベル付けだと考えています。 インフラストラクチャに紐づくラベルは多種多様ですが、大きく分類すると、自動で付与できるものと、それ以外の人が判断して付与するものがあります。 自動で付与できるものは、OS、ハードウェア、ネットワーク、インストールされたミドルウェア、クラスタ内の役割などの情報です。 一方で、どのサービスのホストなのか、どのロールなのかといったことは、人間が最初に決めて付与しなければなりません。自動で決定できるとしても、人間が与えたルールにしたがい決定することが多いと思います。2 このラベルを用いて、リポジトリのディレクトリ構成を管理していることもあります。[8]

以上のように引き継がれた機能がある一方で、ラックや仮想ホストの管理など、クラウド時代にそぐわない機能は削ぎ落とされました。 逆に、死活監視やメトリック監視、外形監視機能は統合されました。

メトリックの収集と時系列グラフについては、SaaSとして提供するために、NAT超えを意識し、Pull型ではなく、Push型のアーキテクチャになっています。 ホストにインストールされたmackerel-agentのリクエストを[9][10]に書いた時系列データベースに格納します。

このように、Mackerelは監視機能をひと通り備えているため、サーバ「監視」サービスと銘打っていますが、その起源は、サーバ「管理」サービスです。 実際、サーバ「管理」ツールとしてのMackerelをうまく活用していただいている例[11]があります。 このブログでも、AnsibleのDynamic Inventoryとの連携[12]やServerspecとの連携[13]など、サーバ「管理」ツールとしてのMackerelをいくつか紹介しています。

その他のサーバ「管理」ツール

社内Mackerelと同じサーバ管理ツールは、他にもあり、ここでは、Collins、Yabitzなどを紹介します。

Collins

Collins[14]はTumblrで開発されているインフラストラクチャ管理ツールです。

Collinsの特徴は、Assetsベースのデータモデルです。Assetsはなんでもよく、事前設定されているものはServer Node、Rack、Switch、Router、Data Centerなどです。 さらに、このAssetsオブジェクトに対して、キーバリュー形式のTagsを付与できます。Tagsはハードウェア情報などユーザが管理できないものはManaged,外部自動化プロセスから動的に設定されるものはAutomated、ユーザによって設定されるものはUnmanagedというように3種類のタイプを持ちます。

このように、Collinsは抽象的なデータ表現により各種インフラストラクチャ要素を管理しており、具体的なデータ表現をもつ社内Mackerelとは対照的です。

Yabitz

Yabitz[15]は、旧ライブドアで開発されたホスト管理アプリケーションです。READMEでは、「ユーザ(多くの場合は企業)が保有するホスト、IPアドレス、データセンタラック、サーバハードウェア、OSなどの情報を管理するためのWebアプリケーション」と説明されています。 機能一覧を見るかぎり、社内Mackerelによく似ています。

いずれのソフトウェアも、死活監視機能やメトリック可視化機能は備えておらず、構成レジストリとしての役割に専念しているという印象です。 他にも、Zabbixのホストインベントリなどがサーバ管理機能にあたると思いますが、Zabbixはあまりに機能が多いので、よく知らずに言及することを控えました。

これからのサーバ「管理」ツール

昨今のインフラストラクチャの進化は激しく、従来のサーバ・ネットワーク機器といった管理単位よりも、さらに動的な要素やそもそもサーバとしての体裁をなしていないインフラストラクチャを管理していく必要があります。

コンテナやマネージドサービスの台頭により、管理の単位はもはやサーバだけではなく、プロセス、クラスタ、Functionなどに置き換わりつつあります。 実際、[9]のアーキテクチャの管理では、Lambda FunctionやDynamoDB Tableなどがホストとして登録されています。

サーバ構築と運用コストが激減し、インフラストラクチャ要素をデータのように扱えるようになってきた結果、マイクロサービスやサーバレスアーキテクチャのような要素同士の関係がより複雑になりやすいアーキテクチャが広まってきました。このようなアーキテクチャのもとでは、1つ1つの要素を管理するというより、関係そのものを管理する必要がでてくると考えます。 ネットワークグラフをTCPコネクションを追跡して可視化する実験[16]に既に取り組んでいました。

さらに、関係性の管理というとまず可視化が思い浮かびます。しかし、人がみて判断するその先として、関係性を表現したグラフ構造をAPIで操作することにより、システムの自動化につなげられないかを考えています。例えば、自動化が難しいレイヤとしてキャパシティプランニングやコストプランニングがあります。書籍「SRE サイトリライアビリティエンジニアリング」[17]の18章「SRE におけるソフトウェアエンジニアリング」にて、サービスの依存関係とパフォーマンスメトリックなどを入力として、キャパシティプランニング計画を自動生成するソフトウェアが紹介されています。 サービスの依存関係を管理するのが普通は大変で、書籍によると執筆時点では人間が設定を書いているように読めます。しかし、関係性のグラフ構造をプログラマブルに操作できるのであれば、プランニングを自動化しやすくなると思います。

参考文献


あとがき

先日、はてなWebオペレーションチームのテックリード - Hatena Developer Blog にて、Mackerelチームとの研究会をやるという話を書きました。 モニタリング研究会では、モニタリングの過去・現在・未来をテーマに、まず過去を知ることから始めており、その一環としてMackerelの源流をまとめました。

Mackerelのサーバ監視以外の「管理」の側面と「管理」と「監視」を統合し何ができるのかという点については、まだ十分に伝えられていないと思っています。 Mackerel本について、mattnさんに書いていただいた書評(Big Sky :: 「Mackerel サーバ監視[実践]入門」を読んだ。)に

これは本書で知ったのですが、どうやら はてな社は Mackerel をホスト管理としても使っている様で、数千いるサーバのロールをうまくラベリングして運用されているとの事でした。

とあり、このような運用手法を伝えていきたいですね。

このように、人の脳やExcelでは管理しきれない未知を明らかにするという観点で、「管理」や「監視」といった概念が組み合わさって、「観測」となり、その先にどのようなインフラストラクチャをつくっていくかをこれからやっていきます。


  1. mackerel2という社内Mackerelの改良版では、タグという概念で、複数のロールをさらに集約し、同じ設定で監視できるようになっています。これは、ロールはMySQL

  2. 例えば、サービスごとにネットワークレンジが決まっているなど。

時系列データベースという概念をクラウドの技で再構築する

サーバ監視サービスMackerelにおいて開発中の、高解像度・長期間のサーバメトリック収集を実現するための新しい時系列データベースDiamondを紹介します。具体的には、Amazon ElastiCache、Amazon DynamoDB、Amazon S3を組み合わせ、Amazon Kinesis StreamsとAWS Lambdaによりコンポーネント間を接続した、階層構造のデータストアアーキテクチャの設計と実装を解説します。

2018/06/05 追記: この記事の内容をWSA研#2でより一般的なアーキテクチャレベルでの貢献として書き直しました。 サーバレス時代におけるヘテロジニアス時系列データベースアーキテクチャ - ゆううきブログ

はじめに

先日開催されたAWS Summit Tokyo 2017にて、「時系列データベースという概念をクラウドの技で再構築する」というタイトルで登壇しました。 この記事では、講演した内容に加えて、時間の限られた講演では触れられなかった内容を併せて議論します。

タイトルに時系列データベースとあるので、時系列データベースの話をもちろん書きます。しかし、AWS Summitでの発表ベースの記事なので、「AWS」を用いたシステム設計という切り口で話を進めます。 具体的には、Write-Intensive Application(書き込み要求が支配的となるアプリケーション)をAWS上で設計するための議論の土台になればと考えています。 時系列データベースは比較的単純なデータモデルを扱うため、よいモデルケースになるのではないかと思います。 時系列データベースとしての機能比較や実装の詳細についてはまた別の機会に紹介します。

背景

Mackerelでは、成長しつづけるサービスのスケーラビリティの確保と、データ量とI/Oがひと桁またはふた桁増加するような機能実現が求められています。

Mackerelの重要な機能のひとつに、メトリックのグラフ化機能があります。 開発中の新時系列データベースは、このグラフ化機能について、より高解像度でより長期間のメトリック収集と保持を実現しようとしています。 さらに、1つのグラフに1000以上のメトリックが含まれている状況でも高速に表示できるようにするなどの性能向上や、それ以外に、メトリックの異常検知など将来的な機能追加に対するワークロードに対して対応できるようにしたいと考えています。

Mackerelにおけるメトリックの収集とグラフ化の仕組みの概要は、以下の図のようになっており、前述の機能要求にとって、時系列データベースというコンポーネントが重要になってきます。

時系列データベースとはそもそも何でしょうか。時系列データベースとは、時系列データを扱うことに特化したデータベースであり、サーバモニタリングやIoTの文脈でのセンサーデータの収集のために使われます。有名な実装として、OpenTSDBInfluxDBGraphite などがあります。地味にみえて、多くの実装が存在し、学術研究論文になっているものもあります。id:rrreeeyyy さんの 時系列データベースに関する基礎知識と時系列データの符号化方式について - クックパッド開発者ブログ が詳しいので、一読することを薦めます。

Mackerelで運用している時系列データベースについては、Mackerelを支える時系列データベース技術 - ゆううきブログ の記事にまとめています。2年前の記事ですが、現状でも概ねこの通りの構成で運用しています。1台あたりピーク時で150k write IOPSを叩き出しており、サーバモニタリング向け時系列データベースの探究 / The study of time-series database for server monitoring - Speaker Deck で紹介したようにパッチをあててパフォーマンスを改善してきました。

ところが、MackerelのGraphite運用には、以下の4つの問題を抱えています。

まず、スケールアウトのための運用コストが大きいという問題です。書き込みI/Oのスケールアウト手法として、水平分割(sharding)が一般的です。Graphite自体にはconsistent-hashingにより、水平分割する仕組みがあります。しかし、シャードの増減により、ハッシュキーとノードのマッピングが変更されたときに、データを再配置するための仕組みはGraphite本体には実装されていないため、運用でカバーする必要があります。

次の問題は、データ保持期間を増やすと金銭的なコストが激増するというものです。前述したようにスケールアウトのための運用コストが大きいことから、書き込みI/Oをスケールアップするために、NANDフラッシュメモリを利用しています。非常に性能が高い一方で高価なハードウェアなので、容量単価が大きいという特徴があります。 したがって、データ保持期間を増やすと、ディスク上のデータ量が増加し、安価なハードウェアにのせることに比べてお金がかかることになります。 一般の解決策は、圧縮してディスクに格納するか、既に書き込まれたデータを低速で容量単価の小さいストレージに移動するような仕組みにすることです。 前者の圧縮については、1で紹介されている差分符号化やXOR符号化のテクニックをGraphiteに実装すれば、実現できそうではあります。しかし、これらのエンコーディングにより、ランダムアクセスできなくなるため、Graphiteのラウンドロビンデータベース構造とうまく噛み合うかがわからないところです。圧縮は基本的に、CPU負荷とトレードオフになるため、CPU負荷がボトルネックとなる可能性もあります。 後者のデータ移動については、Graphiteのラウンドロビンデータベースの、古いデータを新しいデータで上書きしていくという性質のため、別のストレージに効率よくデータを移動させることが難しく、データ構造を大きく変更する必要があります。

3つ目の問題は、データロスト耐性が低く、フル同期のための運用コストが大きいことです。アプリケーションから書き込みすると、Graphiteのメモリ上のキューにデータが非同期に書き込まれるため、サーバダウンによりキューの中身をロストしてしまいます。デュアルライトにより、別のサーバには書き込まれているので、そちらからデータを同期するなど、運用でカバーしなければなりません。これを解決するには、GraphiteにWAL(Write Ahead Log)を実装するなど、大きな変更を強いられます。

最後に、新規にメトリックが投稿されたときに、未来の領域をファイル作成時に確保するので、ディスク使用効率が低いという問題があります。これは2つめの問題と関連します。なぜこのようなデータ構造になっているかは http://graphite.readthedocs.io/en/latest/whisper.html?highlight=rollup#disk-space-efficiency に書かれています。このデータ構造は、コンテナのようなImmutable Infrastructureの概念と相性が悪く、非効率です。

これらの4つの現状の問題点と、冒頭に書いたような新しい機能要求を考慮すると、根本的なアーキテクチャの刷新が必要だと考えました。

既存の時系列データベース

まず、既存の時系列データベースの調査から始めました。Andreas Baderらのサーベイ論文2Open Source Time Series DB Comparison3にオープンソースの時系列データベース実装がまとめられています。

時系列データベースの概念

前述のサーベイ論文[^1]では、時系列データベースの定義は、以下のような性質を満たすDBMSのこととされています。

  • タイムスタンプ、値、属性(メトリック名など)で構成されるデータの行を格納できる
  • 時系列としてグループ化された複数の行を格納できる
  • データ行に対してクエリを発行できる
  • タイムスタンプまたは時間範囲をクエリに含められる

この定義を満たすものを実装するのはさほど難しくありません。しかし、実際には、分散/クラスタリング、Function、Rollup Aggregation(自動丸め)、タグ、複数のデータ解像度、クエリ言語などの時系列データベースにまつわる機能要求があります。 特に、今回のようなスケーラビリティを確保する目的であれば、分散/クラスタリングが重要になってきます。

時系列データベースの分類

時系列データベースのOSS実装は大きく2つの分類があると考えています。それは、他の汎用DBMS上に実装されたもの(TSDB on DBMS)と、時系列データベースに最適化したストレージエンジンをもつもの(TSDB standalone)です。 前者にあたるものは、例えば、OpenTSDBやKairosDBなどがあります。一方、後者にあたるものは、GraphiteやInfluxDB、Prometheusなどがあります。 前者のDBMSとして、HBase、Cassandra、Riak、ElasticsearchなどのいわゆるNoSQLが使用されます。もちろん、TimescaleDBのようにRDBMSであるPostgreSQLをベースにした実装も存在します。前述の時系列データベースとしての定義を満たすだけなら、ACID保証が必要ないので、NoSQLを利用するケースが多いようです。

時系列データベースを実装する側の視点でみると、TSDB on DBMSは、分散/クラスタリング機構を自前で実装せずにすむため、実装が楽というメリットがあります。一方で、TSDB standalineは分散/クラスタリング機構も実装しなければならないというデメリットがありますが、TSDB on DBMSと比較して時系列データベースに最適化できるというメリットがあります。

時系列データベースを運用する側の視点でみると、たいていのTSDB on DBMSはCassandraなどの分散システムとしての運用コストが高いといわれるDBMSを利用しており、一方で、TSDB standaloneは分散システムとしての信頼性を測るための実績が少ないといえます。実際には、製品ごとに細かくメリット・デメリットがありますが、大雑把にこのように認識しています。

さらに、Mackerelで採用するという視点でみると、既存の時系列データベースをそのまま採用するデメリットとして、Rollup Aggregationに対応していないものや、インタフェースが大きく変わるので変更コストがある、Mackerelの現在または将来のワークロードに対してスケールしない可能性があります。

新時系列データベースDiamondのアーキテクチャ

方針

調査の内容を踏まえて、既存の時系列データベースを採用せずに、Amazon DynamoDBなどのAWSマネージドサービスを採用し、マネージドサービス上に独自の時系列データベースアプリケーションを実装するという方針にしました。 マネージドサービスを採用したのは、時系列データベースの分散/クラスタリング機構に必ずついてまわるデータベースの検証・運用コストを削減するためです。はてなでは、特定ベンダーのロックインをなるべく避けるという技術選択方針がありますが、今回は、Mackerelの成長速度や将来の機能要求を考慮して、ある程度のロックインを受け入れることにしました。 独自に、TSDB on DBMSにあたるものを開発することにしたのは、ひとえにMackerelの要求を満たす実装がないか、要求を満たすかどうかの検証に時間がかかるためです。AWSマネージドサービス採用によりデータベースの検証/運用コストを削減できるので、その代わりの開発工数を確保できると考えました。

この大方針に沿って、Graphite運用の4つの問題点を解決できるか考えます。

まず、負荷分散の運用コストの解決です。前述したようにDynamoDBなどのフルマネージドサービスの利用により、運用コストを削減できます。水平分割のためのキーの設計を間違えなければ、お金を払った分だけI/Oスループットがスケールするので、検証も比較的楽になります。 ところが、DynamoDBのI/O課金が高いため、今のMackerelのI/Oを工夫せずにDynamoDBに向けるとインフラコストが大きく増加します。 したがって、個々のデータポイントを別々に書き込むのではなくまとめて書き込み、I/Oコストを下げる必要があります。 最終的には、前段にElastiCache(Redis)を配置し、ライトバックキャッシュ(講演ではバッファと呼んだ)として利用することにしました。

次に、データ保持期間についての解決です。DynamoDBのディスク容量課金は感覚的には安く感じましたが、1分解像度のデータを年単位で保持しようとすると、そこそこのコストがかかります。 S3のコストはスタンダードストレージでもDynamoDBの1/10程度に収まるので、ここでコストを浮かせておけば、他の機能拡充にコストをあてられるため、なるべくS3を使いたいと考えました。 とはいえ、S3のレイテンシはDynamoDBに比べて1桁以上大きいかつ、DynamoDBよりも内部的なパーティションあたりのスループットが低い可能性があります(要確認 リクエスト率およびリクエストパフォーマンスに関する留意事項 - Amazon Simple Storage Service)。 Mackerelの場合、古い高解像度データはほとんど参照されないという参照局所性があるので、参照回数が小さいデータの表示は多少遅くてもよいという性質があります。 そこで、この性質を利用し、ホットデータをDynamoDB、コールドデータをS3に配置することでコスト最適化することを考えました。

この時点で既に、階層型データストアアーキテクチャになることが決定しています。

3つ目に、データロスト耐性の向上です。これは簡単で、メモリ上のキューではなく、ディスク書き込みするメッセージキューを採用することです。OSSなら、KafkaやRabbitMQなどがこれにあたり、AWSでは、Amazon Kinesis Streamsになります。内部的な実装としてはキューではないと思いますが、キューのように利用できます。Kinesis Streamsは直近の24時間分のレコードをディスクに保存し、投稿したレコードをLambda functionの引数に渡すことも簡単です。Kafkaほどレイテンシが低いわけではないそうですが、どのみちMackerelのデータポイントはインターネットごしに投稿されるので、もともとユーザに反映されるまのでレイテンシが大きいので、無視できる程度のレイテンシの差だと考えました。キューというよりは、Using logs to build a solid data infrastructure (or: why dual writes are a bad idea) - Confluentに書かれているように、アプリケーションレベルのWAL(Write Ahead Log)を前段に配置していると捉えてもよいかもしれません。

最後に、ディスク使用効率の向上です。容量問題はS3の利用で解決できるので、ラウンドロビンデータベース構造にする必要がなく、未来の領域を確保することはしません。 圧縮や符号化については、RedisやDynamoDB上でレコード単位で圧縮しようとすると、レコードに対するデータポイントの更新時に、レコード内のデータを全て読み込んでからデータポイントを更新し、レコードの内容を差し替えるということをしなければならないため、余分なread I/Oとネットワーク帯域を圧迫する可能性があります。OSのファイルのようなseekできるストレージであれば、必要な分だけ読み出せるので、効率が良いと考えます。(しかし、これを書きながら、データサイズが小さくなっているのだから、ネットワーク帯域はさほど気にならない可能性もあるということに思いあたりました。)

さらに、時系列データを読み出すコンポーネントをMicroservicesとして開発しています。Graphite互換のインタフェースを実装し、新システム移行時のインタフェース変更コストを小さくしています。1つのクエリに1000以上のメトリックが含まれることがあるため、各メトリックのタスクを並行処理できるように、軽量スレッドでI/O多重化できるGo言語を実装言語として選択しました。

設計

前節の方針を元に、新時系列データベースのアーキテクチャの設計の概要を以下にまとめます。

  • 金銭コスト最適化のために参照局所性を利用する。データ参照頻度に応じて適切なデータストアへデータを移動させる
    • ホットデータをDynamoDB、コールドデータをS3に配置
    • ライトバックキャッシュのストレージとしてElastiCache(Redis)を利用
    • DynamoDBのTTL機能によりシームレスにデータ移動
  • Kinesis Streamsに対して先行ログ書き込みし、データロスト耐性と耐障害性の向上させる
  • Graphite互換インタフェースにより、各ストレージからデータ取得するWebアプリケーションを実装する

アーキテクチャ図を以下に示します。

このように複数のデータストアを組み合わせる場合、データをシンプルな手法で移動させるためのアイデアが必要です。 2017年2月にDynamoDBがTTLサポートされました。 TTLがexpireしたレコードをDynamoDB Triggers経由でLambda functionに渡すことができるため、簡単に古いデータをS3へ配置することができます。

この機能がリリースされたとき、ちょうどデータ移動の仕組みに困難さを感じていたところでした。当時は、タイムウィンドウごとにDynamoDBのテーブルを用意して、古いタイムウィンドウテーブルをテーブルごとDataPipelineによりS3にエクスポートすることを考えていました。いわゆる、MySQLで日時カラムに対してパーティションを切り、古いパーティションをパーティションごとDROPするという手法に近いと思います。 テーブルファイルがS3に配置されても、巨大なテーブルファイルに対してクエリするのは現実的ではないため、テーブルファイルをレコード単位に分割してS3に保存し直すような手間のかかる処理が必要でした。 テーブル単位による管理を強いられるため、アイテム単位で細かくデータ配置を制御したくなったときに、どうしようもなくなるという問題もありました。

古くなったデータを別のストレージに移動したいというのは一般的な要求なので、データベースのTTLとイベント通知というサーバーレスアーキテクチャらしい仕組みは、汎用的に利用できるアーキテクチャだと考えています。(2018/05/04追記: TimeFuzeアーキテクチャ構想 - 処理とデータとタイマーを一体化したデータパイプライン - ゆううきブログ として一般化して提案しました。)

実装

実装についての詳細は、スライドを参照してください。時系列データベース固有の話になります。Redis/DynamoDB上のスキーマ設計、Redisによるライトバックキャッシュ、Graphite互換アプリケーションのI/O多重化について簡単に紹介しています。

考察

Write-Intensive Applicationとして、例えばログ収集や、チャットメッセージングなどがあります。ログやチャットメッセージと違い、メトリックのデータポイントは固定長のデータなので、データ構造を最適化しやすいという特徴があります。したがって、可変なデータを書き込むアプリケーションの場合、時系列データベースでは考えなくてよかったようなデータ構造の工夫が必要かもしれません。

サービスの仕様変更により、データ構造を変更したくなったとき、3箇所にデータを保持していると、それぞれ変更を加えなければいけないというデメリットがあります。これについては、場合によっては、今あるデータ構造に追加の変更をするよりは、前段のKinesis Streamsから別のストレージに最適な構造で書き込むことも考えられます。

3層構造のデータストアアーキテクチャを提案しましたが、必ずしも3層にする必要はないと思います。ディスク使用が少なければElastiCacheとDynamoDB、書き込みI/Oが少なければ、DynamoDBとS3、readレイテンシを気にしなければ、RedisとS3というように、2層で対応できることもあるでしょう。 ちょうど手元のマシンでRAM+SSD+外部ストレージで大抵のことが事足りるように、3層あれば多くの状況でコスト最適化できると考えています。

DynamoDBにはDAXというライトスルーキャッシュが最近実装されました。もし、DAXにライトバックキャッシュが実装されれば、DiamondアーキテクチャのうちRedisの層は不要になるかもしれません。

その他、運用の観点で、スナップショットバックアップについては、ElastiCache自体にバックアップ機構があり、DynamoDBでは前述のDataPipelineによるS3への定期バックアップが可能であり、S3上のファイルは一旦作成されたら基本的に更新しないので、スナップショットバックアップはそれほど必要ないと考えています。

さらに、Lambda functionの実装にバグがあるとデータロストの危険性がないかについては、前段のKinesis Streamsに24時間(追加コストで1週間)データ保持されるので、原理上はそこからリカバリできるはずです。functionの実行がエラーになるケースでは、functionの実行がリトライされます。ただしこれには、functionの実行がべき等である必要があります。Diamondの場合、RedisとDynamoDBのデータ構造がタイムスタンプをキーとしたハッシュマップになっているので、データポイントの書き込みはべき等になっています。

Diamondアーキテクチャのデメリットとして、構成要素が多いことが挙げられます。Kinesis streamsもあわせると、4つのデータストアを併用することになります。一般に構成要素の数が増加すると運用コストも増加しますが、マネージドサービスの利用やCloudFormationのようなInfrastructure As Codeの利用により、運用・管理コストを抑えられると考えています。 しかし、Diamond自体のモニタリングは複雑になるため、モニタリング手法もあわせて提案する必要があると考えています。

資料

プレゼンテーション資料

参考文献

あとがき

「時系列データベースという概念をクラウドの技で再構築する」というタイトルは、少年ジャンプで連載中の食戟のソーマの第115話で、主人公 幸平創真の「親子丼という概念をフレンチの技で再構築する」という台詞から拝借したものです。 主人公は定食屋のせがれで、定食屋としての技術の限界を超えるため、フランス料理の技術を学び、日本の庶民の料理である親子丼を抽象化して、フレンチの技を用いて再構成するというお話になっています。 自分では、この話をとても気に入っていて、今回、ちょうど同じように、時系列データベースの構成要素を取り出し、マネージドサービスやサーバレスアーキテクチャなどのクラウドならではの技術を用いて再構築していると感じ、このタイトルをつけました。

今回話をしたかったのは、単に使っているOSSを列挙するようなものや込み入った実装の話ではなく、アーキテクチャの話です。 最近、アーキテクチャと実装の違いについて考えているのですが、まだあまりよい答えをもっていません。少なくともいえるのは、アーキテクチャには汎用性があり、実装するソフトウェアだけでなく他のソフトウェアにも通用するなにかがあるということです。 アーキテクチャの観点では、Webアプリケーションは参照局所性にあわせて複数のデータストアを併用するのは昨今では当たり前なので、今回のようなTTL + Lambda Functionのようにそこにもっとサーバレスというかイベント駆動な考え方を持ち込み、体系化できないかということを考えていたりします。

Mackerelでは、時系列データベース以外にも、おもしろいソフトウェアアーキテクチャを実現できるチャンスがまだまだたくさんあります。僕の場合は、最近は機械学習を支える効率のよいシステムやグラフDBのアーキテクチャに興味があります。 はてなでは、アーキテクチャを設計・実装し、本番投入し、運用まで持っていくことに興味があるエンジニアを募集しています。

また、今年のはてなインターンでは、Mackerelやはてなのインフラストラクチャを支えるシステムを開発できる、「大規模システムコース」と「クラウドサーバ管理システムコース」があります。 はてなサマーインターン2017

追記


  1. 時系列データベースに関する基礎知識と時系列データの符号化方式について - クックパッド開発者ブログ

  2. Andreas Bader, Oliver Kopp, Michael Falkenthal. “Survey and Comparison of Open Source time Series Databases”. In proceedings of BTW 2017.

  3. Open Source Time Series DB Comparison

Serverspec + Mackerel APIによるインフラテストの実運用化

この記事は Mackerel Advent Calendar 2015 の24日目の記事です。 前回は、id:hitode909 による 三度の飯より監視と通知!Mackerelで自分の心拍数を監視しよう - hitode909の日記 でした。

今回は、Mackerel APIを用いてServerspecによるサーバ構成テストを実運用化した話を紹介します。 Serverspec単体では手の届かないかゆいところをMackerelでサポートするところがポイントです。 Mackerelはもちろんですが、他のサーバ管理ツールにも通用する汎用的な話になるように心がけています。

続きを読む

Mackerelを支える時系列データベース技術

【追記 2018/01/06】現在Mackerelは、時系列データベースという概念をクラウドの技で再構築する - ゆううきブログの時系列データベース実装へ移行しています。

サーバモニタリングサービス Mackerel で採用している時系列データベース Graphite を用いたシステムの構築と運用事情を紹介します。Graphiteについては、プロビジョニングやアプリケーションからの使い方、Graphite自体のモニタリングなど様々なトピックがありますが、特に大規模ならではのトピックとして、Graphiteの内部アーキテクチャ、パフォーマンスチューニングおよびクラスタ構成についての知見を書きます。

続きを読む

Ansible + Mackerel APIによる1000台規模のサーバオペレーション

Ansible と Mackerel API を組み合わせて、1000台規模のサーバ群に対して同時にパッケージの更新やその他のサーバオペレーションのための方法を紹介します。 タイトルに Mackerel とありますが、それほど Mackerel に依存しない話です。 (AnsibleとDockerによる1000台同時SSHオペレーション環境 - ゆううきブログに続編を書いています。)

背景

社内では、サーバ構成管理ツールとして Chef を使用しています。 Chef Server は運用が大変なので使用しておらず、knife-solo と Mackerel APIを組み合わせてホストと Chef role とのマッピングに Mackerel のロール情報を用いています。 また、Mackerel の Ruby クライアントを利用して recipe 内で API を叩いて、Mackerel から動的にホスト情報を参照するといったこともやっています。

続きを読む

Go言語によるCLIツール開発とUNIX哲学について

この記事ははてなエンジニアアドベントカレンダー2014の8日目です。

今回は、Go言語でサーバ管理ツール Mackerel のコマンドラインツールmkr を作るときに調べたこと、考えたこと、やったことについて紹介します。(mkr は現時点では開発版での提供になります。)

コマンドラインツールについて

コマンドラインツールを作るにあたって、@ さんの YAPC Asia 2014 での発表資料が非常に参考になります。 書籍 UNIXという考え方ーその思想と哲学 の内容をベースに、コマンドラインツールはどうあるべきかということが丁寧に説明されています。

続きを読む

tmux + ssh + Mackerel API を組み合わせたとにかくモダンなサーバオペレーション

冗長化させたホストやスケールアウトさせたホストなどの同じサーバ構成をもつホストグループや、あるサービスに所属するホスト全てに同時にsshして同時に操作したいことがある。 複数のホストに同時ログインするツールとして cssh があるけど、毎回複数のホスト名をチマチマ入力したり、すぐに古くなるホスト一覧ファイルを手元に持ちたくない。Immutable Infrastructure 時代にはそぐわない。Immutable Infrastructure 時代にはホスト名なんて毎日変化するし誰も覚えてない。サーバ管理ツール上のグループ名を使ってグループ配下のホストに同時にsshしたい。 あと、cssh は個人的に挙動がなんか微妙なので、代わりに tmux と ssh を組み合わせている。 cssh はマスタとかスレーブとか気持ちはわかるけど、複数ウィンドウ操作は使い慣れたターミナルマルチプレクサを使いたい。

Clusterssh demo - YouTube

もう1台1台丁寧に ssh したり、毎回複数のホスト名をチマチマ指定して cssh する時代は終わった。 (タイトルに Mackerel と書いてるけど、半分以上は Mackerel に依存しない話です。)

続きを読む