Mysql: Erro estranho na conexão interrompida

Criado em 5 dez. 2013  ·  25Comentários  ·  Fonte: go-sql-driver/mysql

Quando mato conexões com consultas de longa duração, recebo coisas como estas:

[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

Estou acostumado a ver este erro:

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

Até onde eu sei, esse erro é enviado pela conexão de rede de volta para o cliente que foi eliminado. Isso está sendo mascarado no driver ou no banco de dados / sql, ou não é um erro transmitido via protocolo como eu acho? Podemos deixar mais claro o que está acontecendo, de alguma forma?

bug thinking

Comentários muito úteis

Eu acho que esse é o 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 comentários

Não, nenhum erro é transmitido. O erro é que nada pode ser recebido: wink:
Mas pode ser uma boa ideia imprimir uma mensagem de erro mais descritiva do que EOF

Acho que os erros statement.go:24: Invalid Connection são resultado de http://golang.org/issue/5718
Esses erros devem desaparecer quando a lógica de reconexão automática for corrigida no pacote database / sql.

EOF é apenas io.EOF , não tenho certeza se devemos filtrar e substituir isso. É uma espécie de idioma Go usá-lo para casos como este (como, por exemplo, no pacote net, de onde este erro se origina). Mas pelo menos o significado deve ser documentado em algum lugar.

Qual a sua opinião?

Eu gostaria de ouvir o que @gkristic pensa sobre isso também. Ele está estudando isso.

Eu segui o código em database / sql. Os erros statement.go:24: Invalid Connection não são resultado de http://golang.org/issue/5718 , embora eu concorde com @julienschmidt em que o pacote deve tentar novamente. Existem até dez tentativas para chamadas Query() e Exec() quando executadas no nível do banco de dados, mas nenhuma quando você usa um receptor Stmt.

A "conexão inválida" que @xaprb viu é devido à conexão MySQL não estar mais disponível quando Close() é chamado para uma instrução preparada, ou seja, stmt.mc.netConn é nulo aqui . É uma mensagem inofensiva, pois a conexão no banco de dados / sql será encerrada assim que ErrBadConn for retornado.

Mas essa não é a única possibilidade que vejo; database / sql (Go 1.2) pode ter alguns problemas de simultaneidade que também podem terminar com essa mensagem. Se uma instrução (banco de dados / sql) for fechada quando uma conexão de driver a estiver usando, a instrução de driver será programada para ser fechada no próximo putConn() por noteUnusedDriverStatement() . Mas putConn() poderia ser executado antes de removeOpenStmt() ser chamado (consulte (*Stmt) finalClose() ). Se, depois de chamar funções pendentes onPut , a própria conexão for fechada devido ao limite de conexão inativa, então o pacote tentará fechar a instrução novamente, resultando na mensagem. Mais uma vez, isso é inofensivo, mas mesmo assim irritante.

O banco de dados / sql do IMHO Go precisa de uma revisão cuidadosa ...

@gkristic você sugere alguma mudança no driver?

O pacote database / sql tem algumas falhas, espero fazer algumas melhorias para o Go 1.3. Revisitar o gerenciamento de dependências é um item da minha lista.

Se você descobrir problemas como este, informe-o em https://code.google.com/p/go/issues/list.

Dado que essas condições (ou seja, conexão perdida ou fechamento duplo por banco de dados / sql) são inofensivas, eu esperaria que o driver as ignorasse silenciosamente, em vez de imprimir a mensagem "Conexão inválida". Na minha opinião, o último pode ser: assustador, se você não sabe que é inofensivo; irritante, uma vez que você faz; mas possivelmente enganoso, se houver uma mensagem idêntica impressa em outro lugar (e há, exceto para o número da linha), ocultando um aviso real que você poderia facilmente ignorar. Se stmt.mc ou stmt.mc.netConn forem nulos na instrução Close() function, eu favoreceria um retorno sem mais registros. Além disso, observe que retornar driver.ErrBadConn lá (conforme apresentado em 4d3764bbcb17c31575642626baeab1bcdc30c301) não tem absolutamente nenhum efeito, porque o banco de dados / sql nunca verifica o código de retorno para um fechamento de instrução.

Como observação lateral, provavelmente adicionaria uma função para ajustar o logger. Atualmente, errLog é inicializado dentro do pacote e é privado. Ele imprime com erro padrão que pode ou não estar disponível; ou seja, um processo pode optar por fechar o descritor por outros motivos. Mas mesmo que isso não aconteça, o usuário pode ter uma ideia diferente sobre o registro (pense em arquivos, syslog, qualquer coisa). O driver pode fornecer este registrador padrão, mas talvez também permitir que o usuário defina outro.

Assim que eu tiver algum tempo livre, prepararei um pequeno exemplo para o problema que mencionei antes e escreverei um relatório.

Obrigado!

@gkristic sobre o logger - você quer dizer algo como https://github.com/go-sql-driver/mysql/pull/182 (mesclado com o master há uma semana)?

@arnehormann Oh, cara ... exatamente isso. Tenho trabalhado com a v1.1. Eu verifiquei as outras coisas no master também antes de postar, mas esqueci de verificar o registro. Desculpe e obrigado!

@gkristic não é um problema: sorrindo:

Alguma mudança que deve ser feita antes do próximo lançamento? PRs bem-vindos :)

