GA

2025/06/10

Oracle Linux 8でMySQL 5.7のrpmをビルドする

TL;DR


MySQL Product Archives で見たら、MySQL 5.7はOracle Linux(に限らずRHEL系の)8に対応したrpmはなかった。けど欲しい。

というわけで(el7用のrpmファイルでも動くような気はするけど一応) Oracle Linuxのコンテナイメージ の中でrpmbuildするメモ。

# wget http://repo.mysql.com/yum/mysql-5.7-community/el/7/SRPMS/mysql-community-5.7.44-1.el7.src.rpm
# rpm -i mysql-community-5.7.44-1.el7.src.rpm

# dnf install rpm-build

# rpmbuild -bb ~/rpmbuild/SPECS/mysql.spec
error: Failed build dependencies:
        cyrus-sasl-devel is needed by mysql-community-5.7.44-1.el8.x86_64
        libaio-devel is needed by mysql-community-5.7.44-1.el8.x86_64
        ncurses-devel is needed by mysql-community-5.7.44-1.el8.x86_64
        numactl-devel is needed by mysql-community-5.7.44-1.el8.x86_64
        openldap-devel is needed by mysql-community-5.7.44-1.el8.x86_64
        openssl-devel is needed by mysql-community-5.7.44-1.el8.x86_64
        perl is needed by mysql-community-5.7.44-1.el8.x86_64
        perl(Carp) is needed by mysql-community-5.7.44-1.el8.x86_64
        perl(Config) is needed by mysql-community-5.7.44-1.el8.x86_64
        perl(Cwd) is needed by mysql-community-5.7.44-1.el8.x86_64
        perl(Data::Dumper) is needed by mysql-community-5.7.44-1.el8.x86_64
        perl(English) is needed by mysql-community-5.7.44-1.el8.x86_64
        perl(Errno) is needed by mysql-community-5.7.44-1.el8.x86_64
        perl(Exporter) is needed by mysql-community-5.7.44-1.el8.x86_64
        perl(Fcntl) is needed by mysql-community-5.7.44-1.el8.x86_64
        perl(File::Basename) is needed by mysql-community-5.7.44-1.el8.x86_64
        perl(File::Copy) is needed by mysql-community-5.7.44-1.el8.x86_64
        perl(File::Find) is needed by mysql-community-5.7.44-1.el8.x86_64
        perl(File::Path) is needed by mysql-community-5.7.44-1.el8.x86_64
        perl(File::Spec) is needed by mysql-community-5.7.44-1.el8.x86_64
        perl(File::Spec::Functions) is needed by mysql-community-5.7.44-1.el8.x86_64
        perl(File::Temp) is needed by mysql-community-5.7.44-1.el8.x86_64
        perl(Getopt::Long) is needed by mysql-community-5.7.44-1.el8.x86_64
        perl(IO::File) is needed by mysql-community-5.7.44-1.el8.x86_64
        perl(IO::Handle) is needed by mysql-community-5.7.44-1.el8.x86_64
        perl(IO::Pipe) is needed by mysql-community-5.7.44-1.el8.x86_64
        perl(IO::Select) is needed by mysql-community-5.7.44-1.el8.x86_64
        perl(IO::Socket) is needed by mysql-community-5.7.44-1.el8.x86_64
        perl(IO::Socket::INET) is needed by mysql-community-5.7.44-1.el8.x86_64
        perl(JSON) is needed by mysql-community-5.7.44-1.el8.x86_64
        perl(Memoize) is needed by mysql-community-5.7.44-1.el8.x86_64
        perl(POSIX) is needed by mysql-community-5.7.44-1.el8.x86_64
        perl(Sys::Hostname) is needed by mysql-community-5.7.44-1.el8.x86_64
        perl(Time::HiRes) is needed by mysql-community-5.7.44-1.el8.x86_64
        perl(Time::localtime) is needed by mysql-community-5.7.44-1.el8.x86_64
        time is needed by mysql-community-5.7.44-1.el8.x86_64
        zlib-devel is needed by mysql-community-5.7.44-1.el8.x86_64

依存のものを入れる。

# dnf install -y cyrus-sasl-devel libaio-devel ncurses-devel numactl-devel openldap-devel openssl-devel perl time zlib-devel perl-JSON

# rpmbuild -bb ~/rpmbuild/SPECS/mysql.spec
Executing(%prep): /bin/sh -e /var/tmp/rpm-tmp.5u4iqi
+ umask 022
+ cd /root/rpmbuild/BUILD
+ cd /root/rpmbuild/BUILD
+ rm -rf mysql-5.7.44
+ /usr/bin/mkdir -p mysql-5.7.44

