2014年10月30日木曜日

Nginxのレスポンスタイムをパーセンタイル値で計測するMunin plugin

Alberto Permuy Leal

https://github.com/takeshiyako2/munin-nginx_request_time

nginxのレスポンスタイムをパーセンタイル値で計測するMunin pluginです。
id:t-cyrillさんのプラグインがオリジナルです。これをLTSVに対応させました。
90パーセンタイル, 95パーセンタイル値とMAX値をグラフにします。(MAX値は別グラフ)


min 最小値
median 中央値
percentile90 90パーセンタイル
percentile95 95パーセンタイル


パーセンタイルとは?
計測値の分布(ばらつき)を小さい数字から大きい数字に並べ変え、パーセント表示することによって、小さい数字から大きな数字に並べ変えた計測値においてどこに位置するのかを測定する単位。
 例えば、計測値として100個ある場合、5パーセンタイルであれば小さい数字から数えて5番目に位置し、50パーセンタイルであれば小さい数字から数えて50番目に位置し、95パーセンタイルであれば小さい方から数えて95番目に位置する。
 このようにパーセンタイルは全体における自分の位置を測定する単位として用いられ、企業年金においては年金ALMにおいて計算された数値を説明するのに用いられることがある。
パーセンタイル(percentile)|用語集|企業年金連合会
http://www.pfa.or.jp/yogoshu/ha/ha17.html


 Nginxの$request_timeは、nginxがリクエストを受けてからレスポンスをクライアントに返しきるまでの時間なので、変に遅いクライアントが居ないとも限らない・・・。
平均値だと、極端な異常値が少しでもあったばあい、これに引きづられて数字が大きくなったりして、あまり信用できなくなったりします。
測定誤差をできるだけ減らしたいので、平均値ではなくてパーセンタイルを取ろうという考え方です。

以下、セットアップ方法です。


nginxのログフォーマットをLTSVに変更。※ LTSV公式サイトを参考にします。http://ltsv.org/
# emacs /etc/nginx/nginx.conf

    log_format  ltsv  "time:$time_local"
                      "\thost:$remote_addr"
                      "\tforwardedfor:$http_x_forwarded_for"
                      "\treq:$request"
                      "\tstatus:$status"
                      "\tsize:$body_bytes_sent"
                      "\treferer:$http_referer"
                      "\tua:$http_user_agent"
                      "\treqtime:$request_time"
                      "\tapptime:$upstream_response_time"
                      "\tvhost:$host";

    access_log  /var/log/nginx/access.log  ltsv; # mainをltsvに変更


nginxをリロード。
# /etc/init.d/nginx configtest
# /etc/init.d/nginx reload

nginxのログを読めるようにしておきます。
# chmod 644 /var/log/nginx/access.log

logrotateの設定も変えておきます。
# emacs /etc/logrotate.d/nginx

        create 640 nginx adm
->
        create 644 nginx adm
CPANモジュールをインストール。
# cpanm install Text::LTSV
# cpanm install File::ReadBackwards
# cpanm install Statistics::Lite
# cpanm install Statistics::Descriptive
Muninプラグインを設置
# cd /usr/share/munin/plugins/
# wget --no-check-certificate https://raw.githubusercontent.com/takeshiyako2/munin-nginx_request_time/master/nginx_request_time
Muninプラグインにリンクを貼る
# ln -s /usr/share/munin/plugins/nginx_request_time /etc/munin/plugins/nginx_request_time
# ln -s /usr/share/munin/plugins/nginx_request_time /etc/munin/plugins/nginx_request_time_max
munin-nodeをリスタート。
# service munin-node restart
簡単ですね!

※ 他にも、レスポンスタイムの可視化として有効なのは、例えば、[10ms ~ 50ms], [51ms~ 100ms], [101ms以上]で別々でカウントしたりする方法があります。こちらも実装しておくと安心できるでしょう。

参考)
『性能エンジニアリング入門(2):負荷テストのデータ、読めてますか? (1/2)』
http://www.atmarkit.co.jp/ait/articles/1201/06/news121.html

負荷テストの勘所 その2 | Insight Technology, Inc.
http://www.insight-tec.com/technical-information/%E8%B2%A0%E8%8D%B7%E3%83%86%E3%82%B9%E3%83%88%E3%81%AE%E5%8B%98%E6%89%80%E3%80%80%E3%81%9D%E3%81%AE%EF%BC%92.html

負荷テストについて基本的なメモ - ablog
http://d.hatena.ne.jp/yohei-a/20090722/1248264521

