GCEインスタンスでpostgresqlをフェイルオーバーさせる

GCEでは、単一インスタンスに同一ネットワークのIPアドレスを複数持たせる事ができない。
複数のネットワーク インターフェースの概要と例

つまり、Virtual IPを同一セグメントに持たせた構成は出来ない。

クラスタを組みたかったけど、今回の要件としては

1. Active/Standbyの構成にする
2. Activeのpostgresが止まった場合、Standbyを昇格する
3. フェイルバックは行わない。
4. フェイルオーバー後、App側で検知。
   必要な設定変更後、動的にサービスの再起動を行う。
5. 1分以内にサービスが復旧される。

とシンプルな構成にする。

PostgreSQL

要件1、2には、pg_keeperを使う。
クラスタでは無いのでスプリットブレインの検知などは出来ない。
その為、アプリケーション側に今のActive機の情報を教える必要がある。

スプリットブレイン対策用のDB、Table作成

postgres=#  create database pg_state;
postgres=#  create table failover_log (unixtime int, host varchar(10));

インストール(Actice/Standby共に)

cd /usr/local/src

git clone https://github.com/MasahikoSawada/pg_keeper.git

export PATH=/usr/pgsql-9.6/bin/:$PATH

make USE_PGXS=1

make USE_PGXS=1 install

postgresql.conf書き換え(Actice/Standby共に)

vim postgresql.conf

shared_preload_libraries = 'pg_keeper'
pg_keeper.my_conninfo = 'host=10.0.0.10 port=5432 dbname=postgres'
pg_keeper.partner_conninfo = 'host=10.0.0.11 port=5432 dbname=postgres'
pg_keeper.keepalive_time = 2
pg_keeper.keepalive_count = 3
pg_keeper.after_command = 'sleep 1 ; psql -d pg_state -c "insert into failover_log values(`date +%s`, \'`hostname`\');" -x'

Activeが止まった場合、pg_keeper.keepalive_time秒 × pg_keeper.keepalive_count回 チェックを行い、全てNGの場合にフェイルオーバーを実行し、最後にpg_keeper.after_commandの内容が実行される。
今回は、フェイルオーバー後に[unixtimestamp, hostname]を pg_state.failover_logに入れている。

app側

これはアプリケーションのよるので参考まで。
monitor_master_db.pyというモニタリングスクリプトを作成し、root権限で動かす事にした。
動きとしては、Active/Standby両機のDBのpg_state.failover_logをチェックし、タイムスタンプが若い方をDB接続先として、設定ファイル(yaml)を書き換えデーモンの再起動を行う。

#!/bin/env python3

import os,sys
import yaml
import psycopg2
import codecs
import subprocess

yaml_file = '/PATH/TO/env.yaml'
dbs = ['postgresql://postgres@db01:5432/pg_state'
         ,'postgresql://postgres@db02:5432/pg_state']

def get_item():
    arr = []
    for db in dbs :
        try:
            dbcon = psycopg2.connect(db)
            cur = dbcon.cursor()
            cur.execute('select * from failover_log order by unixtime desc limit 1')
            result = cur.fetchone()
            cur.close()
            dbcon.close()
            arr.append(result)
        except :
            pass
    if len(dbs) == len(arr):    # Active/Standby共にデータ取得成功
        if arr[0][0] > arr[1][0]:
            return arr[0][1]
        else :
            return arr[1][1]

    else :                             # 片系が停止している
        return arr[0][1]


def overwrite(db_name):
    with codecs.open(yaml_file, 'r', 'utf-8') as read :
        env_dict = yaml.load(read)

        if env_dict['db_master'][0]['address'] != '{}:5432'.format(db_name) or env_dict['db_slave'][0]['address'] != '{}:5432'.format(db_name):
            env_dict['db_master'][0]['address'] = '{}:5432'.format(db_name)
            env_dict['db_slave'][0]['address'] = '{}:5432'.format(db_name)

            with codecs.open(yaml_file, 'w', 'utf-8') as write :
                yaml.dump(env_dict, write, encoding='utf8', allow_unicode=True, default_flow_style=False)

            try:
                subprocess.check_call(["systemctl", "restart", "デーモン"])
            except :
                pass

作成したmonitor_master_db.pyをcronで動かす。
cronは普通に書くと1分が最小の実行単位だが、以下のように書くと5秒単位でスクリプトを実行してくれる。

# 5秒間隔
* * * * * for i in `seq 1 12`;do sleep 5; python3 /usr/local/bin/monitor_master_db.py; done

# 10秒間隔の場合
* * * * * for i in `seq 1 6`;do sleep 10; python3 /usr/local/bin/monitor_master_db.py; done

この状態で、Active側のDBを落として、フェイルオーバーされApp側の接続先も変更される事を確認する。
Slave側が昇格前にfailover_logへのinsertが実行される場合、pg_keeper.after_commandのsleepを大きくする。

pg_keeper.after_command = 'sleep 5 ; psql -d pg_state -c "insert into failover_log values(`date +%s`, \'`hostname`\');" -x'

パフォーマンスカウンタのネットワークのスケール

スケール調整の覚書

グラフ枠のプロパティ/グラフ/垂直スケール の最大値を100から1000に上げる