..
+ cmake ../mysql-5.7.44 -DBUILD_CONFIG=mysql_release -DINSTALL_LAYOUT=RPM -DCMAKE_BUILD_TYPE=Debug -DWITH_BOOST=.. '-DCMAKE_C_FLAGS= -g -pipe -Wall -Werror=format-security   -Wp,-D_GLIBCXX_ASSERTIONS -fexceptions -fstack-protector-strong -grecord-gcc-switches -specs=/usr/lib/rpm/redhat/redhat-hardened-cc1 -specs=/usr/lib/rpm/redhat/redhat-annobin-cc1 -m64 -mtune=generic -fasynchronous-unwind-tables -fstack-clash-protection -fcf-protection' '-DCMAKE_CXX_FLAGS= -g -pipe -Wall -Werror=format-security   -Wp,-D_GLIBCXX_ASSERTIONS -fexceptions -fstack-protector-strong -grecord-gcc-switches -specs=/usr/lib/rpm/redhat/redhat-hardened-cc1 -specs=/usr/lib/rpm/redhat/redhat-annobin-cc1 -m64 -mtune=generic -fasynchronous-unwind-tables -fstack-clash-protection -fcf-protection' -DWITH_INNODB_MEMCACHED=1 -DINSTALL_LIBDIR=lib64/mysql -DINSTALL_PLUGINDIR=lib64/mysql/plugin/debug -DMYSQL_UNIX_ADDR=/var/lib/mysql/mysql.sock -DMYSQLX_UNIX_ADDR=/var/run/mysqld/mysqlx.sock -DFEATURE_SET=community -DWITH_EMBEDDED_SERVER=1 -DWITH_EMBEDDED_SHARED_LIBRARY=1 -DWITH_NUMA=ON '-DCOMPILATION_COMMENT=MySQL Community Server - Debug (GPL)' -DMYSQL_SERVER_SUFFIX=
/var/tmp/rpm-tmp.AHE541: line 47: cmake: command not found
error: Bad exit status from /var/tmp/rpm-tmp.AHE541 (%build)

RPM build errors:
    Bad exit status from /var/tmp/rpm-tmp.AHE541 (%build)

cmake忘れてた…というかBuildRequiresに書いておいてくれればいいのに。そのほか、ビルド中に転けたパッケージも入れた。

# dnf install -y cmake gcc gcc-c++ libtirpc-devel
# dnf install -y --enablerepo=ol8_codeready_builder rpcgen
# rpmbuild -bb ~/rpmbuild/SPECS/mysql.spec

これで完成。

# ll ~/rpmbuild/RPMS/x86_64/mysql-community-*
-rw-r--r--. 1 root root  22908224 Jun 10 03:31 /root/rpmbuild/RPMS/x86_64/mysql-community-client-5.7.44-1.el8.x86_64.rpm
-rw-r--r--. 1 root root    323348 Jun 10 03:31 /root/rpmbuild/RPMS/x86_64/mysql-community-common-5.7.44-1.el8.x86_64.rpm
-rw-r--r--. 1 root root   3790152 Jun 10 03:32 /root/rpmbuild/RPMS/x86_64/mysql-community-devel-5.7.44-1.el8.x86_64.rpm
-rw-r--r--. 1 root root  59816800 Jun 10 03:32 /root/rpmbuild/RPMS/x86_64/mysql-community-embedded-5.7.44-1.el8.x86_64.rpm
-rw-r--r--. 1 root root 172178112 Jun 10 03:33 /root/rpmbuild/RPMS/x86_64/mysql-community-embedded-devel-5.7.44-1.el8.x86_64.rpm
-rw-r--r--. 1 root root   1866328 Jun 10 03:32 /root/rpmbuild/RPMS/x86_64/mysql-community-libs-5.7.44-1.el8.x86_64.rpm
-rw-r--r--. 1 root root 166402044 Jun 10 03:31 /root/rpmbuild/RPMS/x86_64/mysql-community-server-5.7.44-1.el8.x86_64.rpm
-rw-r--r--. 1 root root 150149116 Jun 10 03:32 /root/rpmbuild/RPMS/x86_64/mysql-community-test-5.7.44-1.el8.x86_64.rpm

2025/06/09

