元RX-7乗りの適当な日々 このページをアンテナに追加 RSSフィード Twitter

RX-7(FD3S)WRX STI関連のキーワードで検索されて来られた方へ。
右サイドのカテゴリ『』をクリックすると関連する項目だけが表示されます。
日々の写真は『Flickr』で公開しています。

2014/03/27

特定のソースIPアドレスからpingを送りたいとき


人生で彼是5回くらいググっている気がするので写経しておく。

サーバに複数のネットワークインターフェースがついていたり、IPエイリアス(VIP)を付与していたりして、複数のIPアドレスを持っている場合、特定のIPアドレスをソースとしてpingを送りたい、というかICMP echo requestを送り付けたい場合とかがある。


そういうときはpingコマンドの"-I"オプションを使うとお手軽、と。

$ ping (ターゲットになるIPアドレス or ホスト名) -I (ソースとなるIPアドレス or インターフェース名)

実行すると、

$ ping 10.0.100.1 -I 10.0.101.200
PING 10.0.100.1 (10.0.100.1) from 10.0.101.200 : 56(84) bytes of data.
64 bytes from 10.0.100.1: icmp_seq=1 ttl=255 time=0.993 ms
64 bytes from 10.0.100.1: icmp_seq=2 ttl=255 time=0.832 ms

・・・・・

こんな感じで、fromのところが、ソースとして指定したIPアドレスになっていますね。

