私たちはWebアプリケーションのバックエンドとしてInnoDBテーブルを使用しており、数週間前にMySQLを再起動する必要があるまで、約2年間はすべてが順調でした。 (実際には使用していませんが、DNSの逆引き参照を無効にしていませんでしたが、ホスティングシステムはそれらの要求への応答を突然停止しました。現在は無効になっています。)残念ながら、構成ファイルが変更されたため、比較のために元の状態のコピーを用意します。
最も重大な問題を修正した後は、本当の謎が残ります。高負荷のもとでは、データベースクエリは通常よりもかなり長くかかり始めます。その間、7台のApacheサーバーから数百のオープン接続があります。 SHOW PROCESSLISTを実行すると、これらの接続の半分以上が「データの送信」状態にあり、多くの場合数百秒の時間がかかります。クエリのほとんどすべてがSELECTであり、同様のクエリがまとまってしまう傾向があります。実際、リストの最も低いクランプはまったく同じクエリになる傾向があり(クエリキャッシュにあると思います)、それぞれ2つの整数の1104行を返します。他のよくある違反者は、数百の単一整数行、いくつかの単一整数行、または単一のCOUNT(*)結果のリストです。
これらのいずれかの期間中にWebサーバーのシャットダウンを試みましたが、問題はWebサーバーを再起動してから1分以内に戻りました。ただし、mysqldを完全に再起動すると、問題は翌日まで解決しました。問題は何であり、どのように検証および/または修正できますか?
これは、 innodb_file_per_table
、default-storage-engine = innodb
、および一時テーブルを作成する頻繁にアクセスされるページの組み合わせの欠陥であることが判明しました。接続が閉じるたびに、テーブル バッファプールLRUからページを破棄 が削除されます。これにより、サーバーは少しの間停止しますが、実際に問題を引き起こしていたクエリでは決して停止しません。
さらに悪いことに、まったく関係のない理由でサーバーを再起動する前に、innodb_file_per_table
設定がmy.cnf
ファイルで何ヶ月もの間問題を抱えていました。その間、一時テーブルを問題なく使用していました。 (NOCが突然DNSサーバーを停止し、skip-name-resolve
を有効にしていないため、すべての新しい接続がハングし、何時間も変更されたことを認めません。)
幸い、問題のあるページを書き換えて、より高速なクエリのセットを使用して、ほとんどの作業をフロントエンドWebサーバーにロードでき、それ以来問題は発生していません。
まあ、よく思い出すと(DBで作業してからしばらく経っています)、innodbテーブルでWHERE句を指定しないCOUNT(*)クエリは、MyISAMテーブルやメモリテーブルよりも遅くなることで有名です。
また、これは偶然Xen DomUですか?
フロントエンド言語とは何ですか? PHPの場合、MySQLまたはMySQLiを使用していますか?彼らは永続的な接続を使用していますか?
基盤となるオペレーティングシステムについては言及していませんが、Linuxの場合は、最初に_free -m
_の出力を確認し、最後の2行に特別な注意を払って、メモリが全体的にタイトかどうかを確認します。
_[0:504] callisto:cyanotype $ free -m
total used free shared buffers cached
Mem: 3961 3816 144 0 184 1454
-/+ buffers/cache: 2177 1784
Swap: 2898 0 2898
_
ここに、正常なシステムがあります(これは私のワークステーションです)。 2列目はバッファーとキャッシュを除外しているため、実際には2177MBのメモリーを使用しており、1784メガバイトをすぐに使用できます。
最後の行は、今のところswapをまったく使用していないことを示しています。
次に、vmstat(8)
を指定して、システムが狂ったように破壊されているかどうかを確認することも役立ちます。
_[0:505] callisto:cyanotype $ vmstat 5 10
procs -----------memory---------- ---swap-- -----io---- -system-- ----cpu----
r b swpd free buff cache si so bi bo in cs us sy id wa
0 0 0 134116 189828 1499948 0 0 11 3 44 49 1 1 98 0
0 0 0 143112 189836 1489688 0 0 0 6 526 2177 1 1 98 0
0 0 0 139268 190504 1491864 0 0 512 4 663 4704 2 1 96 1
2 0 0 136688 191084 1493484 0 0 473 5 641 3039 1 1 97 1
0 0 0 52636 191712 1518620 0 0 5066 4 1321 6600 8 2 86 4
5 0 0 72992 193264 1377324 0 0 10742 31 1602 7441 12 3 80 5
2 1 0 84036 193896 1202012 0 0 10126 43 2621 4305 31 2 57 10
3 0 0 42456 195812 1060904 0 0 3970 75 55327 9806 43 5 41 10
8 1 0 34620 197040 942940 0 0 3554 64 50892 12531 43 6 44 6
^C
[0:506] callisto:cyanotype $
_
(私のデスクトップでは、ここではそれほど多くのことを実行していません。申し訳ありません。8個の完全に優れたコアの無駄遣いです。)
「b」列に多くの時間を費やしているプロセスがある場合、それらはブロックされ、何かを待っていることを意味します。多くの場合、それはIOです。ここで重要な列はsi
とso
です。それらに高い値が入力されているかどうかを確認します。もしそうなら、これはあなたの問題かもしれません-何かが実際に努力することができるよりも多くのメモリを消費しています。 top(4)
を使用してメモリ%で列を並べ替えると(先頭がShift + m)、原因が表示される場合があります。
システムがスワップに対してゴミを出し、ディスクを飽和させ、スレッドとプロセスをブロックすることは不可能ではありません。ツールiostat(8)
(パッケージの一部sysstat
)には通常、旋回して、ブロックされているプロセスがIO_WAITでスタックしていることを確認します。飽和したディスクは、特にシステムが頻繁にスワップしている場合、高負荷のもとでシステム全体に悪いニュースをもたらす可能性があります。
たとえば、5秒ごとに拡張統計を使用してiostatを実行します。
_[0:508] callisto:cyanotype $ iostat -x 5
Linux 2.6.35-23-generic (callisto) 2010-11-30 _x86_64_ (8 CPU)
avg-cpu: %user %Nice %system %iowait %steal %idle
16,55 0,12 2,70 2,60 0,00 78,02
Device: rrqm/s wrqm/s r/s w/s rsec/s wsec/s avgrq-sz avgqu-sz await svctm %util
sdc 0,00 2,00 1,00 0,80 27,20 22,40 27,56 0,01 3,33 3,33 0,60
sdd 0,00 12,60 67,60 4,80 4222,40 139,20 60,24 0,62 8,62 3,29 23,80
sde 0,00 0,00 0,00 0,00 0,00 0,00 0,00 0,00 0,00 0,00 0,00
sdf 0,00 0,00 0,00 0,00 0,00 0,00 0,00 0,00 0,00 0,00 0,00
avg-cpu: %user %Nice %system %iowait %steal %idle
32,02 0,10 1,83 0,44 0,00 65,61
Device: rrqm/s wrqm/s r/s w/s rsec/s wsec/s avgrq-sz avgqu-sz await svctm %util
sdc 0,60 3,20 11,00 0,80 265,60 32,00 25,22 0,05 3,90 2,88 3,40
sdd 0,00 8,20 0,00 3,00 0,00 89,60 29,87 0,02 8,00 7,33 2,20
sde 0,00 0,00 0,00 0,00 0,00 0,00 0,00 0,00 0,00 0,00 0,00
sdf 0,00 0,00 0,00 0,00 0,00 0,00 0,00 0,00 0,00 0,00 0,00
avg-cpu: %user %Nice %system %iowait %steal %idle
49,26 0,22 3,12 0,12 0,00 47,28
Device: rrqm/s wrqm/s r/s w/s rsec/s wsec/s avgrq-sz avgqu-sz await svctm %util
sdc 6,20 3,00 7,40 3,80 208,00 54,40 23,43 0,09 7,86 2,50 2,80
sdd 0,00 15,20 0,20 4,00 1,60 152,00 36,57 0,03 6,67 6,19 2,60
sde 0,00 0,00 0,00 0,00 0,00 0,00 0,00 0,00 0,00 0,00 0,00
sdf 0,00 0,00 0,00 0,00 0,00 0,00 0,00 0,00 0,00 0,00 0,00
avg-cpu: %user %Nice %system %iowait %steal %idle
16,00 0,54 1,05 1,07 0,00 81,35
Device: rrqm/s wrqm/s r/s w/s rsec/s wsec/s avgrq-sz avgqu-sz await svctm %util
sdc 4,20 0,00 31,40 0,00 3204,80 0,00 102,06 0,17 4,90 2,68 8,40
sdd 0,00 28,20 0,20 2,60 1,60 246,40 88,57 0,02 7,14 7,14 2,00
sde 0,00 0,00 0,00 0,00 0,00 0,00 0,00 0,00 0,00 0,00 0,00
sdf 0,00 0,00 0,00 0,00 0,00 0,00 0,00 0,00 0,00 0,00 0,00
^C
_
これにより、ボリュームが飽和しているかどうかを簡単に確認できます。たとえば、ここでは、ディスクの使用率が非常に低いこと、システムがCPUサイクルのほとんどをアイドリングなどに費やしていることなどがわかります。その割合が主に%IOWAIT列にある場合、IOここにボトルネックがあります。おそらくこれをすべて知っていますが、確認のためにすべての基礎をカバーしています。
アイデアはあなたの設定ファイルが変更され、それの履歴がないことです(バージョン管理下に設定ファイルを置くことはまさにその理由のために素晴らしいアイデアです)-そして突然変更されたバッファのサイズが不可能になることは不可能ではないので高価になりますSELECTを使用しないCOUNT(*)のようなクエリは、突然リソースを奪い始めます。
ツールの以前の使用法から学んだことを踏まえて、構成ファイル(変更された唯一のものであり、原因である可能性が高い)を調べて、バッファーの値が平均的な負荷に対して正気であるかどうかを確認する必要があります。
_query_cache_size
_の値、特に_sort_buffer
_のサイズなど、バッファーの大きさはどれくらいですか? (それがメモリに収まらない場合、ディスク上で実行されますが、想像できると思いますが、莫大なコストがかかります)。
_innodb_buffer_pool_size
_の大きさは?
_table_cache
_の大きさはどのくらいですか。最も重要なのは、その値がファイルハンドルのシステム制限内に収まるかどうかです。 ([mysqld]とOSレベルの両方でopen-files-limit)。
また、これが真実であるかどうか頭から覚えていませんが、自動インクリメントフィールドをコミットする必要がある場合は常に、innodbが実際にテーブル全体をロックしていることは間違いありません。私はグーグルしました、そしてそれがまだ本当であるかどうかわかりませんでした。
また、innotop(1)
を使用して、何が起こっているかを詳細に確認することもできます。
これが何らかの形で役立つか、出発点になると思います:)