CentOSユーザがUbuntu16.04にMySQL構築してドツボにはまる(徹底チューニング編)

色々苦労したので記録する。
UbuntuでNUMAをOFFにしたりscsi_mod.use_blk_mqを有効にする資料は日本だとここだけっぽい
間違っていたらツッコミを全力でしていただけると助かります。

#OSインストール
##パーティション作成
編集するならディスクのパーティショニングにて手動を選ぶ
CentOSでも同じだが
LVMは論理ボリュームマネージャーの設定で設定する
ガイドではboot領域のインストール先のフォーマットがext2になってます。
私はext3かext4のデフォルトに変更します。
ext2はさすがにジャーナルがないので怖い
/もXFSにするのでしたら標準はext4なので変更しましょう。
また、スワップサイズのデフォルトもCentOSと違い大容量でも物理メモリ+αになっています。

##起動パラメータチューニング
Ubuntuの知識がなくてかなりはまったポイント
`/etc/default/grub`
のGRUB_CMDLINE_LINUX_DEFAULTが通常起動の起動パラメータ
GRUB_CMDLINE_LINUXがレスキューモードでも有効な起動パラメータになります。
物理CPUが2個以上でNUMAをOFFにしたい場合numa=off
SSDはscsi_mod.use_blk_mq=yが最適。
blk_mqを指定しない場合noopよりはdeadlineの方がいい？
https://wiki.debian.org/SSDOptimization#Low-Latency_IO-Scheduler

```
sudo vi /etc/default/grub
- GRUB_CMDLINE_LINUX_DEFAULT=""
+ GRUB_CMDLINE_LINUX_DEFAULT="numa=off scsi_mod.use_blk_mq=y"

sudo update-grub
```

**update-grubを実行しないと反映されません**
設定確認コマンドは
`sudo numactl --hardware`
`sudo tree /sys/block/sda/mq` ないしは` cat /sys/block/sd*/queue/scheduler`
設定前と設定後のdiffを見ると反映されているかわかりやすいです。

#基本操作
##sudo
sudoはそのままだと\*(アスタリスク)が使えません
sh -c "grep innodb /var/lib/mysql/\*"のように`sh -c "コマンド"`で実行できます。
手順書にsudoがないドキュメントも多数ありますがその場合は許されるなら
`sudo su`ないしは`sudo bash`でrootになってから実行した方が楽です。
##NW設定
`/etc/network/interfaces`で全てのI/Fが設定できます。CentOSよりこれはかなり楽。
`ip addr`でI/F名を先に確認しましょう。
bondingでしたら下にサンプルがあります。
##apt
`sudo apt-get install`でインストールと更新
`sudo apt-get update`で最新のパッケージリスト取得
`sudo apt-get upgrade`でカーネル以外の最新パッケージ適応
`sudo apt-get dist-upgrade`でカーネル含め最新のパッケージ適応
`sudo apt-get clean`でアーカイブ削除

##initスクリプトの自動確認
個別なら`update-rc.d xxx enable`
全体を管理したい場合はsysv-rc-confで制御
ただし、`sudo apt-get install sysv-rc-conf`しないと未だにインストールされません
##systemdスクリプトの自動起動確認
こちらがわかりやすい
http://eng-entrance.com/linux_startup#systemd

**ヘルプ**

#OSチューニング
##ファイルシステム編集2
CentOSと同じく/etc/fstabを編集。
ここは人によって違うと思いますが私の場合
/bootは信頼性重視でdata=journalを入れてもいいと思います。
/rootは**ext4のlazytime**
ext4にするならnoatimeは若干怖いがatimeの改良版lazytimeは使って問題ないと判断
/var/lib/mysqlは**ext4かXFSのnoatime,nobarrier,lazytime**
atimeがなくてもmysqlは問題なくbarrierもデータ保護から悩ましいですがないとパフォーマンスがいいのでクラウドやDCなら
ext4ではstripe-width
xfsではagcount,sunit/swidthの設定も検討した方がいいようです。
（注意）
<a href="http://ymmt.hatenablog.com/entry/2018/02/13/143716">
XFSは4.10からnobarrierが無視される</a>そうですが聞いたら
<a href="http://smalldatum.blogspot.jp/2018/01/xfs-nobarrier-and-413-linux-kernel.html">Ubuntu16.04も無効にされる</a>そうです


##sysctl編集
CentOSと同じく/etc/sysctl.confに記載して良さそうです。
**どなたか/etc/sysctl.d/にルールがあるなら教えてください**
vm.swappiness = 1
は最低限有効にしましょう
IPv6が不要なら
net.ipv6.conf.all.disable_ipv6 = 1
net.ipv6.conf.default.disable_ipv6 = 1
も追加。
Ubuntu16.04のパラメータは優秀なのであまりいじらなくても良さそうです。

##rc.local
標準で有効になっているようです(なっていなければsudo systemctl enable rc-local.service)
transparent_hugepageを無効化するなら(環境次第なのですがメモリを多く使うミドルウェアは無効推奨が多い)
RHEL6ではTPHはデータベースのワークロードには推奨されません。とあります。

```
sudo vi /etc/rc.local
+ if test -f /sys/kernel/mm/transparent_hugepage/enabled; then
+   echo never > /sys/kernel/mm/transparent_hugepage/enabled
+ fi
+ 
+ if test -f /sys/kernel/mm/transparent_hugepage/defrag; then
+    echo never > /sys/kernel/mm/transparent_hugepage/defrag
+ fi
```
##bonding設定
bonding設定は
https://help.ubuntu.com/community/UbuntuBonding
に公式手順がありこの通りで動きます。
sudo modprobe bondingがなぜかこけたことがありますが再起動すれば問題がありませんでした。

