2015年8月30日日曜日

Elixir + Phoenix で HelloWorld

概要

Elixirという関数型の言語を試してみました
そして、PhoenixというWebアプリケーションフレームワークを使って「HelloWorld」ページを表示してみました

環境

  • Mac OS X 10.10.4
  • Homebrew 0.9.5
  • Elixir 1.0.5
  • Phoenix 1.0.0

Elixir インストール

  • brew install elixir
  • brew intall node

node というか npm が必要になるので node もインストールします

Phoenix インストール

mixは erlang のためパッケージ管理ツールで Elixir でも使えます
Github からソースをダウンロードしてインストールします
~/.mix/archives/phoenix_new-1.0.0.ezというパスで管理されるようです

HelloWorld 用のプロジェクトを作成

  • mix phoenix.new hello_phoenix

hello_phoenixというサンプルプロジェクトを作成します
途中[Y/n]を聞かれる部分があると思うので全部 Yes でOKです

実行

  • cd hello_phoenix
  • mix phoenix.server

とすると起動するはずです
以下のように表示されればOK

[info] Running HelloPhoenix.Endpoint with Cowboy on http://localhost:4000
30 Aug 10:46:50 - info: compiled 5 files into 2 files, copied 3 in 2282ms

これでブラウザで localhost の 4000 番にアクセスすれば HelloWorld のページが表示されるはずです

phoenix_hello_world.png

最後に

感覚的に Ruby on Rails に非常に似ていると思いました

HelloWorld が表示された次は Guilde にそってやっていけばアプリ開発に必要な一通りのことは学べると思います

Tips

  • 古い記事で Phoenix の 0.31 というバージョンをインストール記事がありましたが、それだとコンパイルエラーになりうまく動作しませんでした

2015年8月29日土曜日

APNs を使ったプッシュ送信で受信時のサウンドを変更する方法

概要

iOS の RemoteNotification (APNs) を使ってプッシュを受信した際の受信音を変更する方法を紹介します

環境

  • OS X 10.10.4
  • Xcode 6.4

音声ファイルをアプリに追加する

/System/Library/Sounds/Purr.aiff

XcodeのSupporting Files配下にドラッグアンドドロップする

add_sound.png

こんな感じになればOK
追加する音声ファイルは何でもOKです
findとかで検索すればいっぱい出てくると思います

プッシュを送信する

APNs にリクエストする際のペイロードは以下のような感じにします

aps: {
    alert =     {
        body = test;
        title = "sound test";
    };
    sound = "Purr.aiff";
}

soundの部分をアプリに追加した音声ファイルをそのまま指定します
他は適当でOKです

確認する

Xcode に実機を接続してビルドしましょう
アプリが起動したらバイブをOFFにして音が出るしましょう

これでプッシュを送信すると default ではない追加した音声ファイルの音でプッシュが受信されると思います

2015年8月28日金曜日

NCMB で Android に対してダイアログプッシュしてみた

概要

NCMB で Android 端末に対してダイアログプッシュというのができるみたいなのでやってみました
普通のプッシュは Android の上部通知バーが表示されるのに対してダイアログプッシュはその名の通りプッシュ受信時にダイアログを表示することができます

環境

  • Android 4.0.4 (実機 : SH-01D)
  • Eclipse 4.4.2
  • NCMB.jar 1.5.3

事前準備

今回はこのサンプルを使って説明します
事前に必要になる作業

  • NCMB の登録
  • Google Developer Console で SenderId と APIキーの取得
  • サンプルが動作する環境の作成

は実施しておいてください
サンプルが動作してとりあえず実機の Android でプッシュが受信できるところまでできればOKです
では、コーディングしていきます

コーディング

表示するダイアログの定義をする

AndroidManifext.xml に以下を追記します

<activity
  android:name="com.nifty.cloud.mb.NCMBDialogActivity"
  android:excludeFromRecents="true"
  android:launchMode="singleInstance"
  android:noHistory="true"
  android:theme="@android:style/Theme.Wallpaper.NoTitleBar">
</activity>

これは NCMB.jar に含まれている、Activityを指定しているだけです
<application>タグ内に記載すればOKです

カスタムレシーバを作成する

com.example.android_ncmb_sample.utils.DialogPushReceiver を作成します
android.content.BroadcastReceiver を継承してください

create_receiver.png

作成したら以下のように変更します

package com.example.android_ncmb_sample.utils;

import com.nifty.cloud.mb.NCMBDialogPushConfiguration;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;

public class DialogPushReceiver extends BroadcastReceiver {

    @Override
    public void onReceive(Context context, Intent intent) {
        if (intent.getExtras().getString("com.nifty.Dialog").equals("1")) {
            NCMBDialogPushConfiguration dialogPushConfiguration = new NCMBDialogPushConfiguration();
            dialogPushConfiguration.setDisplayType(NCMBDialogPushConfiguration.DIALOG_DISPLAY_DIALOG);
            NCMBPush.dialogPushHandler(context, intent, dialogPushConfiguration);
        }
    }

}

基本は onReceive を変更すればOKです
ダイアログフラグがONのときにだけダイアログプッシュを表示するようにします

カスタムレシーバの定義を追記する

AndroidManifext.xml に以下を追記します

<receiver android:name="com.example.android_ncmb_sample.utils.DialogPushReceiver" >
  <intent-filter>
    <action android:name="com.example.android_ncmb_sample.utils.DIALOG" />
  </intent-filter>
</receiver>

<receiver>タグ内に存在しているandroid:nameには作成したダイアログプッシュ用のレシーバを定義します
<action>タグ内に存在しているandroid:nameには「好きな文字列を指定してください」
ここは何でもOKです
プッシュを送信する際にactionというパラメータを指定するのですが、そのパラメータと<action>タグで指定した文字列にマッチする reciever が自動でコールされる仕組みになっています

