web-dev-qa-db-ja.com

Mysql 5.7.23からMysql 8.0への移行による極端なパフォーマンスの損失(ステータス、構成を含む)

これに12時間まっすぐ座っていた(今は正午なので、また目が覚めたら読みます/返信します)。
パフォーマンスを向上させるために、私たちの生産的な環境のデータベースのアップグレードを推奨するという大きな誤りを犯しました。
戻ることはできません。6テラバイト近くのストレージであり、mysql 8.0ではダウングレードできません。
また、アップグレード前のスナップショットバックアップを使用することは、解決策ではありません(作業日数)。

サーバーを最新バージョンに切り替えたことによる恐ろしいパフォーマンスを解決したい

いくつかの詳細:
環境:AWS i3.8xlarge上のLinux Stretch(32 CPU、240GB RAM)
Server:バインドマウントとホストネットワークを使用したmysql/Dockerコンテナー内のMysql 8.0
ストレージ:20,000 IOPSが予約されたAmazon AWS EBS IO1ストレージ(6 TB)。
ストレージは、fioテストで500mb /秒〜600mb /秒を提供します。
CPU:通常、32コアは50-60%使用されますが、mysql 8.0以降はアイドル状態です(10-15%使用)
[〜#〜] ram [〜#〜]:200GBはmysql専用で、8.0より前はそれほど長くはかかりませんでした中古。現在、mysqlがバッファを満たすことができるまでには何時間もかかります。

コアの問題:速度は5.7と比較して約20倍低下しました
Innodb/mysqlはディスクを効率的に使用していません。
元の構成を使用して15 mb /秒で読み取っていました(IBDファイルが正しく読み取られなかったため、単純なカウントの実行には数分かかりました)
それ以降、パフォーマンススキーマを無効にしました。これにより、少なくともサーバーを10%の負荷で再び動作させることができました。
ビンのログを無効にしました。多分、それはもう少し助けになりました、確かではありません。
読み取り/書き込みスレッドを64に増やしました(サーバーが完全に停止しました)。

私はmysqlの設定を調整するために8時間を費やしましたが、mysqlを5mb/secだけから現在は50mb/secまで「プッシュ」することができました。

確認するには:
もちろん、ディスクをテストしましたIO Dockerの内側から、それは外側とまったく同じです。
メインディスクはほとんどアイドル状態で、他のディスクは完全にアイドル状態です。
システムは、占有される必要があるときに90%アイドル状態です。

Innodbステータス:
https://Pastebin.com/XDgyNbk

MySQL設定:

[mysqld]
user=mysql
pid-file        = /var/run/mysqld/mysqld.pid
socket          = /var/run/mysqld/mysqld.sock
datadir         = /var/lib/mysql

tmpdir          = /mysql_tmp  

# compatibility
default_authentication_plugin=mysql_native_password
character_set_server=latin1
collation_server=latin1_swedish_ci



log-error       = /var/log/mysql_error.log
bind-address    = 0.0.0.0
sql_mode= "NO_ENGINE_SUBSTITUTION"

interactive_timeout     = 3600
wait_timeout            = 900

max_allowed_packet      = 64M
thread_stack            = 256K
thread_cache_size       = 192

max_connections         = 1600
max_user_connections    = 1500

#query_cache_limit       = 3M
#query_cache_size        = 200M
#query_cache_type       = 1
table_open_cache        = 2500


key_buffer_size          = 64M   # index in memory for myisam
innodb_buffer_pool_size = 190G
innodb_log_file_size = 256M
tmp_table_size = 250M
max_heap_table_size = 250M
join_buffer_size = 2M
#pagecleaners  - those were uncommented on 5.7
#innodb_buffer_pool_instances=8
#innodb_page_cleaners=2
innodb_io_capacity=5000
innodb_io_capacity_max=20000

# tried 64, that totally stalled the database
innodb_read_io_threads = 8
innodb_write_io_threads = 8

#in pre 5.7 times I had consistent 300mb/sec writes, now it's useless
innodb_lru_scan_depth=256

skip-name-resolve

secure_file_priv=""
#innodb_checksum_algorithm = crc32
#binlog_checksum = CRC32

# this one at least made it possible so I can go to bed, with performance_schema the database was unuseable    
performance_schema=OFF
skip-log-bin 

Sysctl fs

fs.aio-max-nr = 1048576
fs.aio-nr = 139264
fs.binfmt_misc.status = enabled
fs.dentry-state = 355223        335269  45      0       0       0
fs.dir-notify-enable = 1
fs.epoll.max_user_watches = 51660308
fs.file-max = 25224638
fs.file-nr = 19136      0       25224638
fs.inode-nr = 70145     5686
fs.inode-state = 70145  5686    0       0       0       0       0
fs.inotify.max_queued_events = 16384
fs.inotify.max_user_instances = 128
fs.inotify.max_user_watches = 8192
fs.lease-break-time = 45
fs.leases-enable = 1
fs.mqueue.msg_default = 10
fs.mqueue.msg_max = 10
fs.mqueue.msgsize_default = 8192
fs.mqueue.msgsize_max = 8192
fs.mqueue.queues_max = 256
fs.nr_open = 1048576
fs.overflowgid = 65534
fs.overflowuid = 65534
fs.pipe-max-size = 1048576
fs.protected_hardlinks = 1
fs.protected_symlinks = 1
fs.quota.allocated_dquots = 0
fs.quota.cache_hits = 0
fs.quota.drops = 0
fs.quota.free_dquots = 0
fs.quota.lookups = 0
fs.quota.reads = 0
fs.quota.syncs = 62
fs.quota.warnings = 1
fs.quota.writes = 0
fs.suid_dumpable = 0

iostatスナップショット:

avg-cpu:  %user   %Nice %system %iowait  %steal   %idle
          13.86    0.71   10.84    3.23    0.11   71.26

Device:            tps    kB_read/s    kB_wrtn/s    kB_read    kB_wrtn
xvdh           1795.31     13923.89     26159.95  256609017  482112504

ご覧のとおり、14mb /秒で読み取り、26mb /秒で書き込みを行っています。
mysql 5.7では、最大200MBの読み取りと書き込みを実行していました。

ディスクは基本的にアイドルです。 10倍のパフォーマンスを提供できますが、不明な理由により、innodb/mysqlはもう実行していません。

更新:変数とグローバルステータス: https://Pastebin.com/pzhXV7hq
https://Pastebin.com/jBTYLbY6

私が強制された別の変更:
Apache/phpを介して1秒あたり100人のユーザーが接続しているため、すべての接続で通常「SELECT count(*)FROM information_schema.processlist」がトリガーされました。これらの選択の代わりに、代わりに、5秒ごとにプロセスリストをinnodbテーブルに挿入する非同期タスクを作成しました。
これは、新しいmysqlの反応がいかに低いかを示すもう1つの兆候であり、プロセスリストによってさえ詰まっています。

ulimit

   core file size          (blocks, -c) 0
    data seg size           (kbytes, -d) unlimited
    scheduling priority             (-e) 0
    file size               (blocks, -f) unlimited
    pending signals                 (-i) 985342
    max locked memory       (kbytes, -l) 64
    max memory size         (kbytes, -m) unlimited
    open files                      (-n) 65536
    pipe size            (512 bytes, -p) 8
    POSIX message queues     (bytes, -q) 819200
    real-time priority              (-r) 0
    stack size              (kbytes, -s) 8192
    cpu time               (seconds, -t) unlimited
    max user processes              (-u) 985342
    virtual memory          (kbytes, -v) unlimited
    file locks                      (-x) unlimited

大きなアップデート
あなたの提案を考慮し、IRCで私に言われたことを考慮して、半日かけて内部を読みました。
私は専門家の反対をしました:私は一度に10の変更を行いました、私は段階的な変更プロセスでそれほど多くの再起動をする余裕がありません:
1)チョークせずにシステムに多くの並列書き込みの機会を与える

