Mysql: Error extraño en la conexión interrumpida

Creado en 5 dic. 2013  ·  25Comentarios  ·  Fuente: go-sql-driver/mysql

Cuando elimino las conexiones que tienen consultas de larga duración, obtengo cosas como esta:

[MySQL] 2013/12/05 22:17:19 packets.go:30: EOF
[MySQL] 2013/12/05 22:17:19 statement.go:24: Invalid Connection
[MySQL] 2013/12/05 22:17:27 packets.go:30: EOF
[MySQL] 2013/12/05 22:17:27 statement.go:24: Invalid Connection
[MySQL] 2013/12/05 22:17:39 packets.go:30: EOF
[MySQL] 2013/12/05 22:17:39 statement.go:24: Invalid Connection

Estoy acostumbrado a ver este error:

2013 (HY000) at line 1: Lost connection to MySQL server during query

Hasta donde yo sé, ese error en realidad se envía a través de la conexión de red al cliente que murió. ¿Está esto enmascarado en el controlador o en la base de datos / sql, o no es un error transmitido a través del protocolo como creo? ¿Podemos dejar más claro lo que está sucediendo, de alguna manera?

bug thinking

Comentario más útil

Yo pienso que éste es el problema:

package main

import (
    "database/sql"

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

func main() {
    db, _ := sql.Open("mysql", "/")
    defer db.Close()
    tx, err := db.Begin()
    if err != nil {
        panic(err)
    }
    defer tx.Commit()
    stmt1, err := tx.Prepare("SELECT 1")
    if err != nil {
        panic(err)
    }
    rows1, err := stmt1.Query()
    if err != nil {
        panic(err)
    }
    stmt2, err := tx.Prepare("SELECT 2")
    if err != nil {
        // rows1 is not closed -> triggers busy buffer because transaction is on one connection
        // and stmt1, stmt2 use the same one.
        // Move rows1.Close() in front of tx.Prepare and it disappears
        panic(err)
    }
    rows2, err := stmt2.Query()
    if err != nil {
        panic(err)
    }
    rows1.Close()
    rows2.Close()
    stmt1.Close()
    stmt2.Close()
}

Todos 25 comentarios

No, no se transmite ningún error. En realidad, el error es que no se puede recibir nada: guiño:
Pero podría ser una buena idea imprimir un mensaje de error más descriptivo que EOF

Supongo que los errores statement.go:24: Invalid Connection son el resultado de http://golang.org/issue/5718
Esos errores deberían desaparecer cuando la lógica de reconexión automática se corrija en el paquete database / sql.

EOF es solo io.EOF , no estoy seguro de si deberíamos filtrar y reemplazar esto. Es una especie de modismo de Go usarlo para casos como este (como, por ejemplo, en el paquete net, de donde se origina este error). Pero al menos el significado debería estar documentado en alguna parte.

¿Cual es tu opinion?

Me gustaría escuchar lo que @gkristic piensa de esto también. Lo ha estado estudiando.

Seguí el código en database / sql. Los errores statement.go:24: Invalid Connection no son el resultado de http://golang.org/issue/5718 , aunque estoy de acuerdo con @julienschmidt en que el paquete debería intentar reintentar. Hay hasta diez intentos para las llamadas Query() y Exec() cuando se ejecutan en el nivel de base de datos, pero ninguno cuando utiliza un receptor Stmt.

La "conexión no válida " Close() para una declaración preparada, es decir, stmt.mc.netConn es nulo aquí . Es un mensaje inofensivo, porque la conexión en la base de datos / sql se cerrará tan pronto como se devuelva ErrBadConn .

Pero esa no es la única posibilidad que he visto; database / sql (Go 1.2) puede tener algunos problemas de concurrencia que pueden terminar con ese mensaje también. Si una declaración (base de datos / sql) se cierra cuando la conexión de un controlador la está usando, la declaración del controlador está programada para cerrarse en el próximo putConn() por noteUnusedDriverStatement() . Pero putConn() podría ejecutarse antes de que se llame a removeOpenStmt() (ver (*Stmt) finalClose() ). Si, después de llamar a las funciones pendientes onPut , la conexión en sí se cierra debido al límite de conexión inactiva, el paquete intentará cerrar la declaración nuevamente, lo que dará como resultado el mensaje. Una vez más, esto es inofensivo, pero no obstante molesto.

En mi humilde opinión, la base de datos / sql de Go necesita una revisión cuidadosa ...

@gkristic ¿sugiere algún cambio en el controlador?

El paquete database / sql tiene algunas fallas, espero hacer algunas mejoras para Go 1.3. Revisar la gestión de la dependencia es un elemento de mi lista.

Si descubre problemas como este, infórmelo en https://code.google.com/p/go/issues/list.

Dado que estas condiciones (es decir, conexión perdida o doble cierre por base de datos / sql) son inofensivas, esperaría que el controlador las omita en silencio, en lugar de imprimir el mensaje "Conexión no válida". En mi opinión, lo último puede ser: aterrador, si no sabes que es inofensivo; molesto, una vez que lo haces; pero posiblemente engañoso, si hay un mensaje idéntico impreso en otro lugar (y lo hay, excepto por el número de línea), ocultando una advertencia real que podría omitir fácilmente. Si stmt.mc o stmt.mc.netConn son nulos en la función de instrucción Close() , preferiría una devolución sin más registros. Además, tenga en cuenta que devolver driver.ErrBadConn allí (como se presentó en 4d3764bbcb17c31575642626baeab1bcdc30c301) no tiene absolutamente ningún efecto, porque database / sql nunca verifica el código de retorno para un cierre de declaración.

Como nota al margen, probablemente agregaría una función para ajustar el registrador. Actualmente, errLog se inicializa dentro del paquete y es privado. Imprime con error estándar que puede estar disponible o no; es decir, un proceso puede optar por cerrar el descriptor por otras razones. Pero incluso si no es así, el usuario puede tener una idea diferente sobre el registro (piense en archivos, syslog, lo que sea). El controlador podría proporcionar este registrador predeterminado, pero tal vez también permitir al usuario configurar otro.

Tan pronto como tenga algo de tiempo libre, prepararé un pequeño ejemplo para el tema que mencioné antes y escribiré un informe.

¡Gracias!

@gkristic con respecto al registrador: ¿te refieres a algo como https://github.com/go-sql-driver/mysql/pull/182 (se fusionó con el maestro hace una semana)?

@arnehormann Oh, hombre ... exactamente eso. He estado trabajando con v1.1. También verifiqué las otras cosas en el maestro antes de publicar, pero olvidé verificar el registro. ¡Lo siento y gracias!

@gkristic no es un problema en absoluto: sonriendo:

¿Algún cambio que deba hacerse antes del próximo lanzamiento? PR bienvenidos :)

