ツナワタリマイライフ

日常ネタから技術ネタ、音楽ネタまで何でも書きます。

Galera Clusterの同期の仕組みを公式ドキュメントから読み解く(3) Replication API

はじめに

第3弾です。引き続き以下のページを訳していきます。

Technical Description — Galera Cluster Documentation

take-she12.hatenablog.com

take-she12.hatenablog.com

Replication API

同期レプリケーションには"eager replication"を用います。クラスタのノードは1つのトランザクションを、レプリカ更新によってすべてのノードに同期します。これは、トランザクションがコミットするとき、すべてのノードは同じ値を持つことを意味します。(訳注:これがすなわちeager replicationのことですね) このプロセス はグループコミュニケーションを通じてwrite-setを扱います。

途中にある図はgalera clusterとその周辺コンポーネントアーキテクチャです。

  • データベース管理システム(DBMS)
    • データベースサーバはそれぞれ個別のノード上で実行されます。galera clusterはMySQLまたはMariaDBを扱うことができます。
  • wsrep API
  • Galeraレプリケーションプラグイン
  • グループコミュニケーションプラグイン

    • 様々なグループコミュニケーションシステムがGalera Clusterを利用可能になる。例えばgcommとspreadがある。
  • 訳者コメント:

    • gcommは、複数ノードがいたとして、クラスタ間の通信をサポートするもので、それがグループコミュニケーションと言われている。それをgalera replication pluginがサポートする。そしてdlopen -> wsrep hooksの層でwrite-setの伝搬をサポートし、実際にDBMSにコミットされる、という風に理解した。個人的には上下逆のほうがわかりやすい。

wsrep API

wsrep APIはデータベースに対する一般的なレプリケーションプラグインインターフェイスである。アプリケーションのコールバックとレプリケーションプラグインの呼び出しの集合を定義する。

wsrep APIはデータベースサーバに状態を持たせるレプリケーションモデルを使用する。状態はデータベースの中身に紐づく。データベースを使用しているとき、クライアントがデータベースの内容を修正すると、それは状態を変更することを意味する。wsrep APIはATOMICな変更、あるいはトランザクションの集合(訳注:これはwrite-setを意味すると思う)として、データベースの状態変更を表現する。

データベースクラスタでは、すべてのノードが常に同じ状態である。これらは、同じ順番で状態変更を同期させる。

より技術的な視点で見ると、Galera Clusterは以下のプロセスで状態変更を行う

  1. クラスタ内の1つのノードで、データベースに対する変更が行われる
  2. データベースで、wsrep hooksがwrite-setへの変更として解釈する
  3. dlopen() が wsrep provider functionにwsrep hooksを利用可能にする
  4. Galeraレプリケーションプラグインがwrite-set証明とレプリケーションクラスタに対して扱う

(訳注:特にこれまでの説明と同じ気がする。。。)

クラスタ内の各ノードで、優先度の高いトランザクションによってアプリケーションプロセスが発生する。(?)

Global Transaction ID

クラスタ間で状態を個別に保つために、wsrep APIはGlobal Transaction ID(GTID)を用います。これは状態変更を特定し、最後の状態変更と現在の状態との関係を特定します。

Global Transaction IDは以下のコンポーネントを含みます。

  • State UUID: 状態とそれが受ける変更のシーケンスの識別子
  • Ordinal Sequence Number: シーケンスの中で変更位置を示すために使われる、64-bit signed integerのシーケンス番号。

Global Transaction IDはアプリケーションの状態と状態変更の順番の成立を比較します。これを変更が適用されたかどうかと、変更が与えられた状態に全てに適用可能かどうかを決定するために使うことができます。

(訳コメント:Global Transaction IDでクラスタ内の各ノードがどこまでDBの変更を書き込んでいるかを管理しているみたいですね。write-setなのかわかりませんが、ある塊でState UUIDが変更されて、1つのstate UUIDの中では後半のOrdinal Sequence Numberで位置を特定できそうです。となるとState UUIDはどの単位で変わるのかが気になりますね。。。)

Galera Replication Plugin

Galera Replication Pluginはwsrep APIを実装します。wsrep Providerを操作します。

より技術的な観点からみると、Galera Replication Pluginは以下のコンポーネントを含みます。

  • Certification Layer: このレイヤーはwrite-setを準備し、証明チェックを行い、受け入れられるかを保証します
  • Replication Layer: このレイヤーはレプリケーションプロトコルを管理し、順番を並び替えます
  • Group Communication Framework: このレイヤーはGalera Clusterに接続する様々なgroup communication systemのためのプラグイン構造です。

Group Communication Plugins

Group Communication Frameworkは様々なgcommシステムに対してのプラグイン構造を提供します。

Galera Clusterは独自のgrouo communication system layerを実装しています。これは仮想的にQoSと同期する実装です。仮想的な同期はデータ転送とクラスタのメンバーシップサービスをひとまとめにし、メッセージ配信セマンティクスに明確な形式を提供します。(?)

仮想的な同期が一貫性を保証している一方で、スムースなマルチマスター操作のために必要な時間同期は保証しません。これを避けるために、Galera Clusterは自身で設定可能な時間フロー制御を実装しています。フロー制御は1秒単位でノードを同期させます。

これに加えて、Group Communication Frameworkは複数の送信元からの全てのメッセージ順番を提供します。これを用いてマルチマスタクラスタでのGlobal Transaction IDを生成しています。

Transaportレベルでは、Galera Clusterは対象無向グラフです。すべてのデータベースノードは互いにTCPコネクション上で接続します。デフォルトではTCPはメッセージレプリケーションクラスタメンバシップサービスの両方に用いられますが、LANでのレプリケーションUDPマルチキャストを使うこともできます。

(訳コメント:まずGroup Communicationの仕組みでメンバ管理、メンバ間の通信、メッセージの順番を管理している。replication pluginを通じてwsrep APIを叩き、GTIDを生成して一貫性を保証している、ということですね。わかったようなわからんような。)

MySQL5.7でレプリケーションを試す

はじめに

仕事でMariaDBを扱っているのですが、本屋でMySQLまわりもパラパラと見ていると、この本が詳しそうだったので書いました。

詳解MySQL 5.7 止まらぬ進化に乗り遅れないためのテクニカルガイド (NEXT ONE)

詳解MySQL 5.7 止まらぬ進化に乗り遅れないためのテクニカルガイド (NEXT ONE)

まず第1章のMySQLの概要、第2章のレプリケーションを読みました。本書はMySQL5.7の膨大な新機能をセクションごとに解説する本ですが、MySQL自体初学の人間(私とか)でも非常に詳しい説明がなされていて、この本を最初に見ればよかった、という思いです。

今回、第2章で扱われているレプリケーションについて、MySQL5.7の導入とともに実践してみます。

MySQL5.7のinstall

CloudGarageさんお世話になります。やっぱりレプリケーションもできる、3台貸し出しは本当に助かる。

take-she12.hatenablog.com

installは以下の記事通り、CentOS 7.3に対して行いましたので省略。

weblabo.oscasierra.net

# yum remove mariadb-libs
# rm -rf /var/lib/mysql/
# yum localinstall http://dev.mysql.com/get/mysql57-community-release-el7-7.noarch.rpm
# yum -y install mysql-community-server
# systemctl enable mysqld.service
# systemctl start mysqld.service

設定

初期パスワードがログに出ます。

[root@mysql57-2 ~]# grep "temporary password" /var/log/mysqld.log 
2017-11-08T11:49:27.602209Z 1 [Note] A temporary password is generated for root@localhost: By30kodp0g/v

ログイン後に、パスワードをrootに変更したいですが、制限が厳しいのでそれを緩和させてやります。

以下の記事が参考になりました。

qiita.com

[root@mysql57-2 ~]# mysql -uroot -pBy30kodp0g/v
mysql: [Warning] Using a password on the command line interface can be insecure.
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 3
Server version: 5.7.20

Copyright (c) 2000, 2017, Oracle and/or its affiliates. All rights reserved.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql> set password for root@localhost=password('passwordPASSWORD@999');
Query OK, 0 rows affected, 1 warning (0.00 sec)

