日頃の行い

個人的な日頃の行いをつらつら書いてます\\\\ ٩( 'ω' )و ////

mackerelを利用してhubotが死んだ時に気がつくようにした

趣味でhubotいじったりしてるんですが、たまに死んでる時があります。
Slackでコマンド打って何も返ってこないと切なくなるので、
死んだ時に死んでしまうとは情けないと言えるようにしたいというのが今回の目的です。

突然の死の原因

ログを見るとこんな感じで突然の死を遂げているようです。
接続エラーでリトライしてもダメなときにclientを止めているように見えます。

[Sun Jun 14 2015 03:58:52 GMT+0900 (JST)] INFO Connecting...
[Sun Jun 14 2015 03:58:54 GMT+0900 (JST)] INFO Logged in as dark of ngineerxiv, but not yet connected
[Sun Jun 14 2015 03:58:55 GMT+0900 (JST)] INFO Slack client now connected
[Sun Jun 14 2015 14:25:38 GMT+0900 (JST)] ERROR Last pong is too old: 14.823
[Sun Jun 14 2015 14:25:38 GMT+0900 (JST)] INFO Reconnecting in 1000ms
[Sun Jun 14 2015 14:25:39 GMT+0900 (JST)] INFO Attempting reconnect
[Sun Jun 14 2015 14:25:39 GMT+0900 (JST)] INFO Connecting...
[Sun Jun 14 2015 14:25:41 GMT+0900 (JST)] INFO Slack client closed

