MySQL8.0のCommercial版のInnoDBClusterとxtrabackup（増分）など


######経緯と前置き
わたしがためしてみたのは[商用(コマーシャル)試用版](https://edelivery.oracle.com/)のMySQL8.0.15/CentOS7.5です（Oracleアカウントでログインして落としてくるやつ）。

長いので忙しい人はあとでもしくは気になるとこだけどうぞ。そうでもない人はゆっくりしていってどうぞ。
VMからなので最初が不要なら飛ばしてどうぞ。

######とりあえずTerraformでAzureにVMを立てる

```
$ az login
$ az account set --subscription "***mysubscription-id****"
$ az account list -o table
$ az vm image list --location "japanwest"

  {
    "offer": "CentOS",
    "publisher": "OpenLogic",
    "sku": "7.5",
    "urn": "OpenLogic:CentOS:7.5:latest",
    "urnAlias": "CentOS",
    "version": "latest"
  },
```
これをつかう

terraformを入れる。tfファイルがazure向けになってる状態でinit打つ

```
$ wget https://releases.hashicorp.com/terraform/0.11.11/terraform_0.11.11_linux_amd64.zip 
$ unzip /usr/local/src/terraform_0.11.11_linux_amd64.zip 
$ sudo mv terraform /usr/local/bin/
$ terraform init
```
varsとtfをととのえる
https://qiita.com/smallpalace/items/a95ed056c408d2185c38

```
$ cat terraform.tfvars 
default_user = "*****"
default_password = "******"
resouce_group_name = "my-resouce-group"
location = "Japan West"
azurerm_virtual_network_name = "myvnet01VNET"
azurerm_virtual_network_address_space = "10.0.0.0/16"
subnet_count_num = 2
azurerm_subnet_name = "mysubnetPub01Subnet,mysubnetPub02Subnet"
azurerm_subnet_address_prefix = "10.0.0.0/23,10.0.2.0/23"
machine_count_num = 3
azurerm_security_group_name = "mysg2"
azurerm_source_address_prefix = "ｘｘｘ"
virtual_machine_name_test = "test-my8-db"
storage_account = "mystorageaccount"
account_tier = "Standard"
account_replication_type = "LRS"
vm_size = "Standard_B2s"
storage_image_reference_publisher = "OpenLogic"
storage_image_reference_offer = "CentOS"
storage_image_reference_sku = "7.5"
storage_image_reference_version = "latest"

$ cat terraform.tf
variable "default_user" {}
variable "default_password" {}
variable "resouce_group_name" {}
variable "location" {}
variable "azurerm_virtual_network_name" {}
variable "azurerm_virtual_network_address_space" {}
variable "subnet_count_num" {}
variable "azurerm_subnet_name" {}
variable "azurerm_subnet_address_prefix" {}
variable "azurerm_security_group_name" {}
variable "azurerm_source_address_prefix" {}
variable "machine_count_num" {}
variable "virtual_machine_name_test" {}
variable "storage_account" {}
variable "account_tier" {}
variable "account_replication_type" {}
variable "vm_size" {}
variable "storage_image_reference_publisher" {}
variable "storage_image_reference_offer" {}
variable "storage_image_reference_sku" {}
variable "storage_image_reference_version" {}

provider "azurerm" {
}
resource "azurerm_resource_group" "test" {
  name = "${var.resouce_group_name}" 
  location = "${var.location}" 
}
resource "azurerm_availability_set" "test" {
  name                = "${var.resouce_group_name}-ailabilitySet1"
  location            = "${azurerm_resource_group.test.location}"
  resource_group_name = "${azurerm_resource_group.test.name}"
  platform_fault_domain_count  = 2
  platform_update_domain_count = 2
  managed             = true
}
resource "azurerm_virtual_network" "test" {
  name = "${var.azurerm_virtual_network_name}" 
  address_space = ["${var.azurerm_virtual_network_address_space}"]
  location = "${azurerm_resource_group.test.location}" 
  resource_group_name = "${azurerm_resource_group.test.name}" 
}
resource "azurerm_subnet" "test" {
  count = "${var.subnet_count_num}"
  name = "${element(split(",",var.azurerm_subnet_name), count.index%length(split(",", var.azurerm_subnet_name)))}" 
  resource_group_name = "${azurerm_resource_group.test.name}" 
  virtual_network_name = "${azurerm_virtual_network.test.name}" 
  address_prefix = "${element(split(",",var.azurerm_subnet_address_prefix), count.index%length(split(",", var.azurerm_subnet_address_prefix)))}" 
}
resource "azurerm_network_security_group" "test" {
  name                = "${var.azurerm_security_group_name}"
  location            = "${azurerm_resource_group.test.location}"
  resource_group_name = "${azurerm_resource_group.test.name}"
  security_rule {
    name                       = "allow-isao"
    priority                   = 100
    direction                  = "Inbound"
    access                     = "Allow"
    protocol                   = "Tcp"
    source_port_range          = "*"
    destination_port_range     = "*"
    source_address_prefix      = "${var.azurerm_source_address_prefix}"
    destination_address_prefix = "*"
  }
  tags {
    environment = "Test"
  }
}
resource "azurerm_public_ip" "test" {
  count = "${var.machine_count_num}"
  name = "${format("${var.virtual_machine_name_test}%02d", count.index + 1)}-pip" 
  location = "${azurerm_resource_group.test.location}" 
  resource_group_name = "${azurerm_resource_group.test.name}" 
  public_ip_address_allocation = "static" 
  domain_name_label = "${format("${var.virtual_machine_name_test}%02d", count.index + 1)}-pip" 
  tags {
      environment = "test" 
    }
}
resource "azurerm_network_interface" "test" {
  count = "${var.machine_count_num}"
  name = "${format("${var.virtual_machine_name_test}%02d", count.index + 1)}-nic1" 
  location = "${azurerm_resource_group.test.location}" 
  resource_group_name = "${azurerm_resource_group.test.name}" 
  ip_configuration {
      name = "${format("${var.virtual_machine_name_test}%02d", count.index + 1)}-ip" 
      subnet_id = "${element(azurerm_subnet.test.*.id, count.index)}" 
      private_ip_address_allocation = "dynamic" 
      public_ip_address_id = "${element(azurerm_public_ip.test.*.id, count.index)}" 
  }
  network_security_group_id = "${azurerm_network_security_group.test.id}"
}
resource "azurerm_storage_account" "test" {
    name = "${var.storage_account}" 
    resource_group_name = "${azurerm_resource_group.test.name}" 
    location = "${azurerm_resource_group.test.location}" 
    account_tier = "${var.account_tier}" 
    account_replication_type = "${var.account_replication_type}" 
    tags {
        environment = "staging" 
    }
}
resource "azurerm_storage_container" "test" {
    count = "${var.machine_count_num}"
    name = "${format("${var.virtual_machine_name_test}%02d", count.index + 1)}-vhds" 
    resource_group_name = "${azurerm_resource_group.test.name}" 
    storage_account_name = "${azurerm_storage_account.test.name}" 
    container_access_type = "private" 
}
resource "azurerm_virtual_machine" "test" {
  count                 = "${var.machine_count_num}"
  name                  = "${format("${var.virtual_machine_name_test}%02d", count.index + 1)}" 
  location              = "${azurerm_resource_group.test.location}" 
  resource_group_name   = "${azurerm_resource_group.test.name}" 
#  availability_set_id   = "${azurerm_availability_set.test.id}"
  network_interface_ids = ["${element(azurerm_network_interface.test.*.id, count.index)}"]
  vm_size               = "${var.vm_size}" 
  storage_image_reference {
    publisher = "${var.storage_image_reference_publisher}" 
    offer = "${var.storage_image_reference_offer}" 
    sku = "${var.storage_image_reference_sku}" 
    version = "${var.storage_image_reference_version}" 
  }
  storage_os_disk {
    name              = "${format("${var.virtual_machine_name_test}%02d", count.index + 1)}-osdisk1" 
    vhd_uri = "${azurerm_storage_account.test.primary_blob_endpoint}${element(azurerm_storage_container.test.*.name, count.index)}/myosdisk1.vhd" 
    caching           = "ReadWrite" 
    create_option     = "FromImage" 
    os_type           = "linux" 
  }
  os_profile {
    computer_name  = "${format("${var.virtual_machine_name_test}%02d", count.index + 1)}" 
    admin_username = "${var.default_user}" 
    admin_password = "${var.default_password}" 
  }
  os_profile_linux_config {
    disable_password_authentication = false
  }
  tags {
    environment = "test" 
  }
}
```
※セキュリティグループが自動で当たる用になど。
※なんかストレージコンテナ使うやり方だとちょっと旧いみたいな話があるのですみません。

新たに消して作られるのを防ぐために既存リソースをいろいろimport

```
$ cat import-sample.txt 
terraform import azurerm_virtual_network.test /subscriptions/***mysubscription-id****/resourceGroups/my-resouce-group/providers/Microsoft.Network/virtualNetworks/myvnet01VNET
terraform import azurerm_subnet.test[0] /subscriptions/***mysubscription-id****/resourceGroups/my-resouce-group/providers/Microsoft.Network/virtualNetworks/myvnet01VNET/subnets/mysubnetPub01Subnet
terraform import azurerm_subnet.test[1] /subscriptions/***mysubscription-id****/resourceGroups/my-resouce-group/providers/Microsoft.Network/virtualNetworks/myvnet01VNET/subnets/mysubnetPub02Subnet
terraform import azurerm_storage_account.test /subscriptions/***mysubscription-id****/resourceGroups/my-resouce-group/providers/Microsoft.Storage/storageAccounts/mystorageaccount
terraform import azurerm_resource_group.test /subscriptions/***mysubscription-id****/resourceGroups/my-resouce-group
#terraform import azurerm_network_security_group.group1 /subscriptions/***mysubscription-id****/resourceGroups/my-resouce-group/providers/Microsoft.Network/networkSecurityGroups/my-sg2
```

securitygroupは別に作ることにした。

※可用性セットはBlobベースの管理ディスクのやつだとmanagedで配置できないらしいのでコメントにした

```
terraform import azurerm_storage_account.storageAcc1 /subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/myresourcegroup/providers/Microsoft.Storage/storageAccounts/myaccount

* azurerm_virtual_machine.test.1: compute.VirtualMachinesClient#CreateOrUpdate: Failure sending request: StatusCode=0 -- Original Error: autorest/azure: Service returned an error. Status=<nil> Code="OperationNotAllowed" Message="Addition of a VM with managed disks to non-managed Availability Set or addition of a VM with blob based disks to managed Availability Set is not supported. Please create an Availability Set with 'Aligned' SKU in order to add a VM with managed disks to it." Target="test-my8-db02"
* azurerm_virtual_machine.test[0]: 1 error(s) occurred:


$ terraform plan
$ terraform apply
```

とりあえず3インスタンス完成した。tfstateのなかみにIPとかでてるがshowとか打ってもでてくる。

```
$ terraform show|grep ' ip_address'
  ip_address = xx.xx.126.53
  ip_address = xx.xx.128.27
  ip_address = xx.xx.141.49

$ terraform show|grep ' private_ip_address '
  private_ip_address = 10.0.0.9
  private_ip_address = 10.0.2.5
  private_ip_address = 10.0.0.8
```
とりあえずつながるはずなのでつないでみる
ポータルからみるとセキュリティグループにプライベート全開ルールAllowVnetInBoundがあるので3台でpingとsshがとおるあたりを確認。

######VMのNWの高速化

https://docs.microsoft.com/ja-jp/azure/virtual-network/virtual-network-optimize-network-bandwidth#centos
https://docs.microsoft.com/ja-jp/azure/virtual-network/create-vm-accelerated-networking-cli
ここらへん↑を見て対応。AzureでなくAWSだったらPlacementGroupつかうとかそういう感じでしょうか。たぶん。グループレプリケーション的に低遅延じゃないとなための対応（試験なのでアレですが本番は要るはずなので一応書いとく）。
そもそもサポートされてるVM（D/DSv3、E/ESv3、Fsv2、Ms/Mms ）じゃないと高速ネットワーク有効化できないようですが対応してるVMならHiper-vいれてポータルから有効化できる模様。


######SELinuxとFirewalldを無効化してTimezoneを設定するAnsibleを流す

これを忘れるとReplication組む時に詰みます。重要です。
スマートスタイルさんが記事にされてるので単純に無効化するのに抵抗がある場合
https://www.s-style.co.jp/blog/2018/12/3079/
このあたり↑をみるとよさそうな気がします。

```
# ansible-playbook -i hosts base.yml --ask-sudo-pass -D -vv
```
適当に自作リポジトリをcloneして流す

######ダウンロードして展開、カスタムリポジトリに配置

[オラクルのサイト](https://edelivery.oracle.com/)にログインしてからダウンロードできまして評価版を落としてきました。（特になやむところはなかった）

で、それぞれディレクトリ掘ってzipを開け、そのうちのrepoとか名前の一部についてるtarアーカイブを解凍して

```
# tar xvzf mysql-commercial-8.0.15-1.1.el7.x86_64.repo.tar.gz

# ls mysql-8.0/8.0.15/
mysql-commercial-backup-8.0.15-1.1.el7.x86_64.rpm           mysql-commercial-libs-8.0.15-1.1.el7.i686.rpm
mysql-commercial-client-8.0.15-1.1.el7.i686.rpm             mysql-commercial-libs-8.0.15-1.1.el7.x86_64.rpm
mysql-commercial-client-8.0.15-1.1.el7.x86_64.rpm           mysql-commercial-libs-compat-8.0.15-1.1.el7.i686.rpm
mysql-commercial-common-8.0.15-1.1.el7.i686.rpm             mysql-commercial-libs-compat-8.0.15-1.1.el7.x86_64.rpm
mysql-commercial-common-8.0.15-1.1.el7.x86_64.rpm           mysql-commercial-server-8.0.15-1.1.el7.x86_64.rpm
mysql-commercial-devel-8.0.15-1.1.el7.i686.rpm              mysql-commercial-test-8.0.15-1.1.el7.x86_64.rpm
mysql-commercial-devel-8.0.15-1.1.el7.x86_64.rpm            mysql-router-commercial-8.0.15-1.1.el7.x86_64.rpm
mysql-commercial-embedded-compat-8.0.15-1.1.el7.i686.rpm    repodata
mysql-commercial-embedded-compat-8.0.15-1.1.el7.x86_64.rpm
```
READMEみるとオレオレrepoに公開してインストールと書いているので一応そのとおりに。

```
$ sudo mv mysql-8.0 /var/www/html/rpm/
$ sudo mv RPM-GPG-KEY-mysql /var/www/html/rpm/mysql-8.0/
$ sudo chown -R apache. /var/www/html/rpm/mysql-8.0
```


######サーバ入れる

＠DBサーバ

```
vi /etc/yum.repos.d/mysql8-comm.repo

[mysql-8.0]
name=mysql-8.0
baseurl=http://mysite/rpm/mysql-8.0/
gpgkey=http://mysite/rpm/mysql-8.0/RPM-GPG-KEY-mysql
gpgcheck=1
enabled=0

[mysql-8.0.15]
name=mysql-8.0.15
baseurl=http://mysite/rpm/mysql-8.0/8.0.15/
gpgkey=http://mysite/rpm/mysql-8.0/RPM-GPG-KEY-mysql
gpgcheck=1
enabled=1

# yum repolist

# yum install mysql-commercial-libs mysql-commercial-server mysql-commercial-devel mysql-commercial-backup 
```

######クライアントとrouter入れる

```
# yum install mysql-commercial-libs mysql-commercial-common mysql-router-commercial 
# rpm -ivh mysql-router-commercial-8.0.15-1.1.el7.x86_64.rpm
```

ちなみにコミュニティ版のリポジトリの入れ方

```
	rpm -ivh https://dev.mysql.com/get/mysql80-community-release-el7-1.noarch.rpm
	[mysql80-community]が入る
```

######設定を考えて起動してみる
8.0向けとgtid、group_replication向けという観点で設定を調査して更新。

```conf:db2のmy.cnf
# cat /etc/my.cnf
# For advice on how to change settings please see
# http://dev.mysql.com/doc/refman/8.0/en/server-configuration-defaults.html

[mysqld]
#
# Remove leading # and set to the amount of RAM for the most important data
# cache in MySQL. Start at 70% of total RAM for dedicated server, else 10%.

## for innodb settings.
innodb_buffer_pool_size = 3G
innodb_old_blocks_time = 50000
innodb_log_buffer_size = 8M
innodb_log_file_size = 128M
innodb_lock_wait_timeout=50
innodb_open_files = 2048
innodb_flush_method = O_DIRECT
innodb-flush-neighbors = 0 #for SSD(8default0,57default1)
innodb-page-size = 16k #for SSD(4k)
innodb_io_capacity=400 #SSDならふやす（diskのiopsカタログ性能を指定）
innodb_io_capacity_max=3000
innodb_read_io_threads=8
innodb_write_io_threads=8
innodb_file_per_table
innodb_print_all_deadlocks = ON
innodb_buffer_pool_dump_at_shutdown = ON
innodb_buffer_pool_load_at_startup  = ON

#
# Remove the leading "# " to disable binary logging
# Binary logging captures changes between backups and is enabled by
# default. It's default setting is log_bin=binlog
# disable_log_bin

## for replication(gtid on).
server-id= 200 #require this uniq different vars each replication hosts
log_bin=mysql-bin
#log-bin-trust-function-creators=1
relay-log=mysql-relay-bin
binlog-row-image = MINIMAL
binlog_expire_logs_seconds=864000 #10days retain binarylogs.
log-slave-updates=1
###gtid
gtid-mode=ON
enforce-gtid-consistency
binlog_format=row # because gtid on.
binlog_checksum=NONE
###clush safe replication
master_info_repository = TABLE
relay_log_info_repository = TABLE
relay_log_recovery=ON
relay_log_purge=ON
###other repli param
sync-master-info = 1000
sync-relay-log = 1000
slave_net_timeout=120
slave-exec-mode = IDEMPOTENT
slave-rows-search-algorithms = 'INDEX_SCAN,HASH_SCAN'
slave-type-conversions = ALL_NON_LOSSY
#skip-slave-start
###group replication
transaction_write_set_extraction=XXHASH64
loose-plugin_load = group_replication.so
loose-group_replication_group_name="fb58bfbb-fabd-4f88-89ff-477f830e47f4" #set this common vars at repl hosts（uuid)
loose-group_replication_start_on_boot = off
loose-group_replication_local_address = "10.0.2.5:24901"
loose-group_replication_group_seeds = "10.0.0.9:24901,10.0.2.5:24901,10.0.0.8:24901"
loose-group_replication_bootstrap_group = off
loose-group_replication_ip_whitelist='10.0.0.0/8'
loose-group_replication_single_primary_mode=ON #ignore multi-primary
loose-group_replication_enforce_update_everywhere_checks=OFF #ignore multi-primary
report-host=10.0.2.5
###group commit
binlog_group_commit_sync_delay=2500
binlog_group_commit_sync_no_delay_count=256

### for Multi thread slave
#slave_parallel_workers = 32
#slave_parallel_type = LOGICAL_CLOCK
#slave_preserve_commit_order=1

# Remove leading # to set options mainly useful for reporting servers.
# The server defaults are faster for transactions and fast SELECTs.
# Adjust sizes as needed, experiment to find the optimal values.
# join_buffer_size = 128M
# sort_buffer_size = 2M
# read_rnd_buffer_size = 2M

## for memory settings.
max_connections = 150
thread_cache_size = 600
table_open_cache =2048
open_files_limit = 8100
wait_timeout = 60
key_buffer_size=8M
max_allowed_packet = 16M
max_heap_table_size = 32M
tmp_table_size = 32M
###session memory settings
sort_buffer_size = 2M
join_buffer_size = 2M
read_buffer_size = 512K
read_rnd_buffer_size = 2M
myisam_sort_buffer_size = 32M

#
# Remove leading # to revert to previous value for default_authentication_plugin,
# this will increase compatibility with older clients. For background, see:
# https://dev.mysql.com/doc/refman/8.0/en/server-system-variables.html#sysvar_default_authentication_plugin
## basic settings.
default-storage-engine=innodb
default-authentication-plugin=mysql_native_password
explicit_defaults_for_timestamp = true
port=3306
user=mysql
datadir=/var/lib/mysql
socket=/var/lib/mysql/mysql.sock
#skip-name-resolve
log_timestamps=SYSTEM

character-set-server = utf8mb4 #5.7utf8
collation-server = utf8mb4_ja_0900_as_cs #5.7utf8_general_ci

log-error=/var/log/mysqld.log
pid-file=/var/run/mysqld/mysqld.pid
slow_query_log=1
slow_query_log_file=/var/run/mysqld/slow.log
long_query_time = 0.6
min_examined_row_limit=10000

[mysqldump]
quick
max_allowed_packet = 16M


##https://www.slideshare.net/yoku0825/mysql-80
##https://yakst.com/ja/posts/3726
##https://image.slidesharecdn.com/mysql-performance-tuning-okuno-170616121131/95/mysql-57-27-638.jpg?cb=1497615210
```
わりと頑張りました↑がテスト環境でしか試してないのでそこんとこよろしくおねがいします。(sessionバッファ多いし搭載メモリ少ないしmysqltunerとかかけたらいいだろうなとか色々あります。）

group_replication_group_nameは以下の用に適当に生成して設定。
（これがクラスタの識別子になるので複数クラスタ作る場合に別のに変える）

```
# uuidgen
fb58bfbb-fabd-4f88-89ff-477f830e47f4
```

どの設定ファイル読んだかわかる方法（includeには未対応らしい）

```
> SELECT * FROM performance_schema.variables_info LIMIT 10;
```
https://yoku0825.blogspot.com/2016/09/mysql-800mycnf.html

いちおう自動起動と起動。

```
systemctl start mysqld
systemctl enable mysqld
```

で、初期パスワードgrepしてつけなおし

```
# grep pass /var/log/mysqld.log 
# mysql_secure_installation --use-default

# vi ~/.my.cnf
[mysql]
user=root
password=
```

パスワードポリシー変えたい場合

```
mysql> show global variables like 'vali%';
+--------------------------------------+--------+
| Variable_name                        | Value  |
+--------------------------------------+--------+
| validate_password.check_user_name    | ON     |
| validate_password.dictionary_file    |        |
| validate_password.length             | 8      |
| validate_password.mixed_case_count   | 1      |
| validate_password.number_count       | 1      |
| validate_password.policy             | MEDIUM |
| validate_password.special_char_count | 1      |
+--------------------------------------+--------+
7 rows in set (0.00 sec)

mysql> set global validate_password.policy='LOW';
mysql> show global variables like 'vali%';
+--------------------------------------+-------+
| Variable_name                        | Value |
+--------------------------------------+-------+
| validate_password.check_user_name    | ON    |
| validate_password.dictionary_file    |       |
| validate_password.length             | 8     |
| validate_password.mixed_case_count   | 1     |
| validate_password.number_count       | 1     |
| validate_password.policy             | LOW   |
| validate_password.special_char_count | 1     |
+--------------------------------------+-------+
```

とりあえずhostsに以下を設定

```
# vi /etc/hosts
10.0.0.9 test-my8-db01 db1
10.0.2.5 test-my8-db02 db2
10.0.0.8 test-my8-db03 db3
```

######グループレプリケーションについて

グループレプリケーションとは、3台あれば、プライマリからセカンダリへの切り替えが自動的に勝手に行われる、他のセカンダリが自動でプライマリの切り替わりに追随して整合性が保たれる、フェイルオーバー後の切り戻しも特に要らずそのままセカンダリを追加するとまた勝手に切り替わるため復旧の手間があまりなくて省力運用に、という公式提供のHAソリューション、という認識。仮想IPを切り替えるというような必要はないが名前解決は必要。

手動で組むより[mysqlshell](https://dev.mysql.com/doc/mysql-shell/8.0/en/mysql-shell-commands.html)で組むほうがいいです。設定が永続化するのと手順が簡単だから。

はまったとこ
・looseをつけないと関連オプションは初回起動時にプラグインがロードされてないらしくエラーで止まる（手動でロードする必要は特になかった）
・1台だけで行うbootstrap作業は先に完了させておかないと指定ポートListenしない（あとここでSELinuxが有効で設定してないと無限に待つ）
・パラメータの不足は特になかったがマルチマスタで起動さすのが推奨されてないことをInnoDBClusterをmysqlshellで組むやりかたでサジェストされてオプション変更した。
・古い記事はみずにマニュアル見たほうがよかった。（長いけど）

予想できる刺身タンポポ
・名前解決が案外重要っぽいというかrouterはWEBとかAPサーバに入れるのがスタンダードっぽい関係でなのかhostsで名前解決だとフロントの構成の増減が激しいとDBのレプリカノード追加しただけで全台のhosts更新するとかはだいぶめんどくさいと思うので内部DNSで名前引けるようにするのがよさそう。
ansibleとかsystemmanager的なアレで一括でドカンと更新なぞ余裕で大した手間の違いがない場合はまあ気にしなくていいかも。もしくはRouterをWEBに入れる構成じゃなくてLB配下に並べる感じだとマシそうですかね。

グループレプリケーションの要件（リンク先をガン見推奨）
https://dev.mysql.com/doc/refman/8.0/en/group-replication-requirements.html
必須：ストレージエンジンInnoDB、Tableに主キー付、Networkパフォーマンス低遅延、バイナリログ、GTID、log-slave-updates、binlog_format=row、レプリケーション情報リポジトリはTABLE、など。
あとreplicate-ignore-dbというようなレプリケーションフィルタはグループレプリケーションでは使えないとか5秒以上かかる巨大なトランザクションはNGでグループから外れるとか。
https://dev.mysql.com/doc/refman/8.0/en/group-replication-limitations.html
https://dev.mysql.com/doc/refman/8.0/en/replication-options-slave.html#option_mysqld_replicate-do-table
GTIDの制限も。
https://dev.mysql.com/doc/refman/8.0/en/replication-gtids-restrictions.html

1台落ちても大丈夫なようにするには最低３台いるんやで、と。
https://dev.mysql.com/doc/refman/8.0/en/group-replication-fault-tolerance.html

マルチマスタは競合の解決のために遅いしシングルが公式推奨なようです。
https://www.percona.com/blog/2018/07/09/innodb-cluster-in-a-nutshell-part-1/

ipv6つかおうという人がいるかわからないけど確か8.0.14以上からとかだったかと。
https://mysqlhighavailability.com/ipv6-support-in-group-replication/

あと8.0.14からgroup_replication_consistencyというパラメータが。
https://mysqlhighavailability.com/group-replication-consistent-reads/

8.0.15のグループレプリケーションが5.7.25より遅いというベンチ結果をみかけたのですが、
https://www.percona.com/blog/2019/02/21/mysql-8-is-not-always-faster-than-mysql-5-7/
どうやらlatin1の場合だけみたいなことをあとからみました。よかったです。
https://www.percona.com/blog/2019/02/27/charset-and-collation-settings-impact-on-mysql-performance/

公式セミナ資料
https://www.mysql.com/jp/why-mysql/presentations/mysql-replication-update-201811-jp/

######バイナリログを別のディレクトリ（ディスク）にしてI/O分散さすやりかた

ただしmysqlbackupだと増分バックアップするときにそのディレクトリが認識されないという事象に遭遇中です。。なんでかにゃー。なんか--log-binとかがバックアップ時でなくレストアで展開するときのオプションだけなんですよね。謎い。Xtrabackupは大丈夫な気がするのでもうそっちでいいことにしました。

```
# systemctl stop mysqld
# mkdir /var/lib/mybinlog
# mv /var/lib/mysql/mysql-bin.* /var/lib/mybinlog/
# chown -R mysql. /var/lib/mybinlog
# vi /etc/my.cnf
# grep log_bin /etc/my.cnf
# default. It's default setting is log_bin=binlog
# disable_log_bin
log_bin=/var/lib/mybinlog/mysql-bin
log_bin_index=/var/lib/mybinlog/mysql-bin.index

# systemctl start mysqld

mysql> show global variables like '%log%';

| log_bin                                        | ON                                     |
| log_bin_basename                               | /var/lib/mybinlog/mysql-bin            |
| log_bin_index                                  | /var/lib/mybinlog/mysql-bin.index      |

もしリレーログも場所変えたければ以下のあたりが変わるように設定する（basenameは設定できない）
| relay_log                                      | mysql-relay-bin                        |
| relay_log_index                                | /var/lib/mysql/mysql-relay-bin.index   |
```

※Azureの追加ディスクに対してblobのディスクじゃなくて管理ディスクじゃないとダメっぽい



######mysqlshell入れる

設定チェックしてくれたりsqlクライアントとして使えたりクラスタ組んだりできる管理ツールのようなやつです。つながるとこならどこに入れても別にオッケーだとおもいます。

```
# yum install mysql-commercial-libs mysql-commercial-client
# cd /home/user1/mysql8/shell
# unzip V981489-01.zip 
# rpm -ivh mysql-shell-commercial-*
# rpm -qa|grep mysql
```
とりあえずdb03にshellでつないでみて設定をチェック。

```
#  mysqlsh --uri root＠10.0.0.8:3306
MySQL Shell 8.0.15-commercial
```
######InnoDBClusterをmysqlshellで組む

https://dev.mysql.com/doc/refman/8.0/en/mysql-innodb-cluster-production-deployment.html

・ユーザつくる

```
SET SQL_LOG_BIN=0;
create user ic＠'%' identified by 'xxxxxxxx';
GRANT SELECT,ALTER, ALTER ROUTINE, CREATE, CREATE ROUTINE, CREATE TEMPORARY TABLES, CREATE VIEW, DELETE, DROP, EVENT, EXECUTE, INDEX, INSERT, LOCK TABLES, REFERENCES, SHOW VIEW, TRIGGER, UPDATE ON mysql_innodb_cluster_metadata.* TO ic＠'%';
GRANT SELECT ON performance_schema.global_status TO ic＠'%';
GRANT SELECT ON performance_schema.replication_applier_configuration TO ic＠'%';
GRANT SELECT ON performance_schema.replication_applier_status TO ic＠'%';
GRANT SELECT ON performance_schema.replication_applier_status_by_coordinator TO ic＠'%';
GRANT SELECT ON performance_schema.replication_applier_status_by_worker TO ic＠'%';
GRANT SELECT ON performance_schema.replication_connection_configuration TO ic＠'%';
GRANT SELECT ON performance_schema.replication_connection_status TO ic＠'%';
GRANT SELECT ON performance_schema.replication_group_member_stats TO ic＠'%';
GRANT SELECT ON performance_schema.replication_group_members TO ic＠'%';
GRANT SELECT ON performance_schema.threads TO ic＠'%' WITH GRANT OPTION;
GRANT SELECT,DELETE,INSERT,UPDATE ON `mysql`.* TO `ic`＠`%`;
GRANT CREATE USER, FILE, GRANT OPTION, PROCESS, RELOAD, REPLICATION CLIENT, REPLICATION SLAVE, SHUTDOWN, SUPER ON *.* TO ic＠'%';
GRANT SELECT ON sys.* TO ic＠'%';
show grants for ic＠'%';
FLUSH PRIVILEGES;
SET SQL_LOG_BIN=1;
```


・mysql-shellでそれぞれのホストにつなぐ

```
#  mysqlsh --uri root＠10.0.0.9:3306
```
・設定チェック

```
 MySQL  JS > dba.checkInstanceConfiguration('root＠10.0.0.9')
```

・クラスタをつくる、マスタ予定のホストにつなぐ

```
#  mysqlsh --uri ic＠10.0.0.9:3306
 MySQL  10.0.0.9:3306 ssl  JS > var cluster = dba.createCluster('testCluster', {ipWhitelist:'10.0.0.0/22,127.0.0.1/8'});

 MySQL  10.0.0.9:3306 ssl  JS > var cluster = dba.getCluster();

 MySQL  10.0.0.9:3306 ssl  JS > cluster.addInstance('ic＠10.0.0.8')
 MySQL  10.0.0.9:3306 ssl  JS > cluster.addInstance('ic＠10.0.2.5')


 MySQL  10.0.0.8:3306 ssl  JS > cluster.status(); 
{
    "clusterName": "testCluster", 
    "defaultReplicaSet": {
        "name": "default", 
        "primary": "10.0.0.9:3306", 
        "ssl": "REQUIRED", 
        "status": "OK", 
        "statusText": "Cluster is ONLINE and can tolerate up to ONE failure.", 
        "topology": {
            "10.0.0.8:3306": {
                "address": "10.0.0.8:3306", 
                "mode": "R/O", 
                "readReplicas": {}, 
                "role": "HA", 
                "status": "ONLINE"
            }, 
            "10.0.0.9:3306": {
                "address": "10.0.0.9:3306", 
                "mode": "R/W", 
                "readReplicas": {}, 
                "role": "HA", 
                "status": "ONLINE"
            }, 
            "10.0.2.5:3306": {
                "address": "10.0.2.5:3306", 
                "mode": "R/O", 
                "readReplicas": {}, 
                "role": "HA", 
                "status": "ONLINE"
            }
        }, 
        "topologyMode": "Single-Primary"
    }, 
    "groupInformationSourceMember": "10.0.0.9:3306"
}

```

db1につないでクラスタ作ったので1のmodeがR/Wで追加した2と3がR/Oになってる。
"status": "OK",ということなのでとりあえずここまでCluster組むとこまではいけたようです。

mysql-shellで使えるクラスタ関連のメソッドとかログの見方とか色々載ってた。
https://dev.mysql.com/doc/refman/8.0/en/mysql-innodb-cluster-production-deployment.html

以下のメソッドがある模様
dba.configureInstance()
dba.createCluster()
Cluster.addInstance()
Cluster.removeInstance()
Cluster.rejoinInstance()

あと`\help`うつとほかのメソッドなども確認可能。
`\? dba`と打つとInnoDBCluster関連のメソッドのヘルプがでてくる感じでした。
それと1回切り替わったあとにread_onlyのままだと`> cluster.removeInstance('ic＠10.0.0.8')`してみても失敗する

persisted_globals_load がONで8.0.11以上だと上記メソッドによる変更で設定が永続化されるとのこと。
たしかにmysqldをrestartしても勝手に復活していました。persisted_globals_loadは特に何もしてないのでデフォルト値がONかも。


######routerをつかってクライアントからつなぐ

GroupReplication＋MySQLRouterでInnoDBClusterっていうことになるらしいです。
MySQLrouterはどこにいれるのかというとWEB・APサーバ側がいるホストに入れるのが手っ取り早いようです（内部ロードバランサの下に複数台ならべてもよいぽい）。router側でレプリカの追加などを勝手に追っているようでWEBサーバ側の設定更新が必要ということでもなさそうでした(※たぶんhostsで名前解決でなければ)。べんり。hostsでもいいので名前解決の手段が要るようではあります。

```
# rpm -ivh mysql-router-commercial-8.0.15-1.1.el7.x86_64.rpm
```
マスタノードに対してbootstrap指定

```
# mysqlrouter --bootstrap root＠10.0.0.9:3306 --user=mysqlrouter
Please enter MySQL password for root: 

Bootstrapping system MySQL Router instance...
Checking for old Router accounts
Creating account mysql_router2_gr1qtrvanxh6＠'%'
MySQL Router  has now been configured for the InnoDB cluster 'testCluster'.

The following connection information can be used to connect to the cluster after MySQL Router has been started with generated configuration..

Classic MySQL protocol connections to cluster 'testCluster':
- Read/Write Connections: localhost:6446
- Read/Only Connections: localhost:6447
X protocol connections to cluster 'testCluster':
- Read/Write Connections: localhost:64460
- Read/Only Connections: localhost:64470

Existing configuration backed up to '/etc/mysqlrouter/mysqlrouter.conf.bak'

# systemctl start mysqlrouter
# systemctl status mysqlrouter
● mysqlrouter.service - MySQL Router
   Loaded: loaded (/usr/lib/systemd/system/mysqlrouter.service; disabled; vendor preset: disabled)
   Active: active (running) since Sat 2019-02-16 05:44:16 JST; 9s ago
 Main PID: 80947 (main)
   CGroup: /system.slice/mysqlrouter.service
           └─80947 /usr/bin/mysqlrouter -c /etc/mysqlrouter/mysqlrouter.conf
```

```
# mysqlsh --uri root＠127.0.0.1:6446 --sql
Please provide the password for 'root＠127.0.0.1:6446': ************
Save password for 'root＠127.0.0.1:6446'? [Y]es/[N]o/Ne[v]er (default No): Y
MySQL Shell 8.0.15-commercial

Copyright (c) 2016, 2019, 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 '\?' for help; '\quit' to exit.
Creating a session to 'root＠127.0.0.1:6446'
Fetching schema names for autocompletion... Press ^C to stop.
Your MySQL connection id is 510
Server version: 8.0.15-commercial MySQL Enterprise Server - Commercial
No default schema selected; type \use <schema> to set one.

 MySQL  127.0.0.1:6446 ssl  SQL > show databases;
+-------------------------------+
| Database                      |
+-------------------------------+
| hoge                          |
| information_schema            |
| mysql                         |
| mysql_innodb_cluster_metadata |
| performance_schema            |
| sys                           |
+-------------------------------+
6 rows in set (0.0013 sec)

 MySQL  127.0.0.1:6446 ssl  SQL > create database fuga;
Query OK, 1 row affected (0.0291 sec)
```
Read Onlyポート(6447)から接続して更新クエリーを流した場合、read_only=ON となっていたのでエラーになる
更新はプライマリノードへ、参照はラウンドロビンに。（lvsのように重み指定はできなさそうだけど[公式のセミナースライド](https://www.mysql.com/jp/why-mysql/presentations/mysql-replication-update-201811-jp/)を思い出して見た感じ自律的に負荷調整してるようなことが書かれていた。他にはHAproxyとかsqlproxyとかクラウドの内部ロードバランサとかですかね）

```
mysqlsh --uri root＠127.0.0.1:6447 --sql -e "select ＠＠hostname"

# mysqlsh --uri root＠127.0.0.1:6447 --sql -e "select ＠＠hostname"
＠＠hostname
test-my8-db02
```
クライアントからはshell使わない場合は`# mysql -u root -p -h 127.0.0.1 -P 6447`というようにmysqlコマンドでポートとホスト指定でも大丈夫。

以下テーブル見るとweightというカラムは存在はしてました。

```
mysql> select * from mysql_innodb_cluster_metadata.instances;
+-------------+---------+---------------+--------------------------------------+---------------+------+--------+--------------------------------------------------------------------------------------------+------------+---------------+-------------+
| instance_id | host_id | replicaset_id | mysql_server_uuid                    | instance_name | role | weight | addresses                                                                                  | attributes | version_token | description |
+-------------+---------+---------------+--------------------------------------+---------------+------+--------+--------------------------------------------------------------------------------------------+------------+---------------+-------------+
|           2 |       2 |             2 | 8d2d8373-2b7d-11e9-b2b3-000d3a40a1a9 | 10.0.0.9:3306 | HA   |   NULL | {"mysqlX": "10.0.0.9:33060", "grLocal": "10.0.0.9:33061", "mysqlClassic": "10.0.0.9:3306"} | NULL       |          NULL | NULL        |
|           3 |       3 |             2 | 9edddf91-2b83-11e9-98a5-000d3a40a4e5 | 10.0.2.5:3306 | HA   |   NULL | {"mysqlX": "10.0.2.5:33060", "grLocal": "10.0.2.5:33061", "mysqlClassic": "10.0.2.5:3306"} | NULL       |          NULL | NULL        |
|           4 |       1 |             2 | 1194533a-34cc-11e9-a37a-000d3a40a0eb | 10.0.0.8:3306 | HA   |   NULL | {"mysqlX": "10.0.0.8:33060", "grLocal": "10.0.0.8:33061", "mysqlClassic": "10.0.0.8:3306"} | NULL       |          NULL | NULL        |
+-------------+---------+---------------+--------------------------------------+---------------+------+--------+--------------------------------------------------------------------------------------------+------------+---------------+-------------+
3 rows in set (0.00 sec)
```

######切り替えテストと復旧作業

http://mita2db.blogspot.com/2017/01/group-replication-3.html
普通にmysqld落としてみるとマスタが勝手に切り替わってました。
特に何かをするということもなくMHAのようにIPの切り替えするスクリプトを用意しなくて大丈夫。
手動でマスタを切り替えるメソッドはなんとなく見かけてないので切り戻す運用とかはしない前提かrestartすればokという話なのかも。

```
systemctl restart mysqld
# mysql
mysql> SELECT * FROM performance_schema.replication_group_members;
+---------------------------+--------------------------------------+-------------+-------------+--------------+-------------+----------------+
| CHANNEL_NAME              | MEMBER_ID                            | MEMBER_HOST | MEMBER_PORT | MEMBER_STATE | MEMBER_ROLE | MEMBER_VERSION |
+---------------------------+--------------------------------------+-------------+-------------+--------------+-------------+----------------+
| group_replication_applier | 8d2d8373-2b7d-11e9-b2b3-000d3a40a1a9 | 10.0.0.9    |        3306 | ONLINE       | SECONDARY   | 8.0.15         |
| group_replication_applier | 9edddf91-2b83-11e9-98a5-000d3a40a4e5 | 10.0.2.5    |        3306 | ONLINE       | PRIMARY     | 8.0.15         |
| group_replication_applier | a2e1d4ef-2b83-11e9-b210-000d3a40a0eb | 10.0.0.8    |        3306 | ONLINE       | SECONDARY   | 8.0.15         |
+---------------------------+--------------------------------------+-------------+-------------+--------------+-------------+----------------+
3 rows in set (0.00 sec)

```

問題があった場合の検知方法などについて、
ONLINE以外のステータスだったらとか規定の台数じゃなかったらとかログに不穏なワードがでてたら検知みたいなことでいいのかという感じでスクリプトはなんとなく作ったりはしました。sqlでONLINEかとってくるくらいならいけるかんじだった。

######Backupしてスレーブノードを増やしてみる

論理バックアップでSQLでとるmysqldumpだとレストアがデータ増えるほど果てしなく遅いのでmysqlbackupとか（Xtrabackupも）物理バックアップを使う方向で必要なユーザを準備

バイナリログのディレクトリ分けてる関係でXtrabackup使います。（なにかがたらなかったのかmysqlbackupではそうしてると増分でとれなかった）

ちなみにmysql8.0ならxtrabackupのバージョンも8.0じゃないといけなくて後方互換性はないですよとマニュアルに書かれています。

```sql:Xtrabackupのユーザ追加
create user 'exbackup'＠'%' identified by '********';
GRANT RELOAD,BACKUP_ADMIN,REPLICATION CLIENT,CREATE TABLESPACE,PROCESS,SUPER,CREATE,INSERT,SELECT ON *.* TO 'exbackup'＠'%';
CREATE DATABASE IF NOT EXISTS PERCONA_SCHEMA;
GRANT CREATE, INSERT, SELECT ON PERCONA_SCHEMA.* TO 'exbackup'＠'%';
FLUSH PRIVILEGES;
> show grants for 'exbackup'＠'%';
```

必要な権限など
https://www.percona.com/doc/percona-xtrabackup/LATEST/using_xtrabackup/privileges.html

旧いバージョンのなんかGCPで書かれてるのがあったので一応書いとく。
https://cloud.google.com/solutions/mysql-hot-backups?hl=JA
8.0のマニュアルにはinnobackupexは廃止されたのでxtrabackupに切り替えてねと書かれている
https://www.percona.com/doc/percona-xtrabackup/8.0/innobackupex/innobackupex_script.html
https://www.percona.com/doc/percona-xtrabackup/LATEST/installation/yum_repo.html

```shell-session:Xtrabackupのinstall
# yum install https://repo.percona.com/yum/percona-release-latest.noarch.rpm
# percona-release enable-only tools release
# yum install libev
# yum install percona-xtrabackup-80
# rpm -qa|grep xtrabackup
percona-xtrabackup-80-8.0.4-1.el7.x86_64
```

既存ノードはずして更新して復活さす。
プライマリノードでdb3をremoveして、sqlモードにして適当に更新する

```
> \c ic@10.0.0.9
> var cluster = dba.getCluster();
> cluster.status(); 
> cluster.removeInstance(ic@10.0.0.8)
> cluster.status(); 
> \sql
> \c root@10.0.0.9
> INSERT INTO hoge.sample(value) VALUES (1), (2), (3), (4), (5), (6), (7), (8), (9), (10);
> select count(*) from hoge.sample;
> \c root@10.0.0.8
> select count(*) from hoge.sample;
```
で、物理バックアップとってそれをつかってレストアをする。

・とりあえずローカルにストリーミングで増分バックアップをしてみる

なぜストリーミングかというとディレクトリが山ほどできるのが個人的にアレだっただけですがプリペアをそのホストで事前にやりたければディレクトリで取るのがいいかもしれない。管理サーバとかでやるほうがDBに負荷かからないとか場所があればそれもよさそう。

```
datetime=$(/bin/date +%Y%m%d-%H%M)
backup_dir=/mnt/backup/xtrabackup_backupfiles
backup_log=${backup_dir}/backup.log
backup_conf=${backup_dir}/backup.cnf

## base backup
xtrabackup --defaults-extra-file=${backup_conf} --parallel=4 \
  --stream=xbstream --backup > ${backup_dir}/base.xb

## incremental backup
  newest_lsn=＜baseの標準出力末尾のlsnを指定（スクリプトにする時実行ログに出しといてgrep+awk＞
  xtrabackup --defaults-extra-file=${backup_conf} --parallel=4 \
  --incremental --incremental-lsn=${newest_lsn} \
  --stream=xbstream --backup > ${backup_dir}/inc.${datetime}.xb


## backup_confの内容
[mysqld]
port=3306
socket=/var/lib/mysql/mysql.sock
datadir=/var/lib/mysql
log_bin=/var/lib/mybinlog/mysql-bin
log_bin_index=/var/lib/mybinlog/mysql-bin.index

## できたファイル
# ls -lhrt /mnt/backup/xtrabackup_backupfiles/
total 67M
-rw-r--r-- 1 root root  62M Feb 19 15:05 base.xb
-rw-r--r-- 1 root root 1.5M Feb 19 16:52 inc.20190219-1650.xb
-rw-r--r-- 1 root root  902 Feb 19 17:11 backup.log
-rw-r--r-- 1 root root 3.6M Feb 19 17:13 inc.20190219-1712.xb
```
転送する

```
##scp転送する場合
# scp -Cp ./*.xb myuser@db3:/tmp/

##blobストレージに投げる（アカウント準備等は別途）
# export AZURE_STORAGE_ACCOUNT=mystorageaccount
# AZURE_STORAGE_ACCESS_KEY='mystorageaccesskey'
# export AZURE_STORAGE_ACCESS_KEY=${AZURE_STORAGE_ACCESS_KEY}
# AZ_CMD=/usr/bin/az
# export container_name=mycontainer-name
# ${AZ_CMD} storage blob upload --container-name ${container_name}   --file base.xb  --name base.xb   --account-name ${AZURE_STORAGE_ACCOUNT} --account-key ${AZURE_STORAGE_ACCESS_KEY}
# ${AZ_CMD} storage blob upload --container-name ${container_name}   --file inc.^Cb  --name inc.*.xb   --account-name ${AZURE_STORAGE_ACCOUNT} --account-key ${AZURE_STORAGE_ACCESS_KEY}
# ${AZ_CMD} storage blob upload --container-name ${container_name}   --file inc.20190219-1712.xb  --name inc.20190219-1712.xb   --account-name ${AZURE_STORAGE_ACCOUNT} --account-key ${AZURE_STORAGE_ACCESS_KEY}
```
データ取ってきて復旧さす

```
# export AZURE_STORAGE_ACCOUNT=mystorageaccount
# AZURE_STORAGE_ACCESS_KEY='mystorageaccesskey'
# export AZURE_STORAGE_ACCESS_KEY=${AZURE_STORAGE_ACCESS_KEY}
# export container_name=mycontainer-name
# AZ_CMD=/usr/bin/az

# mkdir -p /mnt/restore/20190220
# cd /mnt/restore/20190220
# blob_name=base.xb
# destination_file=base.xb
# az storage blob download --container-name $container_name \
 --name $blob_name --file $destination_file --output table \
 --account-name ${AZURE_STORAGE_ACCOUNT} --account-key ${AZURE_STORAGE_ACCESS_KEY}

# az storage blob list --container-name $container_name --account-name ${AZURE_STORAGE_ACCOUNT} --account-key ${AZURE_STORAGE_ACCESS_KEY} --query '[].{Name: name, Lastmodified: properties.lastModified}'|grep inc| \
>   sed -e 's/[",]//g' -e 's/\t/,/g'
    Name: inc.20190219-1650.xb
    Name: inc.20190219-1712.xb

# blob_name=inc.20190219-1650.xb
# destination_file=inc.20190219-1650.xb
# az storage blob download --container-name $container_name \
 --name $blob_name --file $destination_file --output table \
 --account-name ${AZURE_STORAGE_ACCOUNT} --account-key ${AZURE_STORAGE_ACCESS_KEY}

# blob_name=inc.20190219-1712.xb
# destination_file=inc.20190219-1712.xb
# az storage blob download --container-name $container_name \
 --name $blob_name --file $destination_file --output table \
 --account-name ${AZURE_STORAGE_ACCOUNT} --account-key ${AZURE_STORAGE_ACCESS_KEY}

##ストリーミングファイルをデータディレクトリに戻してベースバックアップをプリペア
# mkdir base
# cd base/
# xbstream -x <../base.xb 
# xtrabackup --prepare --apply-log-only --target-dir=./base
# mkdir inc1 inc2
# cd inc1
# xbstream -x <../inc.20190219-1650.xb 
# cd ../inc2
# xbstream -x <../inc.20190219-1712.xb 
# ls
backup-my.cnf   mysql                          sys                     xtrabackup_checkpoints
fuga            mysql.ibd.delta                undo_001.delta          xtrabackup_info
hoge            mysql.ibd.meta                 undo_001.meta           xtrabackup_logfile
ib_buffer_pool  mysql_innodb_cluster_metadata  undo_002.delta          xtrabackup_tablespaces
ibdata1.delta   PERCONA_SCHEMA                 undo_002.meta
ibdata1.meta    performance_schema             xtrabackup_binlog_info

## 増分バックアップをベースディレクトリに復元
# cd ../
# xtrabackup --prepare --apply-log-only --target-dir=./base \
--incremental-dir=./inc1
# xtrabackup --prepare --apply-log-only --target-dir=./base \
--incremental-dir=./inc2

##DATADIRは、バックアップを復元する前に、空である必要があります。
##リストアを実行する前にMySQLサーバーをシャットダウンする必要があることに
##注意することも重要です。
##実行中のmysqldインスタンスのデータディレクトリに復元することはできません（部分バックアップをインポートする場合を除く）。

# systemctl stop mysqld
# df -h
# du -sh ./base
# du -sh /var/lib/mysql
# mv /var/lib/mysql{,.20190220}
# mv /var/lib/mybinlog{,.20190220}
# mkdir /var/lib/mysql;chown mysql. /var/lib/mysql
# mkdir /var/lib/mybinlog;chown mysql. /var/lib/mybinlog
# xtrabackup --copy-back --target-dir=./base
～略～
190220 13:48:19 [01]        ...done
190220 13:48:19 completed OK!

# chown -R mysql. /var/lib/mysql
# chown -R mysql. /var/lib/mybinlog
# systemctl start mysqld
# systemctl status mysqld
```

起動しました。
で、クラスタに戻す（≒レプリカ新規追加）にあたり
バイナリログの位置を記録された情報に合わせる必要があるようです。
これを合わせないままクラスタに追加するとMISSINGになるのですが合わせればアッサリONLINEに。

```
# cat base/xtrabackup_binlog_info 
mysql-bin.000003        24324   a2e1d4ef-2b83-11e9-b210-000d3a40a0eb:1-17,adf8e194-2ec3-11e9-b778-000d3a40a0eb:1-88:1000069-1000089
# mysql
> stop groupreplication;
> reset master;set global gtid_purged="a2e1d4ef-2b83-11e9-b210-000d3a40a0eb:1-17,adf8e194-2ec3-11e9-b778-000d3a40a0eb:1-88:1000069-1000089";
> start group_replication;
> SELECT * FROM performance_schema.replication_group_members;
+---------------------------+--------------------------------------+-------------+-------------+--------------+-------------+----------------+
| CHANNEL_NAME              | MEMBER_ID                            | MEMBER_HOST | MEMBER_PORT | MEMBER_STATE | MEMBER_ROLE | MEMBER_VERSION |
+---------------------------+--------------------------------------+-------------+-------------+--------------+-------------+----------------+
| group_replication_applier | 1194533a-34cc-11e9-a37a-000d3a40a0eb | 10.0.0.8    |        3306 | ONLINE       | SECONDARY   | 8.0.15         |
| group_replication_applier | 8d2d8373-2b7d-11e9-b2b3-000d3a40a1a9 | 10.0.0.9    |        3306 | ONLINE       | PRIMARY     | 8.0.15         |
| group_replication_applier | 9edddf91-2b83-11e9-98a5-000d3a40a4e5 | 10.0.2.5    |        3306 | ONLINE       | SECONDARY   | 8.0.15         |
+---------------------------+--------------------------------------+-------------+-------------+--------------+-------------+----------------+
3 rows in set (0.00 sec)

> select * from performance_schema.replication_group_member_stats\G
*************************** 1. row ***************************
                              CHANNEL_NAME: group_replication_applier
                                   VIEW_ID: 15499753606804610:15
                                 MEMBER_ID: 1194533a-34cc-11e9-a37a-000d3a40a0eb
               COUNT_TRANSACTIONS_IN_QUEUE: 0
                COUNT_TRANSACTIONS_CHECKED: 0
                  COUNT_CONFLICTS_DETECTED: 0
        COUNT_TRANSACTIONS_ROWS_VALIDATING: 0
        TRANSACTIONS_COMMITTED_ALL_MEMBERS: a2e1d4ef-2b83-11e9-b210-000d3a40a0eb:1-17,
adf8e194-2ec3-11e9-b778-000d3a40a0eb:1-95:1000069-1000089
            LAST_CONFLICT_FREE_TRANSACTION: 
COUNT_TRANSACTIONS_REMOTE_IN_APPLIER_QUEUE: 0
         COUNT_TRANSACTIONS_REMOTE_APPLIED: 0
         COUNT_TRANSACTIONS_LOCAL_PROPOSED: 0
         COUNT_TRANSACTIONS_LOCAL_ROLLBACK: 0
*************************** 2. row ***************************
                              CHANNEL_NAME: group_replication_applier
                                   VIEW_ID: 15499753606804610:15
                                 MEMBER_ID: 8d2d8373-2b7d-11e9-b2b3-000d3a40a1a9
               COUNT_TRANSACTIONS_IN_QUEUE: 0
                COUNT_TRANSACTIONS_CHECKED: 52
                  COUNT_CONFLICTS_DETECTED: 0
        COUNT_TRANSACTIONS_ROWS_VALIDATING: 0
        TRANSACTIONS_COMMITTED_ALL_MEMBERS: a2e1d4ef-2b83-11e9-b210-000d3a40a0eb:1-17,
adf8e194-2ec3-11e9-b778-000d3a40a0eb:1-95:1000069-1000089
            LAST_CONFLICT_FREE_TRANSACTION: adf8e194-2ec3-11e9-b778-000d3a40a0eb:94
COUNT_TRANSACTIONS_REMOTE_IN_APPLIER_QUEUE: 0
         COUNT_TRANSACTIONS_REMOTE_APPLIED: 31
         COUNT_TRANSACTIONS_LOCAL_PROPOSED: 24
         COUNT_TRANSACTIONS_LOCAL_ROLLBACK: 0
*************************** 3. row ***************************
                              CHANNEL_NAME: group_replication_applier
                                   VIEW_ID: 15499753606804610:15
                                 MEMBER_ID: 9edddf91-2b83-11e9-98a5-000d3a40a4e5
               COUNT_TRANSACTIONS_IN_QUEUE: 0
                COUNT_TRANSACTIONS_CHECKED: 45
                  COUNT_CONFLICTS_DETECTED: 0
        COUNT_TRANSACTIONS_ROWS_VALIDATING: 0
        TRANSACTIONS_COMMITTED_ALL_MEMBERS: a2e1d4ef-2b83-11e9-b210-000d3a40a0eb:1-17,
adf8e194-2ec3-11e9-b778-000d3a40a0eb:1-95:1000069-1000089
            LAST_CONFLICT_FREE_TRANSACTION: adf8e194-2ec3-11e9-b778-000d3a40a0eb:94
COUNT_TRANSACTIONS_REMOTE_IN_APPLIER_QUEUE: 0
         COUNT_TRANSACTIONS_REMOTE_APPLIED: 26
         COUNT_TRANSACTIONS_LOCAL_PROPOSED: 21
         COUNT_TRANSACTIONS_LOCAL_ROLLBACK: 0
3 rows in set (0.00 sec)

```
mysqlshellで戻したい場合はbinlogの位置合わせた後に以下の感じでいける気がします

```sql:プライマリにつなぐ
# mysqlsh
> \c ic@10.0.0.9
> var cluster = dba.getCluster();
> cluster.status();
> cluster.addInstance('ic@10.0.0.8')
> cluster.status();
```
で、db3に無かった外してから追加したレコードがあるのかを件数大丈夫そうかをかくにん。（大丈夫だった）

```sql:db3にて
> select count(*) from hoge.sample;
```

netcatとかつかうやつ↓面白そうというか確かに早そうなのであとで試そうかと思いました。
https://www.percona.com/blog/2018/11/05/how-to-quickly-add-a-node-to-an-innodb-cluster-or-group-replication/
→試したところsshにくらべると実行時間半分くらいになってました。けども、定期バックアップに使うとなると認証の仕組みが無いと危なそうとかエラーハンドリング書くのがアレそうなのでsshで事足りそうというか、人間が見てるときだけでいいかなと思いました。

とりあえず追加するやつはこんなかんじ。

######Backupを組む

・論理より物理とかパフォーマンス最適化とかの話
よく見かける話でmysqldumpは論理バックアップでデータ量に応じてバックアップと特にレストアにかかる時間が比例で増えるという特徴がありまして、データ量によっては話にならないので物理バックアップでリストアしたいよねというのがあります。
物理は論理の、バックアップは49倍・リストアは80倍高速(データ量は73GB)ってかいてあったので一応載せときます。（xtrabackupだと軽くググるとリストアが3倍くらい速いという記事が多いっぽいんですが、おそらくデータ量次第とかそういうことなのかなという認識です）
https://www.mysql.com/jp/products/enterprise/backup.html
で、MySQLの物理バックアップできるのはmysqlbackupかXtrabackupの2択になるようです。（xtrabackupはwindowsには入らない）

以下最適化という項目があったのでマニュアル抜粋。

バックアップのパフォーマンスの最適化：
フル＋増分バックアップ＋圧縮＋innodb_file_per_table=1＋並列＋大量削除後Optimizeとかの定期メンテ推奨
https://dev.mysql.com/doc/mysql-enterprise-backup/8.0/en/backup-performance.html
REDOログのみを使用して増分バックアップを実行する場合 、バックアップ圧縮（つまり、 圧縮オプションの使用）はサポートされない

リストアパフォーマンス最適化：
https://dev.mysql.com/doc/mysql-enterprise-backup/8.0/en/restore-performance.html
復元操作はバックアップと復元のサイクルのフェーズで、バックアップ方法によって大きく異なる
アプリケーションやWebサイトのダウンタイムを最小限に抑えることが重要
ファイル転送用のI / Oやネットワーク速度、データ圧縮解除用のCPU速度、プロセッサコアなど、主に低レベルの考慮事項に依存
データベースサーバーをシャットダウンした状態で常に実行
圧縮で削減できるI/Oと時間より圧縮解除するときにかかる時間の方が長いので非圧縮より時間がかかる

・差分バックアップと増分バックアップの違いについて、
差分は（フル）＋差分（フル以降の更新の差分全てを毎回取る）、復旧データは少ないので作業は楽
増分は（フル+差分）＋増分（前回とった以降の新しいデータのみ毎回取る）、復旧データファイルが多いので手間と時間がかかる
ということになる模様

・伝言で確認した想定要件（と実現可能性のあるプロダクトや手法）
→ある程度の規模でバックアップもレストアも早いのがいい（物理バックアップで低圧縮率非暗号化かな？）
→数分前にポイントインタイムリカバリ（頻度高めの増分バックアップ少し開けてフルバックアップ）
→バイナリログのディスクはI/O分散さすために分けたい（mysqlbackupでできなかったのでxtrabackup一択）
→無停止オンラインバックアップ(xtrabackupは--no-lock＋--apply-logオプション＋Innodbだったらロックせずにいけそう、mysqldumpは--single-transaction）
→クラウドストレージに置く（blob向けのazコマンドはupload-batch等のメソッド追加されて便利になったようでした）
→詳細な復旧手順までがないとmysqldumpに慣れてる人が多いので詰みそう（おそらく自分が真っ先に）

まず要件定義ちゃんとやろうぜみたいなのを見かけたのでペタッと
https://qiita.com/kkitta/items/32be970517fd6b5502a3
こちらも参考になるなあなど
http://blog.father.gedow.net/2012/09/26/percona-xtrabackup-features-vol01/
https://www.slideshare.net/yoku0825/mysql-90289401
https://www.ritolab.com/entry/98

経由地の管理サーバが居ればそこにxbstreamで投げて、居ない場合レプリカのどれかからblobに投げ込むかつ定期でフル＋頻回増分バックアップ取り保持したい期間確認してローテーションさす感じかな。
管理ホストがある場合は最初のフル＋あとずっと増分でとって、送った先でフルに増分をくっつけてから定期でblobに投げ込むのがいいのかな。

オプションを眺めてたところ、増分にするための前回のバックアップ情報を追わせるように自動的に組むのが多少工夫しないとめんどくさそう。でも増分にしないとバックアップの取得と転送のI/O負荷がばかにならないと思われる。
ちょっと古いですが圧縮についてはxbstream –parallel と pbzip2 でかなり幸せにという記事もあって、結果としてはpigzとかつかいました。
http://blog.father.gedow.net/2012/12/05/percona-xtrabackup-parallel/
https://qiita.com/itukizora/items/10a9e7fffff857de374b#%E4%BD%BF%E3%81%84%E6%96%B9

あとはまあバイナリログはポイントインタイムリカバリとか直前までロールフォワードさしたい場合に備えるとなると要る（バイナリログは増分の代わりにしてしまうとSQLに変換してつかう関係で論理で遅そうなので増分からはみ出た最新だけかなーという認識です）のでそれもプライベートセグメント内のどこかのサーバにリアルタイム転送しておいて定期でcronとかでblobにuploadといったところでよさそうでしょうか。
リモートから取得するスクリプト↓書いてる方がいたので参考になりそうです。
https://www.ritolab.com/entry/98
https://dev.mysql.com/doc/refman/8.0/en/mysqlbinlog-backup.html
以下のように--raw と--stop-never でライブバイナリログバックアップを作成するとよい模様。

```
mysqlbinlog --defaults-extra-file=/path_to_cnf/.my_binlog_bkup.cnf -h my-remote-slave-db-address --read-from-remote-server --stop-never --raw --result-file=/path_to_local_backupdir/ mysql-bin.000001 &
```
同じサーバに違うサーバからバイナリログとりに行こうとすると最初にとりにいってたほうのプロセスが落ちる感じだったのでプロセス監視は要るな～と思いました。書きこんでる途中のファイルをblobにアップロードするのは特に問題なさそうな感じでした。

・AzureのBlobに投げ込む先をご用意

マニュアル見たらクラウドストレージに投げ込むオプションがmysqlbackupにはあるようだったけどもサポートしてるのはopenstackとS3のみで、Xtrabackupはクラウドストレージ用のオプションというかxbcloudというコマンドがswiftだけサポートでアルファ版とかかれていました。
azコマンド等と組み合わせてなんとかする方向でよさそう。
既存のストレージアカウントの適当な名前のコンテナを手動でポータルからポチポチ作り投げ込む先の情報を確認しました。

blobに投げ込むスクリプトは↓ここらへんに自分で書いたやつなども。
https://qiita.com/smallpalace/items/7b738ecfb6782d121f75
あとで部分的に組み合わせたりすると思います。

基本的には`az storage blob -h`とか`az storage blob list -h`とかで下の方に表示される実行例のコマンドをmanみたいに見てためすとわかりやすかったです。

・ヒストリテーブルが作れなかった

lsnというザックリ言うと最後にどこまでバックアップできてたかという識別番号があって、それをもって増分バックアップをそこから実施するということになるわけですが、それを特定する方法が3つくらいあって、データベースのテーブルにヒストリを記録してそこを見さすのと前回バックアップ取れたベースのディレクトリを指定してそこのinfoファイルを見さす方法と、識別番号自体を指定する方法があるわけです。
ヒストリがもっとも簡単で確実かなとか思ったわけですが。。
https://bugs.launchpad.net/percona-xtrabackup/+bug/1707811
バグを踏んだのか、グループレプリケーション＋Xtrabackupでhistoryオプションつけてもテーブルはできるがデータが保存されないという現象が。えー。楽をしようとおもったのにlsnをどうにかして取れるようにする必要がありそうです。（まあレプリカで実行しようとしたらそこに書かれるとなると読み取り専用のところ更新していいのかみたいなのが気にはなってたのでまあしょうがないのかなあ）

・いちおうスクリプト参考
標準・標準エラーログは絶対ださないと詰むっぽいようです。

↓いちおう、動確したやつの一部。（リモートサーバに投げつける方、ローカル保存しないパターン）

```
## user difined functions
base_xtrabkup() {
  echo "$(/bin/date +%Y%m%d:%H:%M): commpressed base stream backup is start." >> ${backup_log}
  xtrabackup --defaults-extra-file=${backup_conf} \
   --backup --parallel=${parallel} --no-lock \
   --stream=xbstream --target-dir=${datadir} 2> ${backup_tmp_log}\
   |pigz -c --fast \
   |ssh -i ${sshkey} ${remote_sshuser}@${remote_bkupsrv} "cat - > ${remote_dir}/base-pigz.${datetime}.xb"
  resstat=$(echo $?)
  cat ${backup_tmp_log} >> ${backup_log}
  if [ ${resstat} -ne 0 ];then
    echo "$(/bin/date +%Y%m%d:%H:%M): commpressed base stream backup is failed." |tee -a ${backup_log}| mail -s "NG_DB_BKUP" ${alert_mail_to}
  else
    echo "$(/bin/date +%Y%m%d:%H:%M): commpressed base stream backup is end." >> ${backup_log}
    echo "${today}" > ${backup_dir}/is_base_bkuped_thisweek
  fi
}

increase_xtrabkup() {
  echo "$(/bin/date +%Y%m%d:%H:%M): commpressed increase stream backup is start." >> ${backup_log}
  newest_lsn=$(grep lsn ${backup_tmp_log}|tail -1|awk '{print $8}'|sed -e 's/[^0-9]//g')
  xtrabackup --defaults-extra-file=${backup_conf} \
   --backup --parallel=${parallel} --no-lock \
   --incremental --incremental-lsn=${newest_lsn} \
   --stream=xbstream --target-dir=${datadir} 2> ${backup_tmp_log}\
   |pigz -c --fast \
   |ssh -i ${sshkey} ${remote_sshuser}@${remote_bkupsrv} "cat - > ${remote_dir}/inc-pigz.${datetime}.xb"
  resstat=$(echo $?)
  cat ${backup_tmp_log} >> ${backup_log}
  if [ ${resstat} -ne 0 ];then
    echo "$(/bin/date +%Y%m%d:%H:%M): commpressed increase stream backup is failed." |tee -a ${backup_log}| mail -s "NG_DB_BKUP" ${alert_mail_to}
  else
    echo "$(/bin/date +%Y%m%d:%H:%M): commpressed increase stream backup is end." >> ${backup_log}
  fi
}

## week base backup and rotate old log
if [ ${dayoftheweek} -eq ${base_w} -a ${hourtime} = ${base_h} ];then
  is_base_bkuped_thisweek=$(cat ${backup_dir}/is_base_bkuped_thisweek)
  if [ ${is_base_bkuped_thisweek} = ${today} ];then
    increase_xtrabkup
    exit 0
  else
    test -f ${backup_log}.lastweek1 && mv -f ${backup_log}.lastweek1 ${backup_log}.lastweek2
    test -f ${backup_log} && mv -f ${backup_log} ${backup_log}.lastweek1
    base_xtrabkup
    exit 0
  fi
### hourly increase backup
else
  increase_xtrabkup
  exit 0
fi
```

↓うけとったのを下処理して固めてさらにblobになげつける方（メイン部分）

```
## main proccess
for fl in $(echo ${stream_files[@]}) 
do
  ## set vars kind of file.
  fl_prefix=$(echo ${fl}|awk -F \- '{print $1}')
  ## for base(full) prepare.
  if [ ${fl_prefix} = "base" ];then
    echo "$(/bin/date +%Y%m%d:%H:%M): base prepare is start."
    base_prefix=base_$(echo ${fl}|awk -F \. '{print $2}')
    mv -f ${current_dir}/* ${old_dir}/
    mv -f ${applied_dir}/* ${old_dir}/
    mkdir -p ${current_dir}/${base_prefix} && \
    unpigz -c ${chkstream_dir}/${fl}| xbstream -x -C ${current_dir}/${base_prefix}
    xtrabackup --prepare --apply-log-only --target-dir=${current_dir}/${base_prefix}
    resstat=$(echo $?)
    if [ ${resstat} -ne 0 ];then
      echo "$(/bin/date +%Y%m%d:%H:%M): base prepare and apply-log is failed." | mail -s "NG_DB_BKUP" ${alert_mail_to}
    else
      tar -cf - ${current_dir}/${base_prefix} | pigz -c --fast > ${current_dir}/${base_prefix}.tar.gz
      echo ${base_prefix} > ${current_dir}/base_prefix.txt
      echo "$(/bin/date +%Y%m%d:%H:%M): base prepare is end."
    fi
  ## for increace prepare and apply to base.
  else
    echo "$(/bin/date +%Y%m%d:%H:%M): increace prepare is start."
    base_prefix=$(cat ${current_dir}/base_prefix.txt)
    inc_prefix=inc_$(echo ${fl}|awk -F \. '{print $2}')
    mkdir -p ${current_dir}/${inc_prefix} && \
    unpigz -c ${chkstream_dir}/${fl}| xbstream -x -C ${current_dir}/${inc_prefix}
    xtrabackup --prepare --apply-log-only --target-dir=${current_dir}/${base_prefix} \
     --incremental-dir=${current_dir}/${inc_prefix}
    resstat=$(echo $?)
    if [ ${resstat} -ne 0 ];then
      echo "$(/bin/date +%Y%m%d:%H:%M): increace prepare and apply-log is failed." | mail -s "NG_DB_BKUP" ${alert_mail_to}
    else
      tar -cf - ${current_dir}/${inc_prefix} | pigz -c --fast > ${current_dir}/${inc_prefix}.tar.gz
      mv -f ${current_dir}/${inc_prefix} ${applied_dir}/
      echo "$(/bin/date +%Y%m%d:%H:%M): increace prepare is end."
    fi
  fi
  ## upload to blob storage.
  is_upfiles_exists=($(find ${current_dir} -name "*.tar.gz"))
  if [ -n ${is_upfiles_exists[0]} ];then
    echo "$(/bin/date +%Y%m%d:%H:%M): upload file to blob is start."
    ${AZ_CMD} storage blob upload-batch -d ${container_name}/${container_path}/${base_prefix} \
     -s ${current_dir} --pattern *.tar.gz \
     --account-name ${AZURE_STORAGE_ACCOUNT} --account-key ${AZURE_STORAGE_ACCESS_KEY}
    resstat=$(echo $?)
    if [ ${resstat} -ne 0 ];then
      echo "$(/bin/date +%Y%m%d:%H:%M): upload file to blob is failed" | mail -s "NG_DB_BKUP" ${alert_mail_to}
    else
      mv -f ${chkstream_dir}/${fl} ${applied_dir}/
      mv -f ${current_dir}/*.tar.gz ${applied_dir}/
      echo "$(/bin/date +%Y%m%d:%H:%M): upload file to blob is end."
    fi
  else
    echo "$(/bin/date +%Y%m%d:%H:%M): upload file is not found."
  fi
done
```

増分をフルにつなげるときは--apply-log-onlyじゃないとダメで--apply-logだとエラー出るかんじでした。

あとbinlogのほうの定期blobストレージ投げ込みとプロセスチェックして落ちてたら上げる方のメイン部分↓

```
## log redirect
exec >> ${backup_log}
exec 2>&1

## check process
is_binlog_ps_exist=$(ps -ef|grep -v grep|grep binlog|awk '{print $2}')
if [ -n "${is_binlog_ps_exist}" ];then
  binlog_ps_pid=${is_binlog_ps_exist}
else
  echo "$(/bin/date +%Y%m%d:%H:%M): binlog backup process is down, will running it right now."
  updating_binlog=$(ls -1rt ${binlog_local_bkup_dir}/|grep -v \.log|tail -1)
  mysqlbinlog --defaults-extra-file=${binlog_cnf} -h ${binlog_remote_host} \
   --read-from-remote-server --stop-never --raw \
   --result-file=${binlog_local_bkup_dir}/ ${updating_binlog} &
  is_binlog_ps_exist=$(ps -ef|grep -v grep|grep binlog|awk '{print $2}')
  test -n "${is_binlog_ps_exist}" && binlog_ps_pid=${is_binlog_ps_exist}
  sleep 3
fi

## check binlog files
binlog_list_local=($(find $binlog_local_bkup_dir -type f -name "mysql-bin.*" -mmin -${binlog_search_lastmodify_min}))
if [ -z ${binlog_list_local[0]} ];then
  echo "$(/bin/date +%Y%m%d:%H:%M): update file is not exist."
  exit
fi
## upload binlog files to blob storage.
for fl in $(echo ${binlog_list_local[@]})
do
  filebase=$(basename ${fl})
  echo "$(/bin/date +%Y%m%d:%H:%M): upload binlog file to blob is start." 
  ${AZ_CMD} storage blob upload-batch -d ${container_name}/${container_path}/mysqlbinlog \
   -s ${binlog_local_bkup_dir} --pattern ${filebase} \
   --account-name ${AZURE_STORAGE_ACCOUNT} --account-key ${AZURE_STORAGE_ACCESS_KEY}
  resstat=$(echo $?)
  if [ ${resstat} -ne 0 ];then
    echo "$(/bin/date +%Y%m%d:%H:%M): upload binlog file to blob is failed" | mail -s "NG_DB_BKUP" ${alert_mail_to}
  else
    echo "$(/bin/date +%Y%m%d:%H:%M): upload binlog file to blob is end." 
  fi
done 
```
まあ、世代管理とかはここでは省略。

一応念のため取る気がする論理バックアップの話。
mysqldumpでGTID対応オプションこんな感じ（GTIDに対応するには--routines(-R) --events(-E) --triggersが要るようです）
`--all-databases --quote-names --opt --single-transaction --order-by-primary --hex-blob --flush-logs -R -E --triggers --default-character-set=utf8mb4`

mysqlpump(スキーマとテーブル数次第で並列で取れる方）でGTID対応オプションこんな感じ
`--all-databases --add-drop-table --single-transaction --hex-blob --routines --events --triggers --default-character-set=utf8mb4 --default-parallelism=2`

どっちが早いかは環境によると思うのでリストア時間も混みで測るとよさそう。（--order-by-primaryがdumpでないと使えないあたりがリストアの時にどう影響するかわからない。主キーソートしてあるデータを取り込む方がバッファプールからはみ出る量の場合は早いというのを[sh2さんのベンチ](https://sh2.hatenablog.jp/entries/2012/01/22)で昔見ました）

######レストアについて

とりあえずスレーブコピーしてクラスタ追加するあたりは増分の復旧まで[前述](https://qiita.com/smallpalace/private/132279989b329b401f95#backup%E3%81%97%E3%81%A6%E3%82%B9%E3%83%AC%E3%83%BC%E3%83%96%E3%83%8E%E3%83%BC%E3%83%89%E3%82%92%E5%A2%97%E3%82%84%E3%81%97%E3%81%A6%E3%81%BF%E3%82%8B)しているので、次の項目でポイントインタイムで時間指定リカバリを若干解説。
（実運用する場合の手順は環境に合わせてたぶん作るはず）

######ポイントインタイムリカバリについて

xtrabackupの場合はxtrabackup_binlog_infoとかxtrabackup_binlog_pos_innodbあたりにこのディレクトリの位置がバイナリログのどこまで実行されてるかといった情報がかかれているので、それ以降のバイナリログがあるならそれを丸っとmysqlbinlogでsqlに直してmysqlコマンドで適用してあげるという流れでポイントインタイムリカバリします。

```
# cat base/xtrabackup_binlog_info 
mysql-bin.000003        24324   a2e1d4ef-2b83-11e9-b210-000d3a40a0eb:1-17,adf8e194-2ec3-11e9-b778-000d3a40a0eb:1-88:1000069-1000089
# cat base/xtrabackup_binlog_pos_innodb
mysql-bin.000003        24324
```

mysqlbinlogのオプションには、ポジション指定したり時刻指定したりできるので、うっかりオペミスしたのでいまから５分前までを適用してなかったことにするといったことが可能です。
https://dev.mysql.com/doc/refman/5.6/ja/mysqlbinlog-backup.html
https://dev.mysql.com/doc/refman/8.0/en/mysqlbinlog-backup.html

```
#時間を指定するオプション
#（datetime 引数と同じかそれより遅いタイムスタンプを持つ最初のイベントを読み
#　datetime 値は、mysqlbinlog を実行するマシンのローカルタイムゾーンに相対的）
--start-datetime="2018-12-25 11:25:56"  #読み取り開始時刻指定
--stop-datetime="2019-01-25 11:59:59"   #読み取り停止時刻指定

#バイナリログの位置を指定するオプション
--start-position=24324  #読み取り開始ポジション指定
--stop-never  #読み終わっても待ち受けて続きをよみつづける（--raw等とbkupにつかうかtailで流しとく用途）
--stop-position=99999   #読み取り停止ポジション指定
```

事前にフル・増分バックアップを復旧後、続きのバイナリログを任意の時間まで指定してSQLにしてmySQLで取り込む、という流れの参考コマンド↓。

```
$ mysqlbinlog /path/to/datadir/mysql-bin.000003 /path/to/datadir/mysql-bin.000004 \
    --start-position = 57 --stop-datetime = "11-12-25 01:00:00" | mysql -u root -p
```

ついでにエラーログからslaveが停止した位置のクエリを調べたい、かつbinlog_format=rowの場合に↓。

```
$ mysqlbinlog mysql-bin.000146 -vvv --base64-output=DECODE-ROWS --start-position=76184972 |head -100
```

まあRDSならマネコンの画面からポチポチでもポイントインタイムリカバリができるんですがオレオレマネージド的なことだとこんなかんじに。予算に余裕がある場合は[商用版は本家のライセンス買ってサポート契約するとか](https://www.mysql.com/jp/partners/)、コミュニティ版のサポートも英語大丈夫なら[Perconaさん](https://www.percona.com/services/support/support-tiers-mysql)とか日本語なら[スマートスタイルさん](https://www.s-style.co.jp/products/compare)がなんかしてるみたいなので見積もってみるといいかもしれないですね。
商用ライセンスが要るのは監視・監査・ハイパフォーマンスにする系の機能つかいたくなったりサポートが要るようならかなーと認識していますが詳しいことは本家の方かパートナーさんに確認したらいいと思います。

######暗号化ためしてみる

要件的にクラウドストレージに置くときに必要だったら頑張ろうかなと思ってて、ただ、blobは置かれたもんは勝手に暗号化されてる仕様だったぽいですね。
https://docs.microsoft.com/ja-jp/azure/storage/common/storage-service-encryption?toc=%2fazure%2fstorage%2fblobs%2ftoc.json

一応コマンドのほうもなんとなくテストはしてはみたんですが、xbcryptでやるよりはopensslのほうがわかりやすいし早そうかなあという印象でした。

```
#opensslの場合
##encrypt
# openssl enc -e -aes-256-cbc -salt -pass file:./pw.txt -in xtrabackup.xb -out xtrabackup.xb.enc
##decrypt
# openssl enc -d -aes-256-cbc -salt -pass file:./pw.txt -in xtrabackup.xb.enc -out xtrabackup.xb.dec

#xbcryptの場合
##encrypt
# xtrabackup --defaults-extra-file=~/backup.cnf \
>  --backup --parallel=4 --no-lock \
>  --encrypt=AES256 --encrypt-key-file=/path/.bkkeyfile --encrypt-threads=4 \
>  --stream=xbstream --target-dir=/var/lib/mysql 2> backup.log \
>  |pv|pigz -c --fast|ssh -i ~/.ssh/id_rsa myuser@remotehost "cat -  > /tmp/xtrabackup-comp.xb.xbcrypt"
##decrypt
# unpigz -c /tmp/xtrabackup-comp.xb.xbcrypt| xbstream -x -C /tmp/hoge
# for i in `find . -iname "*\.xbcrypt"`; do xbcrypt -d --encrypt-key-file=/root/.bkkeyfile --encrypt-algo=AES256 < $i > $(dirname $i)/$(basename $i .xbcrypt) && rm -f $i; done
```

######EnterpriseMonitorについて

問題あって問い合わせる時に中の人が即答できるデータが取れると何かのイベントで聞いた記憶があります。私の記憶が確かならばEnterpriseのライセンス買う場合はこれを入れないとカレーを注文して福神漬けだけ食べるようなかんじです。（個人の感想です）
https://dev.mysql.com/doc/mysql-monitor/8.0/en/
グループレプリケーションの監視も余裕のようです↓
http://variable.jp/2017/05/22/mysql-group-replication%E3%81%AE%E3%83%A2%E3%83%8B%E3%82%BF%E3%83%AA%E3%83%B3%E3%82%B0/

サービスマネージャーをどっかに入れてそこで発行されるキーをエージェント入れる時に指定する感じのようです。サービスマネージャーが管理する用のスキーマが要ります。

######スレッドプール

これは商用ライセンス買わないとつかえないものですね。ハイパフォーマンスにする系。
https://dev.mysql.com/doc/refman/8.0/en/thread-pool.html
インストール方法とかはこちらに。
https://dev.mysql.com/doc/refman/8.0/en/thread-pool-installation.html

######Audit（監査）ログ
8.0だとEnterpriseかなあ。perconaやmariaがどうかは知らないです。
https://dev.mysql.com/doc/refman/8.0/en/audit-log.html
あとはProxySQLで出してる人もいるようですが。。
https://builderscon.io/tokyo/2018/session/87e13506-2f80-4fae-af9c-2421c7dbb460
5.7でもいいならMcafeeのもあるようです。
https://github.com/mcafee/mysql-audit/wiki/Installation
AuroraやRDSの監査ログも出たとかみかけたけど8.0じゃなさそう。
https://docs.aws.amazon.com/ja_jp/AmazonRDS/latest/AuroraUserGuide/AuroraMySQL.Updates.html
RDSは8.0は監査ログ未対応とはっきり書いてありました。
https://docs.aws.amazon.com/ja_jp/AmazonRDS/latest/UserGuide/CHAP_MySQL.html

######参考
InnoDBCluster/GroupReplication関連
https://www.s-style.co.jp/blog/2018/12/3079/
https://www.s-style.co.jp/blog/2018/11/2722/
https://dev.mysql.com/doc/refman/8.0/en/group-replication-requirements.html
https://dev.mysql.com/doc/refman/8.0/en/replication-options-slave.html#option_mysqld_replicate-do-table
https://dev.mysql.com/doc/refman/8.0/en/replication-gtids-restrictions.html
https://dev.mysql.com/doc/refman/8.0/en/group-replication-fault-tolerance.html
https://www.percona.com/blog/2018/07/09/innodb-cluster-in-a-nutshell-part-1/
https://www.percona.com/blog/2018/11/05/how-to-quickly-add-a-node-to-an-innodb-cluster-or-group-replication/
https://mysqlhighavailability.com/ipv6-support-in-group-replication/
https://mysqlhighavailability.com/group-replication-consistent-reads/
https://dev.mysql.com/doc/refman/8.0/en/mysql-innodb-cluster-production-deployment.html
https://dev.mysql.com/doc/mysql-router/8.0/en/mysql-router-faq.html
https://dev.mysql.com/doc/refman/8.0/en/mysql-innodb-cluster-using-router.html
https://ngyuki.hatenablog.com/entry/2018/07/02/072619
https://kazuhira-r.hatenablog.com/entry/20180720/1532097960
https://bugs.mysql.com/bug.php?id=94004
https://thesubtlepath.com/blog/mysql/group-replication-gcs-troubleshooting/
https://dev.mysql.com/doc/refman/8.0/en/group-replication-multi-primary-mode.html
http://mita2db.blogspot.com/2017/01/group-replication-3.html
https://qiita.com/rysk001/items/57c0d3191c1cf6d240d1
https://dev.mysql.com/doc/refman/en/server-system-variables.html#sysvar_super_read_only
https://dev.mysql.com/doc/mysql-router/8.0/en/mysql-router-conf-options.html#option_mysqlrouter_dynamic_config
https://www.mysql.com/jp/why-mysql/presentations/mysql-replication-update-201811-jp/

mysqlshell
https://dev.mysql.com/doc/mysql-shell/8.0/en/mysql-shell-commands.html

そのたReplication関連
http://gihyo.jp/dev/serial/01/mysql-road-construction-news/0024
https://www.mysql.com/jp/why-mysql/presentations/mysql-80-for-beginners-replication-doc-jp/
https://github.com/yoshinorim/mha4mysql-manager/wiki

mysqlbackup関連
https://docs.oracle.com/cd/E17952_01/mysql-enterprise-backup-8.0-en/what-is-new.html
https://dev.mysql.com/doc/mysql-enterprise-backup/8.0/en/meb-command-reference.html
https://dev.mysql.com/doc/mysql-enterprise-backup/8.0/en/meb-files-backed-up-summary.html
https://dev.mysql.com/doc/mysql-enterprise-backup/8.0/en/bugs.backup.html
https://dev.mysql.com/doc/mysql-enterprise-backup/8.0/en/backup-history-table-update.html
https://dev.mysql.com/doc/mysql-enterprise-backup/8.0/en/backup-performance.html
https://dev.mysql.com/doc/mysql-enterprise-backup/8.0/en/restore-performance.html
https://dev.mysql.com/doc/mysql-enterprise-backup/8.0/en/backup-compression-options.html#option_meb_compress-method
https://dev.mysql.com/doc/refman/8.0/en/glossary.html#glos_transparent_page_compression
https://dev.mysql.com/doc/mysql-enterprise-backup/8.0/en/advanced.encrypted-binlog-relaylog.html
https://dev.mysql.com/doc/mysql-enterprise-backup/8.0/en/meb-group-replication.html
http://variable.jp/2017/03/13/mysqlbackup%E3%82%92%E5%88%A9%E7%94%A8%E3%81%97%E3%81%9Fobject-storage%E3%81%B8%E3%81%AE%E3%83%90%E3%83%83%E3%82%AF%E3%82%A2%E3%83%83%E3%83%97/
https://dev.mysql.com/doc/mysql-enterprise-backup/8.0/en/mysqlbackup.incremental.html
https://bugs.mysql.com/bug.php?id=88262

xtrabackup関連
https://www.percona.com/doc/percona-xtrabackup/LATEST/xtrabackup_bin/point-in-time-recovery.html#pxb-xtrabackup-point-in-time-recovery
https://www.percona.com/doc/percona-xtrabackup/LATEST/using_xtrabackup/privileges.html
https://cloud.google.com/solutions/mysql-hot-backups?hl=JA
https://www.percona.com/doc/percona-xtrabackup/8.0/innobackupex/innobackupex_script.html
https://www.percona.com/doc/percona-xtrabackup/LATEST/installation/yum_repo.html
https://www.percona.com/doc/percona-xtrabackup/LATEST/using_xtrabackup/configuring.html
https://www.percona.com/doc/percona-xtrabackup/LATEST/xtrabackup_bin/incremental_backups.html#incremental-streaming-backups-using-xbstream
http://blog.father.gedow.net/2012/09/26/percona-xtrabackup-features-vol01/

そのたBackup
https://www.slideshare.net/yoku0825/mysql-90289401
https://www.ritolab.com/entry/98
https://dev.mysql.com/doc/refman/8.0/en/mysqlbinlog-backup.html
https://dev.mysql.com/doc/refman/5.6/ja/mysqlbinlog-backup.html
https://qiita.com/Tocyuki/items/f34ca92b8bf6e0014923

サーバパラメータ
https://www.slideshare.net/yoku0825/mysql-80
https://yakst.com/ja/posts/3726
https://image.slidesharecdn.com/mysql-performance-tuning-okuno-170616121131/95/mysql-57-27-638.jpg?cb=1497615210
https://yoku0825.blogspot.com/2016/09/mysql-800mycnf.html
http://shim0mura.hatenadiary.jp/entry/20130812/1376302018

サンプルデータ生成
https://qiita.com/cobot00/items/8d59e0734314a88d74c7

Azure
https://docs.microsoft.com/ja-jp/azure/virtual-network/virtual-network-optimize-network-bandwidth#centos
https://docs.microsoft.com/ja-jp/azure/virtual-network/create-vm-accelerated-networking-cli
https://docs.microsoft.com/ja-jp/cli/azure/install-azure-cli-yum?view=azure-cli-latest
https://qiita.com/unosk/items/330376faadf648aa8ccc
https://qiita.com/smallpalace/items/a95ed056c408d2185c38
https://qiita.com/smallpalace/items/7b738ecfb6782d121f75
https://docs.microsoft.com/ja-jp/azure/storage/common/storage-service-encryption?toc=%2fazure%2fstorage%2fblobs%2ftoc.json