mysql> SET GLOBAL validate_password_length=4;
Query OK, 0 rows affected (0.00 sec)

mysql> SET GLOBAL validate_password_policy=LOW;
Query OK, 0 rows affected (0.00 sec)

mysql> set password for root@localhost=password('root');
Query OK, 0 rows affected, 1 warning (0.00 sec)

masterノードの設定

bin_log(バイナリログ)の有効化と、replicationのためのserver_idを設定してやります。serveri_idはmasterとslaveで異なる値を設定しましょう。

[root@mysql57 ~]# tail -n7 /etc/my.cnf
# replication
server-id=1
log-bin=mysql-bin

# pasword policy
validate_password_length=4
validate_password_policy=LOW

ちなみにバイナリログとは、データベース上のすべてのテーブル変更の記録です。show binary logsコマンドで一覧できます。

mysql> show binary logs;
+------------------+-----------+
| Log_name         | File_size |
+------------------+-----------+
| mysql-bin.000001 |       177 |
| mysql-bin.000002 |      1181 |
+------------------+-----------+
2 rows in set (0.00 sec)

このバイナリログをSQLのレベルでレプリケーションに使用する方式をStatementBasedReplication(SBR)と呼びます。(statement=SQL)しかし、この方法だとSQLの種類によってデータベースの変更結果がmasterとslaveで異なる場合がある問題があります。(UUID関数など)

その問題に対処するのが行ベースレプリケーション(RowBasedReplication, RBR)です。SQLの実行結果、変更が生じた行の前後を記録する方式なので、SQL文で結果が異なっても大丈夫です。

次にslaveが接続するよためのuserを作成します。

ログが流れてしまいましたが、

> create user 'repl' identified by 'repl';
> grant replication slave on *.* to 'repl';

でいけると思います。以下を参考にしました。

MySQL :: MySQL 5.6 リファレンスマニュアル :: 17.1.1.3 レプリケーション用ユーザーの作成

DBのdump

面倒なことに、slaveに対してはmasterのdbのdumpを流し込んで、同じレベルにしなければなりません。

slaveがmasterに接続する場合、現在のbinary_log_fileの名前と、log_positionという値が必要であるため、その情報が出力される形式でdumpを取る必要があります。

[root@mysql57 ~]# mysqldump -uroot -proot --master-data=2 -A >mysql.dump 
mysqldump: [Warning] Using a password on the command line interface can be insecure.
[root@mysql57 ~]# 

CLIでpassword打つと怒られちゃいますね。このdumpをscpかなんかでslaveに送って、restoreしてください。

slaveの設定

masterと同じでいいです。configでserver_idだけは異なるものにしてください。

レプリケーションの設定です。

mysql> change master to 
    -> master_host='192.168.0.11',
    -> master_port=3306,
    -> master_log_file='mysql-bin.000002',
    -> master_log_pos=990,
    -> master_heartbeat_period=60;
Query OK, 0 rows affected (0.01 sec)

おっと、ここのlog_fileとlog_posはdbのdumpから確認してください。

[root@mysql57-2 ~]# grep -e '-- CHANGE MASTER TO MASTER_LOG_FILE' dump.sql 
-- CHANGE MASTER TO MASTER_LOG_FILE='mysql-bin.000002', MASTER_LOG_POS=990;

replicationをはじめるにはslaveでstart slave statementを実行します。結果は、Slave_IO_Runningがyesであることを確認しましょう。

mysql> start slave user = 'repl' password = 'repl';
Query OK, 0 rows affected, 1 warning (0.00 sec)

mysql> show slave status;
+----------------------------------+--------------+-------------+-------------+---------------+------------------+---------------------+----------------------------+---------------+-----------------------+------------------+-------------------+-----------------+---------------------+--------------------+------------------------+-------------------------+-----------------------------+------------+------------+--------------+---------------------+-----------------+-----------------+----------------+---------------+--------------------+--------------------+--------------------+-----------------+-------------------+----------------+-----------------------+-------------------------------+---------------+---------------+----------------+----------------+-----------------------------+------------------+--------------------------------------+----------------------------+-----------+---------------------+--------------------------------------------------------+--------------------+-------------+-------------------------+--------------------------+----------------+--------------------+--------------------+-------------------+---------------+----------------------+--------------+--------------------+
| Slave_IO_State                   | Master_Host  | Master_User | Master_Port | Connect_Retry | Master_Log_File  | Read_Master_Log_Pos | Relay_Log_File             | Relay_Log_Pos | Relay_Master_Log_File | Slave_IO_Running | Slave_SQL_Running | Replicate_Do_DB | Replicate_Ignore_DB | Replicate_Do_Table | Replicate_Ignore_Table | Replicate_Wild_Do_Table | Replicate_Wild_Ignore_Table | Last_Errno | Last_Error | Skip_Counter | Exec_Master_Log_Pos | Relay_Log_Space | Until_Condition | Until_Log_File | Until_Log_Pos | Master_SSL_Allowed | Master_SSL_CA_File | Master_SSL_CA_Path | Master_SSL_Cert | Master_SSL_Cipher | Master_SSL_Key | Seconds_Behind_Master | Master_SSL_Verify_Server_Cert | Last_IO_Errno | Last_IO_Error | Last_SQL_Errno | Last_SQL_Error | Replicate_Ignore_Server_Ids | Master_Server_Id | Master_UUID                          | Master_Info_File           | SQL_Delay | SQL_Remaining_Delay | Slave_SQL_Running_State                                | Master_Retry_Count | Master_Bind | Last_IO_Error_Timestamp | Last_SQL_Error_Timestamp | Master_SSL_Crl | Master_SSL_Crlpath | Retrieved_Gtid_Set | Executed_Gtid_Set | Auto_Position | Replicate_Rewrite_DB | Channel_Name | Master_TLS_Version |
+----------------------------------+--------------+-------------+-------------+---------------+------------------+---------------------+----------------------------+---------------+-----------------------+------------------+-------------------+-----------------+---------------------+--------------------+------------------------+-------------------------+-----------------------------+------------+------------+--------------+---------------------+-----------------+-----------------+----------------+---------------+--------------------+--------------------+--------------------+-----------------+-------------------+----------------+-----------------------+-------------------------------+---------------+---------------+----------------+----------------+-----------------------------+------------------+--------------------------------------+----------------------------+-----------+---------------------+--------------------------------------------------------+--------------------+-------------+-------------------------+--------------------------+----------------+--------------------+--------------------+-------------------+---------------+----------------------+--------------+--------------------+
| Waiting for master to send event | 192.168.0.11 | repl        |        3306 |            60 | mysql-bin.000002 |                 990 | mysql57-2-relay-bin.000003 |           320 | mysql-bin.000002      | Yes              | Yes               |                 |                     |                    |                        |                         |                             |          0 |            |            0 |                 990 |             531 | None            |                |             0 | No                 |                    |                    |                 |                   |                |                     0 | No                            |             0 |               |              0 |                |                             |                1 | ca6806d3-c473-11e7-9e52-fa163e4c44c2 | /var/lib/mysql/master.info |         0 |                NULL | Slave has read all relay log; waiting for more updates |              86400 |             |                         |                          |                |                    |                    |                   |             0 |                      |              |                    |
+----------------------------------+--------------+-------------+-------------+---------------+------------------+---------------------+----------------------------+---------------+-----------------------+------------------+-------------------+-----------------+---------------------+--------------------+------------------------+-------------------------+-----------------------------+------------+------------+--------------+---------------------+-----------------+-----------------+----------------+---------------+--------------------+--------------------+--------------------+-----------------+-------------------+----------------+-----------------------+-------------------------------+---------------+---------------+----------------+----------------+-----------------------------+------------------+--------------------------------------+----------------------------+-----------+---------------------+--------------------------------------------------------+--------------------+-------------+-------------------------+--------------------------+----------------+--------------------+--------------------+-------------------+---------------+----------------------+--------------+--------------------+
1 row in set (0.00 sec)

masterで変更を加えた結果が、slaveでも反映されていれば成功です。

master側ではこのようなログがでていました。

