MySQLで定期的に SHOW PROCESSLIST を実行して長時間走っているクエリを探す
前略、大きいMySQLのデータベースがあります。すると、大きなデータベースから多くのデータを取得するため、非常に重いクエリが実行されることがあります。
そうするとデータベースが高負荷になるため重い処理を見つけたくなります。 (innodb_query_queued
とかが増えて辛くなる)
MySQLには SHOW PROCESSLIST
というものがあり、実行中のMySQLのプロセス一覧を見ることができ、
クエリの実行状況や実行時間をみることができるのでスロークエリログより便利なことがあります。
(スロークエリログはクエリが完了した場合に出力されるため実行中やクエリを中断した場合に見ることができない)
しかし、SHOW PROCESSLIST
の出力は多いため毎回見るのは疲れます。そこで以下のようなスクリプトで SHOW FULL PROCESSLIST
の出力をフィルターすると便利です。
require 'mysql2' MYSQL_USER = '' MYSQL_PASS = '' LONG_QUERY_THRESHOLD = 60 client = Mysql2::Client.new(host: 'localhost', username: MYSQL_USER, password: MYSQL_PASS) client.query('SHOW FULL PROCESSLIST').each do |row| next unless row["Command"] == "Query" next if row["Time"] < LONG_QUERY_THRESHOLD puts ([Time.now] + row.values.map { |v| v.to_s&.gsub("\n", " ") }).join("\t") end
実行コマンドがQueryかつ実行時間の閾値を超えた場合にのみ出力します。 複数回の出力をフィルターしないので、時間がかかっているクエリはなんども見ることになります。クエリに長い文字列が来ることもあるので、 実運用のことを考えるとある程度の長さで切った方がいいかもですね。
Ansibleのテスト環境をDockerで作ると楽
以前はVagrantを使ってansibleのテスト環境は用意していたんだけど、 vagrantはsnapshotが取れる利点がありつつも、VMを使うのでちょっとというかそれなりに遅くて、 何度も実行するansibleのテスト環境にはちょっと不便だなーと思っていたのですが、 最近Dockerを使ってsshdを起動するだけの環境を用意すれば簡単にテスト環境が作れて便利だったので書いておきます。
Dockerfileを書く
ansibleを流す対象のイメージは Dockerfile
の FROM
に書いておけばよくて、
CentOSとかDebianとか好きなOSを選べばいいと思います。
Dockerfileを置いたディレクトリに id_rsa.pub
を置いておくと authorized_keys
にコピーされるというソリューションです。
FROM amazonlinux:latest MAINTAINER cyrill RUN yum install -y sudo shadow-utils RUN useradd -g wheel ec2-user && echo "ec2-user:ec2-user" | chpasswd ;\ mkdir /home/ec2-user/.ssh;\ sed -i -e 's/^\(%wheel\s\+.\+\)/#\1/gi' /etc/sudoers ;\ echo -e '\n%wheel ALL=(ALL) NOPASSWD:ALL' >> /etc/sudoers && \ echo -e '\nDefaults:root !requiretty' >> /etc/sudoers && \ echo -e '\nDefaults:%wheel !requiretty' >> /etc/sudoers ADD id_rsa.pub /home/ec2-user/.ssh/authorized_keys RUN yum install -y openssh-server openssh-clients && \ ssh-keygen -q -b 1024 -N '' -t rsa -f /etc/ssh/ssh_host_rsa_key && \ ssh-keygen -q -b 1024 -N '' -t dsa -f /etc/ssh/ssh_host_dsa_key && \ ssh-keygen -q -b 521 -N '' -t ecdsa -f /etc/ssh/ssh_host_ecdsa_key && \ sed -i -r 's/.?UseDNS\syes/UseDNS no/' /etc/ssh/sshd_config && \ sed -i -r 's/.?ChallengeResponseAuthentication.+/ChallengeResponseAuthentication no/' /etc/ssh/sshd_config && \ sed -i -r 's/.?PermitRootLogin.+/PermitRootLogin yes/' /etc/ssh/sshd_config && \ echo "root:root" | chpasswd RUN rm -rf /var/cache/yum/* && yum clean all CMD ["/usr/sbin/sshd", "-D"]
最近気づいたんですが、AmazonLinuxのDocker Imageとか配布されてるんですね。 EC2環境のテストにも便利です。よいですね。
Makefileを書く
毎回 docker build
して docker run
してもいいんですが、
正直に言えばdockerのコマンドオプションは覚えやすい感じもないので、
シュッと実行できるようにMakefileを書きます。
シェルスクリプトでもいいのではというご意見もあるかなとは思いますが、
make
とか make clean
とかテスト環境を作ったり消したりするイメージには合ってる感じがして
割と気に入ってます。気にいらないタイプの方は他の好きなツールを使うといいと思います。
.DEFAULT: all all: container run container: docker build . -t ansible run: docker run -d --name ansible -p 30022:22 ansible attach: docker run -it --name ansible -p 30022:22 ansible /bin/bash clean: docker stop ansible && docker rm ansible
こんな感じのMakefileを置いておいて、make
するとsshができる環境が用意されます。
テスト環境を捨てたいときは make clean
して make
すると最初からやり直せます。便利ですね。
ansibleのinventoryファイルを書く
docker run
するとローカルでsshできる環境ができるので、
localhost:30022
にSSHするようにinventoryファイルを用意しておいてansibleではこれを指定して実行するようにします。
ansible-playbook -i inventory/local -K -k playbook.yml
終わりに
まあ便利なんですが、Docker環境に移行し切ったらansibleとかいらないのではとか思いつつ、まああってもいいやという感じで悩み中ですね。
お仕事ではMySQLのでかいDBをいい感じにやってるのであんまり関係ないんですが、シュッとかける話がこれくらいしかなかったので今回はこんなところで。
最近、ラ!関係の旅行で福岡と函館に行ってきたのですが、どちらも最の高という感想なので、みんなも行くといいと思います。
月末は沼津花火大会、来月はコミケ。あ、原稿やります。みんな来てくれ〜〜〜〜
サークル「ゆきいろパラソル」は、コミックマーケット94で「金曜日西地区 "め " 07b」に配置されました!コミケWebカタログにてサークル情報ページ公開中です! https://t.co/Uxfj0cLfRh #C94WebCatalog
— シリル@ガルパ沼🍊⚓️😈 C94金西め07bゆきいろパラソル (@d_cyrill1129) 2018年6月9日
今日弊社チームメンバーには、うちのチームは将来的に業務効率化はして暇になってやることなくなるから覚悟しておけよって言っておいたのでいい感じにやる予定です
— シリル@ガルパ沼🍊⚓️😈 C94金西め07bゆきいろパラソル (@d_cyrill1129) 2018年7月13日
現場からは以上です。
Webアプリケーションをデプロイしたくなったのでsupでやってみる
sup
Golangで書かれたシンプルなデプロイ要ツール。
機能がとてもシンプルで、SSHコマンドを手で書くよりは簡単に書ける程度で、 逆に機能が少なすぎて必要なことが書きづらいことも。
大雑把に現時点でサポートしている機能は以下のような感じ。
- リモートでのコマンド実行(並列可能)
- ローカルでのコマンド実行
- ローカルからリモートへのアップロード
- デプロイ対象の切り替え
Capistranoとかをイメージしていると機能の少なさにびっくりするが、 シンプルゆえに書きやすいところもあるし、 例に挙がっているdockerで使うならいい感じかもしれない。
で、そんなデプロイツールを無理やり感もありつつ、 Webアプリケーションのデプロイに使うとしたらどうするかを考えてみた。
あまりよい例ではなさそうなので、本運用には使えないかもしれない。
というか、ここまでやるならcapistranoを使えという話でもあるが、 諸事情でRubyを入れられないので...
gist91393876ec369f1f1701948b4a648771
時間を取るためにファイルを分けるのは正直微妙だし、変数的な何かは使えなかったのかという気はするけど、 そもそもドキュメントが微妙なので、コード読んで雰囲気でやったしまあこんなもんな気はする(本当か?)
あと、自前でシンボリックリンク張り返したり古いreleaseを消すのは面倒。もうちょっと何とかなってほしい気もする。
うん、微妙だな。なしなし。
nginxでupstreamをhttpsにしたいとき
ちょっとだけ知って置く必要がある設定があるので残しておく。あまり難しくはない。
証明書を更新しておく
CentOSならyum、Debianならapt、その他はいい感じに。
yum install ca-certificate
nginx をビルドする
がんばってください。
SSLを使うことになるので、http_ssl_moduleは入れておく必要がある。
opensslをリンクする場合、新しいものを使うのがおすすめ。
nginx.confを設定する
クライアント証明書が必要な場合は、ちゃんとした証明書と検証用にtrustedな証明書を設定する。
nginx.conf
server { resolver 8.8.8.8; listen 8080; server_name _; proxy_ssl_protocols TLSv1.2; proxy_ssl_ciphers HIGH:!aNULL:!MD5; proxy_ssl_server_name on; proxy_ssl_name REPLACE_REMOTE_ADDR; proxy_ssl_password_file /path/to/client_cert_password; proxy_ssl_certificate /path/to/client_cert_pem_with_password; proxy_ssl_certificate_key /path/to/client_cert_pem_with_password; proxy_ssl_trusted_certificate /path/to/ca-bundle.crt; proxy_set_header Host $host; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Host $host; proxy_set_header X-Forwarded-Server $host; proxy_set_header X-Real-IP $remote_addr; location / { proxy_pass https://REPLACE_REMOTE_ADDR; } }
各設定値について
resolver
外に行く場合の名前解決に使うDNS。IP指定の場合はいらないかもしれない。適切なDNSを指定する。
listen
nginxがlistenするポート
server_name
_
なので何でもマッチする。default_serverにするといい気もする。
proxy_ssl_protocols
proxyで接続する際に使うプロトコル。TLS1.2をサポートしているサーバの場合はこの設定でいい。
proxy_ssl_ciphers
proxyで接続する際に使うcipher。リモート側でサポートしているもので強いものを使う。
proxy_ssl_server_name
SNI対応用。proxy_ssl_nameとセットで使う。
proxy_ssl_name
REPLACE_REMOTE_ADDR
を実際に接続する先の名前に置き換える。
リモートサーバにつなぎに行くときの名前を置く。SNIを使っているサーバがぼちぼちあるので指定するのが無難。
proxy_ssl_password_file
プロキシに使うSSL証明書のパスワードファイル。
クライアント証明書がパスワード付きならここにパスワードファイルを設定する。
proxy_ssl_certificate
クライアント証明書を指定する。クライアント証明書が不要ならいらない気もする。
proxy_ssl_certificate_key
クライアント証明書を指定する。クライアント証明書が不要ならいらない気もする。
proxy_ssl_trusted_certificate
証明書の検証に使う信頼された証明書を指定する。
CentOSだと /etc/pki/tls/certs/
とかに置いてあるらしい。
ディストリビューションによって違うのでいい感じに設定するか、curlのをもってきてもいい。
proxy_set_header
いい感じに設定する
終わり
この辺触る人あんまりいなさそうなので地味なハマり方をして消耗する人はいそう。頑張って欲しい。
カスタムして作った CentOS7.4 をAWSの M5, C5 で動かすときに落ちた沼について書いておく
今回もそこそこの不幸があった。普通にセットアップする分には簡単な案件だけど、ちょっと面倒なオプションがついて、カスタムしてダレカの作ったAMIをいい感じに新しいタイプのインスタンスで動かしたいというのがきた。やれやれ。
前知識
新しい世代のEC2インスタンスタイプ M5/C5 が東京リージョンで利用可能になりました
NITRO世代(C5、M5)へのEC2インスタンスタイプ変更を試してみた(Amazon Linux編)
- https://dev.classmethod.jp/cloud/aws/change-type-to-m5-nitro-generation/
- 元々 M5 タイプに対応していないAMIをアップグレードで対応する場合のことがちょっとだけ書いてある。
- 記事を読むと、ENAを有効にし、NVMeドライバが使えるようにすれば起動するように見える。
- AmazonLinuxの例だが、CentOSでも同じようにできるはず。
EC2で稼働中のCentOS 7を新しいインスタンス M5/C5 で起動させる準備をする
- http://info.m-up.com/news/?category=staffdiary&id=2000001333
- もうちょっと泥臭い感じの内容
- AWSのドキュメント通りにコマンドを流してだいたいうまく起動できた、と書いてある
- 後半kernelを4系にあげてあるが、単に動かしたいだけなら3系でも問題はない
- 新しいkernelを使うメリットは例えばnvmeドライバの改善、まあ気にしなくてもいいかもしれない
VPC 内の Linux インスタンスにおける Elastic Network Adapter (ENA) を使用した拡張ネットワーキングの有効化
- https://docs.aws.amazon.com/ja_jp/AWSEC2/latest/UserGuide/enhanced-networking-ena.html#enhanced-networking-ena-linux
AWSの公式ドキュメント
- 拡張ネットワーク (ENA) が有効になっているか調べる手順
- 同じように modinfo でnvmeドライバも調べておく。CentOS7.4以降のkernelは標準でnvmeドライバをサポートしている
amzn-drivers
から dkms を使ってenaモジュールをビルドする設定を入れておく- この手順で少し足りない箇所があり沼に落ちた。具体的には
dracut
での追加ドライバの指定。詳細は後述
- この手順で少し足りない箇所があり沼に落ちた。具体的には
- 予測可能なネットワークインターフェイス名を無効にする (Disable predictable network interface names)
/etc/udev/rules.d/70-persistent-net.rules
を消す
起動しないM5インスタンス
ena supportのオプションはインスタンスで有効にした状態でスナップショットを取るとAMIにも引き継がれ、AMIから起動したEC2インスタンスもENAが有効になります。
OSの起動前に問題が発生した場合、システムログの出力がないため調査が難しいのですが、インスタンスを停止するとシステムログの出力が得られることがあるので、起動してしばらくしてもSSHができない場合は、インスタンスを停止してシステムログを確認する。
今回の場合、 dracut-initqueue timeout
で停止しており、 switch_root でEBSに切り替えようとしているところでパーティションが見つけられずエラーになっていた。
ログを見た感じ、疑われたポイントは、fstab、grub、initramfs、nvmeドライバ。
EC2 HVMの仕組み
仮想化方式(HVM と PV)についてまとめ
HVMインスタンスの仕組みは、物理マシンに近く、ルートデバイスにあるブートローダーからkernelを起動する。裏側はXenだけど。
なのでシステムログをよく見ると
- ブートローダ (grub) から grub2 を起動
- /boot/grub2/grub.conf を読んで、
kernel vmlinuz
、initrd initramfs.img
みたいなことが行われて - initramfsから起動した小さなOSがルートデバイスの
/
へ switch_root - / からOSを起動
という流れになっているのがわかる。
dracut-initqueue timeout
は initramfs のところで起きているのでその辺りを調べていく。
dracut
RHEL系のディストリビューションで使われているinitramfs生成ツール。
結論を書くと、dracutの設定にnvmeドライバの追記をしていなかったため、/
を見つけられず起動に失敗していただけだった。
dracutにドライバを含めるには、 /etc/dracut.conf.d
以下にファイルを置く。例えば /etc/dracut.conf.d/nvme.conf
として以下のファイルを作成する。
add_drivers+=" nvme "
その後、 dracut
を実行する。
dracut -v -f
これで initramfs が再生成され、中に nvme ドライバが含まれるようになる。確認したい場合は、cpioとかを使って生成されたinitramfsを展開すれば確認できる。
終わりに
疲れた。勘弁してくれ。
まあ、この辺は以前にinitramfsとかブートローダとかnvmeドライバとかその辺を調べてあったから比較的早く解決できた気はする。
どっちかというとPXEBOOT周りを触ってる際に覚えたことだけど、事前知識がなかったらこの問題は相当難しい問題だったと思う。難of難。
AWS触るときにもこの辺りの知識が必要になるってのは意外だけどそんなもんかな。いや、普通にやってたらハマらないしこの辺触らないんだよな...
zabbixについてまとめておく
Zabbixは総合監視ツールでmuninのようなメトリクスグラフを出したり、nagiosのような死活監視を行う機能をまとめて持っている便利ツール。
prometheus + grafana のように高速ではないが、長く使われているためそれなりの情報がある。
反面、古いといえば古臭さはあり、WebGUIでポチポチやる必要があるところが今ひとつだったり、agentで送れるデータが1つだったりする。
また、好みはあるが、個人的にはグラフはイマイチでメトリクスグラフはmuninのほうが簡単で綺麗という感想です。
一応WebAPIがあるので、自動的に設定を作ることはできなくはなさそうだけど、何回も設定するようなものではないし、 自前で作るのは正直面倒ではあります。
あと、zabbix-agentは監視項目が多くなるとホストマシンのCPUを消費する傾向があるので、多すぎる監視項目に気をつける必要がある。 この辺りは最適化テクニックもあるらしいけど、必要な監視のみに削る方が楽。
Zabbixは非常に高機能なので色々なことができるみたいですが、とりあえず使い始めるに当たって必要なところだけまとめる
zabbix-web
ZabbixサーバのWebインターフェイス。 Zabbixは設定をMySQLなどのDBに持つが、Webインターフェイスから設定を変える場合に使う。
管理 > ユーザ
Zabbixはユーザごとにプロファイルを持ち、Webのビューや障害通知のメールなどを設定できる。
デフォルトで Admin
ユーザが設定されているが、複数人で扱う場合にはそれぞれ適切にユーザ登録を行うのがよい。
ユーザには種類があり、「Zabbixユーザー」と「Zabbix特権管理者」がある。 一般ユーザは「Zabbixユーザー」になるが、「設定」や「管理」が行えず、ホスト登録や障害通知のトリガー設定など多くの 運用に必要な設定ができないため、運用者は「Zabbix特権管理者」の権限を使うのがよい。
単に閲覧だけできればよいのであれば「Zabbixユーザー」でもよい。 グループごとに閲覧できる範囲を限定したり、大規模な会社向けの機能っぽいものもあるが割愛する。
設定 > アクション
アクションはZabbixが何かしらの状態変化を検出した場合に何かの動作を自動的に行うというもので、その名前の通りの機能。
何かしらのイベントには、「トリガー」、「ディスカバリ」、「自動登録」、「内部イベント」がある。
トリガーというのは、ホストから取得している数値に変化があった場合に通知として使えるもので、 いわゆるホスト監視目的で使える。障害復旧通知とか。
ディスカバリと自動登録はZabbixがホストを見つけた場合に使うのもので、例えば名前を自動で埋めたり監視項目を自動設定したりできる。 ディスカバリと自動登録は、受け攻めの違い程度なのでどちらも似たような感じで設定する。
内部イベントはその他色々なイベントを実行の条件にできるようだが、特に使っていないのでわからない。
とりあえずの設定で言えばトリガーを設定できれば死活監視の仕組みを作れる。
デフォルトの通知は「Report problems to Zabbix administrators」で「Zabbix administrators via すべてのメディア」となっている。
「Zabbix administrators」というのはデフォルトのユーザグループで、 通知を受け取りたいユーザは「Zabbix administrators」に所属させておけばよいと思う。
「すべてのメディア」とあるが、メディアというのはユーザごとに設定できる通知の方法で、「メール」「SMS」「スクリプト」など任意に設定できる。
Slackのようなチャットツールに通知したい場合は、自前でスクリプトを設定すると簡単にできる。 設定方法はユーザプロフィールの右上のアイコン。
設定 > テンプレート
テンプレートというのは、複数のホストに対してまとめて設定をいれるために使う設定のセットのようなもの。
Zabbixのマニュアルだと、「アイテム」、「トリガー」、「グラフ」、「アプリケーション」、「スクリーン」、「ローレベルディスカバリ」などが 例になっている。
とりあえずの設定で言えば、まずは「アイテム」と「トリガー」を設定できれば十分。
「アイテム」とはホストから取得するデータのことで、具体的には「CPU使用率」や「メモリ使用量」、「起動プロセス数」など。 監視項目と考えてもいいかもしれない。取得するデータは組み込みのもののほか任意のスクリプトから取得することもできる。
「トリガー」はテンプレートの単位で「アイテム」で取得した数値が一定の値を取った時にアクションを行う設定。 具体的には、「アイテム:CPU使用率が50%を超えた場合」といった条件をトリガー起動の条件として設定する。 トリガーの設定にはアイテムの設定が必須となる。
アイテムやトリガーはテンプレートではなくホストごとにも設定できるが設定管理の面からテンプレートを使うのがベター。
設定 > ホストグループ
テンプレートには必ずホストグループを設定する必要があるが、設定してもテンプレートの内容がホストグループに適用されるわけではない。
先の説明通りになるが、テンプレートはホストごとに設定するもので、この設定は対象ホストの選択時に絞り込めるだけにすぎない。
実際にホストにテンプレートを適用するにはリンクをする必要があり、これはホスト側からもテンプレート側からも行える。
ホストグループはホストをまとめる論理単位だが、テンプレートには直接影響しないため注意。イマイチ慣れない機能。
とりあえず
死活監視はこれだけで十分作れる感じはある。長く使われているだけあって、情報は多いし悪くはない。
グラフは好みあるけどZabbix単体だとホストグラフを横断的にみることができないからキツいかなあ。
まあとりあえずいい感じのツールなのは間違いないです。
長い付き合いだったNagiosさんもIcingaになりそうで古いプラグインが使えなくなるとかなんとかだそうで この手の監視ツールも大変だなーという感想です。