Re: セキュアそうでセキュアじゃない少しセキュアな気分になれるmysql_config_editorに直接--passwordを指定できるようにしてみた



  • mysql_config_editor--password, -p だけは引数を受け付けられなくて、常にプロンプトでパスワードを要求する

    • それはそれでいいんだけど、スクリプトとかで動的に .my.login.cnf を作るのに面倒
    • なので --password をオプションで受け付けられるようなパッチを書いてみた
  • .mylogin.cnf は鍵なしでパラメータを読み出せる (パスワードがマスクされているのは単に平文で読みだした後に mysql_config_editor 自身がマスクしているだけ)ので、いじるついでにこれも出せるようにしてみた

    • ちなみに my_print_defaults -s "セクション名" ならマスクもせずに取り出せる( my_print_defaults でいけるって知らなくて足してしまった…)

パッチはこれ。MySQL 5.7.44の mysql_config_editor ベース。
mysql_config_editor_patch

$ cd /path/to/mysql-5.7.44
$ wget https://gist.githubusercontent.com/yoku0825/6d8a2fee64de1b687f7c41bd6052f69e/raw/f860e29acb41990c055b56c73e06a5008bf4c481/mysql_config_editor_patch -O mysql_config_editor.patch
$ patch --backup client/mysql_config_editor.cc mysql_config_editor.patch
$ make mysql_config_editor
$ client/mysql_config_editor set --login-path=yoku0825 -uabc -pdef
$ client/mysql_config_editor print --all
[yoku0825]
user = abc
password = def

2025/05/21

レプリケーション構成でない2つのMySQLに確実にデータを書き込みたいメモ

  • それぞれのMySQLはSemisyncで正しくフェイルオーバーしたりGroup Replicationだったりで書き込みは信用できることにする
  • サロゲートキー(だけ)でなくて比較可能なPRIMARY KEYが存在することにする
  • 取り敢えず簡単なINSERTで考えるけどUPDATEもありそう

という前提で考え事。
FEDERATEDストレージエンジンはそもそもトランザクションをサポートしないので論外とする。

App側の2層コミットっぽいもの

2 Phase Commitはそもそもコーディネーターの障害に対する耐性がない…。

eval
{
  $dbh1->begin;
  $dbh1->do("INSERT INTO ..");
  $dbh2->begin;
  $dbh2->do("INSERT INTO ..");
};

if ($@)
{
  $dbh1->rollback;
  $dbh2->rollback;
}

$dbh1->commit;

### この瞬間にAppのプロセスが落ちるとダメ
$dbh2->commit;

この場合「必ずdbh2の方が足りない状態になる」のは確かかもしれない。

補償トランザクション的な何か

さっきののcommitの部分にさらに一捻り…したところで

eval
{
  $dbh1->commit;
};
$dbh2->rollback if $@;

eval
{
  $dbh2->commit;
};

if ($@)
{
  $dbh1->begin;
  ### ここらへんで落ちるとやっぱりダメ
  $dbh1->do("DELETE FROM ..");
  $dbh1->commit;
}

補償トランザクション形式だとUPDATEの巻き戻しがなかなか大変そうだし、結局落ちるとダメにはなる。この場合もdbh2が足りない状態になるのは当たりだろうか。
ちなみに MySQLのXAステートメント を使ったところでxidをどこかに記録しておかないと処理が引き継げないので結局何も記録せずに単一プロセスでやろうというのは無理。

さっきのと合わせて、dbh1の側の created_at みたいなのにインデックスを張っておいて定期的にスキャンして突合するような感じになるはず。DELETEまで考えるとdbh2側をスキャンしてdbh1側をNested Loopスキャンもしないといけなくなる(何がなくなったのかは片方だけ見てもわからないから)

非同期ダブルライト型

少なくとも片方のMySQLにはある程度確実に書ける(書けなければちゃんとエラーになる(実際semisyncではこれは保証できないんだけどいったん置いておく)、書いた以上はMySQL側がクラッシュしてフェイルオーバーしても残る)という前提に基づくと、

$dbh1->begin;
eval
{
  $dbh1->do("INSERT INTO metadata ..");
  $dbh1->do("INSERT INTO real_table ..");
  $dbh1->commit;
};

$dbh1->rollback if $@;

メタデータ(例えばdbh2に発行するべきINSERT文そのものでもいい)のテーブルへの記録と、dbh1側の書き込みたいテーブルを1つのトランザクションにまとめると、この2つのテーブルに関してはトランザクションで保護される。
$dbh1->commit までにAppがクラッシュした場合はAppとしてエラーになってメタデータもテーブルも残っていない状態になるし、 $dbh1->commit まで到達した場合は両方とも残っている。
で、別途ワーカーが必要。