Olá pessoal, novo usuário do go-sql-driver aqui. Estou percebendo problemas semelhantes, mas gostaria de saber se alguém poderia me ajudar a confirmar que a causa é a mesma? Em crons de longa duração que utilizam goroutines, recebo rotineiramente o seguinte.

[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

Estou mais do que disposto a sujar as mãos aqui, apenas procurando alguma orientação sobre como abordar o problema. É seguro ignorar esse erro de "Conexão inválida" em certas circunstâncias? Existe uma maneira de obter automaticamente outra conexão se isso for detectado?

Uh, oh ... agora que vejo, perdi o comentário de @julienschmidt na última sexta-feira. (Peço desculpas, Julien.) @Rmulley , parece que você este comentário. A "Conexão inválida" em statement.go: 24 é inofensiva. O driver deve fazer o que for apropriado, escolhendo uma conexão diferente. Não tenho certeza sobre o "buffer ocupado"; Não me lembro de ter visto isso. Já faz um bom tempo desde que verifiquei este código. Vou reservar um tempo para dar uma olhada novamente e ver se posso ajudar. Infelizmente, isso não pode acontecer antes do final da próxima semana. Mas eu entrarei em contato com você até então.

@rmulley : Para mim, isso não parece ter relação com esse problema.
Por favor, tente reproduzir este erro com a versão git master atual caso você tenha usado uma versão instalada por go get (que é uma versão mais antiga).
Por favor, abra um novo problema então. Um exemplo de código mínimo que aciona esse erro definitivamente ajudaria.

Parece que (b *buffer) takeBuffer retorna nil . Isso parece acontecer apenas quando b.length > 0 . Isso significaria que, por algum motivo, há dados não lidos no buffer.
Nunca vi esse erro antes e só implementei essas verificações extras para segurança extra. Eu nunca teria acreditado nesse erro em estado selvagem.

De acordo com o nº 206, esse erro realmente desaparece quando o ponto de partida é executado. Não é realmente o caso?

Em primeiro lugar, desculpe pelo atraso na resposta. Eu estava de férias e depois esqueci de fazer o acompanhamento. Garanti que tenho a versão mais recente do driver MySQL e agora estou testando com Go 1.3. Parece que agora estou vendo mais detalhes na mensagem de erro.

[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

É um problema de MySQL do meu lado? (Não encontrei nada de útil online sobre como resolver esse problema)
Ou isso é algo que posso verificar e reconectar no meu código de alguma forma?

Encontrei o mesmo problema descrito por rmulley. a diferença é que o "buffer ocupado" apareceu em uma consulta extremamente curta (tão curta quanto 1 Consulta + 2 Exec's).

Acho que o problema está relacionado com as declarações preparadas. descobri que se eu preparasse uma declaração em uma transação, como

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

Devo fechar este stmt antes de preparar outra declaração, ou encontrarei "buffer ocupado" todas as vezes. se eu não usar instruções preparadas, por exemplo, fazer diretamente para tx like

 tx.Query("...")

ou

tx.Exec("...")

, foi bom.

e, se eu preparar uma instrução e, em seguida, executar outro Query ou Exec outras coisas, está tudo bem ... apenas não prepare outra instrução sem fechar a anterior, e parece bom.

espero que seja realmente onde está o problema.

obrigado.

Você pode criar um pequeno programa Go com o qual o erro possa ser reproduzido?
Parece ser definitivamente um bug no driver, mas não está relacionado ao problema original relatado aqui.
Por favor, crie um novo problema então.

Eu acho que esse é o 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()
}

Acabei de encontrar um problema de buffer ocupado semelhante e posso confirmar que @arnehormann parece estar correto. O problema ocorre ao tentar usar a mesma transação para várias consultas enquanto um objeto de linhas ainda está aberto

Oi pessoal, não sei se isso foi resolvido de alguma forma. Estou vendo esse problema em inserções curtas realizadas com "Exec" ->

var sql = "inserir na tabela (f1, f2 ... f25) valores (?,?, ...?)"
_, err: = db.Exec (sql, ...)

Depois de cerca de 4000, às vezes 5000 inserções, recebo "EOF inesperado" e "Buffer ocupado".
As inserções são compactas (em um loop for), mas há uma solicitação REST entre cada uma, portanto, não é tão rápido; mesma referência de conexão. Este é o Go 1.3.

Obrigado,
Sal

@Sal - o que acontece quando você usa o go 1.4?

Na quarta-feira, 31 de dezembro de 2014 às 22h11, Sal A. Magnone [email protected]
escrevi:

Oi pessoal, não sei se isso foi resolvido de alguma forma. Estou vendo isso
problema em inserções curtas realizadas com "Exec" ->

var sql = "inserir na tabela (f1, f2 ... f25) valores (?,?, ...?)"
_, err: = db.Exec (sql, ...)

Depois de cerca de 4.000, às vezes 5.000 inserções, recebo "EOF inesperado" e "Ocupado
Amortecedor".
As inserções são apertadas (em um loop for), mas há uma solicitação REST entre
cada um, portanto, fogo não tão rápido; mesma referência de conexão. Este é o Go 1.3.

Obrigado,
Sal

-
Responda a este e-mail diretamente ou visualize-o no GitHub
https://github.com/go-sql-driver/mysql/issues/185#issuecomment -68479413.

Obrigado pela sua resposta.

1.4 - mesmo erro. Morreu em 4205 inserções em cerca de 50 minutos (há rede e tela de i / o entre cada inserção).

Refatorei o código para, opcionalmente, continuar de onde parou na vez anterior. Portanto, não é crítico para este aplicativo, mas pode ser crítico para outros aplicativos neste projeto se for um problema de solicitação cumulativa.

-Sal

De: carbocation [mailto: [email protected]]
Enviado: Domingo, 4 de janeiro de 2015 9:50
Para: go-sql-driver / mysql
Cc: Sal A. Magnone
Assunto: Re: [mysql] Erro estranho na conexão interrompida (# 185)

@Sal - o que acontece quando você usa o go 1.4?

Na quarta-feira, 31 de dezembro de 2014 às 22h11, Sal A. Magnone < [email protected] [email protected] >
escrevi:

Oi pessoal, não sei se isso foi resolvido de alguma forma. Estou vendo isso
problema em inserções curtas realizadas com "Exec" ->

var sql = "inserir na tabela (f1, f2 ... f25) valores (?,?, ...?)"
_, err: = db.Exec (sql, ...)

Depois de cerca de 4.000, às vezes 5.000 inserções, recebo "EOF inesperado" e "Ocupado
Amortecedor".
As inserções são apertadas (em um loop for), mas há uma solicitação REST entre
cada um, portanto, fogo não tão rápido; mesma referência de conexão. Este é o Go 1.3.

Obrigado,
Sal

-
Responda a este e-mail diretamente ou visualize-o no GitHub
https://github.com/go-sql-driver/mysql/issues/185#issuecomment -68479413.

-
Responda a este e-mail diretamente ou visualize-o no GitHub https://github.com/go-sql-driver/mysql/issues/185#issuecomment -68635254. https://github.com/notifications/beacon/AA4DdvfCFMdiqPlTZITEs9VrxyyJqqFQks5neUqigaJpZM4BSM1b.gif

Este tópico está se transformando em alguns tópicos agora? Os comentários mais recentes devem ser colocados em um novo problema e este encerrado?

@xaprb Eu concordo, acho que há alguns tópicos em andamento agora. Provavelmente podemos fechar este e transformar https://github.com/go-sql-driver/mysql/issues/185#issuecomment -68479413 em um novo problema.

Esta página foi útil?
0 / 5 - 0 avaliações