これだけだとよくわからない。
(原因ご存知のかたコメント頂きたいです・・・(´・ω・`))
とりあえず再起動すればなんとかなるので、プロセスが死んだことに気がつけるようにします。

そこでmackerelですよ

mackerel.io

他の手段もありそうですが、とりあえず触ってみたかったのでmackerelを使ってみました。
特に他の何かと比較したとかありません。
mackerelにはデフォルトのメトリックがいくつか用意されていますが、今回はカスタムメトリックを利用します。
※メトリクスとも言いますが、mackerelではメトリックで統一しているらしいですね。 用語集 - Mackerel ヘルプ

こちらのメトリックで監視している値が、ある閾値を超えたらアラートを投げるという設定をすることにしました。
2015/06/23現在、Slackへの通知が可能ということなので、
hubotのプロセスが止まっていたらSlackに通知するということをすることにします。

Slackへの通知設定

もう下記ヘルプで解決です←
Incoming hookを利用して、通知してくれるみたいですね。

help-ja.mackerel.io

アラートの条件設定

とりあえず、プロセス数が1未満だとアラートみたいな設定をしました。
この時下記の記事を参考にしています。

tech.im-dmp.net

help-ja.mackerel.io

設定はこんな感じ
ps aux|grep ...|wc -l を利用してプロセス数をechoしています。
ゴリ押しですねw

# Configure
...

[plugin.metrics.dark-ngineerxiv]
command = "echo \"dark.ngineerxiv\t$(ps aux | grep dark|grep make|grep ngineerxiv| grep -v grep | wc -l)\t$(date -u +%s)\""

...


設定したらmackerel-agent serviceを再起動します。
そうすれば数分後に下記のようなグラフがmackerelの自分のページに表示されるはずです。

f:id:arata3da4:20150623003900p:plain

さらにアラートの設定を下記のようにすれば設定完了です。

f:id:arata3da4:20150623004329p:plain

アラートが流れた時の挙動とまとめ

もしhubotが死んだ時こんな投稿がSlackに投稿されます。

f:id:arata3da4:20150623004510p:plain

これでhubotが死んだ時にちゃんと気がつけますね。
dark poem と打つと
オサレなポエムを返してくれるようにしているのですが
返してくれないと本当に悲しくなるので活用していきたいと思います。

この他にも実はtd-agentとかの監視にも使ってますが、その話はまた今度。

(だいたい)新卒エンジニア向け技術交流会vol.3 で話してきたという話

6/6(土)にこんなイベントがありました。ngineerxiv.doorkeeper.jp

(だいたい)という名前はなぜついたのでしょうか。
こちらをみると3月までのイベントは「新卒」になってますね。
あ・・・←

そのイベントの運営やってます。
ずっと新卒でいられると思っていた@ara_ta3(Twitter)です。
新卒じゃなくなったしせっかくなので発表しました。

■スライドなど

www.slideshare.net

途中デモで使ったコードを置いたレポジトリ

github.com

ほんとはdummerを利用してデモをやろうと思ったんですが
このコミュニティSlack使ってるしSlackRTMのplugin公開したからちょうどいいやと思って
SlackRTMのpluginとnorikraを試した感じのConfigファイルになってます。
norikraのクエリは起動後に以下の様なものを追加しました。

SELECT COUNT(*)
FROM slack_rtm.win:time(60 sec)
WHERE type = "message"

資料作成めっちゃ雑だったのですが
みなさん反応が暖かくてやりやすかったですw

□あまり言及できなかった話(資料が間に合ってないだけ)

dummerについてはこちらの記事で書いた気がします。
fluentd試すときめっちゃ便利です。arata.hatenadiary.com

SlackRTMのpluginはこちら
あの時は公開してなかったのですが、現在Gemfileとして公開中です。arata.hatenadiary.com

Gemfile
fluent-plugin-slackrtm | RubyGems.org | your community gem host

■発表した時にあった質問とか

意図とかあってなかったらごめんなさい。
その後飲んで忘れてます

Q.Norikra便利そうだけど、使いドコロが難しいというかなんというか。
 なにかうまく使ってたりしますか?

A.難しいですよね。ログなどをストリーミングで飛ばして、
 その数を数えたりするのが結構便利なので、
 例えばDMPとかだとタグが埋まっているかどうか
 リアルタイムにタグが踏まれた回数を数えることが出来ていい感じなのですが・・・
 他だとDOS攻撃とかの判定に使ったりとか聞いたことありますね。

□参考

ちなみに他の事例の話の時はこちらの資料が浮かびました。

http://dev.classmethod.jp/cloud/aws/block_dos_attack_by_norikra/dev.classmethod.jp

speakerdeck.com


その他は確かNorikraの仕組みがわかっていなくて答えられなかったやつなので、
今は答えません!←
この後私は美味しくピザを食べました。

■他の方の発表

@__papix__ さんと @hoge17296 @hoto17296さんも発表してくれました。
ありがとうございました。

@hoto17296 さんの発表資料

www.slideshare.net

@__papix__ さんのは見つからなかったのでもし見つかったら追記します。

■次回予告

Darkの交流会は3ヶ月毎にやっているので、9月くらいにやると思います。
ぜひ気になる方々参加してみてください〜

MongoDBでArbiterをSecondaryにしたくなったときにする方法

みなさんこんばんは。
brew installするとmongoの3系統が入るようになったんだなぁと
老害気分を感じてしまいました。
そんなにMongoDB詳しくないんですけどね。

概要

今日はArbiterとして登録してしまったレプリカセットを
Secondaryにする方法を探し求めた時の話をします。

方法自体の流れは簡単です。

1. Arbiterをレプリカセットから外す
2. データを消す
3. 再起動
4. レプリカセットにSecondaryとして追加する

です。
参考はこちら

Convert a Secondary to an Arbiter — MongoDB Manual 3.0.2
(SecondaryからArbiterにするには)

ということでこの記事の流れ

1. 環境の説明
2. master用サーバでの操作(Arbiterをレプリカセットから外す)
3. arbiter用サーバでの操作(データを消す+再起動)
4. master用サーバでの操作(レプリカセットにSecondaryとして追加する)

1. 環境の説明

vagrantで3台起動しています。
MongoDBは2.6
インストールは本家または過去の記事を参考にしてください。

arata.hatenadiary.com

など

Vagrantfile

# -*- mode: ruby -*-
# vi: set ft=ruby :

# Vagrantfile API/syntax version. Don't touch unless you know what you're doing!
VAGRANTFILE_API_VERSION = "2"

Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
  config.vm.box = "centos"
  config.vm.box_url = "http://developer.nrel.gov/downloads/vagrant-boxes/CentOS-6.5-x86_64-v20140110.box"

  config.vm.define :web1 do |web|
    web.vm.network :private_network, ip: "192.168.56.101"
  end

  config.vm.define :web2 do |web|
    web.vm.network :private_network, ip: "192.168.56.102"
  end

  config.vm.define :web3 do |web|
    web.vm.network :private_network, ip: "192.168.56.103"
  end
end


そして、レプリカセット用の設定は以下のようなコマンドを実行しました。

$vagrant ssh web1
$mongo --quiet --eval="config = {_id: 'repltry', members: [{_id: 0, host: '192.168.56.101:27017'},{_id: 1, host: '192.168.56.102:27017'},{_id: 2, host: '192.168.56.103:27017', arbiterOnly: true}]};rs.initiate(config)"

2. master用サーバでの操作(Arbiterをレプリカセットから外す)

ここではっと気が付きます。
Arbiterじゃなくて、私はSecondaryにしたかったんだと。
そこで公式ページを確認した所、上で書いた通り、
SecondaryからArbiterにする場合というチュートリアルを発見しました。
同様の方法で、逆のことも出来るはずなので、行いました。

ここではまずArbiterをレプリカセットから外します。
はじめに、masterに設定したweb1にログインして操作します。

repl:PRIMARY> rs.remove("192.168.56.103:27017")
2015-05-04T17:05:38.056+0000 DBClientCursor::init call() failed
2015-05-04T17:05:38.056+0000 Error: error doing query: failed at src/mongo/shell/query.js:81
2015-05-04T17:05:38.058+0000 trying reconnect to 127.0.0.1:27017 (127.0.0.1) failed
2015-05-04T17:05:38.060+0000 reconnect 127.0.0.1:27017 (127.0.0.1) ok
repl:PRIMARY> rs.remove("192.168.56.103:27017")
rror: couldn't find 192.168.56.103:27017 in [
	{
		"_id" : 0,
		"host" : "192.168.56.101:27017"
	},
	{
		"_id" : 1,
		"host" : "192.168.56.102:27017"
	}
]

なんか一回目エラー出てたけど、
ちゃんと消されていたので、問題ないと判断して続けます。

3. arbiter用サーバでの操作(データを消す+再起動)

次にArbiterに設定したweb3にログインして操作します。
mongoのデータ用のPATHは/var/lib/mongoを指定しています

$vagrant ssh web3
[vagrant@localhost ~]$ sudo service mongod stop
[vagrant@localhost ~]$ cp -r /var/lib/mongo/ /tmp/mongo.bk
[vagrant@localhost ~]$ cat /etc/mongod.conf
systemLog:
    destination: file
    path: /var/log/mongodb/mongod.log
    logAppend: true

processManagement:
    fork: true
    pidFilePath: /var/run/mongodb/mongod.pid

replication:
    replSetName: repl

storage:
    dbPath: /var/lib/mongo
[vagrant@localhost ~]$ sudo rm -rf /var/lib/mongo/*
[vagrant@localhost ~]$ sudo service mongod start
Starting mongod: 

これで過去のデータが完全に消えました。
次から行うのはInitialSyncと同じですね。

InitialSyncについてはこちらarata.hatenadiary.com

4. master用サーバでの操作(レプリカセットにSecondaryとして追加する)

後は新規にSecondaryとしてレプリカセットに追加するだけです。

repl:PRIMARY> rs.add("192.168.56.103:27017")
{ "down" : [ "192.168.56.103:27017" ], "ok" : 1 }

以上。
これで、レプリカセットに追加されました。

Arbiterにしてしまったら完全に新しいインスタンスとして
登録しないといけないみたいですね。

これがデータ量大きくなった時にどうなるのかなぁ
まあArbiterからSecondaryに移したい時って、本番環境だとさほどないのかな。

ScalaでDynamoDBに接続するためにAWS SDKを利用してみた時の話

ScalaJavaAWS SDKを使ってDynamoDBを利用した時のメモ
本番ではDynamoDBの本物を利用してましたが、ここではDynamoDB Localを利用します。
Java製のAWS SDKScalaから利用しています。

作業したgithubレポジトリはこちらgithub.com

1. DynamoDBローカルのインストール

下記のページからダウンロードして使います。

docs.aws.amazon.com

DynamoDBローカルの準備や起動についてはREADMEを参考にしてください。

https://github.com/tarata/dynamodb-local-for-blog/blob/master/README.md

2. 適当なテーブルの作成

HashキーやらRangeキーなど設定がありますが、それらについては下記のページを参考にしてください。
今回はHashキーをidにしたテーブル「users」を作成します。

qiita.com

Credentialは $HOME/.aws/credential のkeyを利用しています。

テーブル作成に利用するクラス

これで設定おkです
この後UserモデルだけJavaで書きました
なぜなら、Scala力が足りないからです。

Userモデル

3. テーブルのデータを突っ込む部分と取得する部分

データを突っ込む部分

データを取得する部分

たったこれだけでDynamoDBへのORマッパー的なことが出来ます。
アノテーションで出来て便利ですね!!11
4. ハマったところに続く...


ちなみに、jsonを保存したりしたい場合は以下のサイトが参考になります。
Using Custom Marshallers to Store Complex Objects in Amazon DynamoDB - AWS Developer Blog - Java

4. ハマったところ

com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBMappingException: Failed to instantiate new instance of class
	at com.amazonaws.services.dynamodbv2.datamodeling.ConversionSchemas$StandardItemConverter.createObject(ConversionSchemas.java:629)
	at com.amazonaws.services.dynamodbv2.datamodeling.ConversionSchemas$StandardItemConverter.unconvert(ConversionSchemas.java:420)
	at com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBMapper.privateMarshallIntoObject(DynamoDBMapper.java:690)

Failed to instantiate new instance of class は主に Class.newInstance() を実行した時に出るエラーメッセージみたいですね。
Java力が足りなくてわかりませんでした。
Scala力も足りないしDynamoDB力も足りないので、切り分けが出来なかったのですが、普通にググったら普通にわかってあれがあれでした。

このOR Mapperはデータを取得した際に、今回で言えば、 **User.newInstance()** を実行し、
その後setterでデータを入力しているようです。
なので、引数なしコンストラクタがないと死にます←

IntelliJが「これ使ってないよ!使ってないのに消さないの??」
って言ってきたので消したら動きませんでした。
怖いですね、リフレクションメソッド

5. 最終的にどうしたか

正直Mapperは必要がないので、findAllとsaveといメソッドを持ったRepositoryを定義しました。

UserRepository.scala

UserConversions.scala

こうすればアノテーション地獄にもならずかけます。
そんな複雑なことしないので、ORマッパーを使うよりリポジトリを定義して使ってあげるほうが楽そうです。