Mysql: μ»¨ν…μŠ€νŠΈλ₯Ό μ‚¬μš©ν•œ 쿼리 μ·¨μ†Œμ˜ μ΄μƒν•œ λ™μž‘

에 λ§Œλ“  2018λ…„ 10μ›” 02일  Β·  19μ½”λ©˜νŠΈ  Β·  좜처: go-sql-driver/mysql

μ„œλ²„: MySQL 5.6

μ €μž₯된 ν”„λ‘œμ‹œμ €:

DELIMITER //
CREATE PROCEDURE slowInsert(IN t int)
BEGIN       
       SELECT SLEEP(t);
       INSERT INTO `table_x` (message) VALUES (UUID());
END //
DELIMITER ;

μ½”λ“œ 이동:

package main

import (
    "context"
    "database/sql"
    "time"

    _ "github.com/go-sql-driver/mysql"
)

func main() {
    db, err := sql.Open("mysql", "<url>")
    if err != nil {
        panic(err)
    }
    db.SetConnMaxLifetime(9 * time.Second)
    db.SetMaxIdleConns(12)
    db.SetMaxOpenConns(12)

    ctx := context.Background()
    ctx, cancel := context.WithTimeout(ctx, time.Duration(3)*time.Second)
    defer cancel()

    _, err = db.ExecContext(ctx, "call slowInsert( 10 )") // context will cancel before insert occurs
    if err != nil {
        panic(err)
    }
}

κ°€μž₯ μœ μš©ν•œ λŒ“κΈ€

SHOW FULL PROCESSLIST 및 KILL KILL λ₯Ό μ‚¬μš©ν•˜μ—¬ μ˜¬λ°”λ₯Έ 쿼리에

λΆˆν–‰νžˆλ„ 그것은 λ“œλΌμ΄λ²„ μˆ˜μ€€μ—μ„œ μ‰½κ²Œ κ΅¬ν˜„ν•  수 μ—†μŠ΅λ‹ˆλ‹€. λ“œλΌμ΄λ²„κ°€ μ΄λŸ¬ν•œ λͺ…령을 μ‹€ν–‰ν•˜λŠ” 두 번째 연결이 ν•„μš”ν•©λ‹ˆλ‹€. μ΄λŠ” 곡유 "관리 μ—°κ²°"μ΄κ±°λ‚˜ μš”μ²­ μ‹œ μ—΄λ¦° 연결일 수 μžˆμŠ΅λ‹ˆλ‹€.

μš°μ„ , 이것은 μš΄μ „μžλ₯Ό 훨씬 더 λ³΅μž‘ν•˜κ²Œ λ§Œλ“€ κ²ƒμž…λ‹ˆλ‹€. ν˜„μž¬ μ„Έμ…˜ 및 μ—°κ²°μ˜ λͺ¨λ“  μ²˜λ¦¬λŠ” λ“œλΌμ΄λ²„κ°€ μ•„λ‹Œ database/sql νŒ¨ν‚€μ§€μ— μ˜ν•΄ μˆ˜ν–‰λ˜λ©° μƒˆ μ—°κ²° 등을 μ—¬λŠ” κΈ°λŠ₯만 μ œκ³΅ν•©λ‹ˆλ‹€.

κ·ΈλŸ¬λ‚˜ 훨씬 더 λ¬Έμ œλŠ” μ‹€μ œλ‘œ μ˜¬λ°”λ₯Έ μ„œλ²„λ₯Ό 찾을 수 μžˆλŠ” 방법이 μ—†λ‹€λŠ” κ²ƒμž…λ‹ˆλ‹€(단 ν•˜λ‚˜λ§Œ μžˆλŠ” κ²½μš°κ°€ μ•„λ‹ˆλ©΄). λ“œλΌμ΄λ²„λŠ” 주둜 mysql λ‘œλ“œ λ°ΈλŸ°μ‹± ν”„λ‘μ‹œμ™€ ν•¨κ»˜ λ°°ν¬λ©λ‹ˆλ‹€. 이 경우 SHOW FULL PROCESSLIST κ°€ 잘λͺ»λœ μ„œλ²„μ—μ„œ μ‹€ν–‰λ˜μ–΄ 쿼리λ₯Ό 찾을 수 없을 κ°€λŠ₯성이 λ†’μŠ΅λ‹ˆλ‹€.