2017-11-08T12:10:16.099322Z 12 [Note] Start binlog_dump to master_thread_id(12) slave_server(2), pos(mysql-bin.000002, 990)

slave

2017-11-08T12:09:34.187408Z 2 [Note] Slave SQL thread for channel '' initialized, starting replication in log 'mysql-bin.000002' at position 990, relay log './mysql57-2-relay-bin.000001' position: 4
2017-11-08T12:09:34.188654Z 0 [Note] End of list of non-natively partitioned tables
2017-11-08T12:10:16.096654Z 6 [Note] Slave I/O thread for channel '': connected to master 'repl@192.168.0.11:3306',replication started in log 'mysql-bin.000002' at position 990

slave側ではslave IO threadがmaster threadからのbinary logを受け取り、relay logに書き込みます。それをslave SQL threadがストレージエンジンに書き込むんですね。

おわりに

そこそこ簡単にMySQLレプリケーションが実現できましたが、この感じだとデータに差分がある状態ではレプリケーションができないのかな?と思いました。つまり、稼働中のクラスタに対して、稼働したまま新規slaveを追加するにはどうしたらいいのか、それともできないのか、疑問に思いました。

Galera Clusterの同期の仕組みを公式ドキュメントから読み解く(2) CERTIFICATION-BASED REPLICATION

はじめに

前回に引き続き、galera clusterのtechnical descriptionを読んでいきます。

Technical Description — Galera Cluster Documentation

これ、全部やると全8回になるなぁ。。。どうしようかなぁ。。。(弱気)でもどれも大事そうだからなぁ。。。とりあえずState Transfersは知りたいので、そこまでは1つずつ進んでいくことにします。

CERTIFICATION-BASED REPLICATION

証明ベースのレプリケーションはグループコミュニケーションとトランザクション並べ替え技術を使い同期を実現します。

トランザクションは1つのノード、またはレプリカで楽天的に実行し、コミットするときにそれらは一貫性を保つために調整された証明プロセスを実行します。同時発生するトランザクションの中で、順番を成立させるサービスをブロードキャストすることで、全ノードでの整合性を達成します。

WHAT CERTIFICATION-BASED REPLICATION REQUIRES

すべてのデータベースシステムに証明ベースのレプリケーションを実することは不可能です。いくつか必要なデータベースの特徴があります。

  • Transactional Database
  • Atomic Changes
    • レプリケーションエベントはデータベースとATOMICに変更できる必要があります。特に、一連のデータベースに対する操作は、すべて実行し終えたか、まったく実行していない状態か、そのどちらである必要があります。
  • Global Ordering

HOW CERTIFICATION-BASED REPLICATION WORKS

証明ベースのレプリケーションの基本的な考えは、トランザクションがコミットポイントに到達するまでに実行されることであり、コンフリクトが一切ないことが望ましい。これは楽観的な実行と呼ばれる。

clientがCOMMITコマンドを発行するとき、実際のCOMMITが実行される前ではあるが、変更された行のトランザクションと主キーによって行われたすべての変更は、write-setに収集されます。データベースは他のすべてのノードにこのwrite-setを送ります。

write-setは決定論的に受ける証明テストより、プライマリーキーを用います。これはクラスターの各ノードで行われ、write-setを元にノードを増やします。これによってwrite-setを各ノードが適用するかどうかを決定します。

もし証明テストが失敗すれば、ノードはwrite-setを破棄し、クラスターは元のトランザクションロールバックします。テストが成功すれば、トランザクションはコミットし、write-setはクラスターの残りに適用されます。

CERTIFICATION-BASED REPLICATION IN GALERA CLUSTER

galera clusterにおける証明ベースのレプリケーションの実装は、トランザクションのグローバル順序付けに依存します。

galera clusterはそれぞれのトランザクションにシーケンス番号を割り当てます。トランザクションがコミット地点にたどり着くと、ノードはシーケンス番号が最後にトランザクションが成功した番号と反しているかを確認します。それら2つが関係している間は、トランザクションはそれぞれのノードはお互いに影響を与えません。intervalの間のすべてのトランザクションは、問題となるトランザクションとすべての主キー競合を確認します。競合を検出すれば、証明テストに失敗します。

順序は決定的で、すべてのレプリカがトランザクションを同じ順番で受け取ります。すなわち、すべてのノードは同じ決定をトランザクションの結果実施するのです。トランザクションを開始したノードは、トランザクションをコミットしたかどうかをクライアントとなるアプリケーションに通知できます。

おわりに

訳が不自然なところが多いですが。。。write-setと呼ばれる一連のcommitセットの単位で、それにidを付与してクラスタに配布、primary-keyを元にしてコミットの競合がないかを確認(証明)。これが失敗すれば破棄し、成功すれば受け入れる、という風に読めました。

まだまだ続きます!毎朝書いていこうかな。

Galera Clusterの同期の仕組みを公式ドキュメントから読み解く(1) DATABASE REPLICATION

はじめに

仕事でMariaDBレプリケーションにGalera Clusterを使っています。使い方や、同期されてるかどうかの確認の方法はわかりますが、実際にどんな仕組みで差分を判定し、どんな仕組みで同期をしているかはわかっていません。

そこで公式ドキュメントを読んで理解してみましょう。

Technical Description — Galera Cluster Documentation

かなり物量が多いですね。いくつかピックアップして読んでみましょう。

DATABASE REPLICATION

Database Replication — Galera Cluster Documentation

Database replicationは、database serverである、あるノードから別のノードでデータを頻繁にコピーすることを意味します。すべてのノードが同じレベルの情報を共有する、分散データベースシステムとしてDatabase replicationを考えます。このシステムはよくdatabase clusterとして知られています。

webブラウザやcomputerアプリケーションのような、データベースクライアントはデータベースレプリケーションシステムが見えません。しかし、ネイティブのDBMSの振る舞いに近いことに恩恵を得ています。

MASTER AND SLAVE

多くのデーラベース管理システムはデータベースをレプリケーションします。

もっともよく使うレプリケーションは、オリジナルのデータセットとそのコピーの間の関係をmaster/slaveとして設定するものです。

このシステムでは、masterのデータベースサーバはデータが更新されたことと、ネットワークを通じてslaveにデータを増殖させたことをログに残します。slaveのデータベースサーバはmasterから更新の通知を受け取り、その変更を適用します。

別のレプリケーションは、すべてのノードにmasterの機能を持つmult-masterレプリケーションです。

multi-masterレプリケーションシステムでは、あなたはどのデータベースにも更新を書き込むことができます。これらの更新ははネットワークを通じてすべてのノードに伝搬されます。すべてのデータベースノードはマスターの機能を持つのです。これらには利用可能なログを残さず、システムは更新が成功したかどうかをあなたに示すこともありません。

ASYNCHRONOUS AND SYNCHRONOUS REPLICATION

他のノードへのデータ変更を行う方法に加えて、cluster間のデータ転送方法がいくつかあります。

  • 同期レプリケーション
    • "eager replication"というアプローチ。1つのトランザクション内で、すべてのノードの更新され、同期が完了する。言い換えると、transactionのコミットが発生した時、すべてのノードが同じ値を持つということです。
  • 非同期レプリケーション
    • "lazy replication"というアプローチ。masterのデータベースは非同期でslaveに更新を伝搬させます。masterノードがレプリカを伝搬させたあと、トランザクションはコミットされます。言い換えると、トランザクションがコミットされたとき、かなり短い時間でみると、いくつかのノードは違う値を持つということです。

Advantages of Synchronous Replication

同期レプリケーションのほうが、いくつか利点を持ちます。

  • 高可用性
    • 同期レプリケーションは24時間7日サービスの利用を保証し、高いクラスタ可用性を提供します。
      • ノードがクラッシュしてもデータロスなし
      • データの一貫性維持
      • 複雑で時間のかかるフェールオーバーがない
  • 性能改善
  • クラスタ間の因果関係
    • 同期レプリケーションクラスタ間の関係を(同一であることを)保証します。例えば、SELECTのクエリが他のノードで実行されたとしても、いつも同じ結果を返します。(?)

Disadvantages of Synchronous Replication

