cloudpack の 自称 Sensu芸人 の かっぱこと 川原 洋平@inokara)です。


はじめに

Sensu について調べてて気になった点をメモしたいと思います。あくまでもメモですので内容につきましてはご自身でご確認いただければ幸いです。



脱 RabbitMQ 依存?


ドキュメントのアーキテクチャ図が変わった

Sensu ファンの皆さんならすでにお気づきのことかと思いますが、ドキュメントの Overview に以前掲載されていたアーキテクチャ図が更新されています。

以前のアーキテクチャ図は以下のような図だったと記憶しております。この図は個人的には Sensu のアーキテクチャを説明するには若干説明不足感は否めませんでした。

sensu-rabbitmq-source-exchange_01

最新のアーキテクチャ図は以下のような GIF アニメーションにまでなっておりとても解りやすい図になっている気がします。

sensu-rabbitmq-source-exchange_02
http://sensuapp.org/docs/0.12/overview より引用

基本的には RabbitMQ を監視キューのキューイングサービスとして、一見はアーキテクチャとして変わりはないように見えますが StateTransport という名前で各コンポーネントを分類している点が変わったポイントでとても興味深い書き方かと思っています。


勝手にイメージ

アーキテクチャ図に追加された StateTransport の記述から推測すると Sensu の各コンポーネントを役割毎に抽象化してそれぞれの役割で RedisRabbitMQ 以外のツールでも置き換えられるような方向で開発を進めていこうとする作者の方々の意向を感じられます。

ただ、これはあくまでも個人的なイメージですので、「そんなんことは無い」ってツッコミをうけそうな気がしますが Sensu の良さはまさにコノ部分ではないかと思ったりしているので今後にとても期待しているところです。はい。


ソースコード探訪

で、上記の図を見る前から sensuソースコード内から RabbitMQ に特化(AMQP に特化)した記述が無くなったなーって思っていたら transport というインスタンス変数を呼ぶような作りに変わっていました。その transport は以下の sensu-transport という Gemrequire して利用するようです。

sensu-transport のソースツリーは以下のような構成になっていました。

sensu-transport
├── Gemfile
├── LICENSE.txt
├── README.md
├── Rakefile
├── lib
│   └── sensu
│       ├── transport
│       │   ├── base.rb
│       │   └── rabbitmq.rb
│       └── transport.rb
├── sensu-transport.gemspec
└── spec
    ├── base_spec.rb
    ├── helpers.rb
    ├── rabbitmq_spec.rb
    └── transport_spec.rb

4 directories, 12 files

ここで興味深いのが sensu-transport/lib/sensu/transport/rabbitmq.rb というファイルの存在。中身をちょっと覗いてみると…

gem "amqp", "1.3.0"

require "amqp"

require File.join(File.dirname(__FILE__), "base")

module Sensu
  module Transport
    class RabbitMQ < Base
      def initialize
        super
        @queues = {}
      end

      def connect(options={})
        timeout = create_connection_timeout
        on_failure = on_connection_failure
        @connection = AMQP.connect(options, {
          :on_tcp_connection_failure => on_failure,
          :on_possible_authentication_failure => on_failure
        })

上記のように Gemamqprequire していて RabbitMQ の為の設定を最小限に書くことができている…ということは類似のキュー処理が出来るミドルウェアで置き換えるのでは?という疑問と期待にぶつかります…。

さらに sensu-transport/lib/sensu/transport.rb を見ると…

module Sensu
  module Transport
    def self.connect(transport, options={})
      require("sensu/transport/#{transport}")
      klass = Base.descendants.detect do |klass|
        klass.name.downcase.split("::").last == transport
      end
      object = klass.connect(options)
      object
    end
  end
end

という記述があり、self.connect メソッドが受け取った引数が sensu/transport/ ディレクトリ以下のファイル名となるようなことから、前述のような RabbitMQ 意外の選択肢を選べる、または追加出来るような作りになっていることを垣間見れるますな。



ちなみに


sensu における RabbitMQ の使われ方

これは RabbitMQvhostExchange を確認した。

sensu-rabbitmq-source-exchange_03

ソースコード的にはこのファイルに定義されている。整理すると以下のような感じになると思われる。

Exchange Name Exchange Type 用途
keepalives direct Sensu クライアントとの死活監視
result direct Sensu クライアントのチェック結果をやりとりする
test fanout Sensu クライアントに各種チェックを実行させる

以下、該当部分を抜粋。

@transport.subscribe(:direct, 'keepalives', 'keepalives', :ack => true) do |message_info, message|
@transport.subscribe(:direct, 'results', 'results', :ack => true) do |message_info, message|
@transport.publish(:direct, 'results', MultiJson.dump(payload)) do |info|
@transport.publish(:fanout, subscription, MultiJson.dump(payload)) do |info|

RabbitMQ を想像させるような記述は :direct:fanout くらいで amqp とかで検索すると見つからないから泣きたくなります。sensu-transport というライブラリを require して transport というインスタンス変数を呼ぶようになっていました。

ちょっと脱線…RabbitMQ の Exchange って何?

一言で言いますと…

  • Exchange は生成された Message を受け取り Binding に従って、適切な Message Queue へ渡す

メッセージルーターようなイメージでしょうか。

ちょっと脱線…RabbitMQ の Exchange Type について

  • DirectMessageRouting keyBindingBinding key をチェックして Routing keyBinding key が同じになるキューにメッセージを配送する
  • Fanout – キューすべてに受け取ったメッセージの配送を行う
  • TopicRouting key を元に配送するキューを選択するがキーを階層で区切って部分一致でキューを選択してメッセージを配送する

RabbitMQExchange についてはこちらの記事が解りやすい。上記のメモも本記事を参考にさせて頂いて自分なりに噛み砕いて書いた。



最後に

  • つたない英語翻訳コンニャクで意訳、予想した内容なので、おおいに間違いがあると思います
  • 実際にはソースコードを見るなり試すなりしてください
  • RabbitMQ が嫌いなわけではないですが周辺ツールを自由に組み合わせて監視環境を構築する Sensu らしいなあって思ったりしています

元記事は、こちら