メイン

2010年04月05日

Windows Server, MySQL+PHPで Can't connect to MySQL server on 'localhost' (10061) のエラー

先日、珍しくWindows Serverのインフラ構築を行ったときにハマったこと。
Windows ServerでXoopsを動かすということで、構成は、Windows Server 2008 Standard SP2 32bit + IIS 7.0 + FastCGI + MySQL 5.0.90 + PHP 5.2.12(Non-thread-safe) でした。

インストーラ(.msi)でMySQLサーバをインストールし、PHPもインストールして、MySQLサーバに接続する下記のようなPHPスクリプト <DocumentRoot>/connecttest.php を用意しました。

<?php
mysqli_connect("localhost","<user>","<password>") or die("Error MySQL First Test");
echo "Success MySQL First Test";
?>

ブラウザから http://localhost/connecttest.php にアクセスしてみたところ、何度試しても「Can't connect to MySQL server on 'localhost' (10061)」のエラーとなってしまうのです。
php.iniの内容や、libmysql.dllの置き場所やPHPの各種dllの置き場所も確認しましたが、特に問題なさそうです。

4時間ぐらいかかってやっとわかった原因は、MySQLサーバがTCP/IPのアクセスを禁止するモード(skip-networking)で動作していた、ということでした。
コマンドプロンプトから、'telnet localhost 3306' とやっても'Connection refused'だったので、そこからたどって気づきました。

my.iniで、skip-networkingをコメントアウトし、ポート番号も3306を指定してMySQLを再起動したところ、やっと正常に「Success MySQL First Test」と表示されるようになりました。

-- my.ini
#skip-networking
#port=0
port=3306

...
--

MySQLサーバのインストールの際、Configurration Wizardで、「Enable TCP/IP Networking」という設定箇所があったのですが、ここで「ローカルからしかアクセスしないから」ということで何を思ったのか、チェックボックスをわざわざOFFにしてしまったのが失敗でした。
デフォルトのままインストールしていれば、こんなことにはならなかったはずです。

「Can't connect to MySQL server on 'localhost' (10061)」
でググってみたらいろんな方が質問を投げているのですが、解決例は少ないようですね。
「libmysql.dllの場所が適切ではない」
「パスにphpのディレクトリを追加すべき」
という回答があったりしますが、MySQLクライアントのエラーメッセージが出力されているということは、少なくとも、PHPスクリプトを起動してMySQLクライアントモジュールを使用したということを表しています。
上記2つの回答についてはすでにクリアしている問題で、原因は他にあるということですね。

同じエラーメッセージが出て悩んでいる方は、念のため、my.iniでskip-networkingが記載されていないか、ポート番号(port)が3306か、を確認されるとよいと思います。

なお、MySQL, IISと連携する際のPHPの設定については、下記がとても参考になりました。

・IISにOSSをインストールするための情報サイト [IIS de OSS 64bit]
http://guitarfish.wazure.jp/index.php?PHP5.2.11%E3%81%AEphp.ini%E7%B7%A8%E9%9B%86

2009年03月27日

MySQL サポートしているストレージエンジンの確認方法

サーバにインストールしたMySQL Serverでサポートしているストレージエンジンを確認する方法のメモ書き。

SHOW ENGINES構文で、ストレージエンジンごとにデフォルト、サポートしている/していない、無効などが確認できます。

以下、CentOS 5.2のMySQL5.0.45で確認した例。

mysql> SHOW ENGINES \G

*************************** 1. row ***************************
Engine: MyISAM
Support: DEFAULT
Comment: Default engine as of MySQL 3.23 with great performance
*************************** 2. row ***************************
Engine: MEMORY
Support: YES
Comment: Hash based, stored in memory, useful for temporary tables
*************************** 3. row ***************************
Engine: InnoDB
Support: YES
Comment: Supports transactions, row-level locking, and foreign keys
*************************** 4. row ***************************
Engine: BerkeleyDB
Support: DISABLED
Comment: Supports transactions and page-level locking
*************************** 5. row ***************************
Engine: BLACKHOLE
Support: NO
Comment: /dev/null storage engine (anything you write to it disappears)
*************************** 6. row ***************************
Engine: EXAMPLE
Support: NO
Comment: Example storage engine
*************************** 7. row ***************************
Engine: ARCHIVE
Support: NO
Comment: Archive storage engine
*************************** 8. row ***************************
Engine: CSV
Support: NO
Comment: CSV storage engine
*************************** 9. row ***************************
Engine: ndbcluster
Support: NO
Comment: Clustered, fault-tolerant, memory-based tables
*************************** 10. row ***************************
Engine: FEDERATED
Support: NO
Comment: Federated MySQL storage engine
*************************** 11. row ***************************
Engine: MRG_MYISAM
Support: YES
Comment: Collection of identical MyISAM tables
*************************** 12. row ***************************
Engine: ISAM
Support: NO
Comment: Obsolete storage engine
12 rows in set (0.00 sec)

