- 投稿日:2020-08-18T19:04:10+09:00
nginx image に mysql を入れる際の注意点
対象
docker 環境で nginx の公式image に mysql クライアントをインストールする際に詰まった人
調査&解決
上記のリンクから確認できるが、 公式image は
FROM debian:buster-slim
を使っている。
ベースイメージが debianであることがわかったので https://hub.docker.com/_/debian を見ると
buster-slim は debian 10系で有ることがわかった。buster系では
mysql-client
が存在しないので default-mysql-server を使用してinstallする$ sudo apt-get update $ sudo apt-get install default-mysql-serverこれで入る。
- 投稿日:2020-08-18T16:54:44+09:00
【備忘】Docker Container の MySQL Server にアクセスする方法メモ
Dockerコンテナ上に立てたMySQL Server にアクセスする際に意外と手間取ったのでメモ。
前提
OS: macOS 10.14.6
docker desktop: v2.3.0.3
Dockerイメージ: https://hub.docker.com/r/mysql/mysql-server手順
コンテナ起動してアクセス。ポートマッピングを忘れない!
$ docker run --name=mysql-develop \ -p 3306:3306 \ -d \ mysql/mysql-server $ docker exec -it mysql-develop bash設定ファイル(/etc/my.cnf)に以下を追記。
docker run
で起動している場合、ホストのIPは127.10.0.1
です。my.cnfbind-address = 127.10.0.1ルートユーザでコンテナ内からサーバーにアクセス。
パスワードはコンテナ作成時に自動でせいせされるので、ログから確認する。$ docker logs mysql-develop 2>&1 | grep GENERATED [Entrypoint] GENERATED ROOT PASSWORD: XXXXXXXX $ docker exec -it mysql-develop mysql -u root -p Enter password: # XXXXXXXXリモートアクセス用のユーザー作成、権限付与。
CREATE USER 'myuser'@'localhost' IDENTIFIED BY 'mypass'; CREATE USER 'myuser'@'%' IDENTIFIED BY 'mypass'; GRANT ALL ON *.* TO 'myuser'@'localhost'; GRANT ALL ON *.* TO 'myuser'@'%'; flush privileges;コンテナから抜けて、ホストのクライアントからアクセス。
$ mysql -u remote_user -h '127.0.0.1' -p Enter password: # mypass入力参考
https://stackoverflow.com/questions/16287559/mysql-adding-user-for-remote-access
- 投稿日:2020-08-18T16:37:07+09:00
MySQL⑧ データの集計処理、サブクエリ
users_with_team テーブル
id name score team 1 AAA 11 team-A 2 BBB 22 team-B 3 CCC 33 team-C 4 DDD 44 team-B データの個数を調べる count()
select count() from users_with_team;
➡️4特定のカラムのデータの個数を調べる count(カラム名)
select count(score) from users_with_team;
➡️4sum で合計、 min で最小値、 max で最大値、 avg で平均
select sum(カラム名) from users_with_team; ➡️110
select min(カラム名) from users_with_team; ➡️11
select max(カラム名) from users_with_team; ➡️44
select avg(カラム名) from users_with_team; ➡️27.5重複したレコードを取り除いて取得する distinct カラム名
select distinct team from users_with_team;
team team-A team-B team-C 重複したレコードの数を数える
select count(distinct team) from users_with_team;
➡️3グループ化する
グループごとの合計をだす group by グループ化の基準にするカラム名
select sum(score), team from users_with_team group by team;
逆順にする desc
select sum(score), team from users_with_team group by team desc;
グループ化の後に条件をつける group by グループ化の基準にするカラム名 having 条件
havingでは、グループ化したカラム、集計した値以外使えない
select sum(score), team from users_with_team group by team having sum(score) > 10.0;特定の条件でグループ化する where 条件 group by グループ化の基準にするカラム名
where で条件付きで抽出した後にグループ化する
select sum(score), team from users_with_team where id > 3 group by team;一時的に使用するテーブル サブクエリ
元のテーブル
id name score 1 AAA 11 2 BBB 22 3 CCC 33 4 DDD 44 ここから集計の為のテーブルを一時的に作成する
select sum(t.score), t.team from(
select ⬅️ここから
id,
name,
score,
case
when score > 8.0 then 'Team-A'
when score > 6.0 then 'Team-B'
else 'Team-C'
end as team
from users) as t ⬅️ここまでがサブクエリ
group by t.team;サブクエリを使用しないと users_with_teamテーブルを作成してから集計する
create table users_with_team
select id, name, score,
case
when score > 8.0 then 'Team-A'
when score > 6.0 then 'Team-B'
else 'Team-C'
end as team
from usersselect sum(score), team from users_with_team group by team;
抽出条件を保存する view
viewはテーブルの様に扱われる
viewを作成する create view ビュー名 as 抽出条件
create view top3 as select * from users order by score desc limit 3;
保存された抽出条件を確認する show create view ビュー名;
show create view top3;
viewを削除する
drop view top3;
- 投稿日:2020-08-18T14:36:32+09:00
OSがCatalina以降の環境構築
Command Line Toolsを用意
Command Line ToolsはWebアプリケーション開発に必要なソフトウェアをダウンロードするために必要な機能です。
ターミナルからCommand Line Toolsをインストール
ターミナル$ xcode-select --install出てくるポップアップには「インストール」→「同意する」→「完了」の順にクリック。
Homebrewを用意
Homebrewというソフトウェア管理ツールを導入します。
ターミナル$ cd # ホームディレクトリに移動 $ pwd # ホームディレクトリにいるかどうか確認 $ ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)" # コマンドを実行※処理に時間がかかる可能性のある操作
処理が進んでいくと、「press RETURN to continue or any other key to abort」(「続けるにはエンターキーを、やめるにはそれ以外の入力をしてください」)と表示されるので、ここではエンターキーを入力して先に進めましょう。
さらに、「password: 」と表示されたら、PCのパスワードを入力してください。
ターミナル上でパスワードを入力しても文字は表示されませんが、間違いなく入力はされています。パスワードを入力し終わったらエンターキーを押してください。その後、ダウンロードが完了し、再びコマンドを入力できるようになれば成功です。
Homebrewがインストールされているか確認
以下のコマンドを実行しましょう。
ターミナル$ brew -vHomebrewがインストールされているかを確認します。以下のように、Homebrewのバージョン情報が表示されれば無事にインストールされています。
ターミナル$ brew -v Homebrew 2.1.13Homebrewをアップデート
ターミナル$ brew updateHomebrewの権限を変更
ターミナル$ sudo chown -R `whoami`:admin /usr/local/binrbenv と ruby-buildをインストール
ターミナル$ brew install rbenv ruby-buildrbenvをどこからも使用できるようにする
ターミナル$ echo 'eval "$(rbenv init -)"' >> ~/.zshrczshrcの変更を反映させる
$ source ~/.zshrcreadlineをinstallし、どこからも使用できるようにする
ターミナルのirb上で日本語入力を可能にする設定を行うために、以下のコマンドでインストールしましょう。
ターミナル$ brew install readline $ brew link readline --forcerbenvを利用してRubyをインストール
Webアプリケーション開発用のRubyをインストールします。以下のコマンドを実行しましょう。
ターミナル$ RUBY_CONFIGURE_OPTS="--with-readline-dir=$(brew --prefix readline)" $ rbenv install 2.5.1※処理に10分程度かかる可能性のあるコマンドです。
2.5.1と書いてあるのは今回インストールするRubyのバージョンです。利用するRubyのバージョンを指定
インストールしたRuby 2.5.1を使用するために、以下のコマンドを実行しましょう。
ターミナル$ rbenv global 2.5.1rbenvを読み込んで変更を反映させる
ターミナル$ rbenv rehashRubyのバージョンを確認
ターミナル$ ruby -vRubyのバージョンが、先ほどインストールした2.5.1であることが表示されれば完了です。
MySQLのインストール
MySQLは、Webアプリケーションにおけるデータを蓄積する場所のことです。
ターミナル$ brew install mysql@5.6※処理に時間のかかる可能性があるコマンドです。
MySQLの自動起動設定をする
MySQLは本来であればPC再起動のたびに起動し直す必要がありますが、それは面倒であるため、自動に起動するようにしておきましょう。
ターミナル$ mkdir ~/Library/LaunchAgents $ ln -sfv /usr/local/opt/mysql\@5.6/*.plist ~/Library/LaunchAgents $ launchctl load ~/Library/LaunchAgents/homebrew.mxcl.mysql\@5.6.plistmysqlコマンドをどこからでも実行できるようにする
ターミナル# mysqlのコマンドを実行できるようにする $ echo 'export PATH="/usr/local/opt/mysql@5.6/bin:$PATH"' >> ~/.zshrc $ source ~/.zshrc # mysqlのコマンドが打てるか確認する $ which mysql # 以下のように表示されれば成功 /usr/local/opt/mysql@5.6/bin/mysqlmysqlを起動を確認
ターミナル# mysqlの状態を確認するコマンドです $ mysql.server status # 以下のように表示されれば成功 SUCCESS! MySQL runningRailsを用意
Rubyの拡張機能(gem)を管理するためのbundler(バンドラー)をインストールします。
ターミナル$ gem install bundlerRailsをインストール
ターミナル$ gem install rails --version='5.2.3'rbenvを再読み込み
ターミナル$ rbenv rehashRailsが導入できたか確認
以下のコマンドを実行して、Rails 5.2.3が表示されれば問題なくインストールが完了しています。
ターミナル$ rails -vNode.jsを用意
Railsを動かすためにはnode.jsが必要となり、それをHomebrewを用いてインストールします。
Node.jsのインストール
ターミナル$ brew install nodejsこの時、最後にError: node 13.10.0 is already installedと表示されても問題ありません。
Node.jsが導入できたか確認
以下のコマンドを実行して、v13.10.0のようにバージョンが表示されれば、問題なくインストールが完了しています。
ターミナル$ node -v以上でWebアプリケーション開発のための環境構築は完了です!
- 投稿日:2020-08-18T02:32:39+09:00
MySQLで3億レコード物理削除した話
MySQLで3億レコード物理削除した話
はじめに
こんにちは。webエンジニア社会人をしている kanta13jp1 です。
タイトル通り。MySQLで3億レコード物理削除した話。
ちょっとハマったので備忘録。はじまりはアラート
はじまりはアラートだった。
僕が運用・保守しているバッチサーバでは、mysqlからちょうど直近1ヶ月分のデータを毎日1回selectする定期処理をしている。いつもなら1時間程度で終わる処理のはずが、その日は7,8時間経っても終わらずアラートが鳴り止まない.....。
原因追求
とりあえずリトライしたり、ログ見たりしたもののあんまり悪いところがなかった。
クエリもちゃんとindex効いてる。なんでだろうと思ったらDBの容量が結構大きくなっていたことに気づいた。hoge_table | 350'000'000 |3億5千レコード。インデックスちゃんと効いてたので多分普通に遅いだけっぽい。
必要なデータ取得は1ヶ月分である12'000'000件ほど。このselectクエリが時間かかってトランザクションが長く失敗しているようだった。DB
基本的に毎日400'000件ぐらいinsertされてレコードが増えているこのテーブル。
データ取得は要件的には直近1ヶ月分だけあれば良いので、それだけ持てばよいのだが生憎rotate処理は入っていなかった。自分が開発したものではなく引き継いだものだったのだが、その時点では何も言われていなかったので技術的負債のパスをもらってしまった感じである。
日々のinsertでデータが大きくなり、ついに限界を迎えたときに僕のターンだったというわけだ。
これだけ大きくなるならパーティション切っててほしかったものの、それも残念ながらなかった。
改修
一旦ロジックに手を加えるよりはDB軽くして様子見るほうが工数少ないだろうという方針になった。
3億レコード消せばかなり変わるだろう、ということでdeleteを打つことに......。このときはうまく行くと思っていた......。対応その1
バックアップもしっかりとって、意気揚々とクエリを打ち始めた。
「クエリ打ちまーす」DELETE FROM hoge_table WHERE create_time <= 'YYYY-MM-DD HH:MM:SS';「...」
「...」なんか反応がない、やっぱ時間かかるかあとか思いつつdbのgrafana眺めてたらdisc busyがめちゃめちゃ上がっていた。
「yabeeeeeeeee」
とりあえずクエリを止めた。
対応その2
一回で削除するには量が多すぎたことを反省した。dbのレプリケーション時間も考慮してこまめに削除することが良さそう。
1'000'000件ずつぐらい削除できるスクリプト書いて処理することにした。「実行しまーす」
これでうまく行くと思っていた......。
対応その3
対応その2はどこへ......。処理はうまくいっていたのだが、時間がとてもかかることが判明した。
負荷をかけずに丁寧にやると約2週間必要だった。が、それではサービス要件を満たせず、やむなく中断。そして対応その3である。
テーブルcopyしてrename
なんかdeleteが負荷大きくて良くないのでは。と思いinsertで欲しいテーブルを無から作ろうという方針に切り替えた。
| hoge_table | 350'000'000| | tmp_hoge_table | 50'000'000|レコード数的には上記のような状態になればよいので、insertするほうがデータ処理も1/7程度になって速いはずである。
テーブル作ったあとはrenameしてマスターテーブルとして使い、今の3億レコードテーブルはdropすればokなはず。
truncateやdropはdeleteと違い負荷が少ないのは知っていたので、この方針に。実行
「クエリ打ちまーす」
INSERT INTO tmp_hoge_table SELECT FROM hoge_table create_time > 'YYYY-MM-DD HH:MM:SS';「...」
「...」
「お...?」対応その4
うまく行くかと思ったが、insert終わったあとに無限にエラー吐かれた。mysql怖い。
もう本番作業したくねえよ〜って気持ちでいっぱいだった。まあよく考えると、多分これも1回でinsertしすぎということなんだろう。
とりあえず1日分だけinsertしてみたらうまく行った。「おお!」
このあとは丁寧丁寧に1日分ずつinsert。1ヶ月ぶんあればいいので35回日分を対応。
テーブルrename
ここはすんなりいった。めでたし。
アラート、止まる
バッチ処理の速度も回復した。
今まで1時間かかってたのに2分ぐらいで終わるようになった(は?)問題も解決したのを確認できたので、3億レコードテーブルはdropした。
drop tableに爽快感を覚えるのは初めてだった。まとめ。
他人のバッチ処理のローテート処理忘れでこんなに苦しむとは、って思った機会でした。
些細な設計の粗さが運用として現れて工数を奪うんだなあ......。DBにくわしく
あなたはdeleteするときレプリケーション負荷など気にしてますか?
mysqlに優しくしましょう。まあ今回の内容とか知ってる人は全然困るところじゃないとは思うんですが。
知識がないと難しいねーって。cassandraでdelete多くて死んだパターンも昔経験したので何か近いものがあるのかなあとか思ったり。
また勉強したら記事にでもまとめます。さいごに
※軽い感じに見えるけど実際はめちゃめちゃ慎重にチームでダブルチェックしながら作業進めてたよ。本番dbって怖いよね。
ではでは。
- 投稿日:2020-08-18T00:18:49+09:00
MySQL5.7でGenerated Columnを作成したがmysqldumpしたデータをリストアできなかった話
はじめに
問題が発生したテーブルですが、mysqlの全文検索インデックスを設定したテーブルで、全文検索インデックスはGenerated Column(Stored)で生成したカラムに貼ってありました。mysqldumpを取り、リストを行った所下記エラーが発生しました。
ERROR 3105 (HY000) at line XXX: The value specified for generated column 'XXX' in table 'XXXX' is not allowed.発生環境
Webサーバ: EC2
DB: RDS(mysql5.7)解決方法
本事象ですが、EC2にインストールしていた、
mysql clientが5.6
のため発生した不具合でした。
mysql clientが5.6以前で、mysqldumpを取った際にGenerated Columnは、通常カラムと同様の扱いとなり、insert文に対象カラムの情報が記載されてしまい上記エラー発生します。
同一問題に当たった場合は、--complete-insert
を使ってカラムを下記だして状況確認するのが良いかと思います。clientのバージョンが5.7系であれば、Generated Columnはinsert文に対象カラムとして表示されないはずです。おわりに
今回は、全文インデックスを張る関係で、Generated ColumnはStoredとしていましたが、Viewの場合にmysqldump実行時にエラーが発生するバグが挙がっています。
Generated Column(View Bug)https://bugs.mysql.com/bug.php?id=79148