サンプルではクラス名っぽいものを指定していますが、何でもOKです

動作確認

ここまでできたら動作確認してみます
まず実機をつないで Eclipse 上でアプリを起動しましょう

lunch_app.png

ここは普通に起動すると思います
起動が完了できて Logcat にもログができることを確認したらアプリをバックグラウンドにしてプッシュを送信してみましょう

プッシュを送信する

プッシュの送信は NCMB のコンパネから送信します
ポイントは1つ
プッシュを登録する画面で「Android 端末に送信する」のチェックをONにします
このときに「アクション」と「ダイアログ」を以下のようにします

  • アクション・・・com.example.android_ncmb_sample.utils.DIALOG
  • ダイアログ・・・チェックをON

を必ず設定してください
ちょっと前に説明しましたが、ここで指定したアクションと AndroidManifest.xml の<action>タグ内に記載した文字列がマッチして初めてカスタムレシーバがコールされます

プッシュを受信する

これでプッシュを登録し受信すると以下のように表示されると思います

dialog_result.png

うまく表示されない場合は

  • カスタムレシーバがそもそもコールされていない
  • コールされているけど、Dialog が有効になっていない

あたりを疑ってください
トラブルシュートは実機を接続しながら Logcat とにらめっこすれば、基本は解決できると思います

最後に

割りと簡単にできました
が、たぶんいろいろと事前に触っていて仕組みの流れを理解していたからだと思います
初見だと公式ドキュメントだけだと難しいかもしれないです

2015年8月21日金曜日

Cygwin 上で growlnotify を実行する方法

概要

Growl for Windows をインストールして Cygwin 上でコマンド実行する方法
オプションの指定方法とかいつも忘れるのでメモ

環境

  • Cygwin 1.7.32
  • Growl for Windows 2.0.9

実行方法

$ /c/Program\ Files\ \(x86\)/Growl\ for\ Windows/growlnotify.exe "/t:タイトル" "メッセージ" 2>&1 | nkf -Lu

オプションはダブルクオートでくくると良い
最後のリダイレクトとnkfはなくてもOK、エラーの場合に日本語が化けるので対応しているだけ
スペースをバックスラッシュでエスケープ

2015年8月19日水曜日

Munin みたいなメモリグラフを Zabbix でも監視したい

概要

Munin のメモリのグラフを Zabbix でも監視できないかなと思って調べていたら記事を見つけたのでやってみました
Zabbix 2.4 で実施しているのでスクリプトを Zabbix 2.4 に対応するように修正しています

環境

  • CentOS 6.6 64bit Final
  • Zabbix 2.4.5
  • Munin 2.0.25
  • Python 2.6.6

各種インストール

Munin インストール

とりあえずこれでhttp://hostname/muninに ID/PW でアクセスできることを確認しましょう
今回 munin は使いませんがメモリの使用量が munin で問題なく取得できていることを確認してください

今回利用するメモリ使用量を取得するプラグインは以下にシンボリックリンクとしてあります

/etc/munin/plugins/memory

Zabbix インストール

ここを参考にインストールしています
今回は Munin も Zabbix (MySQL も) すべて同一ホストにインストールしています

インストールが完了したらとりあえずZabbix Server自体が監視できていればOKです

スクリプト設定

公開されている python スクリプトは指定したテンプレートに対してアイテムおよびグラフを登録してくれます
今回は Zabbix 2.4 でも動作するようにスクリプトを修正しています

テンプレート登録

Zabbix の UI にアクセスしてテンプレートを一つ登録してください
今回は「Template_Munin_Memory」というテンプレートを作成した体で話を進めます

zabbix_agentd.conf 修正

  • echo 'UserParameter=munin[*],/etc/munin/plugins/$1 |grep "^$2.value" |cut -d " " -f2' > /etc/zabbix/zabbix_agentd.d/userparameter_munin_plugin.conf

echo 文で conf ファイルを1つ作成します
作成したらservice zabbix-agent restartで再起動しましょう

スクリプト修正

適当なディレクトリに移動してスクリプトを取得しましょう

  • cd work
  • git clone git://github.com/oopsops/scripts.git
  • cd scripts/zabbix

zabbix_munin_plugin.py 修正

  • 39 - 40行目 : Zabbix にアクセスするための ID/PW に変更します
39,40c39,40
< username = "Admin"
< password = "zabbix"
---
> username = "Your ID"
> password = "Your PW"
  • 65行目 : カラーコードを6桁にします
65c65
<   for x in range(1,6):
---
>   for x in range(1,7):
  • 71行目 : graph.create の際に templateid を送信しないようにする