(参考)
http://dev.mysql.com/doc/refman/5.1/ja/show-engines.html

2008年11月17日

MySQL5.0 バイナリログの保存先が変わった?

とあるシステムの構築作業において、CentOS5上でMySQL5.0.45を使用していて気づいたのですが、バイナリログのデフォルトの保存先が変わりましたね。

これまでは、たとえばMySQL5.0.22では、/etc/my.cnfにおいて下記のようにlog-binのみ記述しておくと、datadirで指定したディレクトリ、デフォルトでは/var/lib/mysql にバイナリログが作成されていました。

-- /etc/my.cnf
log-bin
--

ところが、MySQL5.0.45では、PIDファイルと同じディレクトリ /var/run/mysqld に保存されるようになりました。
MySQLのログでも、「起動時に log-bin= で明にしていしてね」というメッセージが出ています。

-- /var/log/mysqld.log
081114 14:31:16 [Warning] No argument was provided to --log-bin,
and --log-bin-index was not used; so replication may break
when this MySQL server acts as a master and has his hostname changed!!
Please use '--log-bin=/var/run/mysqld/mysqld-bin' to avoid this problem.
--

そのままでもよいのですが、バイナリログファイルはデータファイルと同じ場所にないといざというときに見つけにくいので、そのように変更します。

0. MySQLを停止する

# /etc/init.d/mysqld stop

1. /etc/my.cnf にてバイナリログの出力先を明に指定する

log-bin= でbase_nameとしてmysqld-binを指定します。
これで、/var/run/mysqld ではなく、datadir で指定したディレクトリ、デフォルトでは/var/lib/mysql に保存されるようになります。

-- /etc/my.cnf
log-bin=mysqld-bin
--

すでにバイナリログを /var/run/mysqld に生成してしまった場合はそれだけでは不十分なので、以下を行います。

2. /var/run/mysqld 以下に生成されたバイナリログ、インデックスファイルをデータディレクトリに移動

バイナリログファイルmysqld-bin.000001, mysqld-bin.000002, ... と、インデックスファイルmysqld-bin.index を/var/lib/mysql に移動します。

# mv /var/run/mysqld/mysqld-bin.* /var/lib/mysql/

3. インデックスファイルに記載されているバイナリログファイルのパスを修正

-- mysqld-bin.index 修正前
/var/run/mysqld/mysqld-bin.000001
/var/run/mysqld/mysqld-bin.000002
...
--


-- mysqld-bin.index 修正後
/var/lib/mysql/mysqld-bin.000001
/var/lib/mysql/mysqld-bin.000002
...
--

4. MySQLを起動

# /etc/init.d/mysqld start


3. を行わないと、MySQLの起動時にMySQLのログに以下のようなメッセージが出力され、起動に失敗します。

-- /var/log/mysqld.log
081114 14:36:21 mysqld started
081114 14:36:21 InnoDB: Started; log sequence number 0 92391
/usr/libexec/mysqld: File '/var/run/mysqld/mysqld-bin.000001' not
found (Errcode: 2)
081114 14:36:21 [ERROR] Failed to open log (file
'/var/run/mysqld/mysqld-bin.000001', errno 2)
081114 14:36:21 [ERROR] Could not open log file
081114 14:36:21 [ERROR] Can't init tc log
081114 14:36:21 [ERROR] Aborting
--


なお、レプリケーション環境を構築している場合は、スレーブサーバ側でのリレーログも、デフォルトでは/var/run/mysqld に保存されます。

こちらも、/etc/my.cnfにてbasenameを明に指定すると、リレーログがデータディレクトリに保存されるようになります。

-- /etc/my.cnf
relay-log=mysqld-relay-bin
--


これ、いつの間に変わったのでしょうね。
MySQL5.0.22から5.0.45のChangeLogを眺めても見つけられません。

2008年08月01日

MySQL InnoDBを無効にする

MySQLでInnoDBを無効にするには、コンフィグファイル /etc/my.cnf にて下記を追記します。

[mysqld]
...
skip-innodb

デフォルトだと、innodb_buffer_pool_size=8MB + innodb_additional_mem_pool_size=1MBの9MBぐらい、使用メモリを節約できます。

http://dev.mysql.com/doc/refman/5.1/ja/innodb-parameters.html
http://dev.mysql.com/doc/refman/4.1/ja/innodb-start.html

2007年10月10日

Xen MySQLサーバが起動しない

XenでCentOS4.5のゲストOS Domain-U環境を構築し、MySQLサーバ4.1.20を起動しようとしたところ、下記のメッセージが表示され起動に失敗するという現象がありました。

