Help us understand the problem. What is going on with this article?

clojure製Webアプリケーションのメトリクス取得してみた

More than 3 years have passed since last update.

ゴール

clojureで書いたWebアプリケーションの状態を取得して、簡単な可視化をしてみました。これを読むと、簡単にclojure製Webアプリの可視化を試してみる方法が分かります!

モチベーション

仕事で携わっているclojureアプリケーションに、私の未熟のせいで何度もエラーを吐かせてしまっていて、それが悔しくて「ミスったとしても気づける環境を用意しておきたい!!!!!」と思ったのが最初のモチベーションでした。ただそれから行動に移せていなかったので、この機にモニタリングツールを触ってみることにしました。

はなすこと

:bulb: Graphiteについての簡単な紹介
:bulb: 簡単にGraphiteサーバーを立てる方法
:bulb: metricsについての簡単な紹介
:bulb: duct製アプリケーションにアプリケーションメトリクスを吐かせる方法
:bulb: そのメトリクスをGraphiteに食わせる方法
:bulb: メトリクスをグラフに表示する方法

話さないこと

:monkey_face: clojureについて
:monkey_face: ductについて
:monkey_face: Graphiteの難しい話

Graphiteは、モニタリングツールの一種

graphiteのlogo

Graphiteは、モニタリングツールの一種で、低スペックなホストでも多くのリアルタイム情報を収集できるのがウリ、らしいです。

Graphiteは1つのプログラムで動くのではなく、ELKスタックみたいに複数のサブシステムを同時に動かして稼働するシステムの総称で、graphite-web / carbon / whisper の3つのサブシステムから構成されます。それぞれ、

  • graphite-web: 収集したメトリクスをグラフとして描画するGUI
  • carbon: 様々なインターフェースからのメトリクス情報をうけつけるツール
  • whisper: タイムシフト情報を格納するデータストア

の役割を持っています。
また、他にもcollectDというサーバの情報を取得してくれるツールや、statsDと呼ばれる自前のアプリケーション用に様々なインターフェースから情報を取得できるツールなど、様々なモジュールが用意されています。

Graphiteサーバーを立てよう!

さて、そんなGraphiteですが、使うためには上記の各サブシステムやツールを動かすためには当然いろいろなセットアップが必要です。公式もそれを見越してDigitalOceanのコンテナイメージやVagrantのVMを提供してくれています。
しかしDigitalOceanはクラウドサービスだしVagrantはインストールにすごい容量と長いセットアップ時間が必要です。

そこで、Dockerを使います。DockerHubに、GraphiteとstatsDが入ったDockerイメージがアップロードされているので、これをpullしてきてローカルに立てます。(一応、Dockerのインストール方法はこちら)

docker run -d\
 --name graphite\
 --restart=always\
 -p 80:80\
 -p 2003-2004:2003-2004\
 -p 2023-2024:2023-2024\
 -p 8125:8125/udp\
 -p 8126:8126\
 hopsoft/graphite-statsd

(出典: hopsoft/graphite-statsdイメージのREADME)

これだけで、ローカルホストの特定のポートをリッスンするGraphiteサーバーが起動します。セットアップ全くなしで必要なツールが起動するなんて、すごいですね!

metricsは、アプリケーションの状態を送信できるライブラリ

こうして立てたGraphiteサーバーに、アプリケーションの状態を送信しましょう。
metricsはdropwizardのライブラリで、動いているアプリケーションの内部で起こっていることやアプリケーションの状態を外部から取得することができます。これをアプリケーションに埋め込んで、適切な設定をすることで、動いているアプリケーションの内部で起こっていることを外部から監視することができます。

アプリケーションにmetricsを埋め込もう

ではこのmetricsライブラリを、clojure製Webアプリに埋め込みましょう。今回はductで書いたアプリケーションに設定を埋め込みます。
metrics-clojureというmetricsのclojureラッパーがあるので、それを使いましょう。

project.clj
[metrics-clojure "2.7.0"]

ring用の設定やmiddlewareが入っているライブラリ、Graphiteへのデータ送信をしてくれるライブラリも入れておきます。

project.clj
[metrics-clojure-ring "2.7.0"]
[metrics-clojure-graphite "2.7.0"]

これで依存ライブラリはOKです。

metrics-clojureのringモジュールは、middlewareの形で

を追加してくれます。ductにそれを追加しましょう。

system.edn
 :config
 {:app
  {:middleware
   {:functions
    {:hide-errors ;; ...
     ;; 各種middleware設定
     :metrics       #var metrics.ring.expose/expose-metrics-as-json
     :metrics-ins   #var metrics.ring.instrument/instrument}
    :applied
    [:not-found :webjars :ring-defaults :hide-errors :metrics :metrics-ins]

次に、このmiddlewareが設定してくれた情報をGraphiteに送信する処理を開始しなければいけません。これはシステムのライフサイクルに組み込めるので、componentを作って組み込みましょう。

component/graphite.clj
(ns my-app.component.graphite
  (:require [clojure.tools.logging :as log]
            [com.stuartsierra.component :as component]
            [clojure.tools.logging :as log]
            [metrics.reporters.graphite :as graphite])
  (:import [java.util.concurrent TimeUnit]
           [com.codahale.metrics MetricFilter]))

(defrecord Graphite []
  component/Lifecycle
  (start [component]
    (if (:graphite component)
      component
      (let [reporter (graphite/reporter {:host "localhost"
                                         :prefix "gt1gv1"
                                         :rate-unit TimeUnit/SECONDS
                                         :duration-unit TimeUnit/MILLISECONDS
                                         :filter MetricFilter/ALL})]
        (graphite/start reporter 10)
        (log/info "Started Graphite Reporting")
        (assoc component :graphite reporter))))
  (stop [component]
    (if (:graphite component)
      (do
        (graphite/stop (:graphite component))
        (log/info "Stopped Graphite Reporting")
        (dissoc component :graphite))
      component)))

(defn graphite [options]
  (map->Graphite options))

Graphiteへのデータ送信用インスタンスを生成してstart/stopを叩くだけです。シンプルですね。

これで、


user> (dev)
:loaded
dev> (go)
:started

するだけでGraphiteサーバーへの情報送信が始まります。

アプリケーションの内部状態が可視化される

この状態でアプリケーションをしばらく叩くと、Graphiteで以下のようなグラフで情報を可視化することができます。

スクリーンショット 2016-12-11 16.22.27.png

これは、青い線が2xx系レスポンス、紫の線が5xx系レスポンスを示しています。紫のグラフが急に上がると、なにか想定しないInternal Server Errorがユーザーに返却されていることが分かります。(空白の時間は、いろいろ試していてサーバーを止めた時です)

これをよりキレイなGUIで見られるGrafanaと連携させたり、収集した情報を元にアラートをあげるようにすると、アプリケーションの設定は汚さずにアプリケーション内部で起こっていることを可視化することができそうです!

やってみて

モニタリングツール、今まで触ったことがなさすぎて仕組みやすべてのサブモジュールを理解しようとしたらめちゃ辛かったです。
でも一方で、わからないなりに言われたとおりにやれば一旦動くものが見られるようにはなっていて、これから深く知っていくキッカケが手に入ったように思います!

blackawa
このアカウントで発信する内容は個人検証に基づくものであり、現在所属する会社の公式見解を示すものではありません。
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした