たけまるの日記

たけまるの日記です。web関係の技術ネタが多いですが、好きなことを適当に書いています。

最小ダウンタイムでMySQLレプリケーションを構築する

既に稼働しているMySQLレプリケーションを構築する場合の手順です。 結論から言えば、高々1回のマスターDB再起動でレプリケーションの構築が可能で、通常であればダウンタイム1分以内です。 作業中にマスターDBに長時間ロックがかかることもありません。

対象はMySQL5.6ですが、MySQL5系なら同様の手順でいけると思います。 MySQL5.6からはGTIDレプリケーションもサポートされましたが、今回は諸事情により見送ることにしました。

以下手順です。

マスターのbinlog出力を有効にする

master# vi /usr/my.cnf
[mysqld]
log-bin=mysql-bin
server-id=1

master# service mysql restart

唯一のダウンタイムがこれですが、既にバイナリログが有効になっている場合はこの手順は不要です。

レプリケーション用のユーザーを作成

(master)mysql> GRANT REPLICATION SLAVE ON *.* TO 'repl'@'slaveip' IDENTIFIED BY 'slavepass';

マスターのdump取得

master# mysqldump --all-databases --master-data --single-transaction > dbdump.sql

「--master-data」がキモですね。dumpと同時に現在のバイナリログの位置を取得できます。 また、「--single-transaction」することにより、テーブル間の整合性がとれた状態のダンプを、ロックなしに取得できます。(これをつけないダンプ中は書込ロックされます)

スレーブ側の設定

slave# vi /usr/my.cnf
[mysqld]
log-bin=mysql-bin
server-id=10

slave# service mysql restart

スレーブ側をレストア

slave# mysql < dbdump.sql

レプリケーション開始

$ grep -i "CHANGE MASTER TO" dbdump.sql
CHANGE MASTER TO MASTER_LOG_FILE='mysql-bin.000001', MASTER_LOG_POS=12345678;

(slave)mysql> CHANGE MASTER TO
  MASTER_HOST='masterip',
  MASTER_USER='repl',
  MASTER_PASSWORD='slavepass',
  MASTER_LOG_FILE='mysql-bin.000001',
  MASTER_LOG_POS=12345678;
(slave)mysql> START SLAVE;

確認

(master)mysql> show master status;
(slave)mysql> show slave status;

参考

http://mysql.manual.php.to/replication.html#replication-howto http://qiita.com/hit/items/7747394e8f2f6a515535 http://tmtms.hatenablog.com/entry/20110713/mysqldump

1クエリで一度に大量のレコードをupdateしてはいけない

2億レコードくらい入ってるテーブルにこれ流したらディスク逼迫して死んだ。

mysql> UPDATE table SET col = NULL;

数時間後、繋がってるサービスの画面が「500 Internal Server Error」。 みたらディスク空きが0になってた。

なにがでかくなってたかというと

# ls -alh /var/lib/mysql
(抜粋)
-rw-rw----   1 mysql mysql  18G Jan  8 16:58 ibdata1

ちなみにinnodb_file_per_tableは有効(デフォルト)である。 要はテーブルの実データはibdata1には入ってない。 のにこの容量である。

というわけで調べたら、トランザクションの一貫性のため、ibdata1にはUNDOログ(更新前データのスナップショット)が書き込まれるとの事。1トランザクションで全レコードを更新しようとしたため、2億レコード分のスナップショットを作るはめになったらしい。ちなみにこのファイル、一度でかくなったら小さくなることはない。つまり詰んだ。

おかげでリカバリために多くの労力を費やすはめになったのであった。

もう一度言う。

1クエリで一度に大量のレコードをupdateしてはいけない。

参考

https://hiroakis.com/blog/2013/08/22/mysql-%E3%81%AA%E3%81%9Cibdata1%E3%81%8C%E8%82%A5%E5%A4%A7%E5%8C%96%E3%81%99%E3%82%8B%E7%90%86%E7%94%B1%E8%A8%98%E4%BA%8B%E3%81%AE%E6%84%8F%E8%A8%B3/