$dbh1->begin;
my $sth= $dbh1->prepare("SELECT * FROM metadata ORDER BY id ASC LIMIT 1 FOR UPDATE SKIP LOCKED");
my $row= $sth->selectrow_hashref;
eval
{
  $dbh2->begin;
  $dbh2->do("INSERT INTO .."); 
  $dbh2->commit;
}
$dbh2->rollback if $@;
### ここらへんで落ちるとmetadataだけおかしくなる
$dbh1->do("DELETE FROM metadata ..");
$dbh1->commit;

この場合、

  • ワーカーが動くまではdbh1とdbh2で不整合が起こり続ける(dbh2が足りない状態になる)こと
  • ワーカーがクラッシュするとmetadataだけ消えずに余ること
    なのでmetadataと実際のテーブルの更新情報を突合するためのキーは必ず必要になって(dbh1に記録する時にApp側でUUID生成して、実テーブルの方に last_updated_by = ? みたいに持つとか)ワーカーが同じ更新を二重実行しても安全になるようにしてやらないといけない。
    けれどスキャンは必要なさそうだしワーカーの起動が制御しやすそうだなと思ったのでした。

まるでmysql.slave_relay_log_infoとSQLスレッドだな、とは思った。
ただの考え事でした。


【2025/05/21 21:22】

「非同期ダブルライト型」と呼んでいたやつは「Transactional Outboxパターン」という名前がついていると教えてもらいました! ありがとうございますm(_ _)m



トランザクションアウトボックスパターン - AWS 規範ガイダンス

2025/04/18

Oracle Linux 8.10でのMySQL 9.3.0ビルド

MySQL Bugs: #117993: cmake failed MySQL 9.3.0 + Oracle Linux 8.10 で再現しなかったらしく、フレッシュインストールで試す。

$ wget https://dev.mysql.com/get/Downloads/MySQL-9.3/mysql-9.3.0.tar.gz
$ tar xf mysql-9.3.0.tar.gz
$ cd mysql-9.3.0/
$ sudo dnf install -y cmake

$ cmake -DCMAKE_INSTALL_PREFIX=/usr/mysql/9.3.0 -DMINIMAL_RELWITHDEBINFO=OFF -DFORCE_INSOURCE_BUILD=1
CMake Warning:
  No source or binary directory provided.  Both will be assumed to be the
  same as the current working directory, but note that this warning will
  become a fatal error in future CMake releases.

-- Running cmake version 3.26.5
-- Could NOT find Git (missing: GIT_EXECUTABLE)
-- This is .el8. as found from 'rpm -qf /'
-- Looking for a devtoolset compiler
CMake Warning at CMakeLists.txt:393 (MESSAGE):
  Could not find devtoolset compiler/linker in /opt/rh/gcc-toolset-13

CMake Warning at CMakeLists.txt:395 (MESSAGE):
  You need to install the required packages:

   yum install gcc-toolset-13-gcc gcc-toolset-13-gcc-c++ gcc-toolset-13-binutils gcc-toolset-13-annobin-annocheck gcc-toolset-13-annobin-plugin-gcc

CMake Error at CMakeLists.txt:397 (MESSAGE):
  Or you can set CMAKE_C_COMPILER and CMAKE_CXX_COMPILER explicitly.

-- Configuring incomplete, errors occurred!

$ sudo yum install gcc-toolset-13-gcc gcc-toolset-13-gcc-c++ gcc-toolset-13-binutils gcc-toolset-13-annobin-annocheck gcc-toolset-13-annobin-plugin-gcc
$ sudo dnf install -y --enablerepo=ol8_codeready_builder openssl-devel ncurses-devel libtirpc-devel rpcgen cpp
$ rm CMakeCache.txt
$ cmake -DCMAKE_INSTALL_PREFIX=/usr/mysql/9.3.0 -DMINIMAL_RELWITHDEBINFO=OFF -DFORCE_INSOURCE_BUILD=1

通ったわ…。

$ scl -l
You use deprecated syntax "-l|--list", use "list-collections" instead.
gcc-toolset-11
gcc-toolset-13

おま環だった。ごめんUmesh..

2025/04/16

HeatWave MySQLがどれくらいVanilla MySQL GPL版と同じくらいか考える旅 / 読み取りレプリカ編その2

日々の覚書: HeatWave MySQLがどれくらいVanilla MySQL GPL版と同じくらいか考える旅 / 読み取りレプリカ編 の続き。

読み取りレプリカを1つ足してみた。ついでなので “MySQL.8.HA” にしてみたんだけれどこれは単に無視されるのかしら…(クラスタトータルのECPUも8ECPUしか増えなかったので、たぶんこれは関係なく1台だけ足されるんだと思う)