第17回 Webアプリケーションのパフォーマンス改善(1):Perl Hackers Hub|gihyo.jp … 技術評論社
http://gihyo.jp/dev/serial/01/perl-hackers-hub/001701

突然のTwitter砲にもなんとか耐えたさくらVPSに感謝する - As a Futurist...
http://blog.riywo.com/2011/02/07/162154

2014年10月28日火曜日

MySQLスレーブの整合性を保つための3つの設定

David Guthrie

MySQLのスレーブサーバが落ちて、立ち上げた時にマスターとの整合性を心配したくないのであれば以下の設定を入れると良いそうです。

MySQL設定ファイルに追記
# emacs /etc/my.cnf

[mysql]
binlog_checksum            = CRC32
relay_log_info_repository  = TABLE
relay_log_recovery         = ON

MySQLをリスタート
# service mysqld restart


各設定に意味については、下記サイトが参考になります。

binlog_checksum            = CRC32
”バイナリログが破損した場合に破損を検出し易くするために、バイナリログにチェックサムを追加”
http://thinkit.co.jp/story/2014/01/23/4717/page/0/1

relay_log_info_repository  = TABLE
relay_log_recovery         = ON
"MySQL 5.6でスレーブをクラッシュセーフにするには"
http://yakst.com/ja/posts/57


結果、スレーブサーバは以下の様な設定になりました。
※ HandlerSocket の設定込みです。


2014年10月23日木曜日

AWSガチャは下手なチューニングよりも効果が出る?

foxfoto_archives

Amazon EC2は立ち上げるインスタンスによって微妙なパフォーマンス差が出ると言われていて、複数回、インスタンスを立ち上げたり、捨てたりして、良いインスタンスを得ることを”Amazon EC2インスタンスガチャと”呼ばれています。
そのパフォーマンス差は、どれくらいなのか?気になったので測ってみました。

検証環境はこんな感じです。
AMI ID: CentOS 7 x86_64 (2014_09_29) EBS HVM-b7ee8a69-ee97-4a49-9e68-afaee216db2e-ami-d2a117ba.2 (ami-89634988)
Instance Type: c3.xlarge

1)Magnetic(standard)
2)Magnetic(standard) + EBS-Optimized
3)General Purpose (SSD) + EBS-Optimized
4)Provisioned IOPS (IOPS 1000) + EBS-Optimized

上記のディスクを接続した各10インスタンスづつ立てて、ベンチマークします。

fioでベンチマーク

まず。fioでIOPSを調べます。

fioをインストール。
# yum -y install epel-release.noarch
# yum -y install fio
fioをランダムリード・モードで実行。
# fio -rw=randread -bs=4k -size=1G -numjobs=32 -runtime=60 -direct=1 -invalidate=1 -ioengine=libaio -iodepth=32 -iodepth_batch=32 -group_reporting -name=randread


インスタンスによって差異が出てきました。

dbenchでベンチマーク