innodb_read_io_threads = 16  
innodb_write_io_threads = 16  
innodb_thread_concurrency=64  # cpus*2  

2)バックグラウンド同期の高速化:

 innodb_lru_scan_depth=100  

3)パフォーマンスに大きな影響を与える最高の信頼性設定を無効にする

performance_schema=OFF
skip-log-bin 
sync_binlog=0 
innodb_flush_log_at_trx_commit=0  # not crash safe, 0 is crash safe  

4)バックエンドメモリのマルチスレッド化

innodb_buffer_pool_instances=12  

5)ログファイルを大幅に増やし、ログファイルバッファを適度に増やします

innodb_log_file_size = 3G # 
innodb_log_buffer_size = 64M

何が起こったのか:読み取りパフォーマンスが約10倍、書き込みパフォーマンスが1.5倍になりました。私が望んでいるところではありませんが、以前より15倍高速です。 !
IOPSの使用量が〜5-6kから9k-12kに倍増したため、60%に達しましたIO usage
CPU使用率が7%から50%に増加

私の目標は80%ですIOおよびデータベースによるCPU使用率、他の変数がボトルネックになっていると思います。

リアルタイムでの使用:変更の前後に(通常のロードの横に)巨大な挿入を実行しています。
変更前の速度は約3000行/秒でしたが、上記の変更後は8000行/秒です。

