hnwの日記

PHPのmysqlndの圧縮プロトコルについてのメモ

PHP+PDO+MySQLの環境では、PHP-MySQL間の通信についてzlibを使った圧縮プロトコルを利用することができます。この機能は、DBサーバのCPU利用率に十分余裕があり、かつPHP-MySQL間のネットワーク帯域が逼迫している状況で有用です。

MySQLの圧縮プロトコルとそのマニュアル


PHP+MySQLの環境で、圧縮プロトコルは下記のようなコードで利用できます。

<?php
    $options = [
        PDO::MYSQL_ATTR_COMPRESS => true
    ];
    $db = new PDO($dsn, $user, $pass, $options);


MySQLドライバとしてmysqlndを利用している場合*1PHP 5.3.11(2012年4月リリース)以降であれば圧縮プロトコルに対応しています。このことはPHPマニュアルにも下記の通り記載があります。

PDO::MYSQL_ATTR_COMPRESS (integer)


Enable network communication compression. This is also supported when compiled against mysqlnd as of PHP 5.3.11.


https://secure.php.net/manual/en/ref.pdo-mysql.php#pdo.constants.mysql-attr-compress


ただし、この記述は2015年9月頃に追加されたものです。それまでマニュアル上では「PDO_MYSQL+mysqlndは圧縮をサポートしていない」という記述しかありませんでした(2010年頃の記述で、当時は正しかった)。


2015年8月頃に筆者が業務で関わっていた環境で圧縮プロトコルを導入したのですが、マニュアルに明記されていない機能を商用環境で使うのは気が引けたので、マニュアルにバグがあるよ!というバグレポをPHP本家に投げてみました。その甲斐あってか、しばらくしてマニュアルが修正されました。これで今後は安心して利用できるというわけです。

mysqlndの圧縮プロトコルの実装

PHP 7.1.7のソースコード上で、mysqlndの圧縮プロトコルの実装部分を探してみました。


すると、ext/mysqlnd/mysqlnd_net.cext/mysqlnd/mysqlnd_protocol_frame_codec.cに同じようなコードが見つかります。

MYSQLND_METHOD(mysqlnd_pfc, encode)(zend_uchar * compress_buffer, size_t * compress_buffer_len,
                                    const zend_uchar * const uncompressed_data, const size_t uncompressed_data_len)
{
(略)
    error = compress(compress_buffer, &tmp_complen, uncompressed_data, uncompressed_data_len);
(略)
}


このcompress()はzlibの提供する関数で、Deflateアルゴリズムを使って圧縮するものです。ちゃんと真面目な圧縮を使ってるんですね!(驚くところではない気もしますが)


コードを追っていくと、クエリやクエリ結果だけでなく通信内容全体を圧縮していることもわかります。


また、compress()を使っているので圧縮レベルを与える方法はありません。常にデフォルト値(Z_DEFAULT_COMPRESSION、おそらく6)になります。

*1:PHP 5.4.0以降の環境ではデフォルトでmysqlndを利用しているはずです