eager replication protocolはノードに対して1つの操作を同時に行います。これらは2段階のコミットか、ロックを生じます。n個のノードで構成され、oのプロセスがtのトランザクションを行うとき、mのメッセージを受け取ります。その式は

m = n × o × t

これが意味することは、トランザクションのレスポンス時間と競合とデッドとっくが発生する確率が、ノードの数の増加に伴い指数的に増加するということです。

この理由から、非同期レプリケーションが、データベースの性能、スケーラビリティ、可用性という面でもっとも有効なレプリケーションプロトコルとされています。MySQLPostgreSQLは非同期レプリケーションのみを採用していて、このようにオープンソースのdatabaseに広く適用されています。

SOLVING THE ISSUES IN SYNCHRONOUS REPLICATION

いくつか同期レプリケーションに対して問題を解決するアプローチがあります。ここ数年、研究者が同期レプリケーションに対する別の提案を行ってきました。

理論に加えて、いくつかのプロトタイプ実装が保証を示しました。これらの研究から重要な向上をいくつかもたらしました。

  • Group Communication
    • データベース間のコミュニケーションパターンを定義する高いレベルの抽象化です。レプリケーションの一貫性を保証します。
  • Write-sets
    • これは1つのwrite-setメッセージでデータベースの書き込みを束ねます。この実装は同時に1つのノード対する操作をする整合性を回避します。
  • Database State Machine
    • このプロセスはread-onlyのトランザクションをローカルのデータベースで行います。この実装は最初に実行されたトランザクションを更新し、shallow-copies上で行います。そして証明またはコミットのために、read-setとして他のデータベースに伝搬させます。
  • Tansaction Reordering
    • データベースがコミットし、伝搬させる前に、transactionを並べ替えます。この実装は証明テストをpassしたトランザクション数を増加させます。(?)

Galera Clusterが使っている証明ベースのレプリケーションシステムにはこれらのアプローチが組み込まれています。

おわりに

結構時間がかかってしまったのでこのへんで。データベースのレプリケーションに関する一般的な用語や方法を整理したドキュメントですね。同期レプリケーションの優れている点と劣っている点を記載し、mysql(mariadb)では非同期レプリケーションが使われていることがわかりました。また、劣っている点は後半であげた技術によってカバーされていることもわかりました。

全部はやらないと思いますが、あと数回続くと思います!

MariaDBの5.5と10.2でチューニング&ベンチマーク比較(2) - インターネット検索編

はじめに

この休みの間はひたすらこれです。

というわけで前回はベンチマークのための環境準備とmysqltuner先生による指摘反映をして、少し改善しました。

今の問題はupgrade後のほうが性能が落ちているように見えていることです。これを解決するチューニングは何か?というのを探していきたいともいます。

今回はインターネット上で検索してみましょう。「MariaDB チューニング」で期間を直近1年にしぼって検索してみました。

スロークエリを有効にする

性能を判断できる指標は多いほうがいいです。general_query_logを出すと大量になってしまいますが、スロークエリは常に出すべきでしょう。mysqltuner先生もそうおっしゃっていました。

slow_query_log=ON
long_query_time=0.5
log-slow-queries=/var/lib/mysql/slow.log

qiita.com

さて現在のsysbenchでスロークエリが出ているのか、確認してみましたが、スロークエリは出ていませんでした。ただ、今後問題発生したときにまっさきにみたいので、設定しておきましょう。

innodb_buffer_pool_size

現在総メモリの25%にしていますが、ストレージエンジンはinnodbしか使っていないため、80&まで割り当ててみます。1GBなので768MBに設定。

25%と80%で比較してみます。

f:id:take_she12:20171028111335p:plain

改善効果は見られないどころか、一部劣化しているので25%に戻しますかね。

dsas.blog.klab.org

variablesの差分をみる

バージョンが異なり、デフォルト値が変更になったパラメータも多数あります。膨大にありますが、関係ありそうなものを見つけるのに1度やってみます。

mysql -u root -e "show variables;"

thread

[root@mariadb10-2-8 ~]# diff variables_5_5_45.log variables_10_2_8.log | grep thread
> innodb_encryption_threads  0
> innodb_mtflush_threads 8
< innodb_purge_threads   1
> innodb_purge_threads   4
< innodb_thread_concurrency_timer_based  OFF
< performance_schema_max_thread_instances    1000
> performance_schema_max_thread_instances    6100
< pseudo_thread_id   2046
> pseudo_thread_id   2054
> slave_domain_parallel_threads  0
> slave_parallel_threads 0
< thread_pool_max_threads    500
> thread_pool_max_threads    65536
> thread_pool_prio_kickup_timer  1000
> thread_pool_priority   auto
< thread_stack   294912
> thread_stack   299008
> wsrep_slave_threads    1

thread_pool_max_threadsが全然違いますね。

Thread Pool System and Status Variables - MariaDB Knowledge Base

スレッドプール内の最大スレッド数で、これに達すると新しくスレッドが作られなくなります。これは大きい方がいいと思います。

max_allowed_packet

クライアントが送ることができる最大パケットサイズですね。

10.2.8では16MBがデフォルトになったようです。

[root@mariadb10-2-8 ~]# diff variables_5_5_45.log variables_10_2_8.log | grep max_allow
< max_allowed_packet 1048576
> max_allowed_packet 16777216

innodb

大量に出ますが、ぱっとみ何か気づくものはありませんでした。(この中に原因はあるかもしれないけど)