違うベンチマークツールでスループットを調べてみます。
ベンチマークには、dbench(https://dbench.samba.org/)を使います。

dbenchをインストール。
# yum -y install dbench
dbenchを実行。
# dbench 5 -D . > dbench.log



かなりの差が出てしましいました。

まとめ

インスタンスによっては、ディスク性能でけっこうな差がでてしまいました。

Magnetic(standard)はAWSガチャによってかなりの性能差が出ます。EBS-Optimizedをつけても変わりません。

一見、General Purpose (SSD)が良い結果を出しているように見えますが、バーストしている状態だと思われます。数十回ベンチマークをかけたら仕様どおりガクンと性能が落ちました。
(最も低い結果で iops=305, Throughput 75.5844 MB/sec, max_latency=7719.676 ms ほど)
長時間連続して負荷がかかる環境には使わないほうがよいでしょう。
逆に、バッチ処理などの用途では威力を発揮しそうです。
General Purpose (SSD)のバーストについては、こちらの記事が参考になります。
『Amazon EBSのGeneral Purpose(SSD)のバーストルールを理解する | Developers.IO』
http://dev.classmethod.jp/cloud/study-ebs-ssd-burst-rule/

 Provisioned IOPSはまあまあ安定しています。

ちなみにUnixBenchも試してみましたが、これは主にCPUへのベンチマークツールなので、差は殆どありませんでした。
MySQLのマスターサーバなどでディスク性能が要求される用途では、Provisioned IOPSを選ぶと安心できるでしょう。

※ 2014/10/24 General Purpose (SSD) + EBS-Optimized と Provisioned IOPS (IOPS 1000) + EBS-Optimized のベンチマークを追記。

2014年10月21日火曜日

CentOS7にMySQL5.6をyumレポジトリからインストール

Christian Ditaputratama


そういえば、まだ、CentOS 7をあまりいじっていなかったので、とりあえず手始めにMySQLをインストールしてみました。

環境はAmazon EC2です。
AMIは、CentOS 7 (x86_64) with Updates HVMです。

AMI ID: CentOS 7 x86_64 (2014_09_29) EBS HVM-b7ee8a69-ee97-4a49-9e68-afaee216db2e-ami-d2a117ba.2 (ami-89634988)
Instance Type: c3.xlarge
EBS: General Purpose (SSD)

* こちらのURLから最新のMySQLのyumレポジトリを探します。
http://dev.mysql.com/downloads/repo/yum/
Red Hat Enterprise Linux 7のDownloadリンクをクリック -> "No thanks, just start my download."のURLが最新です。

* MySQLのレポジトリをインストール。el7を選びます。
# rpm -i http://dev.mysql.com/get/mysql-community-release-el7-5.noarch.rpm

* MySQLをインストール。
# yum install mysql-community-server mysql-community-devel

* MySQLサービスをスタート。/etc/init.d/mysqldじゃあなくなっているので注意です。
# service mysqld start

* MySQLのステータスをチェック。色々出てくるようになりました。
# service mysqld status -l
edirecting to /bin/systemctl status  -l mysqld.service
mysqld.service - MySQL Community Server
   Loaded: loaded (/usr/lib/systemd/system/mysqld.service; disabled)
   Active: active (running) since Wed 2014-10-22 01:18:38 UTC; 1min 43s ago
  Process: 1513 ExecStartPost=/usr/bin/mysql-systemd-start post (code=exited, status=0/SUCCESS)
  Process: 1454 ExecStartPre=/usr/bin/mysql-systemd-start pre (code=exited, status=0/SUCCESS)
 Main PID: 1512 (mysqld_safe)
   CGroup: /system.slice/mysqld.service
           ├─1512 /bin/sh /usr/bin/mysqld_safe
           └─1652 /usr/sbin/mysqld --basedir=/usr --datadir=/var/lib/mysql --plugin-dir=/usr/lib64/mysql/plugin --log-error=/var/log/mysqld.log --pid-file=/var/run/mysqld/mysqld.pid --socket=/var/lib/mysql/mysql.sock

Oct 22 01:18:37 ip-172-31-7-208 mysql-systemd-start[1454]: Support MySQL by buying support/licenses at http://shop.mysql.com
Oct 22 01:18:37 ip-172-31-7-208 mysql-systemd-start[1454]: Note: new default config file not created.
Oct 22 01:18:37 ip-172-31-7-208 mysql-systemd-start[1454]: Please make sure your config file is current
Oct 22 01:18:37 ip-172-31-7-208 mysql-systemd-start[1454]: WARNING: Default config file /etc/my.cnf exists on the system
Oct 22 01:18:37 ip-172-31-7-208 mysql-systemd-start[1454]: This file will be read by default by the MySQL server
Oct 22 01:18:37 ip-172-31-7-208 mysql-systemd-start[1454]: If you do not want to use this, either remove it, or use the
Oct 22 01:18:37 ip-172-31-7-208 mysql-systemd-start[1454]: --defaults-file argument to mysqld_safe when starting the server
Oct 22 01:18:37 ip-172-31-7-208 mysqld_safe[1512]: 141022 01:18:37 mysqld_safe Logging to '/var/log/mysqld.log'.
Oct 22 01:18:37 ip-172-31-7-208 mysqld_safe[1512]: 141022 01:18:37 mysqld_safe Starting mysqld daemon with databases from /var/lib/mysql
Oct 22 01:18:38 ip-172-31-7-208 systemd[1]: Started MySQL Community Server.

* MySQLを初期化。
※ パスワードは便宜設定してください
# mysql_secure_installation

NOTE: RUNNING ALL PARTS OF THIS SCRIPT IS RECOMMENDED FOR ALL MySQL
      SERVERS IN PRODUCTION USE!  PLEASE READ EACH STEP CAREFULLY!

In order to log into MySQL to secure it, we'll need the current
password for the root user.  If you've just installed MySQL, and
you haven't set the root password yet, the password will be blank,
so you should just press enter here.

Enter current password for root (enter for none):
OK, successfully used password, moving on...

Setting the root password ensures that nobody can log into the MySQL
root user without the proper authorisation.<

Set root password? [Y/n] Y
New password:AAAAAA
Re-enter new password:AAAAAA
Password updated successfully!
Reloading privilege tables..
 ... Success!


By default, a MySQL installation has an anonymous user, allowing anyone
to log into MySQL without having to have a user account created for
them.  This is intended only for testing, and to make the installation
go a bit smoother.  You should remove them before moving into a
production environment.

Remove anonymous users? [Y/n] Y
 ... Success!

Normally, root should only be allowed to connect from 'localhost'.  This
ensures that someone cannot guess at the root password from the network.

Disallow root login remotely? [Y/n] Y  ... Success! By default, MySQL comes with a database named 'test' that anyone can access.  This is also intended only for testing, and should be removed before moving into a production environment. Remove test database and access to it? [Y/n] Y  - Dropping test database... ERROR 1008 (HY000) at line 1: Can't drop database 'test'; database doesn't exist  ... Failed!  Not critical, keep moving...  - Removing privileges on test database...  ... Success! Reloading the privilege tables will ensure that all changes made so far will take effect immediately. Reload privilege tables now? [Y/n] Y  ... Success! All done!  If you've completed all of the above steps, your MySQL installation should now be secure. Thanks for using MySQL! Cleaning up...

* ログインしてみる
# mysql -uroot -pAAAAAA
Warning: Using a password on the command line interface can be insecure.
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 14
Server version: 5.6.21 MySQL Community Server (GPL)

Copyright (c) 2000, 2014, Oracle and/or its affiliates. All rights reserved.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql> SELECT "Hello World!";
+--------------+
| Hello World! |
+--------------+
| Hello World! |
+--------------+
1 row in set (0.00 sec)

ログインできました。
簡単ですね!

2014年10月20日月曜日

Amazon RDSのディスクスペースをチェックするnagiosプラグイン

Docklandsboy

https://github.com/takeshiyako2/nagios-check_rds_free_storage_space

Amazon RDSのディスクスペースをチェックするnagiosのプラグインです。
Amazon RDSの情報は、CloudWatchから調べることができるのですが、非常に見づらいので、nagiosでもチェックできるようにしました。

コードは、こんな感じになりました。

使い方は、以下のようになります。
オプションがたくさんあります。

$ ./check_rds_free_storage_space.rb -a [CloudWatch access_key] -s [CloudWatch secret_key] -r [CloudWatch region] -e [RDS region] -i [DBInstanceIdentifier] -w [Nagios warning level] -c [Nagios critical level]

$ ./check_rds_free_storage_space.rb -a AAAAAA -s SSSSSS -r monitoring.ap-northeast-1.amazonaws.com -e rds.ap-northeast-1.amazonaws.com -i mysql1 -w 30 -c 20

リュージョンのところは、日本の場合は、ap-northeast-1が付くので要注意です。

2014年10月10日金曜日

MySQLサーバのswap増加を解決するチューニングのヒント

MySQLサーバでスワップ(swap)が増えていたので、これを解消しました。
カーネルの設定 vm.swappiness = 1 を入れて解決しています。
こちらのスライドの17ページを参考にしました。



OSは、CentOS6.5です。
# cat /etc/redhat-release
CentOS release 6.5 (Final)


swapを確認
sysstatでswapの状況を確認してみます。
メモリに関しては、こちらのスライドが参考になります。



swapの発生状況を確認

# sar -W
12:00:01 AM  pswpin/s pswpout/s
12:10:01 AM      0.00      0.00
12:20:01 AM      0.00      0.00
12:30:01 AM      0.00      0.00
12:40:01 AM      0.00      0.00
12:50:01 AM      0.00      0.00

pswpin/s 1秒間にスワップ領域からメモリに読み込んだページ数
pswpout/s 1秒間にメモリからスワップ領域へ書き込んだページ数

スワップが多発している訳ではなことがわかります。

swap回数の統計を確認

# sar -B
12:00:01 AM  pgpgin/s pgpgout/s   fault/s  majflt/s  pgfree/s pgscank/s pgscand/s pgsteal/s    %vmeff
12:10:01 AM      1.04   7490.29   2939.23      0.03   9099.59    106.70      0.00    106.70    100.00
12:20:01 AM      0.68    700.46   1314.42      0.02   5203.37     28.75      0.00     28.75    100.00
12:30:01 AM      0.19   1187.17   1449.92      0.01   4704.59     37.38      0.00     37.38    100.00
12:40:01 AM      0.29   2224.01   1333.28      0.01   6425.57    121.65      0.00    121.65    100.00
12:50:01 AM      0.45    671.65   1443.74      0.01   3858.88     42.24      0.00     42.24    100.00

pgpgin/s 1秒間にスワップ領域からメモリへページ・インしたページ数
pgpgout/s 1秒間にメモリからスワップ領域へページ・アウトしたページ数
%vmeff pgsteal / pgscanとして計算された数で、ページ回収の効率性を示す。100%に近い場合、ほぼ全ての非活動リストの末尾から来るページが回収された事を意味する。低すぎる場合(30%以下)、仮想メモリは何らかの問題を有している。出力対象の期間の間にページのスキャンが行われない場合は、このフィールドはゼロを示す。

ページ・アウトが発生していますが、ページ・インは少ないので、スラッシングは少ない状況です。
ページ・インが多い場合は、スラッシングが多発し、アプリケーションのパフォーマンスが劣化している状況なので、サーバのメモリ搭載量を増やすなどの対応が必要です。

参考)sarコマンドのマニュアル
http://backslash0134.blog.fc2.com/blog-entry-63.html


