500 잘못된 검사 방법 [DB Lock 편]

10505 단어 MySQL폐쇄
저는 오즈코웨이 주식회사의 유코@terra_yucco입니다.
최근 일부 API에 500개가 나왔는데 오늘은 날씨가 맑아서 원인을 확인할 수 있어서 그곳에 가는 과정을 적어 보려고 합니다.
※ DB의 Lock 때문에 제목이 스포일러되었습니다.

계기


모니터링 및 사용자의 문의를 통해 특정 API가 HTTP 응답 코드에서 500을 반환한 것 같습니다.
그러나 이 API 자체가 로그를 남기지 않는 등 어디서 어떤 이유로 500이 됐는지 알 수 없다.

1) 먼저 구하다


1단계에서는 우선 다른 처리를 통해 다시 시도하여 구한다.

2) 먼저 오류 확인


FW 출력의 로그와 가져온 새 버전은 어느 정도 원인을 축소시켰다.

FW 로그


ERROR - 2019-06-07 02:19:37 --> Query error: Lock wait timeout exceeded; try restarting transaction

New Relic


APM > 해당 어플리케이션 > EVENTS-Errors

이 메시지의 링크에서 실제 노드가 접근 로그와 일치하는 것을 발견했습니다.
이 밖에 우리는 특정한 처리가 아닌 공공 부분 (insert 장소) 에서 오류가 발생했다는 것을 확보했다.

3) 원인 조사


정기적으로 showprocesslist를 저장하지만 이것만으로는 목표 잠금과 주 잠금을 정확하게 확정할 수 없기 때문에 잠시 다음 처리를 썼습니다.
※ 지금 생각해보면 책상 두 개가 함께 있으면 좋겠다
investigation.sh
#!/bin/bash -u
while [ 1 ]; do

mysql --default-character-set=utf8 --verbose \
  -h <endpoint> \
  -u <user> -p<pass> -D information_schema \
  -e"set session time_zone = 'asia/tokyo'; select now(); select * from innodb_trx\G select * from innodb_lock_waits; select now();" >> /path/to/log/$( date +%Y%m%d_investigation.log )

sleep 300
done
나는 줄곧 이 처리에서 기록을 얻으려고 했지만, 떨어질 때를 고려하여cron은 다음과 같이 설정했다.flock --timeout=1flock을 사용하는ver는 0의 설정을 지원하지 않기 때문에 다중 시작을 간단하게 억제하기 위해 사용됩니다.
crontab
*/5 * * * *     flock --timeout=1 /path/to/lock /path/to/script/investigation.sh

4) 질의 확인


레코드


다음 로그를 받았습니다:.
--------------
set session time_zone = 'asia/tokyo'
--------------

--------------
select now()
--------------

now()
2019-06-07 11:42:35
--------------
select * from innodb_trx
--------------

*************************** 1. row ***************************
                    trx_id: 25511719128
                 trx_state: LOCK WAIT
               trx_started: 2019-06-07 02:42:18
     trx_requested_lock_id: 25511719128:44:952896:791
          trx_wait_started: 2019-06-07 02:42:18
                trx_weight: 3
       trx_mysql_thread_id: 4979812
                 trx_query: INSERT INTO table_A (<columns>) VALUES (<values>)
       trx_operation_state: inserting
         trx_tables_in_use: 1
         trx_tables_locked: 1
          trx_lock_structs: 2
     trx_lock_memory_bytes: 376
           trx_rows_locked: 1
         trx_rows_modified: 1
   trx_concurrency_tickets: 0
       trx_isolation_level: REPEATABLE READ
         trx_unique_checks: 1
    trx_foreign_key_checks: 1
trx_last_foreign_key_error: NULL
 trx_adaptive_hash_latched: 0
 trx_adaptive_hash_timeout: 0
          trx_is_read_only: 0
trx_autocommit_non_locking: 0
*************************** 2. row ***************************
                    trx_id: 25511719119
                 trx_state: LOCK WAIT
               trx_started: 2019-06-07 02:42:18
     trx_requested_lock_id: 25511719119:44:952896:791
          trx_wait_started: 2019-06-07 02:42:18
                trx_weight: 3
       trx_mysql_thread_id: 4980011
                 trx_query: INSERT INTO table_A (<columns>) VALUES (<values>)
       trx_operation_state: inserting
         trx_tables_in_use: 1
         trx_tables_locked: 1
          trx_lock_structs: 2
     trx_lock_memory_bytes: 376
           trx_rows_locked: 1
         trx_rows_modified: 1
   trx_concurrency_tickets: 0
       trx_isolation_level: REPEATABLE READ
         trx_unique_checks: 1
    trx_foreign_key_checks: 1
trx_last_foreign_key_error: NULL
 trx_adaptive_hash_latched: 0
 trx_adaptive_hash_timeout: 0
          trx_is_read_only: 0
trx_autocommit_non_locking: 0
*************************** 3. row ***************************
                    trx_id: 25511719100
                 trx_state: LOCK WAIT
               trx_started: 2019-06-07 02:42:18
     trx_requested_lock_id: 25511719100:44:952896:791
          trx_wait_started: 2019-06-07 02:42:18
                trx_weight: 3
       trx_mysql_thread_id: 4979976
                 trx_query: INSERT INTO table_A (<columns>) VALUES (<values>)
       trx_operation_state: inserting
         trx_tables_in_use: 1
         trx_tables_locked: 1
          trx_lock_structs: 2
     trx_lock_memory_bytes: 376
           trx_rows_locked: 1
         trx_rows_modified: 1
   trx_concurrency_tickets: 0
       trx_isolation_level: REPEATABLE READ
         trx_unique_checks: 1
    trx_foreign_key_checks: 1