これは、パフォーマンスの変化が極端であり、可能なことの50%にしか達していないためです。

更新
問題は半分解決されたと見なすことができると思います。前回成功したものの後に別の更新を行い、パフォーマンスは現在許容範囲です。

最後の変更には、書き込み/読み取りスレッドが含まれていました。私はそれらをそれぞれ32個に入れました。
書き込みバッファが128Mに増加しました(私の重いワークロードの場合、高い方が良い場合があります)
ログファイルが8GBに増加
メモリの断片化を改善するために、buffer_pool_instancesを64(最大)に増加
page_cleanersは64(最大)に増加し、各バッファーインスタンスに1つを持ちます。

書き込みパフォーマンスがさらに約20%向上し、読み取りパフォーマンスがさらに約30%向上しました。

Mysqlのパフォーマンスを許容範囲内に収めるために24時間かかりましたが、単純なアップグレードではありません。

最新のステータス:

Current configuration: https://Pastebin.com/9vsbEQxt
show engine status innodb: https://Pastebin.com/kCjnmtze
show global variables: https://Pastebin.com/aMdQxWcA
global status: https://Pastebin.com/VbG1yzHX
4
John

GLOBAL STATUSおよびVARIABLESのレビュー

観察:

  • バージョン:8.0.13
  • 240 GBのRAM
  • 稼働時間= 10:47:09;一部のGLOBAL STATUS値は、まだ意味がない場合があります。
  • Windowsで実行していません。
  • 64ビットバージョンの実行
  • 完全に(またはほとんど)InnoDBを実行しているようです。

より重要な問題:

table_open_cacheは高いですが、さらに上げるとよいでしょう。 table_open_cache_instancesを32に上げることも役立つ場合があります。

innodb_buffer_pool_instances = 16; innodb_page_cleanersの同上。

innodb_log_file_sizeを8Gに増やします。これを達成する方法の詳細については、8.0マニュアルを参照してください(変更されました)。

なぜあなたはinnodb_flush_method = fsyncを持っているのですか? O_DIRECTは多くの状況で推奨されます。

縮小long_quer_time;スローログを確認してください。調査する必要があるいたずらなクエリがいくつかあります。

CREATE TABLE 5秒ごと?何が起こっている? dayごとに数回以上行うのは珍しいことです。

REPLACEのほとんどはIODKUに取って代わられました。あなたのユースケースは何ですか?

さまざまなSHOWコマンドを頻繁に使用しています。それらの実装は8.0で大幅に変更されており、8.0ではより高速になると予想しますが、これがスローダウンの原因の1つになる可能性があります。

1分あたり10 TRUNCATE TABLE?調子はどう?テーブルの内容を置き換える場合は、通常新しいテーブルを作成してデータを入力し、RENAME TABLEを使用してアトミックにそれを所定の位置に入れ替えます。

