背景
MemSQLについての情報がすごく少ない。Qiitaではタグが付いている記事が3件。ググっても日本語・英語問わず公式サイトの情報以外あまり見かけないような気がする。
以前、リアルタイム分析の環境を作ったときに、MySQL互換のSQLが使えて、MySQLクライアントで接続できて、セットアップが簡単ということでMemSQLを採用し、そこそこのデータを扱ったので、どんな風に環境を作ったかメモを残す。
MemSQLの公式サイトはチュートリアルが親切。導入企業のロゴ見ると、データ量と要求される速度が厳しそうなブランドが並んでいる。
MemSQLのライセンス
- 2年くらい前まで、「Enterprise」と「Community」みたいな区別になっていて、サポートを受けられるか、High Availability関連の機能が使えるか、バックアップ機能が使えるか、が違いだった。メモリーやストレージの容量はCommunity版でも制限は無かったので、EC2を使う費用を山盛りできれば爆速なインメモリーDBをサクッと立ち上げられた
- その後、「Enterprise」と「Developer」になり、Developer Editionは「本番環境での使用は許可しない」ような形になったが、引き続きメモリー等の制限はなく、あくまで開発環境では無料で使えた
- 2018年に、MemSQL6.7が出てから、CommunityとかDeveloperというライセンスが廃止され、クラスター全体でのメモリー制限が128GBまでであれば全ての機能が「Free Tier」として無料で利用できるようになった。以前がフリーミアムっぽい設定だったのに対して、どちらかというと評価版という雰囲気か?
- ライセンスについての記述があまりなくて、実質こうですとか、公式ブログの過去記事にありますとか、そういう感じ
- MemSQL6.7未満では、ライセンスキーを入力しなければHA機能が使えないだけだったが、6.7からはMemSQLのサイトでユーザー登録をして無料版であってもライセンスキーの発行が必要になった。ライセンスキーは1ユーザー1つなので、複数クラスターを建てたいときにはなるべくライセンスを購入しましょう(けっこう良い値段した気がするけど忘れた)
インメモリー vs メモリーテーブル
- MySQLにもメモリーテーブルというのがあるが、単にメモリーにデータがあるというだけ
- メモリーをフル活用するために設計されていないのでは
- ディスクに書き込まないので再起動すると消える
- インメモリーはメモリーを活かしきる
- 内部でのデータ構造がメモリーを活用するために設計されている
- ディスクに非同期で書き込むので適切に運用すればデータは消えない
- DBの起動時にディスクからメモリーにデータを展開するので、起動までけっこう時間がかかる
MemSQLのいいところ
- MySQL用ドライバーが使える(DataGripとかでもMySQLの設定する感じ)
- インメモリーがRow Storeだが、ディスクベースのColumn Storeが使える
- Row StoreとColumn Storeを跨ぐビューが作れる
- 早い
- 簡単
- 128GBまで無料
クラスターをセットアップする
構成
- Master Aggregator として1台
- 個々のLeafノードから戻ってくる集計結果を束ねる役割だが、メモリーやディスクはあまり要らない。
- ネットワーク速度が重要なのでそこそこのサイズのインスタンスを選ぶ。小さすぎるとここがボトルネックになったり、EC2のネットワーククレジットが枯渇して急に遅くなったりする。
- Free Tierの場合、8GBをMaster Aggregatorに割当てるので、その倍〜くらいのメモリーを持つインスタンスタイプが望ましい
- Leafノード(データを格納したり処理するノード)を任意台数
- NVMe SSDが複数あるインスタンスタイプがオススメ。メモリーサイズも多めがいい。CPUコアあたりのメモリー容量が8GB以上になるのが推奨されているので、r5d.4xlargeが適当かもしれない
- 物理的にCPUが複数ある場合、numactlを入れる
- Free Tierの場合、Leafを3台とすると、128GBからMasterの8GBを引いて120÷3で40GBをMemSQLに割当てる。メモリーは余った部分をファイルキャッシュにするので、多くて問題無い。
EC2 ホストのチューニング
- 基本的には、ストレージをなるべく高速にしましょうということで、別途公開したElasticsearchの構成と同じ。
- インスタンスタイプはNVMe SSD(エフェメラルストレージ)が付随するタイプで、なるべくNitro世代を使う。c5d, r5d, m5dあたり。ストレージ容量を稼ぎたい人は世代は古いけどi3でもいいかもしれない。ストレージのデバイス数が多い方がストライピングしたときの性能が出る気がする。
- ルートボリュームのEBSはあまり大きくなくて良い。
- OSはAmazon Linuxで、普通に管理コンソールで出てくるモノを使う。
アプデート
yum -y update
OSの設定を最適化
-
/etc/security/limits.conf
でファイルディスクリプタ、メモリーロック、プロセスが利用できるCPU数を緩和 -
/etc/sysctl.conf
でネットワークとスワップの調整
bash -c 'echo root soft nofile 1048576 >> /etc/security/limits.conf'
bash -c 'echo root hard nofile 1048576 >> /etc/security/limits.conf'
bash -c 'echo * soft nofile 1048576 >> /etc/security/limits.conf'
bash -c 'echo * hard nofile 1048576 >> /etc/security/limits.conf'
bash -c 'echo * soft memlock unlimited >> /etc/security/limits.conf'
bash -c 'echo * hard memlock unlimited >> /etc/security/limits.conf'
bash -c 'echo * soft nproc 128000 >> /etc/security/limits.conf'
bash -c 'echo * hard nproc 128000 >> /etc/security/limits.conf'
bash -c 'echo net.ipv4.tcp_tw_reuse = 1 >> /etc/sysctl.conf'
bash -c 'echo net.ipv4.tcp_fin_timeout = 30 >> /etc/sysctl.conf'
bash -c 'echo net.ipv4.ip_local_port_range = 16384 65535 >> /etc/sysctl.conf'
bash -c 'echo vm.max_map_count = 262144 >> /etc/sysctl.conf'
bash -c 'echo vm.swappiness = 1 >> /etc/sysctl.conf'
NVMeの最適化
- この例ではNitro世代なので、エフェメラルストレージのデバイスは
nvme1
から始まる(0はEBSのルートになっている) -
nvme1
部分をデバイスのかずだけ置き換えて設定を繰り返す
echo 0 > /sys/block/nvme1n1/queue/add_random
echo 1 > /sys/block/nvme1n1/queue/rq_affinity
echo none > /sys/block/nvme1n1/queue/scheduler
echo 1023 > /sys/block/nvme1n1/queue/nr_requests
RAIDでストライピングする
-
/etc/rc.local
に追記する - マウント先を
/var/lib/memsql
にsiteiruga,MemSQL6.7からはデータを格納するディレクトリの変更ができなくなったため。(以前はmemsql-ops
コマンドでディレクトリを移動することができた)
# エフェメラルストレージにディレクトリが残っていなかったら作成する
if [ ! -d /var/lib/memsql ]
then
mkdir /var/lib/memsql
fi
# RAIDが構成されていなかったら構成する
if [ ! -d /dev/md0 ]
then
# NVMeデバイスを束ねてRAIDを作る
mdadm --create --verbose --level=0 /dev/md0 --name=DATA --raid-devices=2 /dev/nvme1n1 /dev/nvme2n1
mkfs.ext4 /dev/md0
mdadm --detail --scan | tee -a /etc/mdadm.conf
# 念のためカーネルオプションを更新
dracut -H -f /boot/initramfs-$(uname -r).img $(uname -r)
# RAIDをマウントする
mount -a
fi
chmod 755 /var/lib/memsql
fstabに追記して再起動
bash -c 'echo /dev/md0 /var/lib/memsql ext4 defaults,nofail,noatime,discard 0 2 >> /etc/fstab'
reboot
MemSQLのインストール
- インストール作業はMaster Aggregatorになるノードで行う
- SSHで個々のノードに繋いで自動的に処理してくれるので便利
- 事前にMasterから各LeafにSSHできるようにして、接続確認しておく
- 有償ライセンスを持っている場合、クラスター全体でMemSQLに割当てるメモリー容量がライセンスで許可されている範囲内にすること
- 無償ライセンスの場合、クラスター全体でMemSQLに割当てるメモリーが128GB以下になる必要がある
- クラスター全体の総メモリー容量ではない
- MemSQLには
memsql_memory
とmemsql_table_memory
の2つの容量指定がある -
memsql_table_memory
はインメモリーのテーブルでデータを格納するのに割当てるメモリーで、memsql_memory
がMemSQLが利用するメモリー。memsql_memory
の80%くらいがmemsql_table_memory
になるのが普通だが、複雑な集計をする場合は7:3とか6:4くらいにした方がいい。
MemSQLをダウンロードする
公式ドキュメント通りで、リポジトリを追加して、yumでインストールする。
sudo yum-config-manager --add-repo https://release.memsql.com/production/rpm/x86_64/repodata/memsql.repo
sudo yum install -y memsql-toolbox memsql-client memsql-studio
Master Aggregatorを構成
MemSQLがこのノードをMaster Aggregatorとして使いますよ、という設定をする。
memsql-toolbox-config register-host --localhost --host 3.0.0.1
Leafノードを構成
MemSQLがこれらのノードをLeafとして使いますよ、という設定をする。
ssh
引数で接続情報を渡している。
memsql-toolbox-config register-host --host 3.0.0.2 --ssh ec2-user@3.0.0.2:10022 -i .ssh/memsql.pem
memsql-toolbox-config register-host --host 3.0.0.3 --ssh ec2-user@3.0.0.3:10022 -i .ssh/memsql.pem
memsql-toolbox-config register-host --host 3.0.0.4 --ssh ec2-user@3.0.0.4:10022 -i .ssh/memsql.pem
全てのノードにMemSQLのバイナリーをインストールする
MemSQLは以前からSSH接続してクラスターをリモートで作成できるのが便利。
memsql-deploy install --all
全てのノード(EC2マシン)にMemSQLノード(MemSQLで使う領域)を作成する
ノードにノードを作成するという言い回しが変だけど…
memsql-admin create-node --password P4ssw0rd --host 3.0.0.1
memsql-admin create-node --password P4ssw0rd --host 3.0.0.2
memsql-admin create-node --password P4ssw0rd --host 3.0.0.3
memsql-admin create-node --password P4ssw0rd --host 3.0.0.4
Master Aggregatorを立ち上げる
- 個々のノードの
MemSQL ID
はmemsql-admin list-nodes
で調べられる - ライセンスはMemSQLのサイトでログインして取得しておく
-
maximum_memory
は Master Aggregatorの動くこのインスタンス/ノードで確保する容量- 今回はFree Tierでの構成なので、クラスター全体で128GBにしたい、Leafに多く割当てたい、のでMaster Aggregatorに8GBを割当てている
memsql-admin update-config --key maximum_memory --value 8192 --memsql-id [MemSQL ID]
memsql-admin restart-node --memsql-id [MemSQL ID]
memsql-admin bootstrap-aggregator --memsql-id [MemSQL ID] --license [License]
Leafを立ち上げる(Leafノードの台数分やる)
- Leaf を3台にするので各40GBメモリーを確保する
- Masterと同じく、
memsql-admin list-nodes
でMemSQL IDを調べる
chown memsql:memsql /var/lib/memsql
memsql-admin update-config --key maximum_memory --value 40960 --memsql-id [MemSQL ID]
memsql-admin restart-node --memsql-id [MemSQL ID]
memsql-admin add-leaf --password P4ssw0rd --memsql-id [MemSQL ID]
調整
-
optimize
でパーティションの分割数やNUMA周りを推奨設定にしてくれる -
maximum_memory
が勝手に大きくなってしまうが、改めてライセンスの範囲内になるように設定し直す(前段の設定と重複するが、前段で設定しないとインストールが出来ないので冗長だけど仕方ない) - 設定し終わったらMemSQLを再起動する。コマンド一発で全ノードでMemSQLの再起動ができる。
memsql-admin optimize
memsql-admin update-config --key maximum_memory --value 8192 --memsql-id [MemSQL ID]
memsql-admin update-config --key maximum_memory --value 40960 --memsql-id [MemSQL ID]
memsql-admin update-config --key maximum_memory --value 40960 --memsql-id [MemSQL ID]
memsql-admin update-config --key maximum_memory --value 40960 --memsql-id [MemSQL ID]
memsql-admin restart-node --all
仕上げ
- MemSQL Studioを使いたい場合は以下のコマンドで起動する
- http://{}ホスト}:8080 でUIにアクセスできる。ELB等でhttpsで繋がるようにするといい
sudo memsql-studio &
- ユーザー作成やテーブル作成は Master Aggregatorで
memsql
コマンドを打てばMySQLクライアントそっくりのコンソールが使える(Masterからは認証無し)
終わりに
- ライセンスが安定しない印象があるので使い方は注意が必要かもしれない。ミッションクリティカルなことに使っていて、ある日突然ライセンス形態変わって焦るのは避けたい
- インメモリーDBで、MySQL用のドライバーがそのまま使えて、UTF-8がデフォルトで、使い勝手はかなりいい
- メモリー制限の範囲内で活用するにはエフェメラルストレージでRAID組んでColumn Storeを活用する必要がある。非同期でディスクに書き込んでもそのディスクが揮発性なのでデータの永続化には向かない。自分の場合はRedshiftで「遅いけど永続化」しつつMemSQLで「爆速だけどリスクは許容」というハイブリッド戦略にしていた
- 全て自己責任でお試しください