それでは! =͟͟͞͞(๑•̀=͟͟͞͞(๑•̀д•́=͟͟͞͞(๑•̀д•́๑)=͟͟͞͞(๑•̀д•́


man

-I interface

interface is either an address, or an interface name. If interface is an address, it sets source address to specified interface address. If interface in an interface name, it sets source interface to specified interface. For ping6, when doing ping to a link-local scope address, link specification (by the '%'-notation in destination, or by this option) is required.

2014/03/25

IT系の文章をWebで翻訳するなら、やっぱりGoogle翻訳かな


と思った。

僕は、恥ずかしながら、あまり英語が得意じゃないので、長文の英語ドキュメントを読むときとか、文書の概観を掴むために、翻訳エンジンを活用することが多い。

で、ふとこの前、色々な翻訳エンジンに、いくつかのIT系の文書を読み込ませてみたんだけど、やっぱりGoogle翻訳が一番わかりやすかった。


↓の比較サンプルは、RedisのPartial Resynchronizationの項だったりするのだけど、「翻訳」でググったときの検索結果上位の翻訳エンジンいくつかの日本語訳の結果。

いくつかの文書の翻訳を比較してみたけど、IT系の文章をWebの翻訳サービスに読み込ませるなら、やっぱりGoogle翻訳かなー、次点でBing翻訳かなーというのが個人的な感想です。


原文

Partial resynchronization

Starting with Redis 2.8, master and slave are usually able to continue the replication process without requiring a full resynchronization after the replication link went down.

This works by creating an in-memory backlog of the replication stream on the master side. The master and all the slaves agree on a replication offset and a master run id, so when the link goes down, the slave will reconnect and ask the master to continue the replication. Assuming the master run id is still the same, and that the offset specified is available in the replication backlog, replication will resume from the point where it left off. If either of these conditions are unmet, a full resynchronization is performed (which is the normal pre-2.8 behavior).

The new partial resynchronization feature uses the PSYNC command internally, while the old implementation uses the SYNC command. Note that a Redis 2.8 slave is able to detect if the server it is talking with does not support PSYNC, and will use SYNC instead.


Google翻訳

部分的な再同期

Redisの2.8以降では、マスタとスレーブは通常、複製リンクがダウンした後に完全再同期を必要とせずに、レプリケーション·プロセスを続行することができます。

これは、マスター側のレプリケーションストリームのメモリ内のバックログを作成することで動作します。マスタとすべてのスレーブは、オフセット複製とマスター実行IDに同意することになるので、リンクがダウンした場合、スレーブは再接続し、レプリケーションを継続するために、マスターを聞いてきます。マスター実行IDを仮定すると、まだ同じであり、オフセットが指定されたレプリケーションバックログで利用可能であることを、複製は中断時点から再開されます。これらの条件のいずれかが満たされていないである場合、完全な再同期は、 (通常のプリ2.8動作)が行われる。

古い実装では、 syncコマンドを使用しながら、新しい部分再同期機能は、内部的にPSYNCコマンドを使用しています。 Redisの2.8スレーブはそれがと話しているサーバーがPSYNCをサポートしていないかどうかを検出するには、代わりに、SYNCを使用することが可能であることに注意してください。


エキサイト翻訳

部分的な再同期

レーディ2.8から始めて、主人と奴隷は応答リンクが落ちた後十分な再同期を要求せずに、応答プロセスを通常継続することができます。

これは、マスター側で応答流れのインメモリ残務を作成することにより働きます。

主人およびすべての奴隷は応答オフセットおよび主人に同意します、idを実行する、したがって、リンクが落ちる時、奴隷は、応答を継続するために再度主人を接続し尋ねるでしょう。

マスターの経営のidがまだ同じで、指定されたオフセットが、応答残務において利用可能である、とすると、応答は、それが終わったポイントから再開するでしょう。

これらの条件のどちらかが満たされていない場合、十分な再同期は行なわれます(それは正常な前2.8振る舞いである)。

新しい部分的な再同期特徴はPSYNCコマンドを内部に使用します。その一方で古いインプリメンテーションはSYNCコマンドを使用しています。

それが一緒に話しているサーバーがPSYNCを支援せずSYNCを代わりに使用するかどうかを、レーディ2.8奴隷が検知することができることに注意してください。


Yahoo!翻訳

部分的な再同期

Redis 2.8から始めて、複製リンクが下がったあと、支配者と奴隷は通常、完全な再同期を必要とすることなく複製プロセスを続けることができます。

これは、マスター側で複製流の記憶の残りをつくることによって働きます。 マスターとすべての奴隷は複製オフセットとマスター動くIDについて同意するので、関連が下がるとき、奴隷は複製を続けるためにマスターを再接続して、尋ねます。 マスターが動くならば、IDはまだ同じことである、そして、オフセットが明記したことは複製残りで利用できると、複製はそれが離れて去った点から再び口を開きます。 これらの状況のどちらでも満たされていないならば、完全な再同期は実行されます(通常のpre-2.8なふるまいである)。

古い実施がSYNC命令を使う間、新しい部分的な再同期機能は内部的にPSYNC命令を使います。 Redis 2.8奴隷がそれが話しているサーバーがPSYNCをサポートしないで、その代わりにSYNCを使うかどうか検出することができることに注意すべきです。


Weblio翻訳

Yahoo!翻訳と同じ


Infoseekマルチ翻訳

Yahoo!翻訳と同じ


@nifty翻訳

部分的な再同期

模写リンクが落ちた後に、完全な再同期を必要とせずに、Redis2.8から始まって、通常、マスターと奴隷は複製プロセスを続けることができます。

これは、マスター側でメモリの模写の流れの予備を作成することによって、働いています。 マスターとすべての奴隷が模写オフセットとマスター走行イドに同意するので、リンクが落ちるとき、奴隷は、模写を続けるようにマスターに再接続して、頼むでしょう。 マスター走行イドを仮定するのはまだ同じです、そして、オフセットが指定したのは、模写予備で利用可能です、模写がそれがやめられたポイントから再開するでしょう。 これらの状態のどちらかがまだ対処されていないなら、完全な再同期は実行されます(通常のpre-2.8の振舞いです)。

新しい部分的な再同期の特徴は内部的にPSYNCコマンドを使用しますが、古い実現はSYNCコマンドを使用します。 Redis2.8奴隷が、それが話しているサーバがPSYNCを支持しないで、代わりにSYNCを使用するかどうか検出できることに注意してください。


livedoor翻訳

Yahoo!翻訳と同じ


So-net翻訳

Yahoo!翻訳と同じ


Bing翻訳

部分的な再同期

Redis 2.8 にはじまって、マスターとスレーブは通常、複製リンクがダウンした後に完全な再同期を必要とせず、レプリケーション プロセスを続行することができます。

これは、マスター側でレプリケーションのストリームのメモリ内のバックログを作成することによって動作します。マスターとスレーブのすべてオフセットと実行 id マスター、のでリンクが下がるとき、スレーブ再接続され、レプリケーションの継続を求めるレプリケーションに同意します。マスター実行 id が同じで、およびオフセット指定はレプリケーション バックログで利用できると仮定すると、レプリケーションは中断した時点から再開されます。これらの条件のいずれかが満たされて、(pre 2.8 動作である) 完全な再同期が実行されます。

新しい部分的な再同期機能を使用して PSYNC 内部的には、古い実装 SYNC コマンドを使用します。Redis 2.8 奴隷と話しているサーバー PSYNC をサポートしていないと同期を代わりに使用されるかどうかを検出することに注意してください。


英日日英 プロが教える基礎からの翻訳スキル

英日日英 プロが教える基礎からの翻訳スキル

2014/03/16

パナソニックのW850Mをお借りできたのでワイプ撮りを試してみた & はてなxパナソニックブロガーイベントの様子


先日、はてな&パナソニック主催のブロガーイベントに参加してきて、パナソニックさんの新しいデジタルハイビジョンビデオカメラ「HC-W850M」をお借りしました。

このビデオカメラの目玉機能は、なんと言ってもサブカメラによるワイプ撮りという点。メインカメラで本当に撮影したいターゲットをズームで撮り、サブカメラは全体像であったり違い被写体を撮ったりなど、その空間を共有できる面白い機能です。


試しに撮影してみた動画がコチラ。

D


これ、スタジオアリスさんでキッズ時計の撮影をしたときに撮ったもの。

僕がビデオカメラの撮影に慣れていないので、ちょっと見辛い感じになっていますが、メインカメラは子供をズームで撮影し、サブカメラは全体を撮影して周りで何が起きているかがわかるような感じです。

メインカメラだけだと、周りのバックグラウンドで何が起きているかわからない動画になってしまいがちなので、こういった撮影の選択ができちゃうのは良いですねー。


ちなみにワイプ撮りの利用シーンは、以下のサイトでわかりやすく書かれています。


ビデオカメラがちょっと欲しくなった

ちなみに、僕はデジタルビデオカメラを持っていません。

子供が生まれたときに少しばかり検討はしましたが、普段、基本的にはiPhoneで動画を撮影しています。理由はiPhoneもレンズの性能は悪くないし、フルHDにも対応していてスペック的に良くなってきているのと、普段は一眼レフを持ち歩くことが多く、主にそちらを使ってしまうから。


Panasonic HC-W850M

今回、ビデオカメラをお借りして、当たり前なんですが、やはり専用品は優秀だなーと思いました。とにかく綺麗だしズームも工学20倍でオートフォーカスも速いし。

あえてバッテリーを大きくしたと言われていた通り、撮っていても全然バッテリーが減らない。旅行とかで1日中つかってても予備バッテリーいらないんじゃないかと思うくらいです。

その恩恵もあって、スタンバイ状態にして持ち歩いていたので、起動も素早く、今だ!という瞬間を見逃しにくいと思いました。


おまけ: はてな&パナソニックのブロガーイベントの様子

はてな東京オフィス

2/22に、はてなさんの東京オフィスで開催されたので行ってきました。


はてな&パナソニックのブロガーイベント

パナソニックの方から製品紹介の話。


はてな&パナソニックのブロガーイベント

新製品も展示されていました。


はてな&パナソニックのブロガーイベント

All About「デジタルビデオ」ガイドの阿部信行氏による動画撮影のコツ的な話もありました。


当日のTweetですが、なかなかタメになる話が満載でしたね。


はてな&パナソニックのブロガーイベント

そのあとは、阿部氏とパナソニックの方から、実機を使ったデモやアドバイスなどの話。


会場の方や阿部氏から、製品担当の方に結構突っ込んだ質問もあったりしたのですが、↑でTweetした通り、製品を開発する上で、様々な試行錯誤があったんだなーと思わせる話であったり、こだわりを垣間見たりなどで、なかなか興味深かったです。


最後に

今回、新製品(しかもハイエンドなやつ)をお借りできて、色々おもちゃとして楽しませてもらったのも良かったですが、純粋に製品開発した裏話なんかは面白かったので、また機会があったら参加したいなーという気持ちになりました。

はてなさん、パナソニックさん、色々とありがとうございましたー!


あわせて読みたい

2014/03/12

Redis

Redis(2.8系)の基本オペレーションとかSentinelの挙動とかの色々メモ


最近必要に迫られて、ようやくRedisをインストールして触ってみました。(Redis童貞からの脱却)

色々と、基本部分ではあるけど、せっかく実際に触りながら勉強したので、このエントリにメモしておこうと思います。

尚、使ってみたRedisのバージョンは、stableの最新版である2.8.7です。(OSは、LinuxのCentOS 6.5)


ちなみに、このエントリに書いていないような、Redisの基本的なアレコレについては、WEB+DB Press Vol.73のRedis特集(2.6向けではありますが)にほとんど書いてあるので読むべし。


さて、話は戻って、ここからが本題。

前提として試してみた環境は、サーバを3台用意して、その各サーバで"redis"プロセスと"redis-sentinel"プロセスを起動させるような構成です。

このエントリでは、設定の詳細というよりはコマンドレベルでのオペレーションとか気になった挙動について書こうと思う。


目次

長くなってしまったので目次をつけておくw

  • Redisのインストール
  • Redisの設定ファイルについて
  • Redisプロセスの起動
  • Redisプロセスの停止
  • インメモリデータの永続化について
  • Append Only File(AOF)モード
    • 手動で、AOFの再構成を行う
    • AOFファイルのチェック
  • レプリケーションの設定
    • 設定の持ち方
  • Slaveの切り離し
  • Redis Sentinelについて
    • Redis Sentinelの構成
  • マスタ/スレーブのノード情報をSentinelに尋ねる
    • マスタ情報の確認
    • スレーブ情報の確認
  • フェイルオーバーの挙動
    • 手動でフェイルオーバー
  • スレーブの再投入
    • データサイズによってのスレーブ再同期時間
    • スレーブ投入時、1台の設定のsentinel monitorのRedisマスタのホストを書き間違えた場合
  • PSYNC(Partial Resynchronization)
  • スレーブとして投入する際、持っているデータがマスタと違った場合
  • 3台のRedis/Sentinelの構成で、1台だけネットワーク分断が起こった場合
  • バックアップ
    • RDBファイルのチェック
  • リストア
  • IPv6での対応
  • 設定を変更するオペレーション
  • 簡易だけど性能テスト

Redisのインストール

いきなりですが、割愛しますw

一応このエントリで使った検証環境は、Redis 2.8.7のRPMファイルを自作していますが、ベースのSPECファイルはRemiリポジトリのものを参考にさせてもらいました。

以下リンク先より、ダウンロードできるRPMで同様のことができるはず。


あと、Redis起動時に警告されるので、

vm.overcommit_memory = 1

sysctl.confでこの辺の設定を有効にしておくとか。

あとは、maxclientsの数にあわせてlimits.confでFDの上限を増やしておくとか。


Redisの設定ファイルについて

ボリュームのある別エントリが書けそうなので、このエントリでは割愛しますw


Redisプロセスの起動

# /etc/init.d/redis start

redis-serverコマンドでもよい。


Redisプロセスの停止

$ redis-cli shutdown

ちゃんとRedis内のコマンドで終了させるが吉のようだ。


[14721] 06 Mar 14:42:19.313 # User requested shutdown...
[14721] 06 Mar 14:42:19.313 * Saving the final RDB snapshot before exiting.
[14721] 06 Mar 14:43:08.700 * DB saved on disk
[14721] 06 Mar 14:43:08.700 * Removing the pid file.
[14721] 06 Mar 14:43:08.700 # Redis is now ready to exit, bye bye...

正常に終了されると、上記のような感じのログになる。


[9480] 06 Mar 14:34:56.291 # User requested shutdown...
[9480] 06 Mar 14:34:56.291 * Saving the final RDB snapshot before exiting.

こちらは、"/etc/init.d/redis stop"で終了させた場合。

スクリプトでkillprocしてるからだと思うけど、"DB saved on disk"が出力されず[FAILED]と表示されてコワい。

(まー、この辺はスクリプト書き直せよ、って話ではある。)


インメモリデータの永続化について

Redisには、インメモリのデータを定期的にスナップショットする(ディスクに書き落とす)仕組みがある。

設定ファイルの"save"項のパラメータに従って自動でやってはくれるが、手動でディスクに書き込むためには以下のRedisのコマンドをたたく。


$ redis-cli save

全てのデータセットをディスクに保存する。ただし、保存が完了するまではデータベースにアクセスできなくなる。


$ redis-cli bgsave

ディスクへの保存処理をバックグラウンドで行ってくれる。(フォークして子プロセスが処理してくれてる。)

保存中もデータへのアクセスは読み書きともに可能。


$ redis-cli lastsave
(integer) 1394162355

最後にスナップショットが取られた時刻は↑のような感じで確認できるが、UNIXTIMEである。


$ date --date "@`redis-cli lastsave`" +"%Y/%m/%d %H:%M:%S"
2014/03/07 12:19:15

なので、古典的ではあるが、dateコマンドをかませば、もう少しビジブルな感じで確認できたりもする。


Append Only File(AOF)モード

Redisのデフォルトのデータ永続化は、上記のスナップショットで、↑にも書いたが定期的にスナップショットを行っている。

デフォルトの設定では、以下のように記載があり、

save 900 1
save 300 10
save 60 10000

これは、最後にSAVE(保存)されてから、

  • 900秒以内に1個以上のkeyが更新された場合
  • 300秒以内に10個以上のkeyが更新された場合
  • 60秒以内に10000個以上のkeyが更新された場合

のいずれかの条件を満たした場合に、BGSAVEを実行するという動作を意味します。


で、これだとマスタに予期せぬダウンが生じた場合に、永続化しているとはいえ、タイミングによっては直近のデータをロストする(失う)ことになります。


そこで、Append Only File(AOF)モードが用意されていて、これは変更操作を全てログに保存するモードになります。MySQLでいうバイナリログみたいなもの。(って書くと突っ込まれるか...)

ログファイルへの出力タイミングは「常に(always)」「1秒ごと(everysec)」「fsyncせずOSに書き出しを任せる(no)」の3種類です。


設定は"appendonly"をyesにして起動すればOK。

ただし、"appendonly"がyesの場合は、"appendfilename"で指定しているログファイルからメモリにロードされるため、途中からAOFを有効にする場合、ログファイルが無い状態から起動するので、データが空っぽになってしまうので、要注意!

途中からAOFを有効にする場合は、必ずRedisの起動中に

$ redis-cli config set appendonly yes

を実行して、オンラインでAOFを有効にしてから、設定ファイルを変更するなりします。


ちなみに、スナップショットに比べて、AOFのログファイルサイズは結構大きくなります。そのため、定期的に再構成が実行されます(バックグラウンドで実行される)。再構成が実行されると、ログファイルがコンパクトになり、以下のようなRedisのログが出力されます。

[1487] 11 Mar 22:29:45.425 * Background append only file rewriting started by pid 2778
[2778] 11 Mar 22:29:45.723 * SYNC append only file rewrite performed
[2778] 11 Mar 22:29:45.724 * AOF rewrite: 8 MB of memory used by copy-on-write
[1487] 11 Mar 22:29:45.726 * Background AOF rewrite terminated with success
[1487] 11 Mar 22:29:45.726 * Parent diff successfully flushed to the rewritten AOF (5119 bytes)
[1487] 11 Mar 22:29:45.726 * Background AOF rewrite finished successfully

手動で、AOFの再構成を行う

以下のコマンドを実行すべし。バックグラウンドで実行される。

$ redis-cli bgrewriteaof

AOFファイルのチェック

redis-check-aofコマンドで行う。

$ redis-check-aof /var/lib/redis/appendonly.aof
AOF analyzed: size=36201089, ok_up_to=36201089, diff=0
AOF is valid

こんな感じ。

もし、壊れていた場合は、"--fix"オプションで修復できるとのこと。


レプリケーションの設定

Redisはマスタに対して複数のスレーブをもてるし、スレーブのスレーブ(孫スレーブ)も作れる。非同期I/Oによるレプリケーション。スレーブはデフォルトRead Only。(slave-read-only が yes になっている)


設定は、スレーブ側のredis.confに以下の記載をする。

slaveof (マスタのIPアドレス) 6379

IPアドレスのところは、名前解決できるホスト名/FQDNとかでもよい。

もし、マスタのRedisを6379ポートで待ち受けていない場合は、6379のところを設定しているポート番号に変える。


$ redis-cli slaveof (マスタのIPアドレス) 6379

ちなみに、こんな感じでRedisのコマンドでも可能。


レプリケーションがはられると、以下のような感じでINFOコマンドで確認できる。

$ redis-cli info replication
# Replication
role:master
connected_slaves:2
slave0: .....
slave1: .....

・・・・・以下省略・・・・・

マスタ側から見ると、どのホストがスレーブなのかと、その状態が分かる。


$ redis-cli info replication
# Replication
role:slave
master_host: .....
master_port:6379
master_link_status:up

・・・・・以下省略・・・・・

スレーブ側から見ると、マスタへのレプリケーションのステータスとかがわかります。


設定の持ち方

個人的には、冗長構成を意識したときに、設定ファイルにマスタのありか(IPアドレスとか)を書いておくと、マスタが変更されたときに怖いことが起こる可能性があるので、設定ファイルには書かずにredis-cliとかで設定しておくのが良いのかなと思っていました。

が、が、、、後述しますが、Redis Sentinelを使っていると、sentinel君が勝手にredis.confに、slaveofを書いてくれたりします・・・w

いずれにせよ、マスタ/スレーブの状態管理は、基本的にSentinelに任せてしまう形がいいと思っている。


Slaveの切り離し

$ redis-cli slaveof no one

スレーブ側から上記のRedisコマンドをたたくと、マスタから切り離される。


追記

Sentinel構成でのスレーブノード切り離しは以下リンク先を参考にしてください。


Redis Sentinelについて

Redis Sentinelを使うと、各サーバのRedisプロセス(マスタ/スレーブ)の状態を監視してくれ、マスタに問題が発生したら、別のスレーブへ自動でフェイルオーバーしてくれるようになります。


port 26379
bind 0.0.0.0
daemonize yes
logfile "/var/log/redis/sentinel.log"
pidfile "/var/run/redis/sentinel.pid"
dir "/var/lib/redis"

sentinel monitor mymaster (マスタのアドレス) 6379 2
sentinel down-after-milliseconds mymaster 10000
sentinel failover-timeout mymaster 900000
sentinel parallel-syncs mymaster 1

Sentinelの設定ファイル(/etc/redis-sentinel.conf)は、↑のような感じにした。

今回、Sentinelは3台構成なので、quorumの数は"2"にしている。(sentinel monitorの項の一番右端のパラメータ)


# /etc/init.d/redis-sentinel [start|stop]

ちなみに、Sentinelの起動/停止は、以下のような感じ。


Redis Sentinelは起動すると、設定してあるRedisのマスタノードにアクセスを行い、レプリケーションまわりの情報などを取得し、スレーブノードを把握します。

また、設定ファイルを確認すると、それらの情報が自動的に書き込まれていることがわかります。(!)


Redis Sentinelの構成

下記リンク先で、けんじおじさんも書いているけど、Split-brain-syndromeを防ぐ意味でも、複数台のSentinelを出来る限りネットワーク構成を意識して、動かしておくべきだと思う。


マスタ/スレーブのノード情報をSentinelに尋ねる

マスタネームの部分(mymaster)は、適宜置き換えてください。

(26379番ポートはSentinelプロセスがLISTENしているポート番号。)


マスタ情報の確認
$ redis-cli -p 26379 sentinel master mymaster
 1) "name"
 2) "mymaster"
 3) "ip"
 4) "(マスタのアドレス)"