Hola chicos, nuevo usuario de go-sql-driver aquí. Estoy notando problemas similares, pero me preguntaba si alguien podría ayudarme a confirmar que la causa es la misma. En crons de larga duración que utilizan goroutines, habitualmente recibo lo siguiente.

[MySQL] 2014/05/14 20:33:05 packets.go:356: Busy buffer
[MySQL] 2014/05/14 20:33:05 packets.go:73: EOF
[MySQL] 2014/05/14 20:33:05 statement.go:24: Invalid Connection
[MySQL] 2014/05/14 20:33:05 connection.go:206: Invalid Connection

Estoy más que dispuesto a ensuciarme las manos aquí, solo buscando alguna orientación sobre cómo abordar el problema. ¿Es seguro ignorar este error de "Conexión no válida" en determinadas circunstancias? ¿Hay alguna forma de capturar automáticamente otra conexión si se detecta?

Uh, oh ... ahora que veo, me perdí el comentario de @julienschmidt del viernes pasado. (Pido disculpas, Julien.) @Rmulley , parece que has tenido el mismo problema que describí anteriormente. Mira este comentario. La "Conexión no válida" en statement.go: 24 es inofensiva. El conductor debe hacer lo apropiado eligiendo una conexión diferente. Sin embargo, no estoy seguro del "búfer ocupado"; No recuerdo haber visto eso. Ha pasado bastante tiempo desde que verifiqué este código. Dedicaré algo de tiempo a echarle un vistazo de nuevo y ver si puedo ayudar. Desafortunadamente, eso no puede suceder antes del final de la próxima semana. Pero me comunicaré contigo para entonces.