71c71
< createdgraphids = zapi.graph.create([{'gitems': (gitems) ,'name': (graph_title),'width':'900','height':'200','yaxismin':'
0.0000','yaxismax':'3.0000','templateid':'0','show_work_period':'1','show_triggers':'1','graphtype':'0','show_legend':'1','
show_3d':'0','percent_left':'0.0000','percent_right':'0.0000','ymin_type':'0','ymax_type':'0','ymin_itemid':'0','ymax_itemi
d':'0'}])["graphids"][0]
---
> createdgraphids = zapi.graph.create([{'gitems': (gitems) ,'name': (graph_title),'width':'900','height':'200','yaxismin':'
0.0000','yaxismax':'3.0000','show_work_period':'1','show_triggers':'1','graphtype':'0','show_legend':'1','show_3d':'0','per
cent_left':'0.0000','percent_right':'0.0000','ymin_type':'0','ymax_type':'0','ymin_itemid':'0','ymax_itemid':'0'}])["graphi
ds"][0]

zabbix_api.py 修正

  • 201 - 206 行目: user.login method の場合に auth パラメータを付与しないようにする
201,206c201,213
<         obj = {'jsonrpc': '2.0',
<                'method': method,
<                'params': params,
<                'auth': self.auth,
<                'id': self.id
<               }
---
>         if method == "user.login":
>             obj = {'jsonrpc': '2.0',
>                    'method': method,
>                    'params': params,
>                    'id': self.id
>                   }
>         else:
>             obj = {'jsonrpc': '2.0',
>                    'method': method,
>                    'params': params,
>                    'auth': self.auth,
>                    'id': self.id
>                   }
  • 230 行目 : user.authenticate を user.login に変更する
230c237
<         obj = self.json_obj('user.authenticate', {'user': l_user,
---
>         obj = self.json_obj('user.login', {'user': l_user,

修正箇所は以上です
とりあえず自分は上記のみで動作しましたが、他にも Zabbix Server のホスト名を記載する部分もあったので環境によってはまだ修正が必要な箇所があるかもしれません

スクリプト実行

  • chmod 755 zabbix_munin_plugin.py
  • ./zabbix_munin_plugin.py memory Template_Munin_Memory

でエラーがでなければOKです
エラーの場合は Exception の内容を確認して上記スクリプトを更に修正する必要があります

各種調整

スクリプトの動作が完了するとテンプレートにアイテムが13個とグラフ1個が追加されます
以下手動での操作ですがやったほうが良さそうな点を紹介します

グラフ修正

  • グラフタイプの変更
    グラフのタイプが「ノーマル」になっているので「積算グラフ」に変更しましょう

  • 不要なアイテムの削除
    グラフから以下のアイテムを削除しましょう

committed
active
inactive
vmalloc_used
mapped

上記はあってもいいのですが積算グラフにすることで縦軸が合わなくなります
Munin のグラフは積算+折れ線グラフでメモリ使用量を表示しており上記のアイテムは折れ線グラフで表示している項目になるため Zabbix では削除しないと縦軸の値が合いません
なので、やるとしたら別途、ノーマルタイプの折れ線グラフを作成して、そちらに移行するといいと思います

完成するとこんな感じになります

sample_memory.png

色はzabbix_munin_plugin.py内でランダムで生成しているので必要に合わせて変更してください

最後に

munin-node を使って Zabbix で Munin ってぽいメモリ監視をすることができました
Python スクリプトも使っているので、スクリプトの実行で失敗しまくる場合は、素直に Munin を使いましょう

Tips

  • Zabbix 2.0.3 でも実施してみましたが Color を作成する for 文のところだけ変更すれば動作しました

2015年8月18日火曜日

Gradle + Eclipse で System.out をコンソールに出力する方法

概要

例えば、JUnitのテスト内でSystem.outしている場合にその内容を出力したいときとかに使えます

環境

  • Windows 7 64bit
  • Eclipse Luna 4.4.1
  • Java 1.8.0_25
  • Gradle 2.1 (Embedded Plugin)

設定方法

Gradle プロジェクトを右クリックして

Run As -> Gradle Build …

ダイアログが表示されたら Arguments タブに移動して Program Args に「-i」を指定します

add_detail_option.png

gradle のオプションでログレベルを INFO に指定することができます
これでSystem.outの内容が Gradle ビルド経由でも Eclipse のコンソールにも出力されます

2015年8月17日月曜日

Zabbix の UserParameter の引数に特殊文字を指定する方法

概要

デフォルトだと UserParameter の引数に特殊文字「*」「{}」等のが使えないらしいです
使えるようにする方法を紹介します

環境

  • CentOS 6.6
  • Zabbix 2.0.3

設定方法

zabbix_agentd.confを修正します
以下の1行を追加すればOKです

UnsafeUserParameters=1

修正したらzabbix-agentを再起動してください
これで特殊文字が使えるようになります

Tips

デフォルトだと使用できない特殊文字の一覧は以下の通りです(真ん中くらい)
https://www.zabbix.com/documentation/2.0/manual/config/items/userparameters

変数を渡したい場合はそのまま使えるようです
例えばホスト名を表す環境変数{HOSTNAME}を渡したい場合は

original.key[{HOSTNAME}]

でOKです

2015年8月14日金曜日

zbx_redis_template を使ってみた

概要

Zabbix で Redis の監視を簡単にできないかなと探していたら便利そうなテンプレートがあったので使ってみました
ということで zbx_redis_template を使ってみました

環境

  • CentOS 6.6
  • Redis 3.0.3
  • Zabbix 2.0.3
  • Python 2.6.3
  • pip 7.1.0

事前作業

Zabbix Agent および Server のインストールと設定
Redis のインストールと設定

は完了させておいてください
ここでは紹介しません
Zabbix Agent は公式から rpm を取得してインストールしました、Redis は Remi を追加して yum インストールしています
Redis サーバを Zabbix ですでに監視可能な状態であることを前提にしています

Redis 側の設定

監視対象の Redis サーバ上に監視に必要な設定をしていきます

pip インストール

  • yum -y install python-pip
  • pip install redis
  • pip install redis argparse

zabbix_agentd.conf 修正

Zabbix Server 設定

Zabbix Server の GUI を操作していきます
GUI が操作できるマシン上で作業してください

git clone https://github.com/blacked/zbx_redis_template.git
でテンプレートをダウンロードしてください

テンプレートをダウンロードしたら GUI を開いて

設定 -> テンプレート -> インポート

で参照からダンロードテンプレートの中からzbx_redis_templates.xml を選択してください

これで作業自体は完了です
問題なく動作すれば Redis の情報が Zabbix Server に登録されはじめます

トラブルシュート

自分が遭遇したトラブルシュートを紹介します

Not supported by Zabbix Agent

多くはこれにハマると思います

監視対象に配置した python スクリプトを直接実行してエラーにならないようにしましょう
python スクリプトは以下のように実行できます

/etc/zabbix/script/redis/zbx_redis_stats.py -p 16379 $1 $2 $3

まずこれでエラーが出なくならないようにしましょう
エラーになる場合大抵の理由は

  • pipでライブラリのインストールが足りていない
  • zbx_redis.confでポートの指定が足りていない

かなと思います
ライブラリのインストールは必要なものを pip intall してください
ポートの指定は zbx_redis.conf 内を以下のように変更することで可能です

/etc/zabbix/script/redis/zbx_redis_stats.py -p 16379 $1 $2 $3

エラーが出なくなったら再度テンプレートの監視設定を有効にする必要があるので、テンプレートから全アイテムにチェックして一括更新でステータスを無効 -> 有効にしてください
こうすることで再度アイテムのチェックが走ります

監視できない項目もある

おそらくバージョンの違いによるものだと思いますが自分の場合は「redis[{HOSTNAME}, dbsize, none]」の値が取得できませんでした
取得できない値は Zabbix Server 側に値があっても仕方ないのでテンプレートから削除しちゃってOKです

2015年8月13日木曜日

Redis Cluster にスレーブノードを追加する方法

概要

前回 までに Redis Cluster を構築し SLOTS についても触れました
今回はノードの追加に関して触れていこうと思います
特に今回は Redis Cluster + Master -Slave 構成を取る方法を例に紹介します

環境

  • Mac OS X 10.10.4
  • Redis 3.0.2

環境構築

環境構築に関しては前回の記事を参考にしてください
Redis Cluster 内に Master が3台ある状態でスタートしたいと思います

追加するノードを準備する

Redis 3.0 以上が動作するノードが準備できればOKです
今回は同一マシン上にノードを追加しますが、もちろんマシンを1台追加して、そこで Redis を動作させてもOKです

まず追加するノードを管理するディレクトリを作成しましょう

cd work/redis-cluster
mkdir 7003
cp /usr/local/etc/redis.conf.default 7003/redis.conf
vim 7003/redis.conf

以下の部分を書き換えます

  • port 7003
  • appendonly yes
  • cluster-enabled yes
  • cluster-config-file nodes-7003.conf
  • cluster-node-timeout 5000

設定ファイルが作成できたら redis を起動しましょう

redis-server work/redis-cluster/7003/redis.conf

もちろんですが、まだ起動しただけでは Redis Cluster には追加されていません
CLUSTER NODESコマンドなどを実行して確認してみると、まだ存在していないのがわかると思います
また、1台なので cluster status も fail になっている思います

作成したノードを追加する

現状は Master ノードが 3 台いる状態で本当であれば、あと 2 台ノードを追加して各 Master ノードに対して Slave ノードを追加したいところですが、今回はとりあえず 1 台の Slave ノードを追加します

追加にはredis-trib.rbを使います
実行するコマンドは以下の通りです

./redis-3.0.3/src/redis-trib.rb add-node --slave 127.0.0.1:7003 127.0.0.1:7000

コマンドの説明です
まず、今回は Slave ノードとして追加したいため add-node コマンドのオプションとして--slaveオプションを使います
–slave オプションの直後に Slave として追加したいノードを指定します
なので今回は127.0.0.1:7003が追加したいノードになります
次の引数ですが、これは Master として動作している既存のノードを指定します
127.0.0.1:7000はすでに Master ノードとして Redis Cluster 内で動作しています
この Master ノードに対する Slave ノードとして Redis Cluster に追加するコマンドになります

では、実際に実行してみましょう

>>> Adding node 127.0.0.1:7003 to cluster 127.0.0.1:7000
Connecting to node 127.0.0.1:7000: OK
Connecting to node 127.0.0.1:7002: OK
Connecting to node 127.0.0.1:7001: OK
>>> Performing Cluster Check (using node 127.0.0.1:7000)
M: dc1e153c61deb8e932327bbdd81edac4c9ce8ba6 127.0.0.1:7000
   slots:0-5460,5741 (5462 slots) master
   0 additional replica(s)
M: cb7a9481f21521dda296de4fefbf11937d9de153 127.0.0.1:7002
   slots:10923-16383 (5461 slots) master
   0 additional replica(s)
M: cf0bbf4043129b3022eff0dc385530d7c6d9f527 127.0.0.1:7001
   slots:5461-5740,5742-10922 (5461 slots) master
   0 additional replica(s)
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.
Automatically selected master 127.0.0.1:7000
Connecting to node 127.0.0.1:7003: OK
>>> Send CLUSTER MEET to node 127.0.0.1:7003 to make it join the cluster.
Waiting for the cluster to join....
>>> Configure node as replica of 127.0.0.1:7000.
[OK] New node added correctly.

上記は正常に追加された場合のログになります
追加されたCLUSTER NODESで確認してみましょう

127.0.0.1:7003> cluster nodes
cf0bbf4043129b3022eff0dc385530d7c6d9f527 127.0.0.1:7001 master - 0 1439368898457 2 connected 5461-5740 5742-10922
dc1e153c61deb8e932327bbdd81edac4c9ce8ba6 127.0.0.1:7000 master - 0 1439368899488 1 connected 0-5460 5741
e8915b149eab015c0e23ec9818e6e6251115e6b0 127.0.0.1:7003 myself,slave dc1e153c61deb8e932327bbdd81edac4c9ce8ba6 0 0 0 connected
cb7a9481f21521dda296de4fefbf11937d9de153 127.0.0.1:7002 master - 0 1439368897435 3 connected 10923-16383

7003 のノードが 7000 の slave として登録されていることがわかると思います
myself, slave の後に記載されているランダムな文字列が node-id
でここに記載されている node-id に対する slave ノードだということを表しています

Failover を試してみる

試しに 7000 のノードをダウンさせてちゃんと 7003 が master に昇格するか確認してみましょう

7000 のノードをダウンさせると 7003 のログに以下のようなログが出ると思います

1443:S 12 Aug 17:46:19.933 * MASTER <-> SLAVE sync started
1443:S 12 Aug 17:46:19.934 # Error condition on socket for SYNC: Connection refused

ある程度の時間 Master ノードとの通信ができないと Failover が発生します
おそらく cluster-node-timeout で指定した時間 Master ノードから応答がないと Failover させる感じだと思います
Failover が発生すると以下のようなログが流れます

1443:S 12 Aug 17:46:20.448 # Starting a failover election for epoch 4.
1443:S 12 Aug 17:46:20.457 # Failover election won: I'm the new master.
1443:S 12 Aug 17:46:20.457 # configEpoch set to 4 after successful failover
1443:M 12 Aug 17:46:20.457 * Discarding previously cached master state.
1443:M 12 Aug 17:46:20.457 # Cluster state changed: ok

Redis Cluster のステータス自体も ok になっていることがわかると思います
この状態でCLUSTER NODESを見てみると
ダウンした 7000 ノードが fail になっていることがわかります

再度 7000 ノードの redis をスタートしてみましょう
すると、7000 番のノードが自動的に 7003 番の Slave ノードとして登録されることが確認できると思います

127.0.0.1:7003> cluster nodes
cf0bbf4043129b3022eff0dc385530d7c6d9f527 127.0.0.1:7001 master - 0 1439369412563 2 connected 5461-5740 5742-10922
dc1e153c61deb8e932327bbdd81edac4c9ce8ba6 127.0.0.1:7000 slave e8915b149eab015c0e23ec9818e6e6251115e6b0 0 1439369408140 4 connected
e8915b149eab015c0e23ec9818e6e6251115e6b0 127.0.0.1:7003 myself,master - 0 0 4 connected 0-5460 5741
cb7a9481f21521dda296de4fefbf11937d9de153 127.0.0.1:7002 master - 0 1439369411538 3 connected 10923-16383

一度死んだノードを再度起動するだけで自動的に Slave として登録してくれるのは便利だと思います

トラブルシュート

特に問題なければ簡単に追加することができます
問題が発生するケースとしては

  • Redis Cluster に追加したいノード上にすでにデータが入っている
  • 追加したいノードが Cluster モードで起動していない
  • 追加したい Redis Cluster が壊れている

あたりかなと思います
1つ目は一旦データをFLUSHALLしてから Redis Cluster 用の設定ファイル ( Mac であれば /usr/local/var/db/redis/nodes-7003.conf とか) を削除して、再度 redis を起動しましょう
2つ目は設定ファイル redis.conf を確認してみましょう
3つ目はそもそもやばい状態です
対応するとしたらredis-trib.rbfixというコマンドがあるのでこれを使うといいかもしれません
それでもダメだとしたら appendonly.aof を削除したり、設定ファイルを削除したりと本格的に Redis Cluster の再構築をしなければいけないことになるのかもしれません

最後に

Redis Cluster は最低 3 個のノードが必要になるので Master - Slave 構成をとろうとするとそれだけで 6 個のノードが必要になります
サービスとして運用するのであれば Master - Slave 構成は必須だと思いますが、Master ノードを追加するたびに Slave ノードも必要になるのでインフラコストは大きくなりそうな気がしました
ノードは1台のマシンで複数のノードを持つことができるのでそれでもいいのかなと思いますが、それだと DR 的にはダメだと思います

2015年8月12日水曜日

Redis Cluster のデフォルト割り当てられている SLOTS を変更してみた

概要

前回 Redis Cluster を 構築してみました
今回は SLOTS に関して触っていこうと思います
デフォルトで配置される各ノードの SLOTS 情報を個別に変更してみたいと思います
例えばある key は必ずこのノードに保存したいという場合に使います

環境

  • Mac OS X 10.10.4
  • Redis 3.0.2

環境構築

環境構築に関しては前回の記事を参考にしてください

ある key の SLOTS 番号を特定する

CLUSTER KEYSLOTコマンドを使います
例として今回は「hoge_key」という string タイプのキーを特定のノードに保存する方法で紹介したいと思います
まず key から計算される SLOTS 番号を特定します

$ redis-cli -c -p 7000
127.0.0.1:7000> CLUSTER KEYSLOT hoge_key
(integer) 5741

hoge_key に該当する SLOT 番号は 5741 番だということがわかりました
この番号は同じキーに対しては必ず普遍的な番号になるので、何度実行しても同じ番号が返ってくると思います

特定した SLOT 番号がどのノードに割り当てられているか調べる

特定した 5741 の番号だとどのノードに保存されるのか調べてみます
現在の SLOT 割り当て状況を確認するにはCLUSTER SLOTSコマンドを利用します

127.0.0.1:7000> CLUSTER SLOTS
1) 1) (integer) 5461
   2) (integer) 10922
   3) 1) "127.0.0.1"
      2) (integer) 7001
2) 1) (integer) 10923
   2) (integer) 16383
   3) 1) "127.0.0.1"
      2) (integer) 7002
