技術共有|MySQL:timestampタイムゾーン変換によるCPU%sys高の問題
作者:高鵬
文章の末尾には彼の著書「MySQL主従原理32講を深く理解する」があり、MySQL主従、GTIDに関する技術知識を深く理解している.本文は学習記録ですので、間違いがあるかもしれませんのでご了承ください.
この問題は友人が出会った@風雲であり、この友人はすでに正しい判断を得ており、以下にいくつかの説明を行う.
一、問題展示以下は問題当時のシステム負荷は以下の通りである.
40.4%syはシステム呼び出し負荷の高い表現であり、友人がperfを以下のように収集した.
次に友達がpstackを採集してくれたので、大量のスレッドが以下の状態にあることに気づきました.
注意してみましょうtz_convertこれはまさにタイムゾーン転換の証拠である.
二、timestampについてtimestamp:4バイトを占有し、内部実装は新紀元時間(1970-01-01 00:00:00)以来の秒であるため、このフォーマットはユーザーに示す際に必要なタイムゾーン変換をして正確なデータを得る必要がある.次にibdファイルにアクセスして内部表現方法を確認し、私の2つのツールinnodbとbcviewを使用しました.
詳細:https://www.jianshu.com/p/719....
timestampの内部表示テストテーブルの作成
内部表示を見てみましょう.
以下に整理します. 000001ac3502:rowid 000000070d52:trx id c80000002f0110:roll ptr 5 c 2 a 4 b 4 d:timestampタイプの実際のデータ十進法は154627561 です.
Linuxコマンドは次のとおりです.
私のLinuxもCST+8タイムゾーンなので、ここのデータもMySQLに表示されています.次にタイムゾーンを調整して、次の値を取ります.
ここで2時間減らしたのが見えます.私のタイムゾーンが+8から+6に変わったからです.
三、timestap変換
新紀元時刻(1970-01-01 00:00:00)以降の秒から実時刻への変換を行う場合MySQLはパラメータtime_zoneの設定には2つの選択肢があります. time_zoneがSYSTEMに設定されている場合:sys_を使用time_zoneが取得したOSセッションタイムゾーンは、OS APIを使用して変換されます.対応変換関数Time_zone_system::gmt_sec_to_TIME time_zoneが実際のタイムゾーンに設定されている場合:「+08:00」など、MySQL独自の方法で変換されます.対応変換関数Time_zone_offset::gmt_sec_to_TIME
実はTime_zone_システムとタイム_zone_offsetはすべてTime_に継承されますzoneクラス、そしてTime_を実現しましたzoneクラスの虚関数が書き換えられているので、上位呼び出しはすべてTime_zone::gmt_sec_to_TIME.
この変換操作は、各行の条件に合致するデータを変換する必要があることに注意してください.
四、問題の修復方案
問題スタックフレームから見ると、この障害はTime_を使用しています.zone_system::gmt_sec_to_TIME関数は変換されるので、次のように考えられます. time_zone:指定したタイムゾーンに設定します.たとえば、'+08:00'です.これにより、OS APIを用いて変換することなく、MySQL自身の内部実装呼び出しTime_に移行するzone_offset::gmt_sec_to_TIME関数.ただし、MySQL独自の実装を使用するとUS%が激化することに注意してください. はtimestampの代わりにdatetimeを使用し、新しいバージョンのdatetimeは5バイトで、timestampより1バイトしかありません.
五、修復前後
%syの使用量の比較友人によると、午前11時すぎに修正が完了したという.time_zoneを'+08:00'に変更し、修正前後のCPU使用率の比較を示します.
修復前:
修正後:
六、予備スタックフレーム time_zone=‘SYSTEM’変換スタックフレーム time_zone='+08:00'変換スタックフレーム
文章の末尾には彼の著書「MySQL主従原理32講を深く理解する」があり、MySQL主従、GTIDに関する技術知識を深く理解している.本文は学習記録ですので、間違いがあるかもしれませんのでご了承ください.
この問題は友人が出会った@風雲であり、この友人はすでに正しい判断を得ており、以下にいくつかの説明を行う.
一、問題展示以下は問題当時のシステム負荷は以下の通りである.
40.4%syはシステム呼び出し負荷の高い表現であり、友人がperfを以下のように収集した.
次に友達がpstackを採集してくれたので、大量のスレッドが以下の状態にあることに気づきました.
Thread 38 (Thread 0x7fe57a86f700 (LWP 67268)):
#0 0x0000003dee4f82ce in __lll_lock_wait_private () from /lib64/libc.so.6
#1 0x0000003dee49df8d in _L_lock_2163 () from /lib64/libc.so.6
#2 0x0000003dee49dd47 in __tz_convert () from /lib64/libc.so.6
#3 0x00000000007c02e7 in Time_zone_system::gmt_sec_to_TIME(st_mysql_time*, long) const ()
#4 0x0000000000811df6 in Field_timestampf::get_date_internal(st_mysql_time*) ()
#5 0x0000000000809ea9 in Field_temporal_with_date::val_date_temporal() ()
#6 0x00000000005f43cc in get_datetime_value(THD*, Item***, Item**, Item*, bool*) ()
#7 0x00000000005e7ba7 in Arg_comparator::compare_datetime() ()
#8 0x00000000005eef4e in Item_func_gt::val_int() ()
#9 0x00000000006fc6ab in evaluate_join_record(JOIN*, st_join_table*) ()
#10 0x0000000000700e7e in sub_select(JOIN*, st_join_table*, bool) ()
#11 0x00000000006fecc1 in JOIN::exec() ()
注意してみましょうtz_convertこれはまさにタイムゾーン転換の証拠である.
二、timestampについてtimestamp:4バイトを占有し、内部実装は新紀元時間(1970-01-01 00:00:00)以来の秒であるため、このフォーマットはユーザーに示す際に必要なタイムゾーン変換をして正確なデータを得る必要がある.次にibdファイルにアクセスして内部表現方法を確認し、私の2つのツールinnodbとbcviewを使用しました.
詳細:https://www.jianshu.com/p/719....
timestampの内部表示テストテーブルの作成
mysql> show variables like '%time_zone%';
+------------------+--------+
| Variable_name | Value |
+------------------+--------+
| system_time_zone | CST |
| time_zone | +08:00 |
+------------------+--------+
mysql> create table tmm(dt timestamp);
Query OK, 0 rows affected (0.04 sec)
mysql> insert into tmm values('2019-01-01 01:01:01');
Query OK, 1 row affected (0.00 sec)
内部表示を見てみましょう.
[root@gp1 test]# ./bcview tmm.ibd 16 125 25|grep 00000003
current block:00000003--Offset:00125--cnt bytes:25--data is:000001ac3502000000070d52c80000002f01105c2a4b4d0000
以下に整理します.
Linuxコマンドは次のとおりです.
[root@gp1 ~]# date -d @1546275661
Tue Jan 1 01:01:01 CST 2019
私のLinuxもCST+8タイムゾーンなので、ここのデータもMySQLに表示されています.次にタイムゾーンを調整して、次の値を取ります.
mysql> set time_zone='+06:00';
Query OK, 0 rows affected (0.00 sec)
mysql> select * from tmm;
+---------------------+
| dt |
+---------------------+
| 2018-12-31 23:01:01 |
+---------------------+
1 row in set (0.01 sec)
ここで2時間減らしたのが見えます.私のタイムゾーンが+8から+6に変わったからです.
三、timestap変換
新紀元時刻(1970-01-01 00:00:00)以降の秒から実時刻への変換を行う場合MySQLはパラメータtime_zoneの設定には2つの選択肢があります.
実はTime_zone_システムとタイム_zone_offsetはすべてTime_に継承されますzoneクラス、そしてTime_を実現しましたzoneクラスの虚関数が書き換えられているので、上位呼び出しはすべてTime_zone::gmt_sec_to_TIME.
この変換操作は、各行の条件に合致するデータを変換する必要があることに注意してください.
四、問題の修復方案
問題スタックフレームから見ると、この障害はTime_を使用しています.zone_system::gmt_sec_to_TIME関数は変換されるので、次のように考えられます.
五、修復前後
%syの使用量の比較友人によると、午前11時すぎに修正が完了したという.time_zoneを'+08:00'に変更し、修正前後のCPU使用率の比較を示します.
修復前:
修正後:
六、予備スタックフレーム
#0 Time_zone_system::gmt_sec_to_TIME (this=0x2e76948, tmp=0x7fffec0f3ff0, t=1546275661) at /root/mysqlall/percona-server-locks-detail-5.7.22/sql/tztime.cc:1092
#1 0x0000000000f6b65c in Time_zone::gmt_sec_to_TIME (this=0x2e76948, tmp=0x7fffec0f3ff0, tv=...) at /root/mysqlall/percona-server-locks-detail-5.7.22/sql/tztime.h:60
#2 0x0000000000f51643 in Field_timestampf::get_date_internal (this=0x7ffe7ca66540, ltime=0x7fffec0f3ff0)
at /root/mysqlall/percona-server-locks-detail-5.7.22/sql/field.cc:6014
#3 0x0000000000f4ff49 in Field_temporal_with_date::val_str (this=0x7ffe7ca66540, val_buffer=0x7fffec0f4370, val_ptr=0x7fffec0f4370)
at /root/mysqlall/percona-server-locks-detail-5.7.22/sql/field.cc:5429
#4 0x0000000000f11d7b in Field::val_str (this=0x7ffe7ca66540, str=0x7fffec0f4370) at /root/mysqlall/percona-server-locks-detail-5.7.22/sql/field.h:866
#5 0x0000000000f4549d in Field::send_text (this=0x7ffe7ca66540, protocol=0x7ffe7c001e88) at /root/mysqlall/percona-server-locks-detail-5.7.22/sql/field.cc:1725
#6 0x00000000014dfb82 in Protocol_text::store (this=0x7ffe7c001e88, field=0x7ffe7ca66540)
at /root/mysqlall/percona-server-locks-detail-5.7.22/sql/protocol_classic.cc:1415
#7 0x0000000000fb06c0 in Item_field::send (this=0x7ffe7c006ec0, protocol=0x7ffe7c001e88, buffer=0x7fffec0f4760)
at /root/mysqlall/percona-server-locks-detail-5.7.22/sql/item.cc:7801
#8 0x000000000156b15c in THD::send_result_set_row (this=0x7ffe7c000b70, row_items=0x7ffe7c005d58)
at /root/mysqlall/percona-server-locks-detail-5.7.22/sql/sql_class.cc:5026
#9 0x0000000001565758 in Query_result_send::send_data (this=0x7ffe7c006e98, items=...) at /root/mysqlall/percona-server-locks-detail-5.7.22/sql/sql_class.cc:2932
#10 0x0000000001585490 in end_send (join=0x7ffe7c007078, qep_tab=0x7ffe7c0078d0, end_of_records=false)
at /root/mysqlall/percona-server-locks-detail-5.7.22/sql/sql_executor.cc:2925
#11 0x0000000001582059 in evaluate_join_record (join=0x7ffe7c007078, qep_tab=0x7ffe7c007758)
#0 Time_zone_offset::gmt_sec_to_TIME (this=0x6723d90, tmp=0x7fffec0f3ff0, t=1546275661) at /root/mysqlall/percona-server-locks-detail-5.7.22/sql/tztime.cc:1418
#1 0x0000000000f6b65c in Time_zone::gmt_sec_to_TIME (this=0x6723d90, tmp=0x7fffec0f3ff0, tv=...) at /root/mysqlall/percona-server-locks-detail-5.7.22/sql/tztime.h:60
#2 0x0000000000f51643 in Field_timestampf::get_date_internal (this=0x7ffe7ca66540, ltime=0x7fffec0f3ff0)
at /root/mysqlall/percona-server-locks-detail-5.7.22/sql/field.cc:6014
#3 0x0000000000f4ff49 in Field_temporal_with_date::val_str (this=0x7ffe7ca66540, val_buffer=0x7fffec0f4370, val_ptr=0x7fffec0f4370)
at /root/mysqlall/percona-server-locks-detail-5.7.22/sql/field.cc:5429
#4 0x0000000000f11d7b in Field::val_str (this=0x7ffe7ca66540, str=0x7fffec0f4370) at /root/mysqlall/percona-server-locks-detail-5.7.22/sql/field.h:866
#5 0x0000000000f4549d in Field::send_text (this=0x7ffe7ca66540, protocol=0x7ffe7c001e88) at /root/mysqlall/percona-server-locks-detail-5.7.22/sql/field.cc:1725
#6 0x00000000014dfb82 in Protocol_text::store (this=0x7ffe7c001e88, field=0x7ffe7ca66540)
at /root/mysqlall/percona-server-locks-detail-5.7.22/sql/protocol_classic.cc:1415
#7 0x0000000000fb06c0 in Item_field::send (this=0x7ffe7c006ec0, protocol=0x7ffe7c001e88, buffer=0x7fffec0f4760)
at /root/mysqlall/percona-server-locks-detail-5.7.22/sql/item.cc:7801
#8 0x000000000156b15c in THD::send_result_set_row (this=0x7ffe7c000b70, row_items=0x7ffe7c005d58)
at /root/mysqlall/percona-server-locks-detail-5.7.22/sql/sql_class.cc:5026
#9 0x0000000001565758 in Query_result_send::send_data (this=0x7ffe7c006e98, items=...) at /root/mysqlall/percona-server-locks-detail-5.7.22/sql/sql_class.cc:2932
#10 0x0000000001585490 in end_send (join=0x7ffe7c007078, qep_tab=0x7ffe7c0078d0, end_of_records=false)
at /root/mysqlall/percona-server-locks-detail-5.7.22/sql/sql_executor.cc:2925
#11 0x0000000001582059 in evaluate_join_record (join=0x7ffe7c007078, qep_tab=0x7ffe7c007758)