MySQL」タグアーカイブ

ZabbixのデフォルトMySQL監視UserParameterは修正が必要

以下はZabbix 3.0.xでの話です。

Zabbix AgentをZabbix SIAのyum Repositoryから導入すると、
/etc/zabbix/zabbix_agentd.d/userparameter_mysql.conf 内にデフォルトでMySQL監視用ユーザーパラメータが定義されますが、その中のZabbix Pingに関しては修正が必要です。以下がデフォルトの定義です。

UserParameter=mysql.ping,HOME=/var/lib/zabbix mysqladmin ping | grep -c alive

これをそのままコンソール上で実行すると、MySQL(MariaDB)が起動している状態で実行すると1を返しますが、停止時には0だけでなく標準エラー出力への文字出力が含まれ、データ型が数値ではなくなってしまいます。

$ HOME=/var/lib/zabbix mysqladmin ping | grep -c alive
mysqladmin: connect to server at 'localhost' failed
error: 'Can't connect to local MySQL server through socket '/var/lib/mysql/mysql.sock' (2)'
Check that mysqld is running and that the socket: '/var/lib/mysql/mysql.sock' exists!
0

数値として受け取れなくなったアイテムは「不明」の状態となり、トリガーが検知しない状態となります。また、これはトリガーのnodata関数が有った場合でも検知されません。

UserParameter=mysql.ping,HOME=/var/lib/zabbix mysqladmin ping 2>/dev/null | grep -c alive

でエラー出力を捨ててみたり

UserParameter=mysql.ping,HOME=/var/lib/zabbix mysqladmin ping 2>&1 | grep -c alive

でエラー出力も標準出力に吐いてgrepに渡す事でMySQLのダウンを検知する事が出来ます。

Gist lf-uraku-yuki/userparameter_mysql_ping.conf

CodeigniterのDB接続不可をハンドリングして再接続する

目的

  • CodeigniterのDB接続不可時に処理をエラーにせずなんとか再接続したい。

前提・用途

  • DBに繋がらないからといってクラッシュされては困るようなクリティカルな処理が有る。
  • Amazon RDSのマルチAZ等のように、冗長化されてはいるが数秒~2分程度のダウンタイムは発生するような構成であり、それに耐えたい。
  • Web APIを提供しているなど、瞬間的に大量のアクセスが発生しDBのmax_connectionを使い切るような状況が起こり得る。が、普段のアクセスは少ない。
  • Codeigniter標準のDBフェイルオーバー機能が使えるほど冗長化された構成ではない(=フェイルオーバー用のDBが無い)。
  • この記事はMySQLにmysqliを使って接続する前提になっています。

方法

Connecting to your Database — CodeIgniter 3.0.6 documentation
http://www.codeigniter.com/user_guide/database/connecting.html

$this->db->reconnect(); を使えば行けそうに思えますが、そもそも最初からDBに接続できなかった場合、reconnect() メソッドはただただfalseを返すような実装になっています。MySQLに上手く接続できているかどうかは、$this->db 、または$this->load->database(‘hoge’, true);が返すオブジェクトのプロパティ、conn_id を見る事で確認可能です。mysqliを使って接続している場合、このプロパティにはmysqliのオブジェクトが格納されており、接続できなかった場合は false が格納されます。

function reconnectDb()
{ 
    if ($this->db->conn_id !== false) {
         return;
     }
     log_message('error', 'DB接続失敗。再接続開始');
    // スクリプト実行可能時間を延ばしておく
     ini_set('max_execution_time', '180');
     for ($retry_count = 0; $retry_count < 8; $retry_count ++) {
         sleep(15);
         $this->load->database(); 
        if ($this->db->conn_id !== false) {
             log_message('debug', 'DB再接続処理OK');
             return; 
        } 
        log_message('debug', 'DB再接続処理NG');
     } 
}  

$this->db->conn_idがfalseであった場合はスクリプトの実行可能時間を延ばしたうえで、再度databaseのロードを試みます。上手く接続できた場合はfalseではなくmysqliのオブジェクトが入っており、DBを使う処理の続行が可能になります。上記のような処理を前述のクリティカルな場所に仕込んでおきます。DBがダウンしていたり、DB側のコネクション制限を使い切っている場合でも再接続の機会を得る事が出来ます。

注意点

  • あくまでDBへの再接続チャンスを得るための処理なので万能ではありません。上記例の場合、15秒ごとの8回のリトライに失敗すればDBには接続できないままです。
  • かなりの時間を待たせる処理になるので、クリティカルな処理、バッチ的な処理、API的な処理でのみ保険的に利用するべきでしょう。
  • バッチ的な処理など、それなりに時間がかかる処理の中で何度もDBにアクセスするような場合は、最初に接続確認を行っても途中でDBがダウンして接続出来なくなるような事も考えられます。$this->db->recconect() メソッドで conn_id プロパティを更新したうえで再度、再接続処理を実行する事もできるはずですが、運悪くDB処理の真っ最中にダウンしたような場合に対しては無力です。
  • CodeigniterのDB接続設定(database.php)にて db_debug を trueにしている場合、DB周りでのError・Warningはそのまま処理の即時停止となり、この再接続処理にたどり着きません。db_debug を false にしている環境でのみ動作します。
  • 上記と同様にディスプレイにPHPのエラーを表示する設定も、DB接続失敗時にWarningが発生しているため非推奨です。

用法、用量を守ってご参考程度に。

Gist lf-uraku-yuki/ci3-db-connect-retry.php