λͺ¨λ“  19 λŒ“κΈ€

μ΄μƒν•œ 행동을 ν•˜κ³  μžˆμŠ΅λ‹ˆλ‹€.
mysql ν΄λΌμ΄μ–ΈνŠΈ(예: 후속 ν”„λ‘œ)μ—μ„œ slowInsert( 10 ) λ₯Ό μ‹€ν–‰ν•  λ•Œ μ‚½μž… 전에 10초 λŒ€κΈ°κ°€ μ‘΄μ€‘λ©λ‹ˆλ‹€. μ €μž₯된 ν”„λ‘œμ‹œμ €κ°€ 잘λͺ»λ˜μ—ˆκ±°λ‚˜ μœ νš¨ν•˜μ§€ μ•Šλ‹€κ³  믿을 μ΄μœ κ°€ μ—†μŠ΅λ‹ˆλ‹€.

μœ„μ˜ Go μ½”λ“œλ₯Ό μ‹€ν–‰ν•˜λ©΄ μ»¨ν…μŠ€νŠΈκ°€ 3초 후에 μ·¨μ†Œλ©λ‹ˆλ‹€. λͺ¨λ‘ μ’‹μŠ΅λ‹ˆλ‹€.
... κ·ΈλŸ¬λ‚˜ μ¦‰μ‹œ μ‚½μž…μ΄ λ°œμƒν•©λ‹ˆλ‹€. (10초λ₯Ό 기닀리지 μ•ŠμŠ΅λ‹ˆλ‹€.)

이제 μ €μž₯된 ν”„λ‘œμ‹œμ €λ₯Ό λ‹€μŒκ³Ό 같이 λ³€κ²½ν•˜λ©΄

DELIMITER //
CREATE PROCEDURE slowInsert(IN t int)
BEGIN       
       SELECT SLEEP(t/2); // <---- The change
       SELECT SLEEP(t/2); // <---- The change
       INSERT INTO `table_x` (message) VALUES (UUID());
END //
DELIMITER ;

Go μ½”λ“œλŠ” μ™„λ²½ν•˜κ²Œ μž‘λ™ν•˜κ³  쿼리λ₯Ό μ·¨μ†Œν•©λ‹ˆλ‹€(즉, μ‚½μž…μ΄ λ°œμƒν•˜μ§€ μ•ŠμŒ).
두 경우 λͺ¨λ‘ mysql ν΄λΌμ΄μ–ΈνŠΈ(sequel pro)λŠ” λŒ€κΈ° 기간을 μ‘΄μ€‘ν•˜λ―€λ‘œ 두 μ €μž₯된 ν”„λ‘œμ‹œμ €κ°€ λ™μΌν•©λ‹ˆλ‹€.

κ·ΈλŸ¬λ‚˜ Go μ½”λ“œμ—μ„œ 두 번째 μ €μž₯된 ν”„λ‘œμ‹œμ €λŠ” μž‘λ™ν•˜μ§€λ§Œ 첫 λ²ˆμ§ΈλŠ” μž‘λ™ν•˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€. μ΄λŠ” λ“œλΌμ΄λ²„μ— μ΄μƒν•œ 버그가 μžˆλ‹€λŠ” 믿음으둜 μ΄μ–΄μ§‘λ‹ˆλ‹€.

@ μ•Œλ ˆμ‹œμ˜€ νŒ”λ£Έλ³΄

버그가 μ•„λ‹™λ‹ˆλ‹€. 아직 쿼리 μ·¨μ†Œλ₯Ό μ§€μ›ν•˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€.
그리고 SLEEP() λŠ” 맀우 νŠΉλ³„ν•œ μΏΌλ¦¬μž…λ‹ˆλ‹€. 연결이 ν™œμ„± μƒνƒœμΈμ§€ μ—¬λΆ€λ₯Ό ν™•μΈν•©λ‹ˆλ‹€.
일반적으둜 MySQL은 쿼리가 μ™„λ£Œλ  λ•ŒκΉŒμ§€ 연결을 ν™•μΈν•˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€.