・・・・・省略・・・・・

スレーブ情報の確認
$ redis-cli -p 26379 sentinel slaves mymaster
1)  1) "name"
    2) "(スレーブ1のアドレス):6379"
    3) "ip"
    4) "(スレーブ1のアドレス)"

・・・・・省略・・・・・

2)  1) "name"
    2) "(スレーブ2のアドレス):6379"
    3) "ip"
    4) "(スレーブ2のアドレス)"

・・・・・省略・・・・・

フェイルオーバーの挙動

実際にマスタを落とすとどういうことが起こるかログで追ってみる。

登場人物は以下の3つ。

  • 旧マスタ(今からダウンする。)
  • 新マスタ(元々はスレーブ。旧マスタのダウン後に、新マスタとして昇格)
  • スレーブ(基本的にスレーブのままだったノード)

まず、テストのため旧マスタをダウンさせる。

[28424] 08 Mar 00:02:30.907 # +sdown sentinel (旧マスタのアドレス):26379 (旧マスタのアドレス) 26379 @ mymaster (旧マスタのアドレス) 6379
[28424] 08 Mar 00:02:31.895 # +sdown master mymaster (旧マスタのアドレス) 6379

この時、スレーブのノードのsentinelのログを見ると、しばらく(およそ"down-after-milliseconds"の設定値)して旧マスタのsdownを検知。(自身のSentinelプロセスが旧マスタのダウンを検知。)