詳細およびその他の観察:

( Innodb_buffer_pool_pages_flushed ) = 96,254,291 / 38829 = 2478 /sec-書き込み(フラッシュ)

( Opened_tables ) = 104,524 / 38829 = 2.7 /sec-テーブルを開く頻度-table_open_cacheを増やす

( table_open_cache ) = 19,000-キャッシュするテーブル記述子の数-通常は数百が適切です。

( Table_open_cache_misses ) = 104,520 / 38829 = 2.7 /sec-table_open_cacheを増やす必要があるかもしれません

( innodb_buffer_pool_size / innodb_buffer_pool_instances ) = 181248M / 8 = 22656MB-各buffer_poolインスタンスのサイズ。 -インスタンスは少なくとも1GBである必要があります。非常に大きなRAMには、16個のインスタンスがあります。

( innodb_page_cleaners / innodb_buffer_pool_instances ) = 4 / 8 = 0.5-page_cleaners-innodb_page_cleanersをinnodb_buffer_pool_instancesに設定することをお勧めします

( (Innodb_buffer_pool_reads + Innodb_buffer_pool_pages_flushed) ) = ((23804167 + 96254291) ) / 38829 = 3091 /sec-InnoDB I/O

( Innodb_os_log_written ) = 249,997,739,520 / 38829 = 6438428 /sec-これは、InnoDBのビジー状態の指標です。

( Innodb_log_writes ) = 411,565,494 / 38829 = 10599 /sec

( Innodb_os_log_written / (Uptime / 3600) / innodb_log_files_in_group / innodb_log_file_size ) = 249,997,739,520 / (38829 / 3600) / 2 / 256M = 43.2-比率-(分を参照)

( Uptime / 60 * innodb_log_file_size / Innodb_os_log_written ) = 38,829 / 60 * 256M / 249997739520 = 0.695-InnoDBログローテーション間の分5.6.8以降、これは動的に変更できます。 my.cnfも必ず変更してください。 -(ローテーション間の60分の推奨はやや恣意的です。)innodb_log_file_sizeを調整します。 (AWSでは変更できません。)

( innodb_flush_method ) = innodb_flush_method = fsync-InnoDBがOSにブロックの書き込みを要求する方法。ダブルバッファリングを回避するには、O_DIRECTまたはO_ALL_DIRECT(Percona)を推奨します。 (少なくともUnixの場合。)O_ALL_DIRECTに関する警告については、chrischandlerを参照してください。

( Innodb_row_lock_waits ) = 41,325 / 38829 = 1.1 /sec-行ロックの取得に遅延が発生する頻度。 -最適化できる複雑なクエリが原因である可能性があります。

( Innodb_dblwr_writes ) = 1,177,834 / 38829 = 30 /sec-「ダブルライトバッファ」はディスクに書き込みます。 「ダブルライト」は信頼性の高い機能です。新しいバージョン/構成の中には、それらを必要としないものがあります。 -(その他の問題の症状)

( Innodb_row_lock_current_waits ) = 54-InnoDBテーブルに対する操作によって現在待機されている行ロックの数。ゼロはかなり正常です。 -何か大きなことが起こっていますか?

( innodb_print_all_deadlocks ) = innodb_print_all_deadlocks = OFF-すべてのデッドロックをログに記録するかどうか。 -デッドロックに悩まされている場合は、これをオンにします。注意:デッドロックが多数ある場合、ディスクに大量に書き込まれる可能性があります。

( Queries ) = 146,600,019 / 38829 = 3775 /sec-クエリ(SP内を含む)

( Created_tmp_tables ) = 43,466,450 / 38829 = 1119 /sec-複雑なSELECTの一部として「temp」テーブルを作成する頻度。

( Created_tmp_disk_tables ) = 69,721 / 38829 = 1.8 /sec-複雑なSELECTの一部としてdisk "temp"テーブルを作成する頻度-tmp_table_sizeとmax_heap_table_sizeを増やします。 MyISAMの代わりにMEMORYを使用する場合の一時テーブルのルールを確認してください。おそらく、マイナーなスキーマまたはクエリの変更により、MyISAMを回避できます。インデックスの改善とクエリの再構成が役立つ可能性が高くなります。

