Memo

メモ > サーバ > 構築: チューニング

■概要
ミドルウェアやWebアプリケーションについてのチューニング例 ただし2022年現在、それぞれを細かくチューニングするよりも ・サーバのスペックを上げる ・サーバの台数を増やす ・データをキャッシュする ・CDNを導入する といった対応の方が手っ取り早い可能性がある チューニングが無駄ということは無いと思うが、焼け石に水だったり、構築内容を無駄に複雑にしてしまう可能性もある チューニングをする前に、それらも含めて検討する
■Webアプリケーション チューニング
Webアプリケーションへの同時アクセス対策メモ http://refirio.org/view/367 Apache Benchを使った負荷テストのやり方 | Web活メモ帳 https://blog.verygoodtown.com/2012/05/apache-bench-ab/ ab コマンドすると、SSL read failed (5) - closing connection | クズリーマンのカス備忘録 https://it-afi.com/apache/ab-%E3%82%B3%E3%83%9E%E3%83%B3%E3%83%89%E3%81%99%E3%82%8B%E3%81%A8%E3%80%8... abツールを使うことで、大量アクセスが発生したときの状況をある程度再現できる SSL環境に対しては ab ではなく abs とすることで実行できる 具体的には、以下のようになる
$ ab -n 300 -c 300 https://example.com/test.php $ abs -n 300 -c 300 https://example.com/test.php
ApacheBenchmark(ab)実行中に問題発生:SSL read failed - closing connection https://teratail.com/questions/2180 「SSL read failed (5) - closing connection」これ自体はabsツールの不具合?詳細はまた調べたい PHPでは microtime() で実行時間を調べることができ、memory_get_usage() や memory_get_peak_usage() で、使用メモリ量を調べることができる http://refirio.org/memos/php/benchmark/ http://refirio.org/memos/php/benchmark/benchmark.php http://refirio.org/memos/php/benchmark/memory.php MySQLのExplainを確認する http://woshidan.hatenablog.com/entry/2015/06/20/165817 MySQLのexplainとかについてしらべたときのメモ http://qiita.com/lastcat_/items/de7b530a94fbcf9ba646 MySQLのEXPLAINを徹底解説!! http://nippondanji.blogspot.jp/2009/03/mysqlexplain.html なぜ、SQLは重たくなるのか?──『SQLパフォーマンス詳解』の翻訳者が教える原因と対策 https://employment.en-japan.com/engineerhub/entry/2017/06/26/110000 MySQLのクエリの良し悪しはrows_examinedで判断する - かみぽわーる http://blog.kamipo.net/entry/2018/03/22/084126 Linuxコマンドでボトルネックを調べる // Speaker Deck https://speakerdeck.com/pyama86/linuxkomandodebotorunetukuwodiao-beru
■Apache チューニング
※preforkでのチューニング例 開発サーバや会員しか使わないサイトなら、設定する意味は少ない 短期間にApacheのプロセス数が大きく波打つようなサイトならチューニングが有効 (プロセスを作成するときの負荷を無くせるので) 基本的にはpreforkの設定はデフォルトのままで大丈夫 ※Apacheに標準で付属している Apache Bench で、負荷テストができる ※Apacheの設定ファイル httpd.conf を編集してチューニングする ※Apache Bench でのテストを飛ばして、はじめからメモリ量をもとに考えても良さそう 【初心者向け】ApacheBench入門 | DevelopersIO https://dev.classmethod.jp/tool/ab-tutorial/ Apache Benchを使った負荷テストのやり方 http://blog.verygoodtown.com/2012/05/apache-bench-ab/ 同時接続数(MaxClients)をいくつに設定すべきか? http://canalize.jp/archives/006925.php Apache Benchでサクッと性能テスト http://qiita.com/flexfirm/items/ac5a2f53cfa933a37192 404 Blog Not Found:tips - Webサーバーの負荷テストならまずab http://blog.livedoor.jp/dankogai/archives/51212610.html Apacheをインストールすれば自動的に使えるようになっているが、nginx環境などの場合は以下でツールのみインストールできる
# yum -y install httpd-tools
Nginx を使っているウェブサーバで ab(ApacheBench)コマンドを入れる | tamulab.jp https://tamulab.jp/install-apache-bench-on-nginx-webserver/ XAMPPの場合、C:\xampp\apache\bin 内に ab.exe が存在している Webアプリケーションへの同時アクセス対策メモ http://refirio.org/view/367 ■Apache Bench の実行例
$ ab -n 100 -c 10 http://refirio.net/ http://refirio.net/ に対し、10人からのリクエストを100回実行 This is ApacheBench, Version 2.3 <$Revision: 655654 $> Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/ Licensed to The Apache Software Foundation, http://www.apache.org/ Benchmarking refirio.net (be patient).....done Server Software: Apache Server Hostname: refirio.net Server Port: 80 Document Path: / Document Length: 399 bytes Concurrency Level: 10 Time taken for tests: 0.028 seconds Complete requests: 100 … 成功したリクエスト(すべて成功) Failed requests: 0 … 失敗したリクエスト(なし) Write errors: 0 Total transferred: 65300 bytes HTML transferred: 39900 bytes Requests per second: 3518.15 [#/sec] (mean) … 1秒間に処理したリクエスト数(数字が大きいほど多く処理できた) Time per request: 2.842 [ms] (mean) … 1リクエストあたりの処理時間 Time per request: 0.284 [ms] (mean, across all concurrent requests) Transfer rate: 2243.51 [Kbytes/sec] received Connection Times (ms) min mean[+/-sd] median max Connect: 0 0 0.5 0 2 Processing: 0 2 0.8 2 5 Waiting: 0 2 0.8 2 4 Total: 1 3 1.0 2 6 WARNING: The median and mean for the total time are not within a normal deviation These results are probably not that reliable. Percentage of the requests served within a certain time (ms) 50% 2 66% 3 75% 3 80% 3 90% 5 95% 5 98% 6 99% 6 100% 6 (longest request)
以下のようにするとkeepaliveの状態でテストできる
$ ab -k -n 2000 -c 200 http://refirio.net/
keepaliveの概要は以下のとおり ・接続を維持したまま複数のデータ転送を行える ・有効にすると通信が早くなる ・HTTP 1.1ではデフォルトで有効になっている キープアライブ - Wikipedia https://ja.wikipedia.org/wiki/%E3%82%AD%E3%83%BC%E3%83%97%E3%82%A2%E3%83%A9%E3%82%A4%E3%83%96 HTTP-KeepAliveとは - コトバンク https://kotobank.jp/word/HTTP-KeepAlive-10754
$ ab -n 3000 -c 35 http://refirio.net/ http://refirio.net/ に対し、35人からのリクエストを3000回実行 Concurrency Level: 35 Time taken for tests: 0.749 seconds Complete requests: 3000 Failed requests: 0 Write errors: 0 Total transferred: 1962265 bytes HTML transferred: 1198995 bytes Requests per second: 4006.01 [#/sec] (mean) Time per request: 8.737 [ms] (mean) Time per request: 0.250 [ms] (mean, across all concurrent requests) Transfer rate: 2558.87 [Kbytes/sec] received $ ab -n 3000 -c 35 http://refirio.net/blog/ http://refirio.net/blog/ に対し、35人からのリクエストを3000回実行 Concurrency Level: 35 Time taken for tests: 68.335 seconds Complete requests: 3000 Failed requests: 0 Write errors: 0 Total transferred: 20271000 bytes HTML transferred: 19548000 bytes Requests per second: 43.90 [#/sec] (mean) Time per request: 797.242 [ms] (mean) Time per request: 22.778 [ms] (mean, across all concurrent requests) Transfer rate: 289.69 [Kbytes/sec] received
■負荷テスト
$ ab -n 1000 -c 100 http://refirio.net/blog/ Concurrency Level: 100 Time taken for tests: 26.575 seconds Complete requests: 1000 Failed requests: 0 Write errors: 0 Total transferred: 6757000 bytes HTML transferred: 6516000 bytes Requests per second: 37.63 [#/sec] (mean) Time per request: 2657.485 [ms] (mean) Time per request: 26.575 [ms] (mean, across all concurrent requests) Transfer rate: 248.30 [Kbytes/sec] received $ ab -n 2000 -c 200 http://refirio.net/blog/ … Load Average が210くらいになったが、なんとかさばけている模様 Concurrency Level: 200 Time taken for tests: 1532.602 seconds Complete requests: 2000 Failed requests: 0 Write errors: 0 Total transferred: 13514000 bytes HTML transferred: 13032000 bytes Requests per second: 1.30 [#/sec] (mean) Time per request: 153260.231 [ms] (mean) Time per request: 766.301 [ms] (mean, across all concurrent requests) Transfer rate: 8.61 [Kbytes/sec] received $ ab -n 3000 -c 300 http://refirio.net/blog/ … 「apr_poll: The timeout specified has expired」となった(このとき、Load Average が270くらいになった) サーバに負荷がかかりすぎたようで、しばらくSSHもHTTPも繋がらなくなった 少なくともこのページでは300人からのアクセスはさばけない Requests per second: 3518.15 [#/sec] (mean) …
1秒間に処理できるリクエスト数(Requests per second)がどんどん小さくなり、 1リクエストあたりの処理時間(Time per request)がどんどん多くなっている これは、リクエストが多くなると処理待ちが多く発生するようになるため。 Apache Bench でのアクセスは、完全な同時アクセスではない 最初はアクセスが少なく、だんだん増えていき、一定数が続き、徐々に減っていく。という実際のアクセスを再現する つまり、上の結果から「秒間200アクセスをさばくサーバ」と言えるわけでは無い 「200人の同時アクセスに耐えられるようにしてほしい」 の要件があった場合、 「秒間200アクセスをさばく」という意味なのか「200人が一定時間をかけて色々なページを見ている状況」 なのか確認しておく必要がある 普通のサーバなら、同時にさばけるのはせいぜい秒間数十くらい? 秒間100などという数字が出てきた時点で、ロードバランサでの複数台構成を考える? ネットワークも考慮できる分、Apache Bench ツールよりLoadImpactの方が便利 だた、他のサーバからabツールを使えばネットワークを考慮に入れられる Abを利用した負荷テスト時にTimeoutになる場合の対処法 http://qiita.com/y-mori/items/83547f4dd604e8e5c509 「TCP: time wait bucket table overflow」や「nf_conntrack: table full, dropping packet.」のエラーメッセージは無かった。 トップページへのリクエストなら大丈夫なので、負荷が高いページヘのリクエストだから問題があった? 今度は、普通のHTMLページに対してリクエストしてみる
$ ab -n 3000 -c 300 http://refirio.net/ Concurrency Level: 300 Time taken for tests: 1.470 seconds Complete requests: 3000 Failed requests: 0 Write errors: 0 Total transferred: 1962265 bytes HTML transferred: 1198995 bytes Requests per second: 2040.96 [#/sec] (mean) Time per request: 146.990 [ms] (mean) Time per request: 0.490 [ms] (mean, across all concurrent requests) Transfer rate: 1303.68 [Kbytes/sec] received $ ab -n 5000 -c 500 http://refirio.net/ Concurrency Level: 500 Time taken for tests: 6.414 seconds Complete requests: 5000 Failed requests: 0 Write errors: 0 Total transferred: 3273489 bytes HTML transferred: 2000187 bytes Requests per second: 779.53 [#/sec] (mean) Time per request: 641.412 [ms] (mean) Time per request: 1.283 [ms] (mean, across all concurrent requests) Transfer rate: 498.40 [Kbytes/sec] received $ ab -n 6000 -c 600 http://refirio.net/ … 完了できない Benchmarking refirio.net (be patient) Completed 600 requests Completed 1200 requests Completed 1800 requests Completed 2400 requests Completed 3000 requests Completed 3600 requests Completed 4200 requests Completed 4800 requests Completed 5400 requests apr_socket_recv: Connection reset by peer (104) Total of 5892 requests completed # vi /var/log/messages … エラーメッセージを確認
kernel: possible SYN flooding on port 80. Sending cookies.
CentOS6などでdmesgにpossible SYN flooding on port(SYN flooding警告)が出た場合の対策方法を考えてみるテスト http://triplesky.blogspot.jp/2014/07/centos6dmesgpossible-syn-flooding-on.html 受け付けられないほどの大量アクセスが来たというログが残っている。 このサーバの接続可能数の飽和点は500程度。余裕を持たせて400程度 また先にテストしたように、PHPプログラムのページの場合は210程度が限界 ただしそのまま210に設定すると、他のサービスが稼働できないくらいの接続を受け入れてしまう可能性がある また、swapも多発してサーバが非常に重くなる可能性がある 実際、abツールで計測している最中はサーバが非常に重くなった。 この状態ではサーバが落ちていなかったとしても「210をさばける」と言うわけにはいかない ■メモリ量からMaxClientsの目安を考えてみる 同時接続数(MaxClients)をいくつに設定すべきか? http://canalize.jp/archives/006925.php MaxClients=使用可能なメモリ量/Apacheの1プロセスが使用するメモリ量 という考え方で計算できる refirio.netサーバではメモリは1GBで、実際に使っているのは500MBくらい。 psで見ると、httpdの1プロセスが2%くらいを使っているので、1プロセスあたり10MBくらい使っている よって、MaxClientsは90〜100くらいが良さそう ↑の数値はRではなくSのプロセスだし、データベースなども考慮する必要がある。 常時立ち上げるなら80くらいでもいいかも? (ただし例えばMySQLを使うなら、MySQLのmax_connectionsとの兼ね合いも考慮する) Sのプロセスでメモリの消費量を計算すると、実際はもっと消費する可能性があるので注意 ある程度サーバに負荷をかけてRのプロセスを表示させ、それをもとに計算した方がいい #なお、某大学の入試サイトサーバではメモリは16GBで、実際に使っているのは1.4GBくらい。 #psで見ると、httpdの1プロセスが0.1%に満たないくらいを使っているので、1プロセスあたり1.4MBくらい使っている #refirio.netとは大きく差があるが、1プロセスあたりの消費メモリは、実行されているプログラムによっても変わる #また、長い間プロセスが使われていないとメモリ量はどんどん小さくなるらしい #このサーバはスペックが高いので、他のプロセスが使われないので、最小状態になっている? #Apacheの使用メモリが搭載メモリ数を超えてしまうと、スワップが発生してサーバが重くなる #逆に少なすぎると503エラーになる /etc/httpd/conf/httpd.conf を編集
<IfModule prefork.c> StartServers 8 … 起動時に生成される子サーバプロセスの数。常に動かしておきたい数に設定しておく MinSpareServers 5 … アイドル状態にいる子サーバプロセスの最小(希望)個数 MaxSpareServers 20 … アイドル状態にいる子サーバプロセスの最大(希望)個数 ServerLimit 256 … MaxClientsに指定可能な値の上限 MaxClients 256 … 起動される子サーバプロセスの最大数。つまり応答できる同時リクエスト数 MaxRequestsPerChild 4000 … 個々の子サーバプロセスが扱うことのできるリクエストの総数。0に設定すると無制限 </IfModule>
一旦以下のように変更する
<IfModule prefork.c> StartServers 80 MinSpareServers 80 MaxSpareServers 80 ServerLimit 80 MaxClients 80 MaxRequestsPerChild 0 </IfModule>
これで様子を見つつ、エラーログに以下のメッセージが記録されたら、400までの値で少しづつ上げて調整する [error] server reached MaxClients setting, consider raising the MaxClients setting 400まで上げてもエラーログがでるようなら、もうその1台のサーバでは対応できない(Apache的に)ので、 ロードバランサで複数台構成を検討する必要がある また、これはあくまでもサーバスペックのみでの話。実際には転送量制限や帯域制限もあるので注意。 Apacheのチューニングメモ http://qiita.com/nownabe/items/1111cc32da9fe63289f0 中規模サイトのApacheチューニング http://qiita.com/kou/items/acb3dcf1dcb428d7a3ec 他にも以下を設定しておくと良さそう Timeout ... 60秒でも長い?10秒くらいでいいかも(ただしAWSの場合は120に設定する) KeepAlive ... OFFでよさそう(AWSの場合は有効に設定する) Amazon ELBをうまくつかうには、KeepAliveを有効にしよう。Timeoutは60秒よりだいぶ長くしよう。その背景。 https://debiancdn.wordpress.com/2012/06/14/amazon-elb%E3%82%92%E3%81%86%E3%81%BE%E3%81%8F%E3%81%A4%E... ※今はサーバスペックが向上しているので、回線(帯域)の方がネックになることがある 帯域をもとに同時にさばける数を計算し、それをもとに判断するという手段もある ※サーバ契約前・構築前ならどのように判断する? ■負荷をかけずに速度計測 以下のように「-c 1」にすれば単一の接続になる また、リクエストの回数も「-n 10」と少なめにする
$ ab -n 10 -c 1 -k http://refirio.net/blog/
Netlifyが日本からだと遅い - id:anatooのブログ https://blog.anatoo.jp/2020-08-03
■nginx チューニング
nginxの基本設定を改めてちゃんと調べてみた - Qiita https://qiita.com/hclo/items/35f00b266506a707447e 開発サーバーでもこれだけはやっておくnginxの設定 - Qiita https://qiita.com/yuse/items/fe05cec1a331306eac19 (コピペ)nginx最大パフォーマンスを出すための基本設定 https://gist.github.com/aliyome/d6a5e4bfb54985145b7297863c03aecb Nginxのパフォーマンスを極限にするための考察 - Qiita https://qiita.com/iwai/items/1e29adbdd269380167d2 nginxのパラメータチューニングとh2o - Qiita https://qiita.com/cubicdaiya/items/235777dc401ec419b14e 応答速度28.8倍。WordPressをApacheからNginxに移行して感じたブログ運営 http://hamako9999.net/apache2nginx/ NginxのRatelimit発動時に、安定したアクセスを提供するngx-smart-ratelimitを開発しました | ten-snapon.com https://ten-snapon.com/archives/2701 以下、いったんVagrant環境でデフォルト設定でベンチマークを取得したのみ ■計測前
$ uptime 18:23:15 up 38 min, 1 user, load average: 0.00, 0.03, 0.07
■計測(PHPで日時を表示するだけのページを計測)
$ ab -n 1000 -c 100 http://192.168.33.11/ This is ApacheBench, Version 2.3 <$Revision: 1430300 $> Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/ Licensed to The Apache Software Foundation, http://www.apache.org/ Benchmarking 192.168.33.11 (be patient) Completed 100 requests Completed 200 requests Completed 300 requests Completed 400 requests Completed 500 requests Completed 600 requests Completed 700 requests Completed 800 requests Completed 900 requests Completed 1000 requests Finished 1000 requests Server Software: nginx Server Hostname: 192.168.33.11 Server Port: 80 Document Path: / Document Length: 167 bytes Concurrency Level: 100 Time taken for tests: 0.435 seconds Complete requests: 1000 Failed requests: 0 Write errors: 0 Total transferred: 323000 bytes HTML transferred: 167000 bytes Requests per second: 2299.92 [#/sec] (mean) Time per request: 43.480 [ms] (mean) Time per request: 0.435 [ms] (mean, across all concurrent requests) Transfer rate: 725.46 [Kbytes/sec] received Connection Times (ms) min mean[+/-sd] median max Connect: 0 5 4.5 5 18 Processing: 10 36 8.1 37 53 Waiting: 1 34 8.5 36 52 Total: 14 41 6.0 42 66 Percentage of the requests served within a certain time (ms) 50% 42 66% 43 75% 45 80% 46 90% 47 95% 48 98% 53 99% 58 100% 66 (longest request)
■計測(インストール直後のLaravelホーム画面を計測。100人で計1000リクエスト)
$ ab -n 1000 -c 100 http://192.168.33.11/ This is ApacheBench, Version 2.3 <$Revision: 1430300 $> Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/ Licensed to The Apache Software Foundation, http://www.apache.org/ Benchmarking 192.168.33.11 (be patient) Completed 100 requests Completed 200 requests Completed 300 requests Completed 400 requests Completed 500 requests Completed 600 requests Completed 700 requests Completed 800 requests Completed 900 requests Completed 1000 requests Finished 1000 requests Server Software: nginx Server Hostname: 192.168.33.11 Server Port: 80 Document Path: / Document Length: 2321 bytes Concurrency Level: 100 Time taken for tests: 32.582 seconds Complete requests: 1000 Failed requests: 0 Write errors: 0 Total transferred: 3229696 bytes HTML transferred: 2321000 bytes Requests per second: 30.69 [#/sec] (mean) Time per request: 3258.241 [ms] (mean) Time per request: 32.582 [ms] (mean, across all concurrent requests) Transfer rate: 96.80 [Kbytes/sec] received Connection Times (ms) min mean[+/-sd] median max Connect: 0 2 3.2 0 14 Processing: 150 3138 590.0 3241 3964 Waiting: 150 3137 590.0 3241 3964 Total: 163 3139 587.4 3242 3964 Percentage of the requests served within a certain time (ms) 50% 3242 66% 3380 75% 3437 80% 3475 90% 3575 95% 3657 98% 3742 99% 3794 100% 3964 (longest request)
※捌ききれている
$ uptime 19:05:20 up 1:20, 1 user, load average: 17.68, 4.66, 1.66
■計測(インストール直後のLaravelホーム画面を計測。200人で計2000リクエスト。1回目)
$ ab -n 2000 -c 200 http://192.168.33.11/ 〜略〜 Concurrency Level: 200 Time taken for tests: 69.349 seconds Complete requests: 2000 Failed requests: 13 (Connect: 0, Receive: 0, Length: 13, Exceptions: 0) Write errors: 0 Non-2xx responses: 13 Total transferred: 6421768 bytes HTML transferred: 4614115 bytes Requests per second: 28.84 [#/sec] (mean) Time per request: 6934.949 [ms] (mean) Time per request: 34.675 [ms] (mean, across all concurrent requests) Transfer rate: 90.43 [Kbytes/sec] received Connection Times (ms) min mean[+/-sd] median max Connect: 0 3 6.6 0 28 Processing: 88 6673 4797.3 5858 60123 Waiting: 60 6673 4797.3 5858 60123 Total: 88 6675 4796.1 5859 60124 Percentage of the requests served within a certain time (ms) 50% 5859 66% 6141 75% 6679 80% 6911 90% 9102 95% 9834 98% 12491 99% 13183 100% 60124 (longest request)
※捌ききれていない
$ uptime 19:12:46 up 1:27, 1 user, load average: 31.74, 11.19, 4.58
■計測(インストール直後のLaravelホーム画面を計測。200人で計2000リクエスト。2回目)
$ ab -n 2000 -c 200 http://192.168.33.11/ Concurrency Level: 200 Time taken for tests: 75.520 seconds Complete requests: 2000 Failed requests: 1 (Connect: 0, Receive: 0, Length: 1, Exceptions: 0) Write errors: 0 Non-2xx responses: 1 Total transferred: 6456186 bytes HTML transferred: 4639855 bytes Requests per second: 26.48 [#/sec] (mean) Time per request: 7552.007 [ms] (mean) Time per request: 37.760 [ms] (mean, across all concurrent requests) Transfer rate: 83.49 [Kbytes/sec] received Connection Times (ms) min mean[+/-sd] median max Connect: 0 3 6.8 0 28 Processing: 89 6553 2782.2 6006 60062 Waiting: 61 6552 2782.3 6006 60062 Total: 89 6556 2780.1 6006 60063 Percentage of the requests served within a certain time (ms) 50% 6006 66% 6553 75% 6902 80% 7081 90% 8592 95% 9344 98% 13094 99% 20815 100% 60063 (longest request)
※捌ききれていない
$ uptime 20:14:49 up 2:29, 1 user, load average: 26.53, 9.69, 4.44
■計測(インストール直後のLaravelホーム画面を計測。200人で計2000リクエスト。keepaliveあり。1回目)
$ ab -k -n 2000 -c 200 http://192.168.33.11/ Concurrency Level: 200 Time taken for tests: 72.615 seconds Complete requests: 2000 Failed requests: 2 (Connect: 0, Receive: 0, Length: 2, Exceptions: 0) Write errors: 0 Non-2xx responses: 2 Keep-Alive requests: 2 Total transferred: 6453816 bytes HTML transferred: 4637710 bytes Requests per second: 27.54 [#/sec] (mean) Time per request: 7261.466 [ms] (mean) Time per request: 36.307 [ms] (mean, across all concurrent requests) Transfer rate: 86.79 [Kbytes/sec] received Connection Times (ms) min mean[+/-sd] median max Connect: 0 3 6.7 0 28 Processing: 90 6385 3016.7 5941 60064 Waiting: 62 6385 3016.7 5941 60064 Total: 90 6387 3014.7 5941 60064 Percentage of the requests served within a certain time (ms) 50% 5941 66% 6212 75% 6634 80% 6809 90% 7346 95% 9025 98% 13095 99% 20571 100% 60064 (longest request)
※捌ききれていないが、先ほどよりは捌けている keepaliveによって、何らかの処理が省略されて負荷が減ったか
$ uptime 19:22:05 up 1:37, 1 user, load average: 26.11, 11.06, 5.85
■計測(インストール直後のLaravelホーム画面を計測。200人で計2000リクエスト。keepaliveあり。2回目)
$ ab -k -n 2000 -c 200 http://192.168.33.11/ This is ApacheBench, Version 2.3 <$Revision: 1430300 $> Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/ Licensed to The Apache Software Foundation, http://www.apache.org/ Benchmarking 192.168.33.11 (be patient) Completed 200 requests Completed 400 requests Completed 600 requests Completed 800 requests Completed 1000 requests Completed 1200 requests Completed 1400 requests Completed 1600 requests Completed 1800 requests Completed 2000 requests Finished 2000 requests Server Software: nginx Server Hostname: 192.168.33.11 Server Port: 80 Document Path: / Document Length: 2321 bytes Concurrency Level: 200 Time taken for tests: 73.802 seconds Complete requests: 2000 Failed requests: 2 (Connect: 0, Receive: 0, Length: 2, Exceptions: 0) Write errors: 0 Non-2xx responses: 2 Keep-Alive requests: 2 Total transferred: 6453686 bytes HTML transferred: 4637710 bytes Requests per second: 27.10 [#/sec] (mean) Time per request: 7380.221 [ms] (mean) Time per request: 36.901 [ms] (mean, across all concurrent requests) Transfer rate: 85.40 [Kbytes/sec] received Connection Times (ms) min mean[+/-sd] median max Connect: 0 3 7.1 0 30 Processing: 92 6286 2990.2 5748 60051 Waiting: 62 6286 2990.2 5748 60051 Total: 92 6289 2988.2 5748 60051 Percentage of the requests served within a certain time (ms) 50% 5748 66% 6240 75% 6598 80% 6743 90% 8217 95% 8827 98% 12684 99% 13564 100% 60051 (longest request) $ uptime 19:52:53 up 2:08, 1 user, load average: 28.34, 9.61, 4.19
■MySQL チューニング
※マシンの搭載メモリをもとに設定を調整する ※MySQLの設定ファイル my.cnf を編集してチューニングする ※MySQLのメモリ設定には、大きく分けて以下の2つがある グローバルバッファ ... mysqld全体で確保するメモリ スレッドバッファ ... コネクションごとに確保するメモリ MySQL 初めてのチューニング http://www.slideshare.net/Craftworks/my-sql-6113813 MySQLのmy.cnfファイルサンプル http://time-complexity.blogspot.jp/2013/10/mysqlmycnf.html MySQLの設定ファイル my.cnf をgithubにて公開しました & チューニングポイントの紹介 http://blog.nomadscafe.jp/2012/10/mysql-mycnf-github.html /etc/my.cnf で設定できる
[mysqld] datadir=/var/lib/mysql socket=/var/lib/mysql/mysql.sock user=mysql # Disabling symbolic-links is recommended to prevent assorted security risks symbolic-links=0 character-set-server = utf8 [mysqld_safe] log-error=/var/log/mysqld.log pid-file=/var/run/mysqld/mysqld.pid
以下のように設定を調整(WebサーバとDBサーバは共通で、搭載メモリは1Gとする)
[mysqld] datadir=/var/lib/mysql socket=/var/lib/mysql/mysql.sock user=mysql # Disabling symbolic-links is recommended to prevent assorted security risks symbolic-links=0 character-set-server = utf8 max_connections = 65 #最大同時接続数 #サーバに合わせて設定する必要がある #SHOW GLOBAL VARIABLES like '%connections%'; で Max_used_connections を参考にするといい(MySQLを起動してからの最大同時接続数) #負荷テストをすると必然的に上がってしまう? #グローバルバッファ innodb_buffer_pool_size = 512M #InnoDBのインデックスやレコードをキャッシュする領域。DB専用サーバなら全体の7〜8割程度、そうでないなら5割程度を割り当てる innodb_additional_mem_pool_size = 8M #InnoDBのテーブル定義情報を格納する領域。それほど気にする必要は無い。エラーログに警告が出たら増やせばいい innodb_log_buffer_size = 8M #InnoDBのトランザクションを管理する領域。大抵は8M、多くても64Mで十分。他のパラメータにメモリを渡すほうが得策 key_buffer_size = 8M #MyISAMで索引検索をする際にインデックス情報を格納する領域。MyISAMを使うなら256M程度にする。DB専用サーバなら全体の25%程度割り当てても問題ない query_cache_size = 128M #SELECT文の実行結果をキャッシュする領域。100〜200Mくらいが推奨されているようだが、128M以上には設定しない方がいい。INSERT, UPDATE, DELETEが頻繁に起こるサーバーでは大きく設定する必要はない #スレッドバッファ myisam_sort_buffer_size = 1M #MyISAMでインデックスのソートに使われる領域。それほど大きくする必要は無い。MyISAMを使うなら8M程度でいい sort_buffer_size = 2M #ソートの際に利用される領域。ORDER BY や GROUP BY を多用するなら多めにするといい。スレッドバッファなので2M以上には設定しない方がいい read_rnd_buffer_size = 1M #ソート後にレコードを読み込む際に利用される領域。ディスクI/Oが減るので、ORDER BY の性能向上が期待できる。ORDER BY を多用するなら多めにするといい。1〜2Mくらいが妥当 join_buffer_size = 128K #インデックスを使用しないテーブルの結合に使われる領域。インデックスを用いないテーブル結合は避けるべきなので、大きくする必要は無い read_buffer_size = 128K #テーブルスキャンの際に利用される領域。インデックスを用いないクエリは避けるべきなので、大きくする必要は無い #メモリ以外の設定 innodb_log_file_size = 128M #InnoDBの更新ログを記録するディスク上のファイル。innodb_buffer_pool_sizeを大きくしたら合わせて大きくする。1M以上に設定する。32bitマシンの場合は4G以下に設定する #innodb_log_file_size * innodb_log_files_in_group(デフォルト2) の値が innodb_buffer_pool_size を超えてはいけない table_open_cache = 1024 #開いたテーブルのファイルポインタを格納する領域。「同時接続数×テーブル数」が最低限必要。1024〜2048が一般的。MyISAMでは1テーブルにつき2つ消費 thread_cache_size = 20 #スレッドをキャッシュにいくつ保存しておくのか決める。実際の稼働状況を把握しないと何とも言えない。max_connectionsの1/3ぐらいか wait_timeout = 10 #接続したクライアントが何もせずにいるとき、接続を切断する時間。単位は秒でDefaultは28800秒(8時間)で、かなり大きい値 #Webでの接続の場合、Webサーバのタイムアウト時間と同じでいい? [mysqld_safe] log-error=/var/log/mysqld.log pid-file=/var/run/mysqld/mysqld.pid
設定内容の妥当性を確認する stack_sizeはコネクションごとに確保される領域。バイナリパッケージの種類によっては変更できないものもあり、256K固定と考えて良さそう 64bitマシンの場合、以下の式が搭載メモリの8〜9割程度になるように(DB専用サーバでないなら7割程度にする) 32bitマシンの場合、以下の式が2GBに近いもしくは上回っていると危険(32bitマシンではソフトに割り当てられるメモリは2Gまでだから?)
innodb_buffer_pool_size + key_buffer_size + (max_connections * (sort_buffer_size + read_buffer_size + read_rnd_buffer_size)) + (max_connections * stack_size) 512M 8M 65 2M 128K 1M 65 256K 520M + ( 65 * 3.2M ) + 65 256K 520M + ( 65 * 3.2M ) + 17M 520M + 210M + 17M 747M
上の設定だと、最大747MのメモリがMySQLに割り当てられることになる スペック(メモリ)が変われば innodb_buffer_pool_size と innodb_log_file_size の値を変更し、それに合わせて max_connections も変更する 他の値も一通り見直す メモリ1Gのサーバなら、以下くらいに抑えてもいいかも?実験中
innodb_buffer_pool_size + key_buffer_size + (max_connections * (sort_buffer_size + read_buffer_size + read_rnd_buffer_size)) + (max_connections * stack_size) 300M 8M 30 2M 128K 1M 30 256K 310M + ( 30 * 3.2M ) + 30 256K 310M + ( 30 * 3.2M ) + 8M 310M + 96M + 8M 414M
MySQLからの結果によってページを出力する場合、Apache的に同時接続数80に耐えられたとしても max_connectionsが65なら同時接続数65までにしか対応できないので注意 MySQLのチューニング http://nohohonlab.exblog.jp/i2 一旦ApacheのMaxClientsと同じ値で良さそう その設定でメモリ不足になるなど問題があるようなら、ApacheのMaxClients側の値を減らす wait_timeoutも設定する?その場合、ApacheのTimeoutと同じ値でいい? チューニングではないが、以下の値も明示的に設定しておくといいかも? max_allowed_packet インポート時に「MySQL server has gone away」が発生したときの対処 http://company.nankikumano.jp/contents/tech_info/104/ ■設定変更時のエラー対策 MySQLのinnodb_log_file_sizeを設定して再起動(service mysqld restart)しようとするとエラーになる
# service mysqld restart mysqld を停止中: [ OK ] MySQL Daemon failed to start. mysqld を起動中: [失敗]
InnoDBは my.cnf で指定された innodb_log_file_size の値と実際のログファイルのサイズが異なるとエラーにするらしい ただし、そのファイルが存在しなかった場合は再作成してくれるらしい よって以下の手順で変更する
mysql> SET GLOBAL innodb_fast_shutdown=0; # service mysqld stop # mv /var/lib/mysql/ib_logfile* /tmp # vi /etc/my.cnf # service mysqld start
これなら大丈夫だった MySQLのinnodb_log_file_sizeを変更したらMySQLが起動しなくなった - /dev/null http://gitpub.hatenablog.com/entry/2013/08/02/001600 innodb_log_file_size のサイズを変更するには - Enjoi Blog http://blog.enjoitech.com/article/196
■ec2-bench
※未検証 ec2-benchを利用し、t2.microのインスタンスを同時に10インスタンス起動させ、 各WebサーバのPHPプログラムに対し、一斉にApache Benchを実行して計測を実施。 ※以下の条件は、全て1インスタンスあたりのもの。(x10インスタンスで同時にリクエスト) 条件:同時リクエスト数:10 全リクエスト数:200 instance_type="t2.micro" instance_count="10" request_number="200" client_number="10" 結果:CPU使用率:90% ディスクスワップ:秒間約2.3MByte程度のスワップが発生。 条件:同時リクエスト数:5 全リクエスト数:200 instance_type="t2.micro" instance_count="10" request_number="200" client_number="5" 結果:CPU使用率:75% ディスクスワップ:部分的に、秒間30kbyte程度のスワップが発生。 所見:瞬間同時アクセス数が100になると、Apacheの起動中プロセスだけでは追いつかず、 新たなプロセスの追加起動が必要な分、一気にディスクスワップが発生してしまい、 CPU使用率が90%を超えてしまうため少々危険。 ただし同時アクセス50の場合は、ある程度落ち着いており、 計測中のブラウザアクセスでも、体感的な表示の遅延がないことから、 サーバダウンの心配はないと考えられる。 ※上記結果は全て、ロードバランサを通していない1インスタンスでのものなので、実運用においてはほぼ問題ない。 以上のことから、インスタンスタイプを保険でt2.smallにしておくことで、 問題無くサーバダウンの回避は可能だと判断できる。 Amazon EC2 を使った負荷テストツール "ec2-bench" を作りました http://blog.manabusakai.com/2014/07/ec2-bench/
■動作確認
ひととおりの設定が終わったら、実際のコンテンツもしくは実際のコンテンツに近いものを設置する データベースにはダミーデータを大量に登録するなど、実際のものに近づける その上で、ロードインパクトや外部サーバからのabツールで実際に攻撃してみて、問題ない範囲を探る ・1ヶ月あたりもしくは1日あたりどれくらいのPVに耐えられるか? ・1秒間にどれくらいのアクセスに耐えられるか? 負荷テストについては Test.txt を参照
■参考
秒間100万クエリ・8万リクエストの「グラブル」安定稼働を支える、Cygames「3つの取り組み」【デブサミ2017】 (1/2):CodeZine(コードジン) https://codezine.jp/article/detail/10044 秒間100万クエリを受け付ける大規模ソーシャルゲームのバックエンドDBシステムの設計・運用ノウハウ // Speaker Deck https://speakerdeck.com/cygames/miao-jian-100mo-kueriwoshou-kefu-keruda-gui-mo-sosiyarugemufalsebatu... モンストを支えるインフラの今とこれから // Speaker Deck https://speakerdeck.com/isaoshimizu/monsutowozhi-eruinhurafalsejin-tokorekara ドラゴンクエストXは「世界は一つ」を実現するためにどのようなサーバ構成にしているのか? - GIGAZINE http://gigazine.net/news/20120824-dragonquest-backstage-cedec2012/ Nianticの求人から推測する『Pokemon GO(ポケモンGO)』のサーバ構成 - Qiita https://qiita.com/shibacow/items/1ac6f65100252b78a707 Amazon AWSでユーザ数1100万以上にスケーリングするためのビギナーズ・ガイド | POSTD https://postd.cc/a-beginners-guide-to-scaling-to-11-million-users-on-amazons/ Amazon CloudFront の デフォルト上限値が更に大幅にアップしました!(2016秋) | Developers.IO https://dev.classmethod.jp/cloud/aws/cloudfront-limit-update-201610/ MySQLのメモリー使用量を最適化する設定のベストプラクティス | Yakst https://yakst.com/ja/posts/3983

Advertisement