3) 1) (integer) 0
   2) (integer) 5460
   3) 1) "127.0.0.1"
      2) (integer) 7000

デフォルトだとおそらく上記の結果が返ってくる思います
これの見方ですが、まず一番左のインデックス 1), 2), 3) は各ノード分存在します
次のインデックスの 1), 2) の部分に表示されている数字がそのノードに割り振られている SLOTS 番号になります

今回の 5741 がどこに割り当てられているかと言うと 7001 番になります

1) 1) (integer) 5461
   2) (integer) 10922
   3) 1) "127.0.0.1"
      2) (integer) 7001

127.0.0.1:7001 は 5461 から 10922 番までの SLOTS が割り当てられているためこの状態で「hoge_key」を SET すると 7001 のノードに保存されることになります
実際に SET コマンドで試してみると以下のようにリダイレクトされていることが確認できると思います

127.0.0.1:7000> SET hoge_key fuga
-> Redirected to slot [5741] located at 127.0.0.1:7001
OK
127.0.0.1:7001> keys *
1) "hoge_key"

ではこの 5741 番が 7000 のノードに保存されるように変更してみたいと思います

SLOTS の情報を変更する

SLOTS の情報を変更するのに使用するコマンドはCLUSTER ADDSLOTSCLUSTER DELSLOTSになります