[28424] 08 Mar 00:02:36.258 # +new-epoch 1
[28424] 08 Mar 00:02:36.258 # +vote-for-leader 42c4a78c19874f75daef42368d568422972e18d9 1
[28424] 08 Mar 00:02:37.068 # +odown master mymaster (旧マスタのアドレス) 6379 #quorum 2/2
[28424] 08 Mar 00:02:37.491 # +switch-master mymaster (旧マスタのアドレス) 6379 (新マスタのアドレス) 6379

そこから、リーダーの選出および、旧マスタのodownを検知。(quorumパラメータで指定した数のSDOWN)

"quorum 2/2"の記載がありますね。そこから新マスタが選ばれて、switch-masterが走ります。


[28424] 08 Mar 00:02:37.491 * +slave slave (スレーブのアドレス):6379 (スレーブのアドレス) 6379 @ mymaster (新マスタのアドレス) 6379
[28424] 08 Mar 00:02:37.493 * +slave slave (旧マスタのアドレス):6379 (旧マスタのアドレス) 6379 @ mymaster (新マスタのアドレス) 6379
[28424] 08 Mar 00:02:42.507 # +sdown slave (旧マスタのアドレス):6379 (旧マスタのアドレス) 6379 @ mymaster (新マスタのアドレス) 6379