mysql> SELECT * FROM performance_schema.replication_group_members;
+---------------------------+-----------+-------------+-------------+--------------+-------------+----------------+----------------------------+
| CHANNEL_NAME              | MEMBER_ID | MEMBER_HOST | MEMBER_PORT | MEMBER_STATE | MEMBER_ROLE | MEMBER_VERSION | MEMBER_COMMUNICATION_STACK |
+---------------------------+-----------+-------------+-------------+--------------+-------------+----------------+----------------------------+
| group_replication_applier |           |             |        NULL | OFFLINE      |             |                |                            |
+---------------------------+-----------+-------------+-------------+--------------+-------------+----------------+----------------------------+
1 row in set (0.00 sec)

前回気が付かなかったけど、読み取りレプリカは bind_address の設定が増えてた。ロードバランサ側のネームスペースのIPアドレスはWEB画面から見られるIPのいずれでもない。

+---------------+-------------------------------------------+
| Variable_name | Value                                     |
+---------------+-------------------------------------------+
| bind_address  | 10.0.0.195/mysql,10.5.195.88/loadbalancer |
+---------------+-------------------------------------------+
1 row in set (0.01 sec)

ロードバランサ側のIPはちゃんと分散するようになった。単純なラウンドロビンじゃないかしら。

$ time for n in {1..100} ; do mysql -h 10.0.0.118 -uadmin -sse "SELECT @@hostname" ;  done | sort | uniq -c
     58 eiewhuzpjiihavkp
     42 fuis3dpz4ueksuzu

real    0m2.259s
user    0m1.027s
sys     0m0.496s

1台クラッシュさせてみると、少なくとも10秒程度でロードバランサから外している気配はなくて、再起動してくるのに合わせてロードバランサに戻っている。これSQL_Threadだけ止めたりしたらどうなるんだろう。

$ while true ; do for n in {1..100} ; do mysql -h 10.0.0.118 -uadmin -sse "SELECT @@hostname" 2> >(sort -u);  done | sort | u
niq -c ; date; sleep 1; done
     50 eiewhuzpjiihavkp
     50 fuis3dpz4ueksuzu
Wed Apr 16 04:59:49 GMT 2025
     56 eiewhuzpjiihavkp
     44 fuis3dpz4ueksuzu
Wed Apr 16 04:59:52 GMT 2025
     50 eiewhuzpjiihavkp
     50 fuis3dpz4ueksuzu
Wed Apr 16 04:59:55 GMT 2025
     51 eiewhuzpjiihavkp
     49 fuis3dpz4ueksuzu
Wed Apr 16 04:59:58 GMT 2025
     43 eiewhuzpjiihavkp
     57 fuis3dpz4ueksuzu
Wed Apr 16 05:00:02 GMT 2025
      6 ERROR 2003 (HY000): Can't connect to MySQL server on '10.0.0.118:3306' (111)
      1 ERROR 2013 (HY000): Lost connection to MySQL server at 'reading initial communication packet', system error: 104
     42 eiewhuzpjiihavkp
     51 fuis3dpz4ueksuzu
Wed Apr 16 05:00:05 GMT 2025
     45 ERROR 2003 (HY000): Can't connect to MySQL server on '10.0.0.118:3306' (111)
     55 fuis3dpz4ueksuzu
Wed Apr 16 05:00:08 GMT 2025
     47 ERROR 2003 (HY000): Can't connect to MySQL server on '10.0.0.118:3306' (111)
     53 fuis3dpz4ueksuzu
Wed Apr 16 05:00:10 GMT 2025
     52 ERROR 2003 (HY000): Can't connect to MySQL server on '10.0.0.118:3306' (111)
     48 fuis3dpz4ueksuzu
Wed Apr 16 05:00:13 GMT 2025
     50 ERROR 2003 (HY000): Can't connect to MySQL server on '10.0.0.118:3306' (111)
     50 fuis3dpz4ueksuzu
Wed Apr 16 05:00:16 GMT 2025
     54 eiewhuzpjiihavkp
     46 fuis3dpz4ueksuzu
Wed Apr 16 05:00:19 GMT 2025

↓エラーログ的にはこのへん。

mysql> SELECT * FROM performance_schema.error_log WHERE error_code <> 'MY-011071'\G

..
*************************** 386. row ***************************
    LOGGED: 2025-04-16 05:00:05.999056
 THREAD_ID: 0
      PRIO: Note
ERROR_CODE: MY-013930
 SUBSYSTEM: Server
      DATA: systemd notify: STATUS=Server startup in progress