まずCLUSTER DELSLOTSを実施します
該当の SLOTS 番号が割り当てられているノード上で実行します

127.0.0.1:7001> CLUSTER DELSLOTS 5741
OK

5471 が該当のノードから削除されました
ちなみにこの状態で 7001 のノードのログを確認すると「Cluster state changed: fail」と表示されていると思います
Redis Cluster は必ず指定の範囲の SLOTS が抜けなく全ノードに適用されている必要があります
なので、DELSLOTS をした直後に上記のログが出力されたことになります

SLOTS が削除できたら次にその SLOTS 番号を割り当てたいノード上でADDSLOTSを実行します
とその前にDELSLOTSのコマンドを他のノードでも実行してください
理由はよくわからんのですが、SLOTS 番号が割り当てられていないノードでも該当の SLOTS 番号が有効になっており、それも削除する必要があります
他のノードでも DELSLOTS を実行したらいよいよ ADDSLOTS します
今回は 7000 番のノードに割り当てたいため 7000 番のノード上で実行します

127.0.0.1:7000> CLUSTER ADDSLOTS 5741
OK

実行が完了すると「Cluster state changed: ok」というログが各ノードに表示されると思います
これで SLOTS 番号の変更が完了です

動作確認

では再度「hoge_key」を SET してみましょう