[root@mariadb10-2-8 ~]# diff variables_5_5_45.log variables_10_2_8.log | grep innodb
< have_innodb    YES
< innodb_adaptive_flushing_method    estimate
> innodb_adaptive_flushing_lwm   10.000000
< innodb_adaptive_hash_index_partitions  1
< innodb_additional_mem_pool_size    8388608
< innodb_autoextend_increment    8
> innodb_adaptive_hash_index_partitions  8
> innodb_adaptive_hash_index_parts   8
> innodb_adaptive_max_sleep_delay    150000
> innodb_autoextend_increment    64
< innodb_blocking_buffer_pool_restore    OFF
> innodb_background_scrub_data_check_interval    3600
> innodb_background_scrub_data_compressed    OFF
> innodb_background_scrub_data_interval  604800
> innodb_background_scrub_data_uncompressed  OFF
> innodb_buf_dump_status_frequency   0
> innodb_buffer_pool_chunk_size  134217728
> innodb_buffer_pool_dump_at_shutdown    ON
> innodb_buffer_pool_dump_now    OFF
> innodb_buffer_pool_dump_pct    25
> innodb_buffer_pool_filename    ib_buffer_pool
> innodb_buffer_pool_load_abort  OFF
> innodb_buffer_pool_load_at_startup ON
> innodb_buffer_pool_load_now    OFF
< innodb_buffer_pool_restore_at_startup  0
< innodb_buffer_pool_shm_checksum    ON
< innodb_buffer_pool_shm_key 0
> innodb_change_buffer_max_size  25
< innodb_checkpoint_age_target   0
> innodb_checksum_algorithm  crc32
> innodb_cleaner_lsn_age_factor  DEPRECATED
> innodb_cmp_per_index_enabled   OFF
< innodb_concurrency_tickets 500
< innodb_corrupt_table_action    assert
< innodb_data_file_path  ibdata1:10M:autoextend
> innodb_compression_algorithm   zlib
> innodb_compression_default OFF
> innodb_compression_failure_threshold_pct   5
> innodb_compression_level   6
> innodb_compression_pad_pct_max 50
> innodb_concurrency_tickets 5000
> innodb_corrupt_table_action    deprecated
> innodb_data_file_path  ibdata1:12M:autoextend
< innodb_dict_size_limit 0
> innodb_deadlock_detect ON
> innodb_default_encryption_key_id   1
> innodb_default_row_format  dynamic
> innodb_defragment  OFF
> innodb_defragment_fill_factor  0.900000
> innodb_defragment_fill_factor_n_recs   20
> innodb_defragment_frequency    40
> innodb_defragment_n_pages  7
> innodb_defragment_stats_accuracy   0
> innodb_disable_sort_file_cache OFF
> innodb_disallow_writes OFF
< innodb_doublewrite_file    
> innodb_empty_free_list_algorithm   DEPRECATED
> innodb_encrypt_log OFF
> innodb_encrypt_tables  OFF
> innodb_encryption_rotate_key_age   1
> innodb_encryption_rotation_iops    100
> innodb_encryption_threads  0
< innodb_fast_checksum   OFF
< innodb_file_format Antelope
> innodb_fatal_semaphore_wait_threshold  600
> innodb_file_format Barracuda
< innodb_file_format_max Antelope
> innodb_file_format_max Barracuda
> innodb_fill_factor 100
> innodb_flush_log_at_timeout    1
< innodb_flush_neighbor_pages    area
> innodb_flush_neighbors 1
> innodb_flush_sync  ON
> innodb_flushing_avg_loops  30
> innodb_force_primary_key   OFF
< innodb_ibuf_accel_rate 100
< innodb_ibuf_active_contract    1
< innodb_ibuf_max_size   402636800
< innodb_import_table_from_xtrabackup    0
> innodb_foreground_preflush DEPRECATED
> innodb_ft_aux_table    
> innodb_ft_cache_size   8000000
> innodb_ft_enable_diag_print    OFF
> innodb_ft_enable_stopword  ON
> innodb_ft_max_token_size   84
> innodb_ft_min_token_size   3
> innodb_ft_num_word_optimize    2000
> innodb_ft_result_cache_limit   2000000000
> innodb_ft_server_stopword_table    
> innodb_ft_sort_pll_degree  2
> innodb_ft_total_cache_size 640000000
> innodb_ft_user_stopword_table  
> innodb_idle_flush_pct  100
> innodb_immediate_scrub_data_uncompressed   OFF
> innodb_instrument_semaphores   OFF
> innodb_io_capacity_max 2000
< innodb_large_prefix    OFF
< innodb_lazy_drop_table 0
> innodb_large_prefix    ON
> innodb_lock_schedule_algorithm vats
< innodb_locking_fake_changes    ON
> innodb_locking_fake_changes    OFF
< innodb_log_block_size  512
< innodb_log_buffer_size 8388608
> innodb_log_arch_dir    
> innodb_log_arch_expire_sec 0
> innodb_log_archive OFF
> innodb_log_block_size  0
> innodb_log_buffer_size 16777216
> innodb_log_checksum_algorithm  DEPRECATED
> innodb_log_checksums   ON
> innodb_log_compressed_pages    ON
< innodb_max_bitmap_file_size    104857600
< innodb_max_changed_pages   1000000
< innodb_max_dirty_pages_pct 75
> innodb_log_write_ahead_size    8192
> innodb_lru_scan_depth  1024
> innodb_max_bitmap_file_size    0
> innodb_max_changed_pages   0
> innodb_max_dirty_pages_pct 75.000000
> innodb_max_dirty_pages_pct_lwm 0.000000
< innodb_merge_sort_block_size   1048576
< innodb_mirrored_log_groups 1
> innodb_max_purge_lag_delay 0
> innodb_max_undo_log_size   10485760
> innodb_mirrored_log_groups 0
> innodb_monitor_disable 
> innodb_monitor_enable  
> innodb_monitor_reset   
> innodb_monitor_reset_all   
> innodb_mtflush_threads 8
< innodb_old_blocks_time 0
< innodb_open_files  300
> innodb_old_blocks_time 1000
> innodb_online_alter_log_max_size   134217728
> innodb_open_files  2000
> innodb_optimize_fulltext_only  OFF
> innodb_page_cleaners   1
> innodb_prefix_index_cluster_optimization   OFF
< innodb_purge_batch_size    20
< innodb_purge_threads   1
> innodb_purge_batch_size    300
> innodb_purge_rseg_truncate_frequency   128
> innodb_purge_threads   4
< innodb_read_ahead  linear
< innodb_recovery_stats  OFF
< innodb_recovery_update_relay_log   OFF
> innodb_read_only   OFF
< innodb_show_locks_held 10
> innodb_sched_priority_cleaner  0
> innodb_scrub_log   OFF
> innodb_scrub_log_speed 256
> innodb_show_locks_held 0
< innodb_simulate_comp_failures  0
> innodb_sort_buffer_size    1048576
< innodb_stats_auto_update   1
> innodb_stats_auto_recalc   ON
> innodb_stats_include_delete_marked OFF
< innodb_stats_on_metadata   ON
> innodb_stats_on_metadata   OFF
> innodb_stats_persistent    ON
> innodb_stats_persistent_sample_pages   20
< innodb_stats_update_need_lock  1
< innodb_strict_mode OFF
> innodb_stats_transient_sample_pages    8
> innodb_status_output   OFF
> innodb_status_output_locks OFF
> innodb_strict_mode ON
> innodb_sync_array_size 1
> innodb_temp_data_file_path ibtmp1:12M:autoextend
< innodb_thread_concurrency_timer_based  OFF
> innodb_tmpdir  
< innodb_use_atomic_writes   OFF
> innodb_track_redo_log_now  OFF
> innodb_undo_directory  ./
> innodb_undo_log_truncate   OFF
> innodb_undo_logs   128
> innodb_undo_tablespaces    0
> innodb_use_atomic_writes   ON
< innodb_use_global_flush_log_at_trx_commit  ON
> innodb_use_global_flush_log_at_trx_commit  OFF
> innodb_use_mtflush OFF
< innodb_use_sys_malloc  ON
< innodb_use_sys_stats_table OFF
< innodb_version 5.5.44-MariaDB-37.3
> innodb_use_trim    ON
> innodb_version 5.7.19

おわりに

今回はバージョン間での性能歳を見つけることができませんでした。

次回は何が原因でトランザクション性能に差分がでているのか、その指標になる値を見つけて、比較したのち、パラメータ変更につなげていきます。

MariaDBの5.5と10.2でチューニング&ベンチマーク比較(1) - mysqltuner編

はじめに

多くは語りませんが仕事でMariaDBを触っており、その一環です。

環境はCloud Garageさん!ありがとうございます!!!

take-she12.hatenablog.com

準備

CloudGarageでCentOS6.8でVM作成。

repoファイルを置く。centos7用に使っていたものを適当に修正。

[root@mariadb5-5-45 ~]# cat /etc/yum.repos.d/MariaDB.repo 
[mariadb]
name = MariaDB
baseurl = http://yum.mariadb.org/5.5.45/centos6-amd64
gpgkey=https://yum.mariadb.org/RPM-GPG-KEY-MariaDB
gpgcheck=1

10系の場合はバージョンをs/5.5.45/10.2.8/g してください。

そしてyum install MariaDBする。

[root@mariadb5-5-45 ~]# rpm -qa | grep Maria
MariaDB-compat-5.5.45-1.el6.x86_64
MariaDB-common-5.5.45-1.el6.x86_64
MariaDB-client-5.5.45-1.el6.x86_64
MariaDB-server-5.5.45-1.el6.x86_64
[root@mariadb10-2-8 ~]# rpm -qa | grep Maria
MariaDB-compat-10.2.8-1.el6.x86_64
MariaDB-common-10.2.8-1.el6.x86_64
MariaDB-client-10.2.8-1.el6.x86_64
MariaDB-server-10.2.8-1.el6.x86_64

sysbenchもyumでinstall。もともとepelが入ってた。ないひとはyum install epel-releaseしてからyum install sysbenchしてください。

[root@mariadb5-5-45 ~]# sysbench --version
sysbench 1.0.9

基本性能

まぁ同じスペックでVM作ってるから同じになるのは当たり前っちゃ当たり前なんですが、念のため両ノードでスペック差がないか、CPU/メモリ/IO観点で調査した。結果は割愛するが、ほぼ同じになった。

方法は以下を参照しました。ありがとうございました。

sysbenchでCPU/メモリ/ディスクのパフォーマンスを計測する。

デフォルト設定でのmysqlベンチマーク

さて次はmysqlベンチマークです。

まず、sysbenchでテストするためのテストユーザとテストテーブルを作成します。