*************************** 387. row ***************************
    LOGGED: 2025-04-16 05:00:05.999924
 THREAD_ID: 0
      PRIO: System
ERROR_CODE: MY-015015
 SUBSYSTEM: Server
      DATA: MySQL Server - start.

..
*************************** 604. row ***************************
    LOGGED: 2025-04-16 05:00:16.789157
 THREAD_ID: 0
      PRIO: System
ERROR_CODE: MY-010931
 SUBSYSTEM: Server
      DATA: /usr/sbin/mysqld: ready for connections. Version: '8.4.4-u5-cloud'  socket: '/var/run/mysqld/mysql.sock'  port: 3306  MySQL Enterprise - Cloud.
*************************** 605. row ***************************
    LOGGED: 2025-04-16 05:00:16.789172
 THREAD_ID: 0
      PRIO: System
ERROR_CODE: MY-013292
 SUBSYSTEM: Server
      DATA: Admin interface ready for connections, address: '127.0.0.1'  port: 7306
*************************** 606. row ***************************
    LOGGED: 2025-04-16 05:00:16.789529
 THREAD_ID: 0
      PRIO: Note
ERROR_CODE: MY-013930
 SUBSYSTEM: Server
      DATA: systemd notify: READY=1
STATUS=Server is operational
MAIN_PID=144141

..

エラーログで思い出したついでに読み取りレプリカを追加した時のエラーログ。

*************************** 1408. row ***************************
    LOGGED: 2025-04-16 05:31:42.525733
 THREAD_ID: 0
      PRIO: Note
ERROR_CODE: MY-013930
 SUBSYSTEM: Server
      DATA: systemd notify: READY=1
STATUS=Server is operational
MAIN_PID=35573

*************************** 1409. row ***************************
    LOGGED: 2025-04-16 05:34:50.412149
 THREAD_ID: 44
      PRIO: System
ERROR_CODE: MY-010597
 SUBSYSTEM: Repl
      DATA: 'CHANGE REPLICATION SOURCE TO FOR CHANNEL 'oci_managed_read_replica' executed'. Previous state source_host='', source_port= 3306, source_log_file='', source_log_pos= 4, source_bind=''. New state source_host='10.0.114.60', source_port= 7306, source_log_file='', source_log_pos= 4, source_bind=''.
*************************** 1410. row ***************************
    LOGGED: 2025-04-16 05:34:50.624034
 THREAD_ID: 47
      PRIO: Note
ERROR_CODE: MY-010581
 SUBSYSTEM: Repl
      DATA: Replica SQL thread for channel 'oci_managed_read_replica' initialized, starting replication in log 'FIRST' at position 0, relay log '/db/replication/relay-log-oci_managed_read_replica.000001' position: 4
*************************** 1411. row ***************************
    LOGGED: 2025-04-16 05:34:50.625468
 THREAD_ID: 46
      PRIO: System
ERROR_CODE: MY-014002
 SUBSYSTEM: Repl
      DATA: Replica receiver thread for channel 'oci_managed_read_replica': connected to source 'ocirpl@10.0.114.60:7306' with server_uuid=07c65c46-18f9-11f0-89e5-020017067068, server_id=-1253503313. Starting GTID-based replication.

HeatWave MySQLがどれくらいVanilla MySQL GPL版と同じくらいか考える旅 / 読み取りレプリカ編

WEB画面から作るレプリケーションの話。

「読み取りレプリカ」を “MySQL.8.Standalone” で1つ追加

ソースから観測

ソースから見ると名前解決が有効になってるのでIPアドレスはわからない。
skip_name_resolve はOFFで変えられない。

mysql> SHOW PROCESSLIST;
..
*************************** 4. row ***************************
     Id: 81
   User: ocirpl
   Host: gh7wpmau16ovyk9e.db0vcn0.mysqlcdbnrt.oraclevcn.com:52048
     db: NULL
Command: Binlog Dump GTID
   Time: 107046
  State: Source has sent all binlog to replica; waiting for more updates
   Info: NULL

..

mysql> SHOW REPLICAS;
+------------+------+------+------------+--------------------------------------+
| Server_Id  | Host | Port | Source_Id  | Replica_UUID                         |
+------------+------+------+------------+--------------------------------------+
| 1488978482 |      | 3306 | 3041463983 | 2ce0e2cf-18fb-11f0-bca9-02001704799d |
+------------+------+------+------------+--------------------------------------+
1 row in set (0.00 sec)

権限的には

あたり。