@rmulley : Para mí, esto parece no tener relación con este problema.
Intente reproducir este error con la versión actual de git master en caso de que haya utilizado una versión instalada por go get (que es una versión anterior).
Entonces, abra una nueva edición. Una muestra de código mínima que desencadena este error definitivamente ayudaría.

Parece que (b *buffer) takeBuffer devuelve nil . Esto parece suceder solo cuando b.length > 0 . Esto significaría que, por alguna razón, hay datos no leídos en el búfer.
Nunca había visto este error antes y solo implementé estas comprobaciones adicionales para mayor seguridad. Nunca hubiera creído este error en la naturaleza.

Según # 206, este error desaparece cuando se ejecuta go desde tip. ¿No es ese realmente el caso?

Primero que nada, perdón por la respuesta tardía, estaba de vacaciones y luego olvidé hacer un seguimiento. Me aseguré de tener la versión más reciente del controlador MySQL y ahora estoy probando con Go 1.3. Parece que ahora veo más detalles en el mensaje de error.

[MySQL] 2014/06/23 11:46:04 packets.go:356: Busy buffer
[MySQL] 2014/06/23 11:46:04 packets.go:73: read tcp xxx.xxx.xxx.xx:3306: connection reset by peer

¿Es esto un problema de MySQL de mi parte? (No he encontrado nada útil en línea sobre cómo resolver este problema)
¿O es esto algo que puedo verificar y luego volver a conectarme en mi código de alguna manera?

Me he encontrado con el mismo problema que describió rmulley. lo que fue diferente es que el "búfer ocupado" apareció en una consulta extremadamente corta (tan corta como 1 consulta + 2 ejecutables).

Siento que el problema está relacionado con declaraciones preparadas. Descubrí que si he preparado un estado de cuenta en una transacción, como

 stmt, err = tx.Prepare("SELECT ...")

Debo cerrar este stmt antes de preparar otra declaración, o encontraré "búfer ocupado" cada vez. si no uso declaraciones preparadas, por ejemplo, haciendo directamente a tx como

 tx.Query("...")

o

tx.Exec("...")

, estuvo bien.

y, si preparo una declaración y luego ejecuto otra Query o Exec otras cosas, también está bien ... simplemente no prepare otra declaración sin cerrar la anterior, y se ve bien.

Espero que sea realmente donde está el problema.

Gracias.

¿Puede tal vez crear un pequeño programa Go con el que se pueda reproducir el error?
Definitivamente parece ser un error en el controlador, pero no está relacionado con el problema original reportado aquí.
A continuación, cree un nuevo problema.

Yo pienso que éste es el problema:

package main

