雑ですが、必要に迫られて作ってみました。
作成の経緯
RDS上でMyISAMの暖気がしたかったのです。RDSだとデータディレクトリcatでOSのキャッシュに載せるとかできないからクエリなどでできないか調べつつ作りました。先人の方々で作っていらっしゃる方いないかなと思って調べてたのですが、やはりInnoDBを使われているケースが殆どでMyISAMはなかなか見つかりませんでした。InnoDBの暖気はmysql5.6から簡単になったし本当に最高な感じしかないですね。(※1)
あと久しぶりにgolangを学びも兼ねて書いてみたくなったので、言語はgoを用いました。
MyISAMの暖気
以下の2つを実行したら再起動直後のウォームアップとして実行しました。
LOAD INDEX INTO CACHE <table_name>
※2- インデックスをmysqlのキャッシュに載せる
SELECT * FROM <table_name>
- データをOSのキャッシュに載せる
はじめはLOAD INDEX INTO CACHE
だけでいけるのかなと思ったけど、ある程度件数があるデータの場合インデックスを使ったクエリでもデータの読み込みに時間がかかったため、SELECT * FROM <table_name>
を実行しデータがOSキャッシュにのるか試してみました。結果、約3千万レコードあるテーブルで15秒ちょっとかかってたクエリが1秒で返ってくるようになったし、SELECTでもちゃんとのってる感じはする…。
RDSとEC2 on MySQLの場合と2パターンで試したけど、
RDS | EC2 on MySQL | |
---|---|---|
読み込み速度 | 15秒 -> 1秒 | 15秒 -> 0.03秒 |
メモリ | インスタンス作成時と変わらず | cached memoryが2GB増 |
みたいな感じでRDSの方はちょっとどうみたらいいかわからなかった。AWSコンソール上でみれるRDSのメモリは純粋にmysqlで使われるメモリのみなのだろうか。一方MyISAMの場合EC2 on MySQLの方がパフォーマンス的にもメモリの使われ方的にも顕著な感じでした。
実装したもの
簡単先述したクエリ2つのクエリを各テーブルごとにgoroutineとして実行してくれるツールを作りました。使い方などはREADMEをご参照ください。
今後
- 現状engineがMyISAMなテーブル全部に対して実行してるけど、きっと全部キャッシュに乗らないケースがあるだろうからtable名指定とかもできるようにしないとかも。
- golangについて素人なので、実装の改善やらないと。
- これでよかったの感ある。良い暖気の方法があれば知りたい。
参考
主にgoで実装するにあたり下記のドキュメント・記事を参考にさせていただきました。ありがとうございました。
- GitHub - lestrrat/go-test-mysqld: Create real MySQL server instance for testing
- GitHub - stretchr/testify: A sacred extension to the standard go testing package
- GitHub - howeyc/gopass: getpasswd for Go
- sql - The Go Programming Language
- GitHub - jessevdk/go-flags: go command line option parser
- mysqld を使ったテストの際に test database がなくてハマった - soh335 memo
- GoでMySQLを使ったテストをする - ぱいぱいにっき
- Go言語で非同期処理の結果を受け取る - Qiita
※1 MySQL :: MySQL 5.6 リファレンスマニュアル :: 14.13.1.5 再起動を高速化するための InnoDB バッファープールのプリロード
- ※2 MySQL :: MySQL 5.6 リファレンスマニュアル :: 13.7.6.5 LOAD INDEX INTO CACHE 構文