mysql> SHOW GRANTS FOR ocirpl;
+-------------------------------------------------------------------------------------------------------------+
| Grants for ocirpl@%                                                                                         |
+-------------------------------------------------------------------------------------------------------------+
| GRANT REPLICATION SLAVE ON *.* TO `ocirpl`@`%`                                                              |
| GRANT CONNECTION_ADMIN,GROUP_REPLICATION_STREAM,SERVICE_CONNECTION_ADMIN,SYSTEM_USER ON *.* TO `ocirpl`@`%` |
+-------------------------------------------------------------------------------------------------------------+
2 rows in set (0.00 sec)

mysql> ALTER USER ocirpl IDENTIFIED BY 'a' RETAIN CURRENT PASSWORD;
ERROR 1227 (42000): Access denied; you need (at least one of) the SYSTEM_USER privilege(s) for this operation

レプリカ側には「ホスト」に属しそうなIPと「ホスト群」に属しそうなIPが払い出されているぽい。

1台しか作ってないのでどっちを使っても同じところにアクセス。

$ for n in {1..100} ; do mysql -h 10.0.0.118 -uadmin -sse "SELECT @@hostname" ;  done | sort | uniq -c
    100 fuis3dpz4ueksuzu

$ for n in {1..100} ; do mysql -h 10.0.0.70 -uadmin -sse "SELECT @@hostname" ;  done | sort | uniq -c
    100 fuis3dpz4ueksuzu

ところで、100回程度でも気が付くくらいには差があった。LB経由の方が若干遅い。

$ time for n in {1..100} ; do mysql -h 10.0.0.118 -uadmin -sse "SELECT @@hostname" ;  done | sort | uniq -c
    100 fuis3dpz4ueksuzu

real    0m2.369s
user    0m1.040s
sys     0m0.489s

$ time for n in {1..100} ; do mysql -h 10.0.0.70 -uadmin -sse "SELECT @@hostname" ;  done | sort | uniq -c
    100 fuis3dpz4ueksuzu

real    0m1.708s
user    0m1.030s
sys     0m0.495s

レプリカから観測

大きめのシェイプじゃないとそもそもレプリカを作れないようになっている関係(?)で replica_parallel_workers はやたら多い。

mysql> SELECT @@replica_parallel_workers;
+----------------------------+
| @@replica_parallel_workers |
+----------------------------+
|                         48 |
+----------------------------+
1 row in set (0.00 sec)

mysql> SELECT name, processlist_user, processlist_host, COUNT(*) FROM performance_schema.threads WHERE type <> 'BACKGROUPND' GROUP BY 1, 2, 3;

..
| thread/sql/replica_io                                    | ociadmin         | localhost                                                 |        1 |
| thread/sql/replica_sql                                   | ociadmin         | localhost                                                 |        1 |
| thread/sql/replica_worker                                | ociadmin         | localhost                                                 |       48 |

..

performance_schema.threads は ociadmin なのに SHOW REPLICA STATUS は ocirpl なのはなんでかと思ったけど、 p_s.threads は単に START REPLICA した時のアカウントが出るっぽい。知らなかった。

mysql> SHOW REPLICA STATUS\G
*************************** 1. row ***************************
             Replica_IO_State: Waiting for source to send event
                  Source_Host: 10.0.114.60
                  Source_User: ocirpl
                  Source_Port: 7306
                Connect_Retry: 60
              Source_Log_File: binary-log.020772
          Read_Source_Log_Pos: 198
               Relay_Log_File: relay-log-oci_managed_read_replica.000306
                Relay_Log_Pos: 377
        Relay_Source_Log_File: binary-log.020772
           Replica_IO_Running: Yes
          Replica_SQL_Running: Yes
              Replicate_Do_DB:
          Replicate_Ignore_DB:
           Replicate_Do_Table:
       Replicate_Ignore_Table:
      Replicate_Wild_Do_Table:
  Replicate_Wild_Ignore_Table:
                   Last_Errno: 0
                   Last_Error:
                 Skip_Counter: 0
          Exec_Source_Log_Pos: 198
              Relay_Log_Space: 655
              Until_Condition: None
               Until_Log_File:
                Until_Log_Pos: 0
           Source_SSL_Allowed: Yes
           Source_SSL_CA_File:
           Source_SSL_CA_Path:
              Source_SSL_Cert:
            Source_SSL_Cipher:
               Source_SSL_Key:
        Seconds_Behind_Source: 0