import (
    "database/sql"

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

func main() {
    db, _ := sql.Open("mysql", "/")
    defer db.Close()
    tx, err := db.Begin()
    if err != nil {
        panic(err)
    }
    defer tx.Commit()
    stmt1, err := tx.Prepare("SELECT 1")
    if err != nil {
        panic(err)
    }
    rows1, err := stmt1.Query()
    if err != nil {
        panic(err)
    }
    stmt2, err := tx.Prepare("SELECT 2")
    if err != nil {
        // rows1 is not closed -> triggers busy buffer because transaction is on one connection
        // and stmt1, stmt2 use the same one.
        // Move rows1.Close() in front of tx.Prepare and it disappears
        panic(err)
    }
    rows2, err := stmt2.Query()
    if err != nil {
        panic(err)
    }
    rows1.Close()
    rows2.Close()
    stmt1.Close()
    stmt2.Close()
}

Me acabo de encontrar con un problema similar de búfer ocupado y puedo confirmar que @arnehormann parece estar en lo correcto. El problema ocurre cuando se intenta utilizar la misma transacción para varias consultas mientras un objeto de filas aún está abierto

Hola chicos, no sé si esto se resolvió de alguna manera. Veo este problema en inserciones breves realizadas con "Exec" ->

var sql = "insertar en la tabla (f1, f2 ... f25) valores (?,?, ...?)"
_, err: = db.Exec (sql, ...)

Después de 4000, a veces 5000 inserciones, obtengo "EOF inesperado" y "Búfer ocupado".
Las inserciones están apretadas (en un bucle for) pero hay una solicitud REST entre cada una, por lo que no es tan rápido; misma referencia de conexión. Esto es Go 1.3.

Gracias,
Sal

@Sal : ¿qué sucede cuando usas go 1.4?

El miércoles 31 de diciembre de 2014 a las 10:11 p.m., Sal A. Magnone [email protected]
escribió:

Hola chicos, no sé si esto se resolvió de alguna manera. Estoy viendo esto
problema en inserciones cortas realizadas con "Exec" ->

var sql = "insertar en la tabla (f1, f2 ... f25) valores (?,?, ...?)"
_, err: = db.Exec (sql, ...)

Después de aproximadamente 4000, a veces 5000 inserciones, obtengo "EOF inesperado" y "Ocupado
Buffer".
Las inserciones están apretadas (en un bucle for) pero hay una solicitud de REST entre
cada uno, tan, no tan rápido fuego; misma referencia de conexión. Esto es Go 1.3.

Gracias,
Sal

-
Responda a este correo electrónico directamente o véalo en GitHub
https://github.com/go-sql-driver/mysql/issues/185#issuecomment -68479413.

Gracias por su respuesta.

1.4 - mismo error. Murió con 4205 insertos en aproximadamente 50 minutos (hay una red y una pantalla de E / S entre cada inserto).

He refactorizado el código para continuar opcionalmente donde lo dejó la vez anterior. Por lo tanto, no es crítico para esta aplicación, pero podría serlo para otras aplicaciones de este proyecto si se trata de un problema de solicitud acumulativa.

-Sal

De: carbocation [mailto: [email protected]]
Enviado: Domingo 4 de enero de 2015 9:50 AM
Para: go-sql-driver / mysql
Cc: Sal A. Magnone
Asunto: Re: [mysql] Error extraño en la conexión interrumpida (# 185)

@Sal : ¿qué sucede cuando usas go 1.4?

El miércoles 31 de diciembre de 2014 a las 10:11 p.m., Sal A. Magnone < [email protected] [email protected] >
escribió:

Hola chicos, no sé si esto se resolvió de alguna manera. Estoy viendo esto
problema en inserciones cortas realizadas con "Exec" ->

var sql = "insertar en la tabla (f1, f2 ... f25) valores (?,?, ...?)"
_, err: = db.Exec (sql, ...)

Después de aproximadamente 4000, a veces 5000 inserciones, obtengo "EOF inesperado" y "Ocupado
Buffer".
Las inserciones están apretadas (en un bucle for) pero hay una solicitud de REST entre
cada uno, tan, no tan rápido fuego; misma referencia de conexión. Esto es Go 1.3.

Gracias,
Sal

-
Responda a este correo electrónico directamente o véalo en GitHub
https://github.com/go-sql-driver/mysql/issues/185#issuecomment -68479413.

-
Responda a este correo electrónico directamente o véalo en GitHub https://github.com/go-sql-driver/mysql/issues/185#issuecomment -68635254. https://github.com/notifications/beacon/AA4DdvfCFMdiqPlTZITEs9VrxyyJqqFQks5neUqigaJpZM4BSM1b.gif

¿Este hilo se está convirtiendo en algunos hilos ahora? ¿Deben incluirse los comentarios más recientes en un tema nuevo y cerrar este?

@xaprb Estoy de acuerdo, creo que hay algunos hilos en curso ahora. Probablemente podamos cerrar este y tomar de https://github.com/go-sql-driver/mysql/issues/185#issuecomment -68479413 a un nuevo problema.

¿Fue útil esta página
0 / 5 - 0 calificaciones