127.0.0.1:7000> SET hoge_key fuga
OK
127.0.0.1:7000> keys *
1) "hoge_key"

今度はリダイレクトされずにちゃんと 7000 番に SET されたことがわかると思います

最後に

Redis Cluster で SLOTS 番号を変更する方法を紹介しました
これを実施中に気づいたのですが、初めに入れた「hoge_key」は 7001 番にリダイレクトされたのですが SLOTS 番号を変更したあとも 7001 番ノードの keys コマンドの結果には現れるようです
ただ、GET コマンドで値を取得しようとすると 7000 番にリダイレクトされてしまいます
つまり 7001 番に存在している hoge_key の値は取得できないけど、存在している謎の値になってしまいました

おそらく今回紹介したDELSLOTS, ADDSLOTSは初期構築やサービス停止しても問題ない状況で使用するコマンドだと思います(SLOTS 番号が 1 つでもない状態になると status is fail になることも確認したので)
構築時に使用した Ruby のredis-trib.rbとか使うといい感じやってくれそうな気がします(詳しくは調べていません)
その辺りは公式の Redis Cluster tutorial を見てもらうとヒントがあるかもしれません
「ダウンタイム 0 で SLOTS 番号を変更する方法」自分も気になったので時間があったら調査してみたいと思います

参考サイト

2015年8月11日火曜日

Redis Cluster を構築してみた

概要

Redis Cluster を Mac 上に構築してみました
とりあえずシングルノードで構築しています

環境

  • Mac OS X 10.10.4
  • Redis 3.0.2
  • Ruby 2.2.0p0
  • Gem 2.4.5
  • redis-rb 3.2.1

インストール方法

  • Redis
brew install redis
  • Ruby
brew install ruby
gem install redis

Cluster 設定

mkdir -p work/redis-cluster
cd work/redis-cluster
mkdir 7000 7001 7002
cp /usr/local/etc/redis.conf.default 7000/redis.conf
cp /usr/local/etc/redis.conf.default 7001/redis.conf
cp /usr/local/etc/redis.conf.default 7002/redis.conf
vim 7000/redis.conf
vim 7001/redis.conf
vim 7002/redis.conf

以下の部分を書き換えてください

  • port 7000
  • appendonly yes
  • cluster-enabled yes
  • cluster-config-file nodes-7000.conf
  • cluster-node-timeout 5000

portcluster-config-fileの数字の部分は各設定ファイルごとに書き換えてください
設定ファイルの書き換えが完了したら一旦各 redis ノードを起動しましょう

redis-server work/redis-cluster/7000/redis.conf
redis-server work/redis-cluster/7001/redis.conf
redis-server work/redis-cluster/7002/redis.conf

Cluster 構築

公式で公開している Ruby スクリプトを使って Cluster は構築します

cd work/redis-cluster
wget http://download.redis.io/releases/redis-3.0.3.tar.gz
tar zvxf redis-3.0.3.tar.gz
./redis-3.0.3/src/redis-trib.rb create 127.0.0.1:7000 127.0.0.1:7001 127.0.0.1:7002

Can I set the above configuration?
と聞かれるので yes を入力します

[OK] All nodes agree about slots configuration.
となれば Cluster の構築は完了です

動作確認

アクセスはお馴染みのredis-cliを使います
Cluster 環境にアクセスする場合は以下のように-c-pオプションを利用します

redis-cli -c -p 7000

Cluster の状態の確認は以下でできます

> cluster info

実際に値を投入してみましょう

127.0.0.1:7000> set hoge fuga
OK
127.0.0.1:7000> set hoge1 fuga
-> Redirected to slot [6811] located at 127.0.0.1:7001
OK
127.0.0.1:7001> set hoge2 fuga
-> Redirected to slot [11000] located at 127.0.0.1:7002
OK

こんな感じで key ごとに値を持つホストが変わってきます
Redis Cluster は SLOTS という概念を持っています
簡単に言うと SET したい key ごとに SLOTS 番号が計算されて、その番号に応じた適切なノードに値が保存されるという仕組みです

Cluster の SLOTS の設定状況の確認は以下でできます

> cluster slots

例えば hoge の SLOTS 番号は 1525 番で 1525 番はどのノードに割り当てられるかと言うとポート 7000 番のノードに割り振られます