そして、Sentinelの持つ情報としてスレーブ情報の更新をします。旧マスタがスレーブへと降格して、ダウンした状態であることが検出されます。


手動でフェイルオーバー

ちなみに、Redis Sentinelを使っていると手動でフェイルオーバーさせることもできます。意図的に実施するので、フェイルオーバーというよりはテイクオーバーと言うべきか。

$ redis-cli -p 26379 sentinel failover mymaster

こんな感じで実行すると、別のスレーブがマスタへと昇格し、旧マスタはスレーブになります。

マスタネームの部分(mymaster)は、適宜置き換えてください。


スレーブの再投入

さて、ここまで↑の流れで旧マスタはダウンしたままですが、復帰させてみます。

この時点で、旧マスタはRedisプロセスもSentinelプロセスも停止したままです。


まず、旧マスタのRedisプロセスを起動します。

[28424] 08 Mar 02:12:28.289 # -sdown slave (旧マスタのアドレス):6379 (旧マスタのアドレス) 6379 @ mymaster (新マスタのアドレス) 6379

すると、他のSentinelから復旧したことが検知(sdownステータスが消滅)され、この時点でスレーブとしてレプリケーションが始まります。なんて優秀な子なの・・・!


次に、Sentinelの設定ファイルは、マスタの指定として、旧マスタが指定されたままの状態ですが、あえてこのままSentinelプロセスを起動してみましょう。