カーネルの設定

vm.swappinessの設定をします。
vm.swappinessは、swap領域の扱いを制御するカーネルの設定です。
この設定値が小さければ小さいほどswapを抑制します。
デフォルトは、vm.swappiness=60です。これを1にします。

参考)Swappiness
http://ja.wikipedia.org/wiki/Swappiness
vm.swappiness = 0 メモリが一杯になるまでスワップを利用しない
vm.swappiness = 60 規定値
vm.swappiness = 100 全体のパフォーマンスに影響しうるほど積極的にスワップ処理を行う

設定を確認
# sysctl vm.swappiness
vm.swappiness = 60

設定変更
# echo 1 > /proc/sys/vm/swappiness

再度、設定を確認
# sysctl vm.swappiness
vm.swappiness = 1

sysctl.confに設定を追記
# vim /etc/sysctl.conf
vm.swappiness = 1

参考)
Linux performance tuning tips for MySQL
http://www.percona.com/blog/2013/12/07/linux-performance-tuning-tips-mysql/
OOM relation to vm.swappiness=0 in new kernel; kills MySQL server process
https://www.percona.com/blog/2014/04/28/oom-relation-vm-swappiness0-new-kernel/


swapしたデータをメモリに戻す

# swapoff -a && swapon -a

swapの量によって時間がかかります。
若干の負荷かかるので注意してください。
今回は、ロードアベレージが +1 ほど増えました。