[root@mariadb5-5-45 ~]# mysqladmin -u root create sbtest
[root@mariadb5-5-45 ~]# mysql -u root
Welcome to the MariaDB monitor.  Commands end with ; or \g.
Your MariaDB connection id is 4
Server version: 5.5.45-MariaDB MariaDB Server

Copyright (c) 2000, 2015, Oracle, MariaDB Corporation Ab and others.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

MariaDB [(none)]> GRANT ALL ON sbtest.* TO 'sbtest'@'localhost' IDENTIFIED BY 'sbtest';
Query OK, 0 rows affected (0.01 sec)

テーブルを準備します。

[root@mariadb5-5-45 ~]# sysbench /usr/share/sysbench/tests/include/oltp_legacy/oltp.lua --db-driver=mysql --oltp-table-size=1000000 --mysql-host=localhost --mysql-password=sbtest prepare
sysbench 1.0.9 (using system LuaJIT 2.0.4)

Creating table 'sbtest1'...
Inserting 1000000 records into 'sbtest1'
Creating secondary indexes on 'sbtest1'...

さてテスト実行です。

[root@mariadb5-5-45 ~]# sysbench /usr/share/sysbench/tests/include/oltp_legacy/oltp.lua --oltp-table-size=1000000 --db-driver=mysql --mysql-host=localhost --mysql-db=sbtest --mysql-user=sbtest --mysql-password=sbtest --time=60 --events=0 --threads=1 --oltp_read_only=off run >> /tmp/sysbench_oltp_read_write_1.log

read/writeのテストをしました。thread数1での結果は。。。

[root@mariadb5-5-45 ~]# grep transactions /tmp/sysbench_oltp_read_write_1.log 
    transactions:                        19970  (332.80 per sec.)
[root@mariadb10-2-8 ~]# grep transactions /tmp/sysbench_oltp_read_write_1.log 
    transactions:                        15385  (256.39 per sec.)

transactionsをみると10.2.8のほうが性能は落ちるようです。

さて、thread数を増やして実行してみます。

結果は以下のようになりました。試験時間は60秒で、数値はtransactions。

threads 5.5.45 10.2.8
1 21367 15911
2 23426 18765
4 23251 20641
8 24237 21442
16 24242 21712
32 24360 21208
64 26085 21627
128 24532 21869

clientの問題か、これ以上のスレッド数ではエラーを吐いてしまった。

[root@mariadb5-5-45 ~]# ./sysbench.sh 
Error in my_thread_global_end(): 83 threads didn't exit
Error in my_thread_global_end(): 57 threads didn't exit
Error in my_thread_global_end(): 103 threads didn't exit

さて、今回の結果は、スレッド数を増やすと差は縮まったものの、どのスレッド数においてもMariaDB5.5のほうが若干性能が良いということがわかった。

参考

blog.apar.jp

qiita.com

mysqltuner

うーん。でもconfigをどう変えてチューニングすればパフォーマンスがあがるかわからない。。。

そこでmysqltunerですよ!

github.com

perlスクリプトで、現在のmysqlサーバに対して「いい感じ」な設定をおすすめしてくれる大変いいやつである。

[root@mariadb5-5-45 ~]# wget https://raw.githubusercontent.com/major/MySQLTuner-perl/master/mysqltuner.pl
--2017-10-27 22:55:06--  https://raw.githubusercontent.com/major/MySQLTuner-perl/master/mysqltuner.pl
raw.githubusercontent.com をDNSに問いあわせています... 
raw.githubusercontent.com に接続しています... 接続しました。
HTTP による接続要求を送信しました、応答を待っています... 200 OK
長さ: 214792 (210K) [text/plain]
`mysqltuner.pl' に保存中

100%[================================================>] 214,792     --.-K/s 時間 0.01s   

2017-10-27 22:55:06 (17.1 MB/s) - `mysqltuner.pl' へ保存完了 [214792/214792]

[root@mariadb5-5-45 ~]# chmod u+x mysqltuner.pl 

githubからraw scriptをwgetして、実行権を与えてやればいい。さぁそれぞれで診断してやろう。

5.5.45の結果

[root@mariadb5-5-45 ~]# ./mysqltuner.pl 
 >>  MySQLTuner 1.7.4 - Major Hayden <major@mhtx.net>
 >>  Bug reports, feature requests, and downloads at http://mysqltuner.com/
 >>  Run with '--help' for additional options and output filtering

[--] Skipped version check for MySQLTuner script
[!!] Successfully authenticated with no password - SECURITY RISK!
[OK] Currently running supported MySQL version 5.5.45-MariaDB
[OK] Operating on 64-bit architecture
 
-------- Log file Recommendations ------------------------------------------------------------------
[--] Log file: /var/lib/mysql/mariadb5-5-45.err(1K)
[OK] Log file /var/lib/mysql/mariadb5-5-45.err exists
[OK] Log file /var/lib/mysql/mariadb5-5-45.err is readable.
[OK] Log file /var/lib/mysql/mariadb5-5-45.err is not empty
[OK] Log file /var/lib/mysql/mariadb5-5-45.err is smaller than 32 Mb
[!!] /var/lib/mysql/mariadb5-5-45.err contains 1 warning(s).
[OK] /var/lib/mysql/mariadb5-5-45.err doesn't contain any error.
[--] 1 start(s) detected in /var/lib/mysql/mariadb5-5-45.err
[--] 1) 171027 22:01:18 [Note] /usr/sbin/mysqld: ready for connections.
[--] 0 shutdown(s) detected in /var/lib/mysql/mariadb5-5-45.err
 
-------- Storage Engine Statistics -----------------------------------------------------------------
[--] Status: +ARCHIVE +Aria +BLACKHOLE +CSV +FEDERATED +InnoDB +MEMORY +MRG_MYISAM +MyISAM +PERFORMANCE_SCHEMA 
[--] Data in InnoDB tables: 241M (Tables: 1)
[OK] Total fragmented tables: 0
 
-------- Security Recommendations ------------------------------------------------------------------
[!!] User '@localhost' is an anonymous account.
[!!] User '@mariadb5-5-45' is an anonymous account.
[!!] User '@localhost' has no password set.
[!!] User '@mariadb5-5-45' has no password set.
[!!] User 'root@127.0.0.1' has no password set.
[!!] User 'root@::1' has no password set.
[!!] User 'root@localhost' has no password set.
[!!] User 'root@mariadb5-5-45' has no password set.
[!!] User '@localhost' has user name as password.
[!!] User '@mariadb5-5-45' has user name as password.
[!!] User 'sbtest@localhost' has user name as password.
[!!] There is no basic password file list!
 
-------- CVE Security Recommendations --------------------------------------------------------------
[--] Skipped due to --cvefile option undefined
 
-------- Performance Metrics -----------------------------------------------------------------------
[--] Up for: 55m 11s (8M q [2K qps], 5K conn, TX: 15G, RX: 664M)
[--] Reads / Writes: 77% / 23%
[--] Binary logging is disabled
[--] Physical Memory     : 996.2M
[--] Max MySQL memory    : 836.0M
[--] Other process memory: 27.0M
[--] Total buffers: 416.0M global + 2.8M per thread (151 max threads)
[--] P_S Max memory usage: 0B
[--] Galera GCache Max memory usage: 0B
[OK] Maximum reached memory usage: 838.8M (84.20% of installed RAM)
[OK] Maximum possible memory usage: 836.0M (83.92% of installed RAM)
[OK] Overall possible memory usage with other process is compatible with memory available
[OK] Slow queries: 0% (0/8M)
[!!] Highest connection usage: 100%  (152/151)
[OK] Aborted connections: 0.35%  (18/5145)
[!!] name resolution is active : a reverse name resolution is made for each new connection and can reduce performance
[!!] Query cache may be disabled by default due to mutex contention.
[!!] Query cache efficiency: 0.0% (0 cached / 5M selects)
[OK] Query cache prunes per day: 0
[OK] Sorts requiring temporary tables: 0% (0 temp sorts / 823K sorts)
[OK] No joins without indexes
[OK] Temporary tables created on disk: 0% (0 on disk / 411K total)
[!!] Thread cache is disabled
[OK] Table cache hit rate: 116% (177 open / 152 opened)
[OK] Open file limit used: 2% (21/1K)
[OK] Table locks acquired immediately: 100% (7M immediate / 7M locks)
 