읽어보기: https://github.com/go-sql-driver/mysql#contextcontext -support

Go 1.8 added database/sql support for context.Context. This driver supports query timeouts and cancellation via contexts. See context support in the database/sql package for more details.

μ•Œκ² μŠ΅λ‹ˆλ‹€. READMEλŠ” μ˜€ν•΄μ˜ μ†Œμ§€κ°€ μžˆμŠ΅λ‹ˆλ‹€. 쿼리 싀행이 μ•„λ‹Œ "λŒ€κΈ°" 쿼리 결과만 μ·¨μ†Œν•©λ‹ˆλ‹€.

MySQL ν”„λ‘œν† μ½œμ€ 쿼리 싀행을 μ·¨μ†Œν•˜λŠ” μ•ˆμ „ν•œ 방법을 μ œκ³΅ν•˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€.
일뢀 CLIλŠ” μ·¨μ†Œλ₯Ό μ§€μ›ν•˜μ§€λ§Œ 일뢀 ν™˜κ²½μ—μ„œλŠ” μ•ˆμ „ν•˜μ§€ μ•Šκ±°λ‚˜ μ•ˆμ •μ μ΄μ§€ μ•ŠμŠ΅λ‹ˆλ‹€.

감사

당신이해야 ν•  일은 νŠΈλžœμž­μ…˜μ„ μ‚¬μš©ν•˜λŠ” κ²ƒμž…λ‹ˆλ‹€. μ»€λ°‹ν•˜μ§€ μ•ŠμœΌλ©΄ λ‘€λ°±λ©λ‹ˆλ‹€.
λ”°λΌμ„œ νŠΈλžœμž­μ…˜μ΄ μ•ˆμ „ν•œ λ™μ•ˆ μ‹œκ°„μ΄ μ΄ˆκ³Όλ©λ‹ˆλ‹€.

@andizzle @alexclifford @edwardhutchison

μ‹œκ°„ 초과 후에 첫 번째 storedProcκ°€ μ‚½μž…λ˜μ§€λ§Œ 두 번째 storedProcλŠ” μ‚½μž…λ˜μ§€ μ•ŠλŠ” μ΄μœ λŠ” λ¬΄μ—‡μž…λ‹ˆκΉŒ? κ·€ν•˜μ˜ μ§„μˆ μ— 따라 μ‚½μž…λ˜κ±°λ‚˜ μ‚½μž…λ˜μ§€ μ•ŠλŠ”λ‹€κ³  κ°€μ •ν•©λ‹ˆλ‹€. λ“œλΌμ΄λ²„κ°€ 쿼리 μ‹€ν–‰ μ·¨μ†Œλ₯Ό μ§€μ›ν•˜μ§€ μ•ŠλŠ” 경우 싀행을 μ·¨μ†Œν•˜λŠ” κ²ƒμ²˜λŸΌ λ³΄μ΄λŠ” μ΄μœ λŠ” λ¬΄μ—‡μž…λ‹ˆκΉŒ?

MySQL λ™μž‘μž…λ‹ˆλ‹€. λ‚˜λŠ” 많이 λͺ¨λ₯Έλ‹€. κ·ΈλŸ¬λ‚˜ SLEEP()은 연결이 λ‹«νž λ•Œ 맀우 μ΄μƒν•œ λ™μž‘μ„ ν•©λ‹ˆλ‹€.

@julienschmidt 이 아이디어에 λŒ€ν•΄ μ–΄λ–»κ²Œ 생각 ν•˜μ„Έμš” ?

SHOW FULL PROCESSLIST 및 KILL KILL λ₯Ό μ‚¬μš©ν•˜μ—¬ μ˜¬λ°”λ₯Έ 쿼리에