以上で、MySQLサーバのswap増加を解決しました。
メモリの量を見てみましょう。チューニングを実施したところからメモリとスワップの使用率が変化しているのがわかります。


2014年10月2日木曜日

Nagiosでドメインの有効期限を監視する check_domain プラグイン

h080


ドメインの有効期限を監視するnagiosプラグインを紹介します。
※ OSは、CentOS6.5です。

公式サイトで扱っている check_domain を試したのですが、うまく期限を検知してくれなかったり、あまり使えない感じで駄目でした・・・。
http://exchange.nagios.org/directory/Plugins/Internet-Domains-and-WHOIS/check_domain/details
色々調べた結果、susatadahiroさんが公開されているプラグインが良かったので、これをforkして利用していきます。
いきます。


whoisライブラリをインストール
# yum -y install jwhois

git cloneして、nagiosプラグインディレクトリに設置します。
# git clone https://gist.github.com/961a772db63ec474b954.git
# cp 961a772db63ec474b954/check_domain /usr/lib64/nagios/plugins/
# chmod 755 /usr/lib64/nagios/plugins/check_domain

動作テストしてみましょう。

30日前でWARNING、10日前でCRITICAL
# /usr/lib64/nagios/plugins/check_domain -d appvador.com -w 30 -c 10
OK - Domain will expire on  20-nov-2014

90日前でWARNING、10日前でCRITICAL
# /usr/lib64/nagios/plugins/check_domain -d appvador.com -w 90 -c 10
WARNING - Domain will expire after 49 days on  20-nov-2014

検知してくれました。

あとは、nagiosのcommands.cfgにコマンドを設定して、、
define command{
        command_name    check_domain
        command_line    $USER1$/check_domain -H $ARG1$ -w 30 -c 10
        }

serviceに追加すればOKです。
define service{
        use                             local-service
        host_name                       localhost
        service_description Domain Expiration
        check_command  check_domain!appvador.com
        }

nagiosを確認してみましょう。




Enjoy!