( Select_full_join ) = 341,473 / 38829 = 8.8 /sec-インデックスなしの結合-JOINで使用されるテーブルに適切なインデックスを追加します。

( Select_scan ) = 20,070,358 / 38829 = 516 /sec-テーブル全体のスキャン-インデックスを追加する/クエリを最適化する(小さなテーブルでない限り)

( Select_scan / Com_select ) = 20,070,358 / 46219009 = 43.4%-全表スキャンを実行する選択の%。 (ストアドルーチンにだまされる可能性があります。)-インデックスを追加する/クエリを最適化する

( Com_insert + Com_delete + Com_delete_multi + Com_replace + Com_update + Com_update_multi ) = (1395278 + 512340 + 0 + 1843851 + 14825066 + 9554) / 38829 = 478 /sec-書き込み/秒-50書き込み/秒+ログのフラッシュにより、通常のドライブのI/O書き込み容量が最大になります

( Com_replace ) = 1,843,851 / 38829 = 47 /sec-INSERT ... ON DUPLICATE KEY UPDATEに変更することを検討してください。

( expire_logs_days ) = 0-binlogを自動的にパージするまでの時間(この日数が経過した後)-大きすぎる(またはゼロ)=ディスク領域を消費します。小さすぎる=ネットワーク/マシンのクラッシュに迅速に対応する必要がある(log_bin = OFFの場合は関係ありません)

( slave_pending_jobs_size_max / max_allowed_packet ) = 128M / 64M = 2-並列スレーブスレッドの場合-slave_pending_jobs_size_maxはmax_allowed_pa​​cket未満であってはなりません

( long_query_time ) = 10-「遅い」クエリを定義するためのカットオフ(秒)。 -提案2

( back_log / max_connections ) = 1,600 / 1600 = 100.0%

( Connections ) = 1,054,868 / 38829 = 27 /sec-接続-wait_timeoutを増やします。プーリングを使用しますか?

( thread_cache_size ) = 192-保持する余分なプロセスの数(スレッドプーリングを使用する場合は関係ありません)(5.6.8以降で自動サイズ設定、max_connectionsに基づく)

異常に大きい:

Bytes_received = 1583925 /sec
Com_begin = 11 /sec
Com_create_db = 0.093 /HR
Com_create_function = 4.1 /HR
Com_create_procedure = 0.37 /HR
Com_create_table = 0.21 /sec
Com_delete = 13 /sec
Com_drop_procedure = 0.37 /HR
Com_insert_select = 29 /sec
Com_insert_select + Com_replace_select = 75 /sec
Com_kill = 0.74 /HR
Com_replace_select = 47 /sec
Com_show_create_db = 2.2 /HR
Com_show_create_trigger = 0.28 /HR
Com_show_events = 0.74 /HR
Com_show_storage_engines = 0.93 /HR
Com_show_warnings = 16 /HR
Com_stmt_close = 919 /sec
Com_stmt_execute = 919 /sec
Com_stmt_prepare = 919 /sec
Com_truncate = 0.16 /sec
Com_update = 381 /sec
Com_update_multi = 0.25 /sec
Handler_commit = 1638 /sec
Handler_delete = 60 /sec
Handler_external_lock = 5083 /sec
Handler_read_key = 58652 /sec
Handler_read_next = 607861 /sec
Handler_update = 40571 /sec
Innodb_buffer_pool_bytes_dirty = 1,309.3MB
Innodb_buffer_pool_pages_data = 1.18e+7
Innodb_buffer_pool_pages_dirty = 83,894
Innodb_buffer_pool_pages_flushed / max(Questions, Queries) = 0.657
Innodb_buffer_pool_pages_misc = 664,249
Innodb_buffer_pool_pages_total = 1.25e+7
Innodb_data_fsyncs = 232 /sec
Innodb_data_pending_fsyncs = 0.46 /HR
Innodb_data_read = 12400226 /sec
Innodb_data_reads = 770 /sec
Innodb_data_writes = 13131 /sec
Innodb_data_written = 88604121 /sec
Innodb_dblwr_pages_written = 2476 /sec
Innodb_dblwr_pages_written / Innodb_dblwr_writes = 81.6
Innodb_log_write_requests = 10906 /sec
Innodb_os_log_fsyncs = 87 /sec
Innodb_os_log_written / (Uptime / 3600) / innodb_log_files_in_group = 11,052.3MB
Innodb_pages_created = 57 /sec
Innodb_pages_written = 2478 /sec
Innodb_rows_deleted = 60 /sec
Innodb_rows_deleted + Innodb_rows_inserted = 658 /sec
Innodb_rows_inserted = 598 /sec
Innodb_rows_updated = 520 /sec
Max_execution_time_set = 0.0MB
Max_used_connections = 768
Select_range = 1250 /sec
Select_range / Com_select = 105.0%
Sort_range = 274 /sec
Sort_scan = 509 /sec
Table_open_cache_hits = 3826 /sec
Threads_cached = 142
Threads_connected = 366
back_log = 1,600
innodb_io_capacity_max = 20,000
innodb_max_dirty_pages_pct_lwm = 1000.0%
innodb_undo_tablespaces = 2
max_error_count = 1,024
max_length_for_sort_data = 4,096
max_user_connections = 1,500
optimizer_trace_max_mem_size = 1.05e+6
slave_pending_jobs_size_max = 128MB