[28424] 08 Mar 02:17:04.590 # -sdown sentinel (旧マスタのアドレス):26379 (旧マスタのアドレス) 26379 @ mymaster 10.34.67.38 6379
[28424] 08 Mar 02:17:06.610 * -dup-sentinel master mymaster (新マスタのアドレス) 6379 #duplicate of (旧マスタのアドレス):26379 or 046473c114c613a4129606d5e7869b8ac74c4898
[28424] 08 Mar 02:17:06.610 * +sentinel sentinel (旧マスタのアドレス):26379 (旧マスタのアドレス) 26379 @ mymaster (新マスタのアドレス) 6379

すると、こんな感じで、Duplicateが検知され、正しい情報に直されて問題なく起動しました・・・。Sentinelの設定ファイルも正しいマスタ/スレーブの情報が記載されています。


データサイズによってのスレーブ再同期時間

試しにまっさらなスレーブ(ゼロデータ)を作って、適当なテストデータを持つ、約2500万Key、約7.0GBメモリデータ量、RDBファイル(後述)約1.9GBで構成されたマスタに対して、レプリケーションをはってみます。

ログを見るとわかりやすいですが、以下のような挙動です。


[22377] 10 Mar 02:37:48.061 * SLAVE OF (マスタのアドレス):6379 enabled (user request)
[22377] 10 Mar 02:37:48.081 * Connecting to MASTER (マスタのアドレス):6379
[22377] 10 Mar 02:37:48.081 * MASTER <-> SLAVE sync started
[22377] 10 Mar 02:37:48.081 * Non blocking connect for SYNC fired the event.
[22377] 10 Mar 02:37:48.083 * Master replied to PING, replication can continue...
[22377] 10 Mar 02:37:48.083 * Partial resynchronization not possible (no cached master)
[22377] 10 Mar 02:37:48.084 * Full resync from master: 39590427e03792c2d34904f163b57c024707e91e:575
[22377] 10 Mar 02:38:37.742 * MASTER <-> SLAVE sync: receiving 2027774958 bytes from master
[22377] 10 Mar 02:38:55.390 * MASTER <-> SLAVE sync: Flushing old data
[22377] 10 Mar 02:38:55.390 * MASTER <-> SLAVE sync: Loading DB in memory
[22377] 10 Mar 02:39:50.654 * MASTER <-> SLAVE sync: Finished with success
  • マスタに接続する
  • 部分再同期を試みる(不可状態だったので完全再同期を実施)
  • マスタからRDBファイルを受信
  • 完全再同期なので古いデータのフラッシュ
  • RDBファイルからメモリへデータの展開
  • 完了後、サービスを開始(この段階でデータにアクセス可能)

「Xeon-E5(SandyBridge), SAS(15000rpm)x4(RAID10), CentOS6系KVMによる仮想マシン」だと、上記のような感じでした。ざっくりですが転送に49秒、メモリへのロードに55秒ですね。

このあたりはマシンのスペックやネットワーク環境に依存しますので、参考までに。


スレーブ投入時、1台の設定のsentinel monitorのRedisマスタのホストを書き間違えた場合

"dup-sentinel master"というログが出力されて検知されます。

その後、設定が正しいステータスに修正されて動き続けるため、心配ご無用でした。


PSYNC(Partial Resynchronization)

Redis 2.8系から、PSYNC(Partial Resynchronization)と呼ばれる部分的な再同期の仕組みをRedisはサポートしています。

Starting with Redis 2.8, master and slave are usually able to continue the replication process without requiring a full resynchronization after the replication link went down.

This works by creating an in-memory backlog of the replication stream on the master side. The master and all the slaves agree on a replication offset and a master run id, so when the link goes down, the slave will reconnect and ask the master to continue the replication. Assuming the master run id is still the same, and that the offset specified is available in the replication backlog, replication will resume from the point where it left off. If either of these conditions are unmet, a full resynchronization is performed (which is the normal pre-2.8 behavior).

Replication ? Redis