-------- Performance schema ------------------------------------------------------------------------
[--] Performance schema is disabled.
[--] Memory used by P_S: 0B
[--] Sys schema isn't installed.
 
-------- ThreadPool Metrics ------------------------------------------------------------------------
[--] ThreadPool stat is enabled.
[--] Thread Pool Size: 1 thread(s).
[--] Using default value is good enough for your version (5.5.45-MariaDB)
 
-------- MyISAM Metrics ----------------------------------------------------------------------------
[!!] Key buffer used: 18.2% (24M used / 134M cache)
[OK] Key buffer size / total MyISAM indexes: 128.0M/99.0K
[!!] Read Key buffer hit rate: 42.9% (7 cached / 4 reads)
[OK] Write Key buffer hit rate: 100.0% (4 cached / 4 writes)
 
-------- InnoDB Metrics ----------------------------------------------------------------------------
[--] InnoDB is enabled.
[--] InnoDB Thread Concurrency: 0
[!!] InnoDB File per table is not activated
[!!] InnoDB buffer pool / data size: 128.0M/241.8M
[!!] Ratio InnoDB log file size / InnoDB Buffer pool size (7.8125 %): 5.0M * 2/128.0M should be equal 25%
[OK] InnoDB buffer pool instances: 1
[--] InnoDB Buffer Pool Chunk Size not used or defined in your version
[OK] InnoDB Read buffer efficiency: 99.79% (81983156 hits/ 82152336 total)
[OK] InnoDB Write log efficiency: 94.41% (3481763 hits/ 3687842 total)
[OK] InnoDB log waits: 0.00% (0 waits / 206079 writes)
 
-------- AriaDB Metrics ----------------------------------------------------------------------------
[--] AriaDB is enabled.
[OK] Aria pagecache size / total Aria indexes: 128.0M/1B
 
-------- TokuDB Metrics ----------------------------------------------------------------------------
[--] TokuDB is disabled.
 
-------- XtraDB Metrics ----------------------------------------------------------------------------
[--] XtraDB is disabled.
 
-------- RocksDB Metrics ---------------------------------------------------------------------------
[--] RocksDB is disabled.
 
-------- Spider Metrics ----------------------------------------------------------------------------
[--] Spider is disabled.
 
-------- Connect Metrics ---------------------------------------------------------------------------
[--] Connect is disabled.
 
-------- Galera Metrics ----------------------------------------------------------------------------
[--] Galera is disabled.
 
-------- Replication Metrics -----------------------------------------------------------------------
[--] Galera Synchronous replication: NO
[--] No replication slave(s) for this server.
[--] This is a standalone server.
 
-------- Recommendations ---------------------------------------------------------------------------
General recommendations:
    Control warning line(s) into /var/lib/mysql/mariadb5-5-45.err file
    Remove Anonymous User accounts - there are 2 anonymous accounts.
    Set up a Password for user with the following SQL statement ( SET PASSWORD FOR 'user'@'SpecificDNSorIp' = PASSWORD('secure_password'); )
    Set up a Secure Password for user@host ( SET PASSWORD FOR 'user'@'SpecificDNSorIp' = PASSWORD('secure_password'); )
    MySQL started within last 24 hours - recommendations may be inaccurate
    Enable the slow query log to troubleshoot bad queries
    Reduce or eliminate persistent connections to reduce connection usage
    Configure your accounts with ip or subnets only, then update your configuration with skip-name-resolve=1
    Set thread_cache_size to 4 as a starting value
    Consider installing Sys schema from https://github.com/mysql/mysql-sys
    Read this before changing innodb_log_file_size and/or innodb_log_files_in_group: http://bit.ly/2wgkDvS
Variables to adjust:
    max_connections (> 151)
    wait_timeout (< 28800)
    interactive_timeout (< 28800)
    query_cache_size (=0)
    query_cache_type (=0)
    query_cache_limit (> 1M, or use smaller result sets)
    thread_cache_size (start at 4)
    innodb_file_per_table=ON
    innodb_buffer_pool_size (>= 241M) if possible.
    innodb_log_file_size should be (=16M) if possible, so InnoDB total log files size equals to 25% of buffer pool size.

結構長いが、!!のところが対応必要な項目。そして最後に対応方針を示してくれている。今回関心があるのは性能なのでPerformance Metricsをみよう。

なるほど、max connectionの151を超えてしまったから先ほど256以上は失敗したんですね。max_connectionは十分大きな値にしましょう。

thread_cacheが0のようなので、thread_cache_sizeを4にしてみましょう。

デフォルトストレージエンジンであるinnodb_bugger_pool_sizeはメモリの25%にあたる256Mぐらいに設定してみましょう。

ちなみに10.2.8での結果もほとんど差がなかったので省略します。

config変更

レビュー指摘反映。(笑うところです)

[root@mariadb5-5-45 ~]# cat /etc/my.cnf
#
# This group is read both both by the client and the server
# use it for options that affect everything
#
[client-server]

[mysqld]
max_connections = 3000
query_cache_size = 0
query_cache_type = 0
query_cache_limit = 1M
thread_cache_size = 3000
innodb_buffer_pool_size = 256M

#
# include all files from the config directory
#
!includedir /etc/my.cnf.d

さて、thread_cache_sizeの指摘はmariadb10.2.8ではでてなかった。それはデフォルト値が10.2からautoとなったからである。max_connectionsが256の小さいほうになるらしい。5系では0である。今回はいずれもmax_connectionsと同じ3000にしておきましょう。

Server System Variables - MariaDB Knowledge Base

service mysql restartを忘れずに。

再計測

ここで余談ですけどscript化しておくとらくですね。

こんな絶望的なファイル出力していたとしても

[root@mariadb5-5-45 ~]# ls /tmp/ | sort -n
sysbench_oltp_read_write_1.log
sysbench_oltp_read_write_1024.log
sysbench_oltp_read_write_128.log
sysbench_oltp_read_write_16.log
sysbench_oltp_read_write_2.log
sysbench_oltp_read_write_256.log
sysbench_oltp_read_write_32.log
sysbench_oltp_read_write_4.log
sysbench_oltp_read_write_512.log
sysbench_oltp_read_write_64.log
sysbench_oltp_read_write_8.log

sortコマンドのセパレータを指定してやればいいですね。

[root@mariadb5-5-45 ~]# ls /tmp/ | sort -t_ -nk5
sysbench_oltp_read_write_1.log
sysbench_oltp_read_write_2.log
sysbench_oltp_read_write_4.log
sysbench_oltp_read_write_8.log
sysbench_oltp_read_write_16.log
sysbench_oltp_read_write_32.log
sysbench_oltp_read_write_64.log
sysbench_oltp_read_write_128.log
sysbench_oltp_read_write_256.log
sysbench_oltp_read_write_512.log
sysbench_oltp_read_write_1024.log

余談でした。で、結果です。

[root@mariadb5-5-45 tmp]# ls /tmp/ | sort -t_ -nk5 | xargs -I{} grep transaction {}
    transactions:                        20963  (349.36 per sec.)
    transactions:                        24208  (403.42 per sec.)
    transactions:                        25565  (426.04 per sec.)
    transactions:                        24855  (414.20 per sec.)
    transactions:                        25634  (427.06 per sec.)
    transactions:                        25672  (427.23 per sec.)
    transactions:                        25843  (430.24 per sec.)
    transactions:                        26327  (437.70 per sec.)
    transactions:                        24750  (410.60 per sec.)
    transactions:                        22730  (371.98 per sec.)
[root@mariadb10-2-8 tmp]# ls /tmp/ | sort -t_ -nk5 | xargs -I{} grep transaction {}
    transactions:                        16510  (275.14 per sec.)
    transactions:                        19560  (325.97 per sec.)
    transactions:                        21380  (356.29 per sec.)
    transactions:                        22405  (373.33 per sec.)
    transactions:                        22544  (375.61 per sec.)
    transactions:                        22200  (369.74 per sec.)
    transactions:                        23139  (385.28 per sec.)
    transactions:                        22164  (368.60 per sec.)
    transactions:                        23066  (383.06 per sec.)
    transactions:                        21922  (362.38 per sec.)