異常な文字列:

bind_address = 0.0.0.0
event_scheduler = ON
explicit_defaults_for_timestamp = ON
have_query_cache = NO
have_ssl = YES
have_symlink = DISABLED
innodb_buffer_pool_dump_at_shutdown = ON
innodb_buffer_pool_load_at_startup = ON
innodb_fast_shutdown = 1
innodb_undo_directory = ./
innodb_undo_log_truncate = ON
master_info_repository = TABLE
optimizer_trace = enabled=off,one_line=off
optimizer_trace_features = greedy_search=on, range_optimizer=on, dynamic_range=on, repeated_subselect=on
relay_log_info_repository = TABLE
slave_rows_search_algorithms = INDEX_SCAN,HASH_SCAN
ssl_ca = ca.pem
ssl_cert = server-cert.pem
ssl_key = server-key.pem
transaction_write_set_extraction = XXHASH64
3
Rick James
UPDATE  task_s_b SET result_delivered=1, result_data='DISABLED',
        result_gathered=1
    WHERE  result_data is NULL
      AND  (assigned_counter >= 4
              OR  c_counter > 2
           ) 

そのテーブルの値の分布に応じて、このクエリmayは問題を引き起こしています。

2つのクエリとして書き直すことを検討してください。

UPDATE  task_s_b SET result_delivered=1, result_data='DISABLED',
        result_gathered=1
    WHERE  result_data is NULL
      AND  assigned_counter >= 4;
UPDATE  task_s_b SET result_delivered=1, result_data='DISABLED',
        result_gathered=1
    WHERE  result_data is NULL
      AND  c_counter > 2;

そして、これらの2つの複合インデックスを指定された順序で列に追加します。

INDEX(result_data, assigned_counter)
INDEX(result_data, c_counter)

詳細については、SHOW CREATE TABLEおよびSHOW TABLE STATUSそのテーブル。

これはmayデッドロックを減らし、サーバーを高速化します。

0
Rick James

現時点で利用可能なデータに基づく即時救済のためのサービスの停止/開始なしで検討すべき提案1月22日19日15:00 CT USA

SET GLOBAL innodb_io_capacity=10000        from your 5000 limit at this time
SET GLOBAL innodb_lru_scan_depth=100        from your 256 to reduce CPU cycles used for this function by 60% EVERY SECOND

SHOW GLOBAL VARIABLESの投稿後;分析が完了すると、さらに提案が表示されます。

0
Wilson Hauck