trx_last_foreign_key_error: NULL
 trx_adaptive_hash_latched: 0
 trx_adaptive_hash_timeout: 0
          trx_is_read_only: 0
trx_autocommit_non_locking: 0
*************************** 4. row ***************************
                    trx_id: 25511719086
                 trx_state: LOCK WAIT
               trx_started: 2019-06-07 02:42:18
     trx_requested_lock_id: 25511719086:44:952896:791
          trx_wait_started: 2019-06-07 02:42:18
                trx_weight: 3
       trx_mysql_thread_id: 4979714
                 trx_query: INSERT INTO table_A (<columns>) VALUES (<values>)
       trx_operation_state: inserting
         trx_tables_in_use: 1
         trx_tables_locked: 1
          trx_lock_structs: 2
     trx_lock_memory_bytes: 376
           trx_rows_locked: 1
         trx_rows_modified: 1
   trx_concurrency_tickets: 0
       trx_isolation_level: REPEATABLE READ
         trx_unique_checks: 1
    trx_foreign_key_checks: 1
trx_last_foreign_key_error: NULL
 trx_adaptive_hash_latched: 0
 trx_adaptive_hash_timeout: 0
          trx_is_read_only: 0
trx_autocommit_non_locking: 0
*************************** 5. row ***************************
                    trx_id: 25511716742
                 trx_state: LOCK WAIT
               trx_started: 2019-06-07 02:42:08
     trx_requested_lock_id: 25511716742:44:952896:791
          trx_wait_started: 2019-06-07 02:42:08
                trx_weight: 3
       trx_mysql_thread_id: 4979817
                 trx_query: INSERT INTO table_A (<columns>) VALUES (<values>)
       trx_operation_state: inserting
         trx_tables_in_use: 1
         trx_tables_locked: 1
          trx_lock_structs: 2
     trx_lock_memory_bytes: 376
           trx_rows_locked: 1
         trx_rows_modified: 1
   trx_concurrency_tickets: 0
       trx_isolation_level: REPEATABLE READ
         trx_unique_checks: 1
    trx_foreign_key_checks: 1
trx_last_foreign_key_error: NULL
 trx_adaptive_hash_latched: 0
 trx_adaptive_hash_timeout: 0
          trx_is_read_only: 0
trx_autocommit_non_locking: 0
*************************** 6. row ***************************
                    trx_id: 25511667859
                 trx_state: RUNNING
               trx_started: 2019-06-07 02:40:38
     trx_requested_lock_id: NULL
          trx_wait_started: NULL
                trx_weight: 557234
       trx_mysql_thread_id: 4974505
                 trx_query: delete from table_A where a_date < DATE_ADD(NOW(),INTERVAL -180 DAY) and status = 1 order by id limit 500
       trx_operation_state: fetching rows
         trx_tables_in_use: 1
         trx_tables_locked: 1
          trx_lock_structs: 556894
     trx_lock_memory_bytes: 376
           trx_rows_locked: 49379043
         trx_rows_modified: 340
   trx_concurrency_tickets: 0
       trx_isolation_level: REPEATABLE READ
         trx_unique_checks: 1
    trx_foreign_key_checks: 1
trx_last_foreign_key_error: NULL
 trx_adaptive_hash_latched: 0
 trx_adaptive_hash_timeout: 0
          trx_is_read_only: 0
trx_autocommit_non_locking: 0
--------------
select * from innodb_lock_waits
--------------

requesting_trx_id       requested_lock_id       blocking_trx_id blocking_lock_id
25511719128     25511719128:44:952896:791       25511667859     25511667859:44:952896:791
25511719119     25511719119:44:952896:791       25511667859     25511667859:44:952896:791
25511719100     25511719100:44:952896:791       25511667859     25511667859:44:952896:791
25511719086     25511719086:44:952896:791       25511667859     25511667859:44:952896:791
25511716742     25511716742:44:952896:791       25511667859     25511667859:44:952896:791
--------------
select now()
--------------

now()
2019-06-07 11:42:35

질의 확인

innodb_lock_waits 방면에서 잠금을 요청한 사무는 모두 5개다.
트랜잭션 ID
  • 25511719128
  • 25511719119
  • 25511719100
  • 25511719086
  • 25511716742
  • 하지만 모두 같은 25511667859에 막혔다.innodb_trx쪽에서 보면 기다리는 쪽은 모두insert, 막는 쪽은 delete이다.
    불필요한 데이터를 삭제하고 전체적인 처리를 줄여서 필요한 데이터의 로그인을 막다니...

    5) 수정


    아직 완성되지는 않았지만 삭제 조회를 보낸 측의 처리를 어떻게 처리하는가는 가능하다.

    부기


    검색을 삭제하는 데 explain을 찾으면 대체적으로 색인을 사용하기 때문에 왜 잠겼을까 생각합니다. 아마도 이 근처의 행동일 것입니다.
  • 14.2.8 InnoDB의 다양한 SQL 문구에 설정된 자물쇠
  • 일반적으로 잠금 읽기, 업데이트 또는 삭제는 SQL 문장을 처리할 때 검색된 모든 색인 레코드에 로깅 잠금을 설정합니다.행에서 제외된 WHERE 조건이 문장에 있든 없든 상관없습니다.InnoDB는 올바른 WHERE 조건을 저장하지 않지만 검색된 색인 범위를 식별합니다.

    Conclusion

  • 500 잘못된 원인은 잘 조사해야 한다
  • UPDATE 또는 DELETE에서 예상치 못한 잠금이 발생할 수 있으므로 조심해서 구현
  • 좋은 웹페이지 즐겨찾기