127.0.0.1:7000> cluster keyslot hoge
(integer) 1525
127.0.0.1:7000> cluster slots
1) 1) (integer) 5461
   2) (integer) 10922
   3) 1) "127.0.0.1"
      2) (integer) 7001
2) 1) (integer) 10923
   2) (integer) 16383
   3) 1) "127.0.0.1"
      2) (integer) 7002
3) 1) (integer) 0
   2) (integer) 5460
   3) 1) "127.0.0.1"
      2) (integer) 7000

上記の SLOTS の設定はデフォルトの状態です
もちろん好きな SLOTS 番号を好きなノードに割り当てることもできます
そのあたりの設定は別の記事で紹介できればと思います

最後に

Redis Cluster はバージョン 3.0 以上の Redis でサポートされています
Cluster を構築すること自体は非常に簡単にできます
また、Master - Slave 構成もサポートしているので 6 台のノードがあれば、 Master - Slave 構成も組めます

実運用でどこまでスケールできるのかとか、運用上発生する具体的なトラブルシューティングの検証とかが結構必要かなと思いました
まだ、Web 上にもその辺の運用話は少ないのかなという印象を受けました
その辺のノウハウが溜まってくるのはもう少し先なのかな

参考サイト

2015年8月6日木曜日

Production 用の証明書を使って NCMB で APNs プッシュ送信の実機テストをする方法

概要

過去に紹介した記事で iOS のプッシュ方法を紹介しました
このときに使用していたプッシュ送信用の証明書は Development 用の証明書を使っており、この証明書は普通アプリ公開時には使用しません
別途 Production (Distribution) 用の証明書を作成してこれを使うのですが、公開する前にテストしたい場合も多いと思います
結構ハマったので自分が実施した手順を紹介します

環境

  • Mac OS X 10.10.4
  • Xcode 6.4
  • iPhone6 (iOS 8.4)
  • Developer Member Center 20150806 時点

手順

基本的な手順はこれと同じです
上記手順の中で注意することを紹介していきます

作成済みのAppIDのプッシュ通知の Distribution 側を有効にする

AppIDがない場合は適当に作成してください

すでに作成したAppIDがある場合は「Edit」からプッシュ通知を有効にすることができます
Edit したらプッシュを有効にする項目があるのでそれのチェックボックスをONにします

ONにしたら続けて証明書を作成しましょう
すぐ下に「Create Certificate」というボタンが出ると思うので Production SSL Certificate の方のボタンをクリックして証明書を作成します
証明書の作成は過去に紹介した方法と同じになります
事前に作成していると思われる CSR を指定して証明書を作成しましょう
Production 用のプッシュ送信用の証明書を作成すると証明書の情報に「APNs Production iOS」と表示されます
production_cert.png

以下は Production 用の証明書まで作成が完了してプッシュ通知が有効になっている状態のAppIDになります
この状態になっていればOKです

enable_push.png

証明書から .p12 ファイルを作成する

先ほど作成した Production 用の証明書ダウンロードします
ダウンロードした証明書をダブルクリックしてキーチェーンアクセスで開きましょう
あとは過去の記事を参考に .p12 ファイルを作成すればOKです

一応、NCMB を想定しているので作成した .p12 ファイルはアップロードしておくといいと思います

Adhoc 用のプロビジョニングプロファイルを作成する

これが一番重要かと思います
Developer Member Center で Adhoc 用のプロビジョニングプロファイルを作成しましょう

作成を開始するとプロビジョニングプロファイルファイルの種類を選択する画面になると思います
そこで Distribution 側の「Ad hoc」を選択しましょう

choice_adhoc.png

次は AppID を選択する画面なのでプッシュ通知を有効にした AppID を選択しましょう
証明書の選択画面ではプッシュ通知用の証明書を選択しません(というかできません)配布用の証明書を素直に選択しましょう
その次で Ad hoc で配布する端末を選択することになると思います
基本は全部チェックでいいと思います、適宜変更してください
そして、最後にプロビジョニングプロファイルの名前を入力します

これで Adhoc 用のプロビジョニングプロファイルの作成完了です
作成したプロビジョニングプロファイルはあとで Xcode と同期して Xcode 上のプロジェクトに指定します

サンプル用のプロジェクトを作成

特に気にすることはないと思います
普通に作成しましょう
過去の記事を参考にデバイストークンを登録する処理までコーディングしてしまってください

プロジェクトをAdhocビルドできるようにする

ここもポイントです

まず

Xcode -> Preferences -> Accounts -> View Details (右下) -> 更新ボタン (左下)

を実行し Developer Menter Center 上のプロビジョニングプロファイルの情報を Xcode に同期しましょう

同期が完了したらプロジェクトのビルドの設定をします

プロジェクトを選択 -> Build Settings -> Provisioning Profile

で先ほど作成した Adhoc 用のプロビジョニングプロファイルを指定しましょう
Provisioning Profile の欄がない場合は実機を接続して一回実機でビルドしようとするとエラーになり、その欄が登場すると思います

Provisioning Profile の欄を設定したら、その上の「Release」の欄を Distribution 用の証明書を指定しましょう
最終的に以下のようになっていればOKです

set_adhoc_build.png

ビルドして .ipa ファイルを作成する

実機を接続 -> Product -> Archive

でビルドします
すると Archives というビルド結果の一覧のダイアログが表示されるので、右側にある「Export」を実行します

まずエクスポート方法を選択します
真ん中の「Save for Ad hoc Development」をクリックします

choice_export_mode.png

次にユーザを指定して、アーカイブが完了したら「Export」ボタンをクリックして .ipa ファイルをエクスポートします
保存先を選択しましょう

作成できた .ipa ファイルを実機に転送する

これは調べるといろいろと方法があるようです (Webサーバを使ったり、TestFlightを使ったり)
今回は iTunes を使った方法を紹介します

実機をつないだ状態で iTunes を立ち上げましょう
立ち上げたら iPhone を選択して App でアプリ一覧を表示しましょう