私はDELLのおすすめに従いbalance-xorで設定していたので少し苦労しました。
理想は当然802.3adです。こちらはネットに資料が色々あるのでそちらを参考に
http://ja.community.dell.com/techcenter/b/weblog/archive/2014/05/16/linux-bonding-mode-0
今は簡略的に以下の設定ファイルにしています。

cat /etc/network/interfaces

```
auto lo
iface lo inet loopback

auto eno1
iface eno1 inet manual
bond-master bond0
bond-primary eno1

# The primary network interface
auto eno2
#iface eno2 inet static
iface eno2 inet manual
bond-master bond0

auto bond0
iface bond0 inet static
        address 192.168.1.1
        netmask 255.255.255.0
        network 192.168.1.0
        broadcast 192.168.1.255
        gateway 192.168.1.254
        # dns-* options are implemented by the resolvconf package, if installed
        dns-nameservers 8.8.8.8

        bond-mode balance-xor
        bond-miimon 100
        bond-slaves none
```

`bond-xmit_hash_policy layer3+4
bond-xmit_hash_policy layer2+3`を入れてもいいと思います。

##特定バージョンのパッケージを入れる
/etc/apt/preferences.d/で調整します。
バックポートや最新リリースのミドルウェアをインストールできます
参考
https://mag.osdn.jp/07/01/25/019207
http://packages.ubuntu.com/ja/

例えばxzをマルチタスク対応の5.2にした場合(標準では5.1.1)
gzipより135%時間がかかりますが圧縮サイズは65%になります。
http://qiita.com/bringer1092/items/10725993bca777029f25

```
sudo vi /etc/apt/sources.list.d/xesty.list
+ deb http://jp.archive.ubuntu.com/ubuntu/ zesty main restricted
+ deb http://security.ubuntu.com/ubuntu zesty-security main restricted

sudo vi /etc/apt/preferences.d/xz
+ Package: *
+ Pin: release n=xenial
+ Pin-priority: 501
+ 
+ Package: xz-utils liblzma5
+ Pin: release n=zesty
+ Pin-Priority: 502

sudo apt-get update
sudo apt-get install xz-utils
xz --version
```


#MySQL
##インストール
標準でも5.7が`sudo apt-get install mysql-server mysql-client`でインストールできますが
最新バージョンではない場合もあり
Oracle公式からバージョン選択してインストールする手順は下記になります。

```
wget http://dev.mysql.com/get/mysql-apt-config_0.8.7-1_all.deb
sudo dpkg -i mysql-apt-config_0.8.7-1_all.deb
sudo apt-get update
sudo apt-get install mysql-community-server
```

ファイル名は下記URLより置き換えて下さい
http://dev.mysql.com/downloads/mysql/

少し戸惑うのがdpkgしたときのCUI?
どのバージョンをインストールするかの確認でこの段階でインストールされるわけではありません。
MySQL Serverのバージョンが希望通りならそのまま一番下のOK
異なる場合はMySQL ServerをEnter、バージョン選択、Enter→一番下のOK

##5.7以外のバージョンインストール
**mysql5.5/5.6はインストールする方法が標準では存在しない**
trustyから引っ張ってくるしかありません。簡単な動作確認済み。
参考
http://askubuntu.com/questions/762384/install-mysql-5-6-on-ubuntu-16-04
0.7.3-1なら5.6が選択できるのですがインストールできませんでした。

```
wget http://dev.mysql.com/get/mysql-apt-config_0.7.3-1_all.deb
sudo dpkg -i mysql-apt-config_0.7.3-1_all.deb
sudo apt-get update
apt-cache policy mysql-server    #5.6が表示されない
apt-cache policy mysql-server-5.6    #詳細情報がない
```
##リミットの解除
systemd共通

```
sudo vi /lib/systemd/system/mysql.service
+ LimitNOFILE=100000
+ LimitNPROC=32768
+ LimitMEMLOCK=infinity
+ LimitAS=infinity
sudo systemctl daemon-reload
sudo systemctl restart mysql.service
```
##起動
意外だったのですが
`/etc/init.d/mysql start`が使えます。
エラーログもsystemdではなくて標準なら/var/log/mysql/error.logに
しっかりエラーを吐いてくれるので確認しましょう

##コンフィグ編集
**Ubuntu16.04+MySQL5.7だけのはずですが
まさかのmy.cnfが起動スクリプトで読み込み禁止な模様**
CentOSのようにしようと/var/lib/mysql*とか/etc/mysql*を削除して、mysqld --initializeしても動作しませんでした
某ACEさんにも以前mysqlはmysql.conf.dなんて運用はしますかね？と相談したことがあり、
トラブルの元になるしmysql_multiでもない限りコンフィグが数百行にもならないから不要と私は判断してましたが
強制的に/etc/mysql/mysql.conf.d/を使わされます。
面倒でも`/etc/mysql/mysql.conf.d/mysqld.cnf`を編集しましょう。

##一般的なディレクトリ構成と変えたい
tmpdirをRAMDISKにしたいとか共有ディスクを使っていて
**一般的ではないディレクトリに配置したい場合AppArmorのせいでこけます。**
https://ja.wikipedia.org/wiki/AppArmor

```
vi /etc/apparmor.d/usr.sbin.mysqld
+ /ramdisk/ r,
+ /ramdisk/** rwk,

service apparmor restart
```
RAMディスクならこんな感じで最終行手前に記載すれば
そのディレクトリをアクセスしてくれるようになります。
**apparmorを再起動しないと反映されません**

#その他
~/.bash_profileが~/.profileになっている。

デフォルトshがbashではなくdash、
なのでshell書く場合は#!/bin/bashが必要にかも。