さくらクラウドでルートパーティションの容量を拡張する方法

追記:この手順を実施する場合の注意を記事中下部に追加しました。

あけましておめでとうございます。

訳あってさくらクラウドを使うことになりました。

250Gのディスクを選択してVMを作成したのだけど、さくらが用意したCentOSのイメージ「[public] 20GB CentOS 6.6 64bit (基本セット)」で起動したらOS上で20Gしか認識されていない…。

それもそのはずで、OSイメージは20Gを前提に作成されたものでした。

別途「100G」というのも用意されていたのですが、今回は250Gにしたかったのでなんとか拡張してみました。

(クリティカルな操作なので自己責任で、バックアップ必須!)

VM作成

  1. 普通にVM作成
    • ディスクソース : [アーカイブ(簡単)]
    • アーカイブ選択 : [public] 20GB CentOS 6.6 64bit (基本セット)
    • ディスクサイズ : [20G]
    • 作成後すぐに起動 : [しない]

追加ディスクの作成(本命ディスク)

  1. 管理画面 [ストレージ] -> [追加]押下
  2. 以下設定
    • ティスクソース : [ブランク]
    • ディスクサイズ : [250GB]
    • 名前 : 「testvm-250G」
  3. [作成]押下

拡張作業

  1. 管理画面 [サーバ] -> 該当VMを選択 -> [詳細] -> [ディスク] -> [接続]押下
  2. [testvm-250G]を選択して[更新]
  3. 接続#1に元の[testvm]、接続#2に[testvm-250G]が接続されているのを確認する
  4. VM起動
  5. 以下コマンド実行
### 起動ドライブはvda、追加したドライブがvdbとして認識されている
# ls /dev/vd*
/dev/vda  /dev/vda1  /dev/vda2  /dev/vdb

### 中身をコピー(3分半程度、速い…!)
# dd if=/dev/vda of=/dev/vdb bs=512M

### パーティションの拡張
# parted /dev/vdb
(parted) unit s
(parted) print
Model: Virtio Block Device (virtblk)
Disk /dev/vdb: 524288000s
Sector size (logical/physical): 512B/512B
Partition Table: gpt

Number  Start     End        Size       File system     Name     Flags
 1      64s       8400487s   8400424s   linux-swap(v1)  primary
 2      8400488s  41943006s  33542519s  ext4            primary  boot

(parted) rm 2
(parted) mkpart primary 8400488s -1s

# ※途中パーティションを修復するか聞いてくるので、F(Fix)を選択する
# ※警告が出てきてもyes/Ignoreを選択して進む

(parted) print
Model: Virtio Block Device (virtblk)
Disk /dev/vdb: 268GB
Sector size (logical/physical): 512B/512B
Partition Table: gpt

Number  Start   End     Size    File system     Name     Flags
 1      32.8kB  4301MB  4301MB  linux-swap(v1)  primary
 2      4301MB  268GB   264GB   ext4            primary
 
(parted) quit

# e2fsck -f /dev/vdb2
# resize2fs /dev/vdb2

一旦パーティションを削除して(!)、再度より大きいパーティションを作るというのがキモですね。こんな事して大丈夫なんですねえ。。