-- /var/log/mysqld.log
070925 16:50:50 [ERROR] bdb: unable to initialize mutex:
Function not implemented
070925 16:50:50 [ERROR] bdb: process-private:
unable to initialize environment
lock: Function not implemented
--

Xen環境では、/lib/tls(Thread Local Storage)ライブラリが有効になっていると性能が悪くなるため、これを無効にすることが推奨されています。
ですが、MySQLでは、bdb(Berkeley DB)まわりのライブラリがTLSを使用しているようで、mysqldの起動時に必要なライブラリを読み込めずにエラーしていました。

この問題を解決するために、bdbまわりのライブラリを使用しないよう、/etc/my.cnf に下記の1行を追加します。

-- /etc/my.cnf
[mysqld]
...
skip-bdb
--

これで、MySQLサーバが正しく起動するようになりました。
なお、skip-bdb オプションを指定することによる違いが、リファレンスマニュアルに記述されています。
http://dev.mysql.com/doc/refman/4.1/ja/bdb-start.html



MySQL は Berkeley DB ライブラリを初期化しなくなるため、大量のメモリを

節約できます。このオプションを使用しているときは BDB テーブルを

使用できません。BDB テーブルを作成しようとすると、代わりに

MyISAM テーブルが作成されます。


通常はストレージエンジンとして、MyISAMまたはInnoDBを使用するでしょうから、問題ありませんね。
「大量のメモリを節約できます」については、mysqldプロセスの使用メモリが約3MBほど少なくなることを確認しました。
Apacheにおける「不要なmod_xxxを読み込まない」と同じく、Xen環境以外でも、skip-bdbをデフォルトで設定してもよいですね。

2007年10月03日

MySQLが落ちる

これまた最近、僕が構築に関わったサービスで、まれにMySQLサーバが落ちる現象が発生していました。バージョンは、RedHat Enterprise Linux 4 Update 4に同梱されていたMySQL Server 4.1.12です。

RPMインストールしたためスタックトレースからの情報が採取できず、調査にも苦労していたのですが、なんとか社内の開発環境でも再現させることができ、情報をたどってひとつのバグにたどり着きました。

MySQL Bugs #11167
http://bugs.mysql.com/bug.php?id=11167

In 4.1 char/varchar fields are limited by 255 characters in length that
makes them longer than 255 bytes in size for such character sets as UTF8.
The functions store_record_in_cache and read_cached_records did not
take into account this Moreover the code did not take into account
that the size of the varchar fields in 5.0 can be up to 65535 bytes.

The fix will appear in 4.1.13 and 5.0.8.

つまり、
「MySQL4.1の仕様では、CHAR型やVARCHAR型は最大で255文字までとなっている。このため、UTF8のようにマルチバイト文字列を扱う場合、255バイトを超えることがある。ところが、MySQLの一部の内部関数では255バイトを超えることを考慮していなかったため、クラッシュすることがあった。ついでに、MySQL5.0ではVARCHAR型は65535バイトまで扱えるようになったのに、それも考慮していなかった。この障害は4.1.13および5.0.8で修正した。」
ということだったのです。

確かにこのサービスではいくつかの表において、VARCHAR(255)で定義した列で255バイトを超えるようなデータが入っていました。

対処として、RHEL4のMySQLの最新バージョン4.1.20-2にバージョンアップすることでこの問題は解決しました。

無事解決してよかったよかった、、、と言いたいところですが、そうではなく、このバージョンアップのために、お客様の一部サービスを一時停止しなければなりませんでした。
バージョンアップ後の検証も含め、けっこうなお時間を割いていただきました。
サービスイン直前のテスト期間中にも何度か発生していたので、その時点でもう少し原因を追っていれば、と悔やまれます。
インフラ構築担当としては、恥ずかしい話です。
やはりサービスイン前には、最新のアップデートをかけておくべきですね。

2007年08月23日

MySQL バイナリログのローテートファイルサイズを変更したい

MySQLバイナリログの自動削除設定については、以前書きましたが、ローテートのファイルサイズを指定できることが(最近)わかりました。

ローテートのファイルサイズは、システム変数 max_binlog_size で指定します。
デフォルトでは1GBです。
/etc/my.cnf の[mysqld]ブロックに記述し、mysqldを再起動すると反映されます。
以下、200MBに変更する場合。

-- /etc/my.cnf
[mysqld]
...
max_binlog_size = 209715200
--

mysqldを停止できないときは、SET GLOBAL構文でシステム変数を変更します。

# mysql -u root -p

まず、現在の設定値を確認。

mysql> SHOW VARIABLES like 'max_binlog_size';
+-----------------+------------+
| Variable_name | Value |
+-----------------+------------+
| max_binlog_size | 1073741824 |
+-----------------+------------+
1 row in set (0.00 sec)

設定変更。

mysql> SET GLOBAL max_binlog_size=209715200;