λΆˆν–‰νžˆλ„ 그것은 λ“œλΌμ΄λ²„ μˆ˜μ€€μ—μ„œ μ‰½κ²Œ κ΅¬ν˜„ν•  수 μ—†μŠ΅λ‹ˆλ‹€. λ“œλΌμ΄λ²„κ°€ μ΄λŸ¬ν•œ λͺ…령을 μ‹€ν–‰ν•˜λŠ” 두 번째 연결이 ν•„μš”ν•©λ‹ˆλ‹€. μ΄λŠ” 곡유 "관리 μ—°κ²°"μ΄κ±°λ‚˜ μš”μ²­ μ‹œ μ—΄λ¦° 연결일 수 μžˆμŠ΅λ‹ˆλ‹€.

μš°μ„ , 이것은 μš΄μ „μžλ₯Ό 훨씬 더 λ³΅μž‘ν•˜κ²Œ λ§Œλ“€ κ²ƒμž…λ‹ˆλ‹€. ν˜„μž¬ μ„Έμ…˜ 및 μ—°κ²°μ˜ λͺ¨λ“  μ²˜λ¦¬λŠ” λ“œλΌμ΄λ²„κ°€ μ•„λ‹Œ database/sql νŒ¨ν‚€μ§€μ— μ˜ν•΄ μˆ˜ν–‰λ˜λ©° μƒˆ μ—°κ²° 등을 μ—¬λŠ” κΈ°λŠ₯만 μ œκ³΅ν•©λ‹ˆλ‹€.

κ·ΈλŸ¬λ‚˜ 훨씬 더 λ¬Έμ œλŠ” μ‹€μ œλ‘œ μ˜¬λ°”λ₯Έ μ„œλ²„λ₯Ό 찾을 수 μžˆλŠ” 방법이 μ—†λ‹€λŠ” κ²ƒμž…λ‹ˆλ‹€(단 ν•˜λ‚˜λ§Œ μžˆλŠ” κ²½μš°κ°€ μ•„λ‹ˆλ©΄). λ“œλΌμ΄λ²„λŠ” 주둜 mysql λ‘œλ“œ λ°ΈλŸ°μ‹± ν”„λ‘μ‹œμ™€ ν•¨κ»˜ λ°°ν¬λ©λ‹ˆλ‹€. 이 경우 SHOW FULL PROCESSLIST κ°€ 잘λͺ»λœ μ„œλ²„μ—μ„œ μ‹€ν–‰λ˜μ–΄ 쿼리λ₯Ό 찾을 수 없을 κ°€λŠ₯성이 λ†’μŠ΅λ‹ˆλ‹€.

쿼리λ₯Ό μ§„μ •μœΌλ‘œ μ·¨μ†Œν•  수 μžˆλ„λ‘ database/sql 에 ν•„μš”ν•œ 사항을 μˆ˜μ •ν•˜λŠ” Go 2 μ œμ•ˆμ„ ν•  수 μžˆμŠ΅λ‹ˆκΉŒ?

λ‚˜λŠ” μ†”μ§νžˆ database/sql λ˜λŠ” 이 λ“œλΌμ΄λ²„κ°€ μ—¬κΈ°μ—μ„œ λ¬Έμ œκ°€ μ•„λ‹ˆλΌ λ‹¨μˆœν•œ MySQL 자체라고 생각 ν•©λ‹ˆλ‹€ . ν•˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€ .

쒋은 μ‹œμž‘μ€ μ„œλ²„λ‘œ 보낸 쿼리에 λŒ€ν•œ

단일 μ„œλ²„ μ„€μ •μ˜ 경우 Postgres와 μœ μ‚¬ν•œ λ°©μ‹μœΌλ‘œ 쿼리 λ₯Ό KILL λͺ…령을 λ³΄λƒ…λ‹ˆλ‹€.

일뢀 ν”„λ‘μ‹œμ˜ κ²½μš°λŠ” 더 μ–΄λ ΅μŠ΅λ‹ˆλ‹€. ν˜„μž¬ μ΄λŸ¬ν•œ ν”„λ‘μ‹œλŠ” λ“œλΌμ΄λ²„μ—κ²Œ μ™„μ „νžˆ 투λͺ…ν•©λ‹ˆλ‹€. ν•„μš”ν•œ 것은 연결이 λ‹€λ₯Έ κΈ°μ‘΄ μ—°κ²°κ³Ό λ™μΌν•œ λ°±μ—”λ“œλ‘œ 열리도둝 보μž₯ν•˜λŠ” μΌμ’…μ˜ λ©”μ»€λ‹ˆμ¦˜μž…λ‹ˆλ‹€.