Source_SSL_Verify_Server_Cert: No
                Last_IO_Errno: 0
                Last_IO_Error:
               Last_SQL_Errno: 0
               Last_SQL_Error:
  Replicate_Ignore_Server_Ids:
             Source_Server_Id: 3041463983
                  Source_UUID: 07c65c46-18f9-11f0-89e5-020017067068
             Source_Info_File: mysql.slave_master_info
                    SQL_Delay: 0
          SQL_Remaining_Delay: NULL
    Replica_SQL_Running_State: Replica has read all relay log; waiting for more updates
           Source_Retry_Count: 0
                  Source_Bind:
      Last_IO_Error_Timestamp:
     Last_SQL_Error_Timestamp:
               Source_SSL_Crl:
           Source_SSL_Crlpath:
           Retrieved_Gtid_Set:
            Executed_Gtid_Set: 9330ac0f-e14a-11ef-a07c-0200170681c1:1-853240
                Auto_Position: 1
         Replicate_Rewrite_DB:
                 Channel_Name: oci_managed_read_replica
           Source_TLS_Version: TLSv1.2,TLSv1.3
       Source_public_key_path:
        Get_Source_public_key: 1
            Network_Namespace:
1 row in set (0.00 sec)

チャンネル名が指定されてたり、ポートが7306になったりしている。
これは admin_port 使ってるんだろうと思うんだけど

mysql> SELECT @@admin_address, @@admin_port;
+-----------------+--------------+
| @@admin_address | @@admin_port |
+-----------------+--------------+
| 127.0.0.1       |         7306 |
+-----------------+--------------+
1 row in set (0.00 sec)

なので、admin_portにアクセスできるのは本来自分自身にしかアクセスできないはず。
ぱっと思いつくのは 127.0.0.1:7306 は mysqld がLISTENして、 10.0.114.60:7306 は (ソースと同じノードに入った) mysqlrouter なりがLISTENして転送してればそうできるかなあと思ったりした。

なおこの 10.0.114.60 (レプリカから見たレプリケーションソースのアドレス) はクライアントからはアクセスできなかった。

mysql> SELECT * FROM mysql.slave_master_info\G
*************************** 1. row ***************************
                Number_of_lines: 33
                Master_log_name:
                 Master_log_pos: 4
                           Host: 10.0.114.60
                      User_name:
                  User_password:
                           Port: 7306
                  Connect_retry: 60
                    Enabled_ssl: 1
                         Ssl_ca:
                     Ssl_capath:
                       Ssl_cert:
                     Ssl_cipher:
                        Ssl_key:
         Ssl_verify_server_cert: 0
                      Heartbeat: 30
                           Bind:
             Ignored_server_ids: 0
                           Uuid:
                    Retry_count: 0
                        Ssl_crl:
                    Ssl_crlpath:
          Enabled_auto_position: 1
                   Channel_name: oci_managed_read_replica
                    Tls_version: TLSv1.2,TLSv1.3
                Public_key_path:
                 Get_public_key: 1
              Network_namespace:
   Master_compression_algorithm: uncompressed
  Master_zstd_compression_level: 3
               Tls_ciphersuites: NULL
Source_connection_auto_failover: 0
                      Gtid_only: 1
1 row in set (0.00 sec)

パスワードが平文で書かれることで(俺の中では)有名な mysql.slave_master_info にはユーザー情報はない。これは CHANGE REPLICATION SOURCE TO source_user = ?, source_password = ? でアカウントを設定せずに START REPLICA USER=? PASSWORD=? で START REPLICA ごとに指定するとこうなるのでそれを使ってる。

確かに自動化されてて人間が START REPLICA を打つことがない今日日のケースではそれは正しい気がする。

mysql> SELECT * FROM mysql.slave_relay_log_info\G
*************************** 1. row ***************************
                             Number_of_lines: 14
                              Relay_log_name: /db/replication/relay-log-oci_managed_read_replica.000001
                               Relay_log_pos: 4
                             Master_log_name:
                              Master_log_pos: 0
                                   Sql_delay: 0
                           Number_of_workers: 0
                                          Id: 1
                                Channel_name: oci_managed_read_replica
                   Privilege_checks_username: NULL
                   Privilege_checks_hostname: NULL
                          Require_row_format: 1
             Require_table_primary_key_check: OFF
 Assign_gtids_to_anonymous_transactions_type: OFF
Assign_gtids_to_anonymous_transactions_value:
1 row in set (0.00 sec)

mysql.slave_relay_log_info には特に面白い情報はない。 REPLICATION_APPLIER 権限を使った分離はされてないってことくらいか。

mysql> SHOW BINARY LOGS;
ERROR 1381 (HY000): You are not using binary logging

レプリカではバイナリログが有効になっていないので、バイナリログを吸い上げるツールをソースに向けたくなくてレプリカ……というわけにはいかなさそう。

取り敢えずこんなところで。