元ディスクをVMから外す、動作確認

  1. 該当VMをシャットダウン
  2. 管理画面 [サーバ] -> 該当VMを選択 -> [詳細] -> [ディスク] -> [接続]押下
  3. 元ディスク(接続#1)の▼を選択して[取外し]
  4. 該当VM起動
  5. 容量が増えてるか確認
  6. 必要なければ元のディスクは削除
[root@testvm ~]# df -h
Filesystem      Size  Used Avail Use% Mounted on
/dev/vda2       243G  1.4G  229G   1% /
tmpfs           499M     0  499M   0% /dev/shm

参考

http://knowledge.sakura.ad.jp/tech/925/

http://ubuntuforums.org/showthread.php?t=1389429

一応参考サイトと違うのは、参考サイトはMBRパーティションが切られているのでfdiskで作業していましたが、CentOS6のイメージだとGPTでパーティションを切っていたため、partedで作業しました。

最初参考サイトを見て、もうちょっとマシな方法がないかと調べたのですが結局この方法となりました。 なんかもうちょっといい方法はないものでしょうかねえ。。

さくらクラウドについて思ったこと

  • さくらVPSと比べると割高
  • さくらVPSが優秀過ぎる
  • とはいえさくらVPSはスケールアップができないのでその点は安心感がある
  • さくらVPSとローカルネットワークが繋がれば最高だけど戦略上しなそう
  • 石狩第一内のVPSクラウド(グローバルIP)間の通信はほぼ理論値通り(100Mbps)出た

追記 2015.2.2

この手順ではデータ不整合となる可能性について指摘を受けました。

よく見ると参考サイトのさくらナレッジでも下部に追記がありました(^^;;;

以下引用

[※編集部追記:本手順の際、ファイルシステムをマウント中のまま dd するとコピー先で不整合が発生する可能性があるため、レスキューモードもしくはシングルユーザーモードで実行ください]

確かに起動中のパーティションをddでコピーする場合、作業中に他のプロセスがディスクを書き込む可能性があるため、データ整合性を保証できない可能性があります。私は検証環境として手軽に用意したかったので問題ないですが、ミッションクリティカルな用途の場合は正攻法で行ったほうがいいと思います。

sshを繋ぎっぱなしにするautossh for mac

sshって結構切れます。 特に一定時間何もコマンドを打っていなかったり、画面に変化がないようなアイドル時間が一定以上続くと切れます。 sshをトンネリングで使っていると切れると困るので、切れても自動で再接続してくれるようにしましょう。

まずはHomebrewでautosshをインストール。

$ brew install autossh

あとは以下のコマンドを打つだけ。

$ autossh -f -M 0 -N -D 1080 -o "ServerAliveInterval 45" -o "ServerAliveCountMax 2" user@host

簡単にオプションについて

  • -f バックグラウンドで動かす

  • -M 0 よくわからんのでおまじない的

autosshの他、以下のように透過的にsshのオプションを指定できる

  • -N シェルを使わない

  • -D 指定ポートでSocks5として振る舞う autosshを使う最大の目的

  • -o sshのパラメータを指定 詳細は以下

  • ServerAliveInterval 45 切断防止のため、指定秒数間隔で応答確認をする

  • ServerAliveCountMax 2 指定回数応答がない場合は切断する(その場合autosshが再接続する)

autosshの終了

$ killall autossh

macにhomebrewでPHP5.6環境をインストールしてみる

してみました。

環境はYosemite(10.10)なのですが、OS標準だとPHP5.5のようです。 Homebrewを使い、PHP5.6を使えるようにします。

なお、Homebrewは入っている前提とします。

事前にXCode(現時点で最新6.1)をインストールし、以下コマンドを実行しておきます。

$ xcode-select --install

brewを最新の状態にします

$ brew update
$ brew upgrade

必要なレポジトリを追加します

$ brew tap homebrew/php
$ brew tap homebrew/dupes

以下コマンドでPHP5.6をインストールします 尚、apacheはOS標準のものを使いました

$ brew install php56 --with-apxs2=/usr/sbin/apxs

これでコマンド上からPHP5.6が使えるはずです

$ php -v
PHP 5.6.3 (cli) (built: Nov 27 2014 22:30:22) 
Copyright (c) 1997-2014 The PHP Group
Zend Engine v2.6.0, Copyright (c) 1998-2014 Zend Technologies

ApacheからPHP5.6を使うように書き換えます(/etc/httpd/conf/httpd.conf)

LoadModule php5_module    /usr/local/opt/php56/libexec/apache2/libphp5.so

Apache経由でphpinfo()を表示させると、PHP5.6が動いているのが確認できました

f:id:takemaru123:20141127224025p:plain

参考

postfixのメールキューを書き換える

注:最終的には諦めてますので有用な情報はそれほどありません

最近のメールサーバーは大体、senderにちゃんと正引きできるドメインが設定されていないと受信拒否されてしまいます。 こちらからメール送信する際、hostnameの設定をしないでメール送信をしてしまい、senderが「xxx@localhost.localdomain」という状態になってしまい、相手のメールサーバーに受取拒否され、「/var/spool/postfix/deferred」にたまっている状態となっておりました。

これをなんとか送信しようというお話。

postfixのメールキューの形式は完全に独自形式のようで、人間が読めるように変換して出力するpostcatというコマンドが用意されています。

$ mailq
-Queue ID- --Size-- ----Arrival Time---- -Sender/Recipient-------
F2180160222      549 Thu Nov 13 20:13:20  xxx@localhost.localdomain

まずこんな感じでキューIDを調べます この場合「F2180160222」ですね

postcat -q F2180160222
*** ENVELOPE RECORDS deferred/F/F2180160222 ***
message_size:             549             179               1               0             549
message_arrival_time: Thu Nov 13 20:13:20 2014
create_time: Thu Nov 13 20:13:20 2014
named_attribute: rewrite_context=local
sender_fullname: 
sender: xxx@localhost.localdomain
*** MESSAGE CONTENTS deferred/F/F2180160222 ***
Received: by localhost.localdomain (Postfix, from userid 501)
    id F2180160222; Thu, 13 Nov 2014 20:13:20 +0900 (JST)
To: hogehoge@gmail.com
Subject: test
From: xxx@localhost.localdomain
Date: Thu, 13 Nov 2014 20:13:20 +0900
Message-ID: <54649250690447cea26330707f000101@localhost>
MIME-Version: 1.0
Content-Type: text/plain; charset=ISO-2022-JP
Content-Transfer-Encoding: 7bit

message


*** HEADER EXTRACTED deferred/F/F2180160222 ***
original_recipient: xxx@localhost.localdomain
recipient: xxx@localhost.localdomain
*** MESSAGE FILE END deferred/F/F2180160222 ***

こんな感じでキューのメールを読むことができます

送信できなかったものについてはsenderのlocalhost.localdomain部分を実在するドメインに無理やりsedで書き換えて送信しました。その場合、アドレス全体の文字数は変えてはいけないようです。フォーマットを解析しようとpostfixのソースもちょっと見たのですが、根が深そうだったので断念しました。

カゴヤのVPSは使うな

ゴヤVPS複数台借りて運用していたのですが、いきなり以下のようなメールが来て大半のインスタンスを停止されました。

カゴヤ・ジャパン サポートセンター (担当者名) です。
平素は当社サービスをご利用いただき誠にありがとうございます。

2014-XX-XX XX:XX 頃、下記Xインスタンスの負荷が著しいために
同ホスト機内にある他のお客様サイトへの影響がございました。

XXXXX インスタンス名 IPアドレス
…(台数分)…

つきましては誠に遺憾ながら上記インスタンスを停止いたしました。
お手数とは存じますが、サイトのお見直しをお願いいたします。

※サイトをお見直しいただきます際には、Apacheを停止しておく、
 アクセス制限を施すなどを行った上でご確認ください。

ご了承のほどよろしくお願いいたします。

ご不明な点がございましたら、いつでもカゴヤ・ジャパン サポートセンターまで
お問い合わせください。

それでは今後ともどうぞよろしくお願いいたします。

普通この手のVPSって、高負荷になったら割り当てるCPU時間とかIO帯域で調整すると思っていたのですが、まさかインスタンス停止とは…。 さくらVPSでずっと高負荷かけても(リソース調整はあるにせよ)何も言われないのに…。 確かに料金を日割りできるなどメリットはありますが、ちょっとケチってコレじゃ割にあわないです。 最初からさくら借りとけばよかった。

金輪際KAGOYAは使わないですし、今カゴヤVPS利用を考えているなら全力で再考をお勧めします。 さくらを借りましょう。(ステマ)