μ‹€μ œλ‘œ μœ μ‚¬ν•œ μ ‘κ·Ό 방식(단일 μ„œλ²„ μ„€μ •μ˜ 경우)에 λŒ€ν•œ 곡개 PR이 μžˆμŠ΅λ‹ˆλ‹€. https://github.com/go-sql-driver/mysql/pull/791

MySQL에 κΈ°λŠ₯ μš”μ²­μ„ μ œμΆœν•  κ²ƒμž…λ‹ˆλ‹€. 쿼리에 ν”„λ‘œμ„ΈμŠ€ IDλ₯Ό ν¬ν•¨ν•˜λ„λ‘ μš”μ²­ν•˜λ©΄ 이전 버전과 ν˜Έν™˜λ˜μ§€ μ•ŠλŠ” λ³€κ²½ 사항이 μƒμ„±λ˜μ–΄ κ±°λΆ€ν•  수 μžˆμŠ΅λ‹ˆκΉŒ?

μ·¨μ†Œμ˜ λ¬Έμ œλŠ” 이뿐만이 μ•„λ‹™λ‹ˆλ‹€. λͺ‡ 가지 λ‹€λ₯Έ λ¬Έμ œκ°€ μžˆμŠ΅λ‹ˆλ‹€.
μ§€κ΅¬μƒμ—λŠ” "μ›κ²©μ—μ„œ μ‹ λ’°ν•  수 μžˆλŠ” μ·¨μ†Œ" ν”„λ‘œν† μ½œμ΄ μ—†μŠ΅λ‹ˆλ‹€.
일뢀 CPUλ₯Ό μ ˆμ•½ν•  λ•Œλ§Œ μ‚¬μš©ν•΄μ•Ό ν•©λ‹ˆλ‹€.

μ–΄μ¨Œλ“ , 이 문제의 μš”μ μ€ λ¬΄μ—‡μž…λ‹ˆκΉŒ?
μ·¨μ†Œλ₯Ό κ΅¬ν˜„ν•˜λ©΄ μ΄μƒν•œ λ™μž‘μ„ ν”Όν•  수 μ—†μŠ΅λ‹ˆλ‹€.
"μ»¨ν…μŠ€νŠΈμ— μ˜ν•΄ μ·¨μ†Œλ¨" 쿼리가 MySQL μ„œλ²„μ—μ„œ μ‹€ν–‰λ˜κ±°λ‚˜ μ·¨μ†Œλ˜μ—ˆλŠ”μ§€ μ•Œ 수 μ—†μŠ΅λ‹ˆλ‹€. 타이밍 λ¬Έμ œμž…λ‹ˆλ‹€.
λ‹Ήμ‹ λ§Œμ΄ ν•  수 μžˆλŠ” 것은 νŠΈλžœμž­μ…˜μ„ μ‚¬μš©ν•˜λŠ” κ²ƒμž…λ‹ˆλ‹€. λͺ¨λ“  쿼리가 λ‘€λ°±λ©λ‹ˆλ‹€.

"쿼리 μ·¨μ†Œ κ΅¬ν˜„"에 λŒ€ν•œ λ¬Έμ œκ°€ μ •λ§λ‘œ ν•„μš”ν•œ 경우 μƒˆ 문제λ₯Ό μ œμΆœν•˜κ³  λ‹«μŠ΅λ‹ˆλ‹€.

λ‚΄ μ†”λ£¨μ…˜μ€ λ‹€μŒκ³Ό κ°™μŠ΅λ‹ˆλ‹€. https://medium.com/@rocketlaunchr.cloud/canceling -mysql-in-go-827ed8f83b30

이 νŽ˜μ΄μ§€κ°€ 도움이 λ˜μ—ˆλ‚˜μš”?
0 / 5 - 0 λ“±κΈ‰