バージョン2.8以前では、マスタとスレーブのレプリケーションリンクがダウンした際に、完全な再同期が必要だったみたいですが、2.8以降では部分的な再同期をサポートしています。

2.8では、レプリケーションストリームをメモリ内のバックログで保持していて、レプリケーションリンクがダウンした後、スレーブがマスタに再接続にいった際に、これまでレプリケーションを行っていたマスタ実行IDをリクエストし、一致していてかつ指定されたオフセットがレプリケーションのバックログから利用可能であれば、レプリケーションが中断されたところから、再開(部分的に同期)します。


ログ的には、

[22862] 10 Mar 21:09:32.225 * Connecting to MASTER (マスタのアドレス):6379
[22862] 10 Mar 21:09:32.226 * MASTER <-> SLAVE sync started
[22862] 10 Mar 21:09:32.227 * Non blocking connect for SYNC fired the event.
[22862] 10 Mar 21:09:32.227 * Master replied to PING, replication can continue...
[22862] 10 Mar 21:09:32.228 * Trying a partial resynchronization (request 7ddd9c24985efd4a0fe3866bfa27291ce2396017:191305).
[22862] 10 Mar 21:09:32.229 * Successful partial resynchronization with master.
[22862] 10 Mar 21:09:32.229 * MASTER <-> SLAVE sync: Master accepted a Partial Resynchronization.

こんな感じで、再接続に成功した後に、partial resynchronizationを試みています。


尚、注意点としては、意図的にレプリケーションを止めた(slaveof no one)ときは、いったんマスタの情報(ID)を失うことになるので、その後もう一度レプリケーションリンクを作成しても、完全な再同期となります。


あと、レプリケーションのバックログのサイズやTTLに関しては、

  • repl-backlog-size
  • repl-backlog-ttl

あたりで指定可能です。


参考

スレーブとして投入する際、持っているデータがマスタと違った場合

マスタが保持しているデータが正しい状態と認識し、スレーブは完全にマスタのデータと同期される状態になる。

(非同期なレプリケケーションをしている以上、タイミングによってはマスタとスレーブのデータがずれてしまうこともあるため、フェイルオーバー時などのデータの取り扱いは注意しておくべし。)


3台のRedis/Sentinelの構成で、1台だけネットワーク分断が起こった場合

redis01redis02redis03
masterslaveslave

という構成だったとしよう。

この3台のうち、redis01だけネットワーク分断が発生して独立してしまったとする。

redis01だけ疎通が取れない状態なので、redis02とredis03は協調して、マスタのフェイルオーバーを行い、redis01はslave扱いにする。

しかし、redis01は、redis02とredis03のスレーブノードがダウンしたという判定をしてマスタであり続ける。


その結果、以下のような状態となる。

redis01redis02redis03
mastermasterslave

次に、ネットワーク分断していたredis01を再びネットワーク疎通が取れた場合、他sentinelの状態を確認し、switch-masterを行い、自身をスレーブにする。その結果、以下の構成となる。

redis01redis02redis03
slavemasterslave

なかなか優秀な挙動だ。


バックアップ

"インメモリデータの永続化について"のところで記載した、SAVE または BGSAVE を実行するとデータがディスクへと保存される。(セーブが完了したかは、LASTSAVEコマンドで確認しましょう)

バックアップはそのファイルを別の場所にとっておけばいい。

ファイルは、redis.confで設定されている"dir"のディレクトリに、"dbfilename"で設定しているファイル名で取得されているはず。


Redis is very data backup friendly since you can copy RDB files while the database is running: the RDB is never modified once produced, and while it gets produced it uses a temporary name and is renamed into its final destination atomically using rename(2) only when the new snapshot is complete.

Redis Persistence ? Redis

尚、RDBファイルは普通にコピーして保存すればよいとの事。


RDBファイルのチェック

Redisには「redis-check-dump」という、RDBファイルに問題が無いかを確認するコマンドがある。

$ redis-check-dump /var/lib/redis/dump.rdb
==== Processed 24821447 valid opcodes (in 2027774941 bytes) ====================
CRC64 checksum is OK

こんな感じで実行してチェックすることができる。


リストア

バックアップの逆のことをすれば良いだけ。要は、RDBファイルをredis.confで指定されている"dir", "dbfilename"に従って配置し、Redisを起動すればOKです。


IPv6での対応

IPv6環境でも稼動させてみたが、Redisプロセス自体は軽く確認していた限り問題なく動いている。

ただし、Sentinel側で、各ノードのIPv6アドレスが正常な形式で取得できず、きちんと動作しない。マスタのダウンを検知して、フェイルオーバー処理は行うものの、途中で全Sentinelプロセス自体がクラッシュして落ちる始末。今後に期待したい。


=== REDIS BUG REPORT START: Cut & paste starting from here ===
[1778] 27 Feb 20:06:22.278 #     Redis 2.8.6 crashed by signal: 11
[1778] 27 Feb 20:06:22.278 #     Failed assertion: <no assertion failed> (<no file>:0)
[1778] 27 Feb 20:06:22.278 # --- STACK TRACE

実は、IPv6を検証したのはバージョン2.8.6ではあったのだが、、、上記のようなログが出力されて落ちた。


設定を変更するオペレーション

例えば、maxmemoryを増やすオペレーションをやってみる。単純だが以下の2通り。

  • redis.confのmaxmemoryのパラメータを変更して、Redisプロセスの再起動
  • 以下のようにRedisのCONFIG SETコマンドを使う

$ redis-cli config set maxmemory 8589934592