若干改善したものの、やはりまだ5.5のほうが性能いいですね。

(これグラフにしたいな)

threads 5.5.45 5.5.45(2) 10.2.8 10.2.8(2)
1 21367 20963 15911 16510
2 23426 24208 18765 19560
4 23251 25565 20641 21380
8 24237 24855 21442 22405
16 24242 25634 21712 22544
32 24360 25672 21208 22200
64 26085 25843 21627 23139
128 24532 26327 21869 22164
256 24750 23066
512 22730 21922

さてmax_connectionsを3000にしたのにも関わらず1024スレッドだとしんじゃったのは謎ですが、再びtunerさんに診断してもらいましょう。

[root@mariadb10-2-8 ~]# Error in my_thread_global_end(): 3 threads didn't exit

[OK] Thread cache hit rate: 75% (514 created / 2K connections)

thread cacheが効いているようですね。

さてvariableについては、5.5.45に対して

    table_open_cache (> 400)
    innodb_file_per_table=ON
    innodb_log_file_size should be (=32M) if possible, so InnoDB total log files size equals to 25% of buffer pool size.

10.2.8に対して

    performance_schema = ON enable PFS
    innodb_log_file_size should be (=32M) if possible, so InnoDB total log files size equals to 25% of buffer pool size.

それぞれで指摘が違います。

各パラメータの意味を調べてみましょう。

table_open_cache

tableのキャッシュ。今回1テーブルでやってるので効果は見られない気がする。 * https://mariadb.com/kb/en/library/optimizing-table_open_cache/ * 10.1.7からdefaultが2000になったそう。(それまでは400) それで指摘が違ったんですね。

開いたテーブルの数を確認すると、

5.5.45

MariaDB [(none)]> show global status like 'opened_tables';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| Opened_tables | 94083 |
+---------------+-------+
1 row in set (0.00 sec)

10.2.8

MariaDB [(none)]> show global status like 'opened_tables';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| Opened_tables | 600   |
+---------------+-------+
1 row in set (0.00 sec)

と大差がついている。ここは10.2.8と同じく2000を設定しよう。(ますます5系の性能があがる気がするが。。。)

innodb_file_per_table

innodbのデータファイルをテーブルごとに作成するみたいです。

https://mariadb.com/kb/en/library/xtradbinnodb-server-system-variables/#innodb_file_per_table

マニュアルによると5.5からデフォルトONみたいなんだけど、なんで5.5には指摘でたんだろう?実際に値を確認してみる。

MariaDB [(none)]> show variables like 'innodb_file_per_table';
+-----------------------+-------+
| Variable_name         | Value |
+-----------------------+-------+
| innodb_file_per_table | OFF   |
+-----------------------+-------+
1 row in set (0.00 sec)

OFFやんけ。というわけで、ONの設定を追加する。

innodb_log_file_size

これはinnodb_buffer_pool_sizeの25%ぐらいにしろと言っている。256Mなので64Mだね。

再々実施

5.5.45のほうではすべてスレッドがしんでしまった。10系では逆に問題なかった。何がいけなかったのだろうか?

ログをみるとibdataのlog file sizeが契機か。

InnoDB: Error: log file ./ib_logfile0 is of different size 0 5242880 bytes
InnoDB: than specified in the .cnf file 0 67108864 bytes!
InnoDB: Possible causes for this error:
 (a) Incorrect log file is used or log file size is changed
 (b) In case default size is used this log file is from 10.0
 (c) Log file is corrupted or there was not enough disk space
 In case (b) you need to set innodb_log_file_size = 48M
171028  0:32:03 [ERROR] Plugin 'InnoDB' init function returned error.
171028  0:32:03 [ERROR] Plugin 'InnoDB' registration as a STORAGE ENGINE failed.
171028  0:32:03 [Note] Plugin 'FEEDBACK' is disabled.
171028  0:32:03 [ERROR] Unknown/unsupported storage engine: InnoDB
171028  0:32:03 [ERROR] Aborting

壊れたので/var/lib/mysql以下全削除、yum remove & installで再インストールして、dbとuser再作成しました。

さて、10系ではtuner先生にあとひところだけ言われます。

performance_schema = ON enable PFS

PERFORMANCE_SCHEMAの概要 - MariaDB Knowledge Base

5.5から採用されたperformanceを計測するためのテーブル、performance schemaはmariadb10.0.12でデフォルトオフになったようです。

メモリを余計に食ってしまい性能が下がってしまわないか気になりますが、onにして再試験してみましょう。

やはり有効にすると両方とも若干落ちました。

おわりに

今回mysqltunerを指標にしてチューニングをし、性能への改善は見られましたが、10.2.8が5.5.45に勝つことはありませんでした。

今回第1回として、様々なアプローチで10.2.8が全力を出し5.5.45を超えるための方法を探していきたいと思います。

CloudGarageのDevAssistProgramに通ったのでさっそくインスタンス作ってみる

はじめに

CloudGarageのDevAssistProgram通りましたー!

CloudGarageさんは定額制のパブリッククラウド。利用料金にビクビクすることがないのでいいですね。

そしてDevAssistProgramです。

cloudgarage.jp

LBが1つと、インスタンス3つもついてきます!なんと1年間無料。承認制です。

わたしはいのうえさんのkubernetesの記事でこのキャンペーンを知りました。

blog.a-know.me

こちらもぜひやってみたい。

注意

審査が通ったあとは、アカウントを作成し、再度アカウント名をメールで送信することでアカウント情報と紐付けされ、キャンペーン対象を無償購入できるようになります。そのため承認がおりても使えるまでは多少タイムラグが生じるのでなるべくはやく返信しましょう。

使ってみる

ではさっそくコントロールパネルからインスタンスを作ってみましょう。

無事審査が通ると以下の画面でキャンペーンプランを購入できます。

f:id:take_she12:20171012182227p:plain

インスタンス作成です。OSはCentOSUbuntuDebianfedoraSuSEといろんな種類が使えますね。Rancherがあるのがめずらしいと思いました。Docker環境がらくらく作れちゃいますね。

f:id:take_she12:20171012182234p:plain

逆にアプリケーションが乗った状態で配られるものもあります。GitlabやRedmineはだいぶインストールが楽になったとはいえ、ソッコー使えるのは結構嬉しいですね。Gitlabはgitlab.comが代替になるとして、個人用のRedmineは欲しいと思ったことあるな。(音楽制作のプロジェクト用に)

f:id:take_she12:20171012182240p:plain

インスタンスを作ると10秒そこらで稼働中になりました。ポートはhttpの80番とsshの22番だけあけておきました。

f:id:take_she12:20171012182249p:plain

実際にログインしてみます。

rootユーザで、インスタンス作成時のパスワードを入力すればログイン完了!

⋊> ~/g/private on master ⨯ ssh root@203.104.226.212                                                                   18:31:39
root@203.104.226.212's password: 
Last failed login: Thu Oct 12 18:26:25 JST 2017 from 171.233.59.3 on ssh:notty
There were 16954 failed login attempts since the last successful login.
Last login: Mon Jun 26 13:22:52 2017
[root@cloudgarage1 ~]# 

22番公開してるからかめちゃくちゃログインアタックかけられてますねw やっぱりport番号は変えないとダメかな。

[root@cloudgarage1 ~]# cat /etc/redhat-release 
CentOS Linux release 7.3.1611 (Core) 

OSはちゃんとCentOS7.3です。

おわりに

(このインスタンスはちゃんと破棄しました)

インストール直後のセキュリティまわりの設定はあとでするとして、個人でLBつきの3台使えるのは開発者にとって非常にうれしいことです。上記のkubernetesだったり、redmine個人用に作ったりもしてみたいですが、まずは直近仕事で使うMariaDBのGalera Clusterを試します。

というわけでCloudGarageの宣伝&導入記事でした。(別に頼まれてません!)