NetworkInterface/NIC名/Bytes Sent/sec
 ・・・ GigaNicを積んでいる場合、スケールは0.00001 でxxxMB/s
     ※グラフ赤線

NetworkInterface/NIC名/Packet Sent/sec
 ・・・ GigaNicを積んでいる場合、スケールは0.001 でxxxMbps
     ※グラフ黄緑線

perfmon_20160913

windows2012のQoSが効かない場合の注意点

新規にwindows2012サーバーを準備し、WindowsでポリシーベースのQOSを使ってS3へのアップロードスピードを帯域制御する方法をトレースしてみた。

QoSの設定はこの通りだが、「出力方向のスロットル率を指定する」には注意が必要。

検証では200MBbpsに設定を行ったが、物理1Gの回線環境で800MBps以上トラフィックが流れてしまう。
qos_1

qos_2

MSに問い合わせをして調査、検証を行った結果、

windows2012のインストール時点のQoSのバグっぽい事まで突き止める。
(Windowsアップデートしたら動きが改善されているので、どこかでパッチが当たった模様)

Windowsアップデート前: 制限の設定値の10倍が実際の制限値となる。
 ・ QoSを200MBps(204800 KBps)に制限 → トラフィックが200MBps以上
 ・ QoSを 20MBps(20480 KBps) に制限 → トラフィックは200MBps以下になる

Windowsアップデート後: 制限の設定値と同じ値が実際の制限値となる。
 ・ QoSを200MBps(204800 KBps)に制限 → トラフィックが200MBps以下になる

MSからKB番号の返答が来たら追記します。

1階に有線LANを通す!

久しぶりの更新w

約3ヶ月振りです(サボり過ぎ!)

さて、我が家のネットワークは、2階の子供部屋に”情報分伝盤”とやらが取り付けられており、そこにアンテナからのTV配線や光の終端装置が設置されています。

嫁が1階でPCを使うので、今までは2階に無線LANのAPを置いていましたが、最近の暑さでAPやルーターが過剰に熱を持ってしまい、日中にネットに繋がらないとクレームを度々言われていました(^^;)

そこで、嫁対策の為に、情報分伝盤の近くに小型の扇風機を置いてルーターを冷ますのと、1階にAPを移設して嫁PCの電波感度の向上を行ってみました!

1階にAPを置くには、LANケーブルを1階に通す必要がありますが、幸い壁の中にCD管が埋め込まれていたので、この中にLANケーブルを
通すことにしました。

ネットで調べてみると、引込み線たる針金が必要らしいですが、数十メートルで\4,000とか結構いい値段がしてしまいます(^^;)

そんなお金は小遣いから捻出出来るはずも無いので、さらに調べてみると、100均のビニール紐と掃除機で代用できると情報を見つけました!

LAN工事ドットコム様

で、まねてみました!

写真は取っていませんでが、ビニール紐+掃除機で、らくらく呼び込み線は開通!

で、ビニール紐の片側にLANケーブルを固定し、反対から引っ張るのみ!

20100822_1.jpg
通ったーーー!

コンセント部分は、Amazonで安価だったモジュラジャックを購入。
モジュラジャック(Amazon)

20100822_2.jpg
ケーブルを剥き、モジュラジャックの所定の位置に配線をして、、、

20100822_3.jpg
付属の部品でケーブルを挟む!
で、コンセント部分の完成!
20100822_4.jpgあとは、壁に取り付けるだけw
20100822_5.jpg
子供らに邪魔されながらの作業でしたが、1人でやって大体2時間程度で終了。
電気屋さんに工事費用に聞いたら¥12,000って言われていた工事が、部品代だけで¥2,000ぐらいで収まったのが1番うれしいw

あと、2階の機器に扇風機の風を当てているので、少しは嫁からのクレームも無くなるかな。

ロードバランサーの動作

syslogさんからロードバランサーの動作概要を引用させて頂きます。

▼least connections <リースト・コネクション> [動的]
最もコネクション数の少ないサーバを選択してロードバランスを行う。
▼hash <ハッシュ> [動的]
クライアントのIPアドレスをハッシュ値計算し、相対させたサーバにバランシングする。つまりあるIPアドレスのものは常にそのサーバにバランシングされる。
▼round robin <ラウンド・ロビン> [静的]
複数のサーバに対して均等にロードバランスを行う。

▼fastest <ファーステスト> [動的]
最も速く応答するサーバを選択してロードバランスを行う。
▼observed <オブザーブド> [動的]
サーバのコネクション数と応答速度を監視して、ロードバランスを行う。
▼predictive <プリディクティブ> [動的]
サーバのコネクション数と応答速度を監視し、各サーバのパフォーマンスを予測してロードバランスを行う。
▼priority <プライオリティ> [静的]
あらかじめ指定されたサーバグループ毎の優先度に応じてロードバランスを行う。
▼ratio <レシオ> [静的]
複数のサーバに対してあらかじめ指定した割合に応じてロードバランスを行う。
▼static load balancing <スタティック・ロードバランシング> [静的]
あらかじめ定義された基準リストに基づいて接続配分を行う方式。その基準としては、現在のサーバ性能や現在の接続負荷は考慮していない。