Mackerelの外形監視システムをGoで書いた話とgo-check-pluginsの話
Go All-Stars
Oct 11th, 2015
Profile
最近作ったgoライブラリ
- https://github.com/Songmu/prompter
- https://github.com/Songmu/enslaver
prompter
Goでプロンプト簡単に出すやつ
twitterID := prompter.Prompt("Enter your twitter ID", "")
lang := prompter.Choose("Which language do you like the most?", []string{"Perl", "Golang", "Scala", "Ruby"}, "Perl")
passwd := prompter.Password("Enter your password")
var likeSushi bool = prompter.YN("Do you like sushi?", true)
var likeBeer bool = prompter.YesNo("Do you like beer?", false)
以下の様な要件を満たします。
- 自動化の妨げになるからターミナルじゃない時はスキップして欲しい
- とにかく簡単にプロンプトを表示させたい
- パスワード入力では入力を隠したい
- 複数の選択肢から上手いこと選択させたい
- 単に(y/n)だけ入力させたい
enslaver
プロセスをずっと殺さないようにしてくれる君
% go get github.com/Songmu/enslaver/cmd/enslaver
% enslaver perl -E 'while (1) { 0.2 > rand() ? (die "DEAD") : (warn "ALIVE!\n");sleep 1 }'
雑なbotを常駐させておくときとかに便利
Mackerelの既存の技術スタック
既存のGoプロダクト
- mackerel-agent
- mackerel-agent-plugins
- mkr
新しいGoプロダクト(今日話す話)
- URL外形監視システム
- go-check-plugins
URL外形監視システム
MackerelのURL外形監視機能
- 指定したURLに対するアクセスが可能であるかを監視することのできる機能
- ユーザの運営しているサービスが動作しているかをサービス外から監視できて便利
- レスポンスタイム監視も
システムの要件
- Mackerel上にある外形監視すべてのチェックを1分以内に完了する必要がある
- とりあえずは毎分数千件程度の外形監視リクエストが処理できれば十分とする
- スケーラビリティは考えておく
- 監視処理の中心はHTTPのリクエスト
- Webアプリケーションとは処理の性質が大きく異なる
- 監視のためのHTTPリクエストをどのように行うかは、監視の設定の管理や監視の結果をどう処理するかとは独立して扱いたい
- hot deploy可能なように
- ゆくゆくは監視元のリージョンを選べるようにというような要望が出てきそう
選択したアーキテクチャー
- Mackerel本体とは別にGoでサブシステムを実装する
- 何らかのジョブキューフレームワークを使わずにスクラッチ
- キューにはRedisを採用
- httpによるジョブ投入 && 結果通知
概念図
実装
- 外形監視システムはHTTPサーバとして動作
- Mackerel本体との通信
- Mackerel本体 -- 監視仕様(JSON) --> 外形監視システム
- 外形監視システム -- 監視結果(JSON) --> Mackerel本体
- 1監視ごとにRedisで実装されたキューに投入
- Redisのキューからジョブを取得し、ワーカーが監視のHTTPリクエストを実行する
見どころ
- httpサーバーの実装
- goroutineの活用とRedis
- 外部リソースへのHTTPリクエストの制御
- ホットデプロイ
HTTPサーバー実装
Graceful Restart
- github.com/braintree/manners
- 処理中のリクエストを強制停止しない
- graceful shutdown
- github.com/lestrrat/go-server-starter/listener
- 反映時のgraceful restartを実現するために、PerlのServer::Starterから得られるソケットをGoでハンドリングするためのライブラリ
- SIGHUP送ったらgraceful restart
- →「いつものPerlアプリケーションの感じ」で運用できて楽
- 参考
Goの常駐プロセスの監視
github.com/fukata/golang-stats-api-handler
http.HandleFunc("/api/stats", stats_api.Handler)
- プロセス監視用のHTTP APIをお手軽に作れる
- めっちゃ便利
goroutineの活用とRedis
goroutineの活用とRedis
- ジョブの投入はRedisのリストに突っ込んで終了
- ジョブの実行
- Redisからジョブを取り出す
- チャンネル経由で複数のgoroutineで実行
外部リソースへのHTTPリクエストの制御
github.com/hakobe/paranoidhttp
ホットデプロイ
デプロイ
- Jenkinsでビルドして成果物をアップロード
- 本番サーバーからcurlで成果物を取得
- 俗にいうpull型deploy
daemontools & Server::Starter
#!/bin/sh
exec 2>&1
set -eu
export PERL_PATH="/opt/perl-5.22.0/"
exec $PERL_PATH/bin/start_server --port 8000 -- /path/to/mackerel-external-monitor
- perl製のやつを利用
- SIGHUPでホットデプロイを実現
- サーバ単体で気軽に再起動できるので楽
- 複数台構成も可能
Goでサブシステムを書いてみて
- 並行処理が効いてくる種類のサブシステムをGoによって実装するのは良い選択だった
- ちょっとしたワーカーシステムをスクラッチで書ける
- リソース食わないし、単体でリスタート可能なので、最低限の冗長性を確保しておけば良いので楽
外形監視システムの話、終わり
第2部 go-check-plugins
チェックプラグインとは?
チェック監視のためのスクリプト共通プロトコル
- Mackerelのチェック監視
- NagiosのNRPE(Nagios Remote Plugin Executor)
- Sensuのチェックプラグイン
- Consul script check
などで採用されている
SPEC
実行ファイルのexit codeが監視結果となる
- 0: OK
- 1: WARNING
- 2: CRITICAL
- その他: UNKNOWN
標準出力が、監視のメッセージとなる
go-check-pluginsはSensuやConsulでも利用可能!
- Goなのでスクリプト言語に比べると高速かつリソース消費が少ない
- Sensuのプラグインの殆どはRubyで書かれている
go-check-pluginsの現状
- v0.0.2を先週リリース
- Mackerelのパッケージリポジトリを加えてあれば以下でインストール可能
yum install mackerel-check-plugins
apt-get install mackerel-check-plugins
- 現状4つのみ
- check-procs
- check-http
- check-load
- check-file-age
- contributeお待ちしています!
以上
We are Hiring
- はてなではエンジニアを募集しています
- 東京でも絶賛採用中
- もちろん京都にもおいでやす