再度確認。

mysql> SHOW VARIABLES like 'max_binlog_size';
+-----------------+-----------+
| Variable_name | Value |
+-----------------+-----------+
| max_binlog_size | 209715200 |
+-----------------+-----------+
1 row in set (0.00 sec)


ディスクストレージ単価が下がった今となっては、デフォルトの1GBでも問題ないでしょう。
ですが、稼働中のサービスを停止できない状況で、データ・ログ領域が容量の少ないパーティションに割り当たっていてディスクを圧迫しているときは、ローテートファイルサイズ設定と自動削除設定で、うまく回避できます。


(参考)MySQL4.1リファレンスマニュアル
http://dev.mysql.com/doc/refman/4.1/ja/show-variables.html


(2007/09/06補足)
FLUSH LOGS文を使用すると、バイナリログを直ちに新規のログにローテートすることができます。
(さっき知りました)

mysql> FLUSH LOGS;

2007年05月25日

MySQL メモリ使用量の計算式

MySQLで使用するメモリの計算式は次のとおりです。

max_connections *
(sort_buffer_size
  + join_buffer_size
+ read_buffer_size
  + read_rnd_buffer_size
+ net_buffer_length
  + max_allowed_packet) <-- カッコ内は1接続あたりの使用メモリ

+ key_buffer_size
+ query_cache_size
+ innodb_buffer_pool_size
+ innodb_additional_mem_pool_size
+ innodb_log_buffer_size

データベース専用サーバであれば、この値が搭載メモリの8〜9割になるように設定するとよいでしょう。
Webサーバやアプリケーションサーバを兼ねるサーバなら、用途に合わせてその割合を減らします。

なお、32bit Linuxでは、1プロセスに割り当てる最大メモリサイズは4GBであるため、上記で4GBを超えるような設定をすると、MySQLがエラーして起動しません。

(2010.04.16追記)
スレッドバッファ分のmax_allowed_packetについては、メモリ使用量の計算式としては適切ではないので削除し、net_buffer_lengthを追加しました。
通信時のバッファについては、接続時にnet_buffer_lengthの値分確保されます。
この値はデフォルトでは16KB。
通信時に必要に応じて、最大でmax_allowed_packetまで拡張されます。
max_allowed_packetはデフォルトで1MB。


また、myisam_sort_buffer_sizeもスレッドバッファとして加算する方もいらっしゃるようです。
これは、MyISAMでREPAIR TABLE, CREATE INDEX, ALTER INDEX文を実行したとき使われるバッファで、デフォルトは8MB。
全文検索エンジンTritonnを使用する場合はなんと1GBとすることが推奨されています。
ですが、同時接続100のとき合計で100GB使用するかというと、そうではないので、接続時に必ずmyisam_sort_buffer_size分を確保するわけではないようです。

ということで、考え得る最大値という意味では、max_allowed_packetやmyisam_sort_buffer_size分を加算することは間違いではないのですが、すべての通信接続でこれらの値分を確保するわけではないので、パラメータチューニングにおける計算式からは削除しました。

2007年04月10日

MySQL バイナリログを自動削除したい

MySQLでは、「バイナリログは自動で削除されないので、手作業で定期的に削除する必要がある」というのが定説だと思っていたのですが、自動削除してくれるオプションがありました。
/etc/my.cnf で下記のように記述します。

[mysqld]
...
expire_logs_days = 30

log-bin など、バイナリログに関する設定の近くに記述するとわかりやすいでしょう。

expire_logs_daysでは、バイナリログを自動削除する日数を指定します。
デフォルトは0。この場合ログファイルは自動削除されません。
なお、ログを削除するタイミングは、MySQLサーバ起動時もしくはログをローテートするときに限られるので、この日数が経過したから といって即座にログファイが削除されるとは限りません。

起動中のMySQLを停止せずに、SET GLOBAL コマンドでも設定できます。
(/etc/my.cnfにも書かないと再起動したときに反映されません。)

# mysql -u root -p
mysql> SET GLOBAL expire_logs_days = 30;

反映されているかどうか、確認します。

mysql> SHOW GLOBAL VARIABLES like 'expire_logs_days';
+------------------+-------+
| Variable_name | Value |
+------------------+-------+
| expire_logs_days | 30 |
+------------------+-------+
1 row in set (0.00 sec)

この機能はMySQL4.1.0で入った機能ですが、なぜか日本語のマニュアルには記述がなく、英語マニュアルに記述されています。

http://dev.mysql.com/doc/refman/4.1/en/server-system-variables.html

ところで。
バイナリログには実行したSQL文が記録されます。
このため、調査に役立てる意味でも、僕がインフラ構築を行う場合は、レプリケーション機能を利用しない場合でも、ディスク容量に余裕がある限りバイナリログを出力するようにしています。

ANTAS(アンタス)