上記は、maxmemoryを8GBに変更した例。

ちなみに、インメモリで持ってる容量を下回る設定も"OK"と返り、設定変更されたので、なかなかカジュアルに変えれる感があって怖い・・・w


簡易だけど性能テスト

  • Xeon-E5(SandyBridge), SAS(15000rpm)x4(RAID10), CentOS6系KVMによる仮想マシン。
  • マスタのデータは、約2500万Key、約7.0GBメモリデータ量、RDBファイル(後述)約1.9GBな状態。
  • AOFは無効
  • マスタ1に対してスレーブ2な環境。
  • マスタにてredis-benchmarkコマンドをローカルに対して実施。

$ redis-benchmark -q
PING_INLINE: 103092.78 requests per second
PING_BULK: 103092.78 requests per second
SET: 86956.52 requests per second
GET: 98039.22 requests per second
INCR: 63291.14 requests per second
LPUSH: 69930.07 requests per second
LPOP: 72992.70 requests per second
SADD: 84033.61 requests per second
SPOP: 84033.61 requests per second
LPUSH (needed to benchmark LRANGE): 68965.52 requests per second
LRANGE_100 (first 100 elements): 43290.04 requests per second
LRANGE_300 (first 300 elements): 22321.43 requests per second
LRANGE_500 (first 450 elements): 17064.85 requests per second
LRANGE_600 (first 600 elements): 13513.51 requests per second
MSET (10 keys): 42016.80 requests per second


$ redis-benchmark -q -d 100
PING_INLINE: 99009.90 requests per second
PING_BULK: 101010.10 requests per second
SET: 72992.70 requests per second
GET: 96153.84 requests per second
INCR: 83333.34 requests per second
LPUSH: 76335.88 requests per second
LPOP: 86956.52 requests per second
SADD: 102040.82 requests per second
SPOP: 100000.00 requests per second
LPUSH (needed to benchmark LRANGE): 76923.08 requests per second
LRANGE_100 (first 100 elements): 39062.50 requests per second
LRANGE_300 (first 300 elements): 12330.46 requests per second
LRANGE_500 (first 450 elements): 7547.17 requests per second
LRANGE_600 (first 600 elements): 5455.54 requests per second
MSET (10 keys): 30030.03 requests per second


$ redis-benchmark -q -d 1000
PING_INLINE: 72992.70 requests per second
PING_BULK: 96153.84 requests per second
SET: 66666.66 requests per second
GET: 68965.52 requests per second
INCR: 74074.07 requests per second
LPUSH: 53763.44 requests per second
LPOP: 70921.98 requests per second
SADD: 77519.38 requests per second
SPOP: 76923.08 requests per second
LPUSH (needed to benchmark LRANGE): 54644.81 requests per second
LRANGE_100 (first 100 elements): 8976.66 requests per second
LRANGE_300 (first 300 elements): 2975.30 requests per second
LRANGE_500 (first 450 elements): 1782.85 requests per second
LRANGE_600 (first 600 elements): 1241.16 requests per second
MSET (10 keys): 15974.44 requests per second


$ redis-benchmark -q -d 10000
PING_INLINE: 64935.07 requests per second
PING_BULK: 64102.56 requests per second
SET: 18115.94 requests per second
GET: 60975.61 requests per second
INCR: 62893.08 requests per second
LPUSH: 21321.96 requests per second
LPOP: 40322.58 requests per second
SADD: 73529.41 requests per second
SPOP: 86956.52 requests per second
LPUSH (needed to benchmark LRANGE): 32679.74 requests per second
LRANGE_100 (first 100 elements): 831.60 requests per second
LRANGE_300 (first 300 elements): 281.19 requests per second
LRANGE_500 (first 450 elements): 188.22 requests per second
LRANGE_600 (first 600 elements): 135.57 requests per second
MSET (10 keys): 14245.01 requests per second

ちなみに、VM to VM (CentOS 6 on KVM, Max 1Gbps)な環境で取得すると、Maxが65000reqests/secあたりでキャップされていた。(ネットワーク通信のオーバーヘッド)


他、参考になるリンク

Redis 2.8 でSentinelまわりの挙動について検証された結果が記載されている。



オススメ (一部は、最近読んでいる本とも言う)
Chef実践入門 ~コードによるインフラ構成の自動化 (WEB+DB PRESS plus) クラウド Amazon EC2/S3のすべて~実践者から学ぶ設計/構築/運用ノウハウ~ [Web開発者のための]大規模サービス技術入門 ―データ構造、メモリ、OS、DB、サーバ/インフラ (WEB+DB PRESS plusシリーズ) エキスパートのためのMySQL[運用+管理]トラブルシューティングガイド [24時間365日] サーバ/インフラを支える技術 ~スケーラビリティ、ハイパフォーマンス、省力運用 Linux-DB システム構築/運用入門 (DB Magazine SELECTION) キャパシティプランニング ― リソースを最大限に活かすサイト分析・予測・配置 スケーラブルWebサイト 実践ハイパフォーマンスMySQL 第3版 ウェブオペレーション ―サイト運用管理の実践テクニック (THEORY/IN/PRACTICE) SQLアンチパターン インターネットのカタチ―もろさが織り成す粘り強い世界― ハイパフォーマンス ブラウザネットワーキング ―ネットワークアプリケーションのためのパフォーマンス最適化 Linuxの教科書―ホントに読んでほしいroot入門講座 (IDGムックシリーズ)