2016-06-09 113 views
0

下面是Postgres的日志PostgreSQL的死锁在插入和更新

Process 10396 waits for RowShareLock on relation 17204 of database 16384; blocked by process 10377. 
Process 10377 waits for ShareLock on transaction 149848948; blocked by process 10396. 
Process 10396: insert into "completed_jobs" ("id", ....... "limitation_code") values ($1, ...... $22) returning "id" 
Process 10377: UPDATE jobs SET status='pending', updated_at=$1 WHERE id=$2 

我从郎去执行这个。所以这是在分布式环境中。

更新是正常执行,

_, err = tx.Exec("UPDATE jobs SET status='pending', updated_at=$1 WHERE id=$2", time.Now().UTC(), job.Id) 
    if err != nil { 
     log.Println(getMessagePrefix(job, nil), "Error updating job status to pending", err) 
    } 
    err = tx.Commit() 

插入是一个事务中,

tx, _ := db.Begin() 
tx.Exec("UPDATE jobs SET status=$1 WHERE id=$6", status) 
tx.Exec("INSERT INTO completed_jobs SELECT * FROM jobs WHERE id=$1", job.Id) 
tx.Exec("DELETE FROM jobs WHERE id=$1", job.Id) 
err := tx.Commit() 

回答

0

在工作排队我一般都用下面的战略,以防止多个进程试图访问同一职位。一般来说,你需要交叉事务控制来处理这个问题。

  • 咨询锁,它是交叉锁定自由锁。这意味着您可以在将它们返回给客户端之前排除进程内作业。这也避免了等待状态要求。
  • 与随机ID的短交易,以防止多个进程可能击中相同的ID。如果使用索引,这一点也很重要,因为如果最终得到长时间运行的事务,则可能会在索引的头部收到大量死元组。

作业队列系统中的并发提出了大量问题。但是这两者解决了最糟糕的问题。