select_app.png

そしたら

ファイル -> ライブラリに追加

で先ほど保存した .ipa ファイルを指定します
すると iTunes 上に先ほど作成したアプリが登録されます

登録できたらインストールをクリックし右したので「転送」をクリックしましょう
これで Adhoc ビルドしたアプリを実機に転送することができます

動作確認してみる

ここまで来たら後はアプリを開いて動作確認してみましょう
今回は前回同様で NCMB の利用を想定しているためアプリを開いたときに NCMB 側にデバイストークンの情報が登録されればOKです
もちろん、サンプルプロジェクトを作成した段階で必要なコーディングは済ませておいてください

デバーストークンが登録できれば、あとは NCMB に .p12 ファイルをアップロードして、プッシュ通知を作成すればOKです

最後に

噂によると Xcodeだけでも .ipa ファイルの転送ができるので、それができる方はわざわざ iTunes とか起動しなくてもいいと思います
ハマったのはやはり Adhoc ビルドするところでしょうか
ずっと Development 用のプロビジョニングプロファイル指定して来たので Adhoc ビルドの存在自体を知りませんでした

Adhoc ビルドしていないアプリでもデバイストークンの登録はできるのですが、.p12 ファイルが Production 用だと証明書と一致せずうまく送信できません

とりあえず APNs は複雑すぎると思います

2015年8月5日水曜日

Google の 2 段階認証を有効にしてみた

概要

2段階認証とはログイン時にID/PWだけでなく、登録した携帯電話に送られてくる確認用のコードを入力して初めてログインしたことにできる機能です
Googleの2段階認証を有効にしたところいろいろとややこしい自体になったので状況をメモしておきます
2段階認証を有効にする方法はここでは紹介しません

環境

  • Google 2段階認証 2015/08/05 時点での機能
  • 有効にしたGoogleアカウントは1つ
  • Google アカウントを利用しているデバイスは全部で7台 (Windows x 2, Mac x 2, iPhone, Android x 2)

遭遇したケース

とりあえず全てがログアウト状態になる

Gmail, GoogleDrive, その他Google認証を使っているアプリ等すべてのアプリがログアウト状態になりました
かつアプリをインストールしている全マシンでログアウト状態になります
かつ各マシンでアプリにログインするたびに携帯に確認コードが飛んできます

SMTP 認証が使えなくなった

Jenkinsのビルド失敗時のメールサーバをGoogleのSMTPサーバを使っていたのですがこれも2段階認証の対象になるようです
2段階認証を有効にすると、そんなケースのために「アプリ用のパスワード」というものを発行できるようになります
Googleアカウントの管理画面からアプリ用のパスワードは発行できます
ここを参考にするといいと思います
アプリ用のパスワードを発行したら、そのパスワードを認証用のパスワードとして使うことで2段階認証が発生せずJenkinsから認証できるようになります
また、アプリ用のパスワードは基本使い捨てなので忘れたら再度発行して入力しましょう
アプリ用パスワードの使い回しはやめたほうがいいです

iPhoneの連絡先の連携ができなくなった

これは上記の理由と同じで「アプリ用のパスワード」を発行して、そのパスワードでiPhoneから認証すればOKです

iPhone上のGoogle系のアプリについて

iPhone上でログアウトになっていたアプリは先ほどの連絡先連携の他に

  • Gmail
  • Google Chrome
  • Google Drive
  • Youtube

でした、これらの認証ですが、Google Chrome だけ 2 段階認証を一回実施したら他のアプリはすでにログイン状態になっていました
理由はよくわからないですが、iPhone上で一度 2 段階認証を実施すると他のアプリの認証もOKになったりするんでしょうか
自分は iPhone 上にインストールしている Google系のアプリはそれだけだったのですが、他のアプリもインストールしている人はもしかしたら別途 2 段階認証 or アプリ用パスワードの発行が必要になるかもしれません

Android上のGoogle系のアプリについて

基本的にはiPhoneと同じです
アプリそれぞれで 2 段階認証してください
Androidの場合は、設定に「アカウントと同期」できる端末もありここで Google アカウントを認証すれば全アプリに認証が適用されるので楽です

Tips

  • 携帯(メールアドレス)が変わる場合は 2 段階認証をOFFにしてから携帯を変更したほうがよさそう
    そうしないと 2 段階認証用のコードを受け取れなくなってしまいログインできなくなるためです
    そんなときを想定しているのか、バックアップコードというものが発行できるようです
    バックアップコードには 10 個の確認コードが含まれており、それぞれ一回しか使えないですが、携帯に送られてくる確認コードと同様に使用することができます
    バックアップコードは印刷して保存しておくことを薦めていました

最後に

とにかく面倒くさいです
それだけセキュアになったと思えば良いといえば良いかなと
まぁ 2 段階認証を設定していても結局 PC とか盗まれて PC にパスワードを設定していなかったらほぼ終わりなんですけどね
それでも Google アカウントを Webのアイデンティティのメインにしているのであれば絶対設定したほうがいいと思います

2015年8月3日月曜日

現在サービスが実行されていないため、Windows Update で更新プログラムを確認できません

ネットでいろいろ調べてドライバが変だったり変なアプリが入っているから
みたいな記事をみたけど全部ハズレ
自分は以下で解決しました

WindodwsUpdateの自動更新をOFFにして手動で更新を行う

ポイントは自動更新をOFFにすること
理由は全然わからんないけど、これで無事WindowsUpdateできました
1年ぶりくらいに起動したWindowsだったので、長期間起動していないケースの方はお試しあれ

ちなみに 2014/06/30 から 2015/08/03 までの1年ちょっとの更新で

更新プログラム数は約 170
更新 -> 再起動の作業を 7 回
更新完了までの時間は約 4:00 ほど

かかりました
面倒くさすぎる