문제

지금 SQLite3을 사용하여 Rails 사이트를 실행해 보세요.

대략 500개의 요청마다 한 번씩, 나는

ActiveRecord::StatementInvalid(SQLite3::BusyException:데이터베이스가 잠겨 있습니다:...

내 코드에 최소한으로 영향을 미치도록 이 문제를 해결하는 방법은 무엇입니까?

저는 현재 SQLLite를 사용하고 있습니다. 소스 제어에 DB를 저장하여 백업을 자연스럽게 만들고 변경 사항을 매우 빠르게 푸시할 수 있기 때문입니다.그러나 동시 액세스를 위해 실제로 설정되지는 않았습니다.내일 아침에 MySQL로 마이그레이션하겠습니다.

도움이 되었습니까?

해결책

기본적으로 sqlite는 데이터베이스가 사용 중이거나 잠겨 있는 경우 차단됨, 사용 중 오류와 함께 즉시 반환합니다.포기하기 전에 잠시 기다렸다가 계속 시도하도록 요청할 수 있습니다.sqlite가 부적절하다고 동의할 때 DB에 액세스하는 스레드가 수천 개 있지 않는 한 일반적으로 문제가 해결됩니다.

    // set SQLite to wait and retry for up to 100ms if database locked
    sqlite3_busy_timeout( db, 100 );

다른 팁

이 사이트가 Rails 사이트라고 말씀하셨는데요.Rails를 사용하면 Database.yml 구성 파일에서 SQLite 재시도 시간 제한을 설정할 수 있습니다.

production:
  adapter: sqlite3
  database: db/mysite_prod.sqlite3
  timeout: 10000

시간 초과 값은 밀리초 단위로 지정됩니다.10초 또는 15초로 늘리면 로그에 표시되는 BusyException 수가 줄어듭니다.

하지만 이는 일시적인 해결책일 뿐입니다.사이트에 진정한 동시성이 필요한 경우 다른 DB 엔진으로 마이그레이션해야 합니다.

이 모든 것들은 사실이지만 다음과 같은 질문에 대한 답은 아닙니다.내 Rails 앱이 프로덕션 환경에서 때때로 SQLite3::BusyException을 발생시키는 이유는 무엇입니까?

@샬마네세:프로덕션 호스팅 환경은 어떤가요?공유 호스트에 있습니까?NFS 공유에 sqlite 데이터베이스가 포함된 디렉터리가 있습니까?(아마도 공유 호스트에서).

이 문제는 NFS 공유를 통한 파일 잠금 현상 및 SQLite의 동시성 부족과 관련이 있을 수 있습니다.

기록만을 위해서.Rails 2.3.8의 한 애플리케이션에서 우리는 Rails가 Rifkin Habsburg가 제안한 "시간 초과" 옵션을 무시하고 있음을 발견했습니다.

좀 더 조사한 결과 Rails 개발에서 관련 버그가 있을 수 있음을 발견했습니다. http://dev.rubyonrails.org/ticket/8811.그리고 좀 더 조사한 끝에 우리는 발견했습니다. 해결책 (Rails 2.3.8로 테스트):

이 ActiveRecord 파일을 편집합니다:activerecord-2.3.8/lib/active_record/connection_adapters/sqlite_adapter.rb

이것을 교체하십시오:

  def begin_db_transaction #:nodoc:
    catch_schema_changes { @connection.transaction }
  end

~와 함께

  def begin_db_transaction #:nodoc:
    catch_schema_changes { @connection.transaction(:immediate) }
  end

그리고 그게 다야!우리는 성능 저하를 발견하지 못했고 이제 앱은 중단 없이 더 많은 청원을 지원합니다(시간 초과를 기다립니다).SQLite 좋네요!

bundle exec rake db:reset

그것은 나를 위해 일했으며 보류 중인 마이그레이션을 재설정하고 표시합니다.

원천: 이 링크

- Open the database
db = sqlite3.open("filename")

-- Ten attempts are made to proceed, if the database is locked
function my_busy_handler(attempts_made)
  if attempts_made < 10 then
    return true
  else
    return false
  end
end

-- Set the new busy handler
db:set_busy_handler(my_busy_handler)

-- Use the database
db:exec(...)

Sqlite는 현재 프로세스가 완료될 때까지 다른 프로세스가 대기하도록 허용할 수 있습니다.

Sqlite DB에 액세스하려는 여러 프로세스가 있을 수 있다는 것을 알고 있을 때 이 줄을 사용하여 연결합니다.

conn = sqlite3.connect('파일명', isolation_level = '독점')

Python Sqlite 문서에 따르면:

어떤 종류의 시작 명세서에서 pysqlite가 connect () 호출로 roligation_level 매개 변수를 통해 또는 Connections의 rophentation_level 속성을 통해 암시 적으로 실행 (또는 전혀 없음)을 제어 할 수 있습니다.

rake db: migration에서도 비슷한 문제가 발생했습니다.문제는 작업 디렉터리가 SMB 공유에 있다는 것이었습니다.폴더를 로컬 컴퓨터에 복사하여 문제를 해결했습니다.

이 문제가 있지만 시간 초과를 늘려도 아무 것도 바뀌지 않습니다, 트랜잭션과 관련된 또 다른 동시성 문제가 있을 수 있습니다. 요약하면 다음과 같습니다.

  1. 거래를 시작합니다( 공유됨 잠그다)
  2. DB에서 일부 데이터를 읽습니다(아직도 공유됨 잠그다)
  3. 그 사이에 다른 프로세스가 트랜잭션을 시작하고 데이터를 씁니다( 예약된 잠그다).
  4. 그런 다음 글을 쓰려고 하면 이제 요청을 하려고 합니다. 예약된 잠그다
  5. SQLite는 SQLITE_BUSY 예외를 발생시킵니다. 즉시 (시간 초과와 별개로) 이전 읽기가 더 이상 정확하지 않을 수 있기 때문입니다. 예약된 잠그다.

이 문제를 해결하는 한 가지 방법은 다음을 패치하는 것입니다. active_record sqlite 어댑터를 획득하기 위한 예약된 패딩을 사용하여 트랜잭션 시작 시 직접 잠급니다. :immediate 운전자에게 옵션을 제공합니다.이렇게 하면 성능이 약간 저하되지만 최소한 모든 트랜잭션은 시간 초과를 준수하고 차례로 발생합니다.이를 수행하는 방법은 다음과 같습니다. prepend (Ruby 2.0+) 이것을 초기화 프로그램에 넣으세요:

module SqliteTransactionFix
  def begin_db_transaction
    log('begin immediate transaction', nil) { @connection.transaction(:immediate) }
  end
end

module ActiveRecord
  module ConnectionAdapters
    class SQLiteAdapter < AbstractAdapter
      prepend SqliteTransactionFix
    end
  end
end

자세한 내용은 여기를 참조하세요: https://rails.lighthouseapp.com/projects/8994/tickets/5941-sqlite3busyExceptions-are-raised-immediately-in-some-cases-despite-setting-sqlite3_busy_timeout

대부분의 답변은 원시 Ruby가 아닌 Rails에 대한 것이며 OP는 레일에 대한 IS 질문입니다. 괜찮습니다.:)

따라서 원시 Ruby 사용자에게 이 문제가 발생하고 yml 구성을 사용하지 않는 경우 이 솔루션을 여기에 남겨두고 싶습니다.

연결을 인스턴스화한 후 다음과 같이 설정할 수 있습니다.

db = SQLite3::Database.new "#{path_to_your_db}/your_file.db"
db.busy_timeout=(15000) # in ms, meaning it will retry for 15 seconds before it raises an exception.
#This can be any number you want. Default value is 0.

잠금이 발생했을 때 어떤 테이블에 액세스하고 있습니까?

장기 실행 트랜잭션이 있나요?

잠금이 발생했을 때 어떤 요청이 아직 처리 중인지 알 수 있습니까?

아아 – 지난 주 동안 내 존재의 골칫거리였습니다.Sqlite3은 프로세스가 실행될 때 db 파일을 잠급니다. 쓴다 데이터베이스에.IE 모든 UPDATE/INSERT 유형 쿼리(어떤 이유로 count(*)도 선택).그러나 여러 읽기를 잘 처리합니다.

그래서 나는 마침내 데이터베이스 호출에 대한 자체 스레드 잠금 코드를 작성할 만큼 좌절감을 느꼈습니다.애플리케이션이 언제든지 데이터베이스에 단 하나의 스레드만 쓸 수 있도록 함으로써 스레드를 1000개까지 확장할 수 있었습니다.

그리고 네, 정말 느립니다.하지만 그것 또한 충분히 빠르고 옳은, 이는 가지고 있으면 좋은 자산입니다.

sqlite3 Ruby 확장에서 교착 상태를 발견하고 여기에서 수정했습니다.그것을 가지고 가서 이것이 당신의 문제를 해결하는지 확인하십시오.

    https://github.com/dxj19831029/sqlite3-ruby

끌어오기 요청을 열었는데 더 이상 응답이 없습니다.

어쨌든 sqlite3 자체에 설명된 대로 일부 바쁜 예외가 예상됩니다.

주의하세요 이 조건으로: sqlite 바쁜

    The presence of a busy handler does not guarantee that it will be invoked when there is 
    lock contention. If SQLite determines that invoking the busy handler could result in a 
    deadlock, it will go ahead and return SQLITE_BUSY or SQLITE_IOERR_BLOCKED instead of 
    invoking the busy handler. Consider a scenario where one process is holding a read lock 
    that it is trying to promote to a reserved lock and a second process is holding a reserved 
    lock that it is trying to promote to an exclusive lock. The first process cannot proceed 
    because it is blocked by the second and the second process cannot proceed because it is 
    blocked by the first. If both processes invoke the busy handlers, neither will make any 
    progress. Therefore, SQLite returns SQLITE_BUSY for the first process, hoping that this 
    will induce the first process to release its read lock and allow the second process to 
    proceed.

이 조건을 충족하면 시간 초과가 더 이상 유효하지 않습니다.이를 방지하려면 시작/커밋 안에 선택을 넣지 마십시오.또는 시작/커밋에 배타적 잠금을 사용하세요.

도움이 되었기를 바랍니다.:)

이는 동일한 데이터베이스에 액세스하는 여러 프로세스의 연속적인 오류인 경우가 많습니다.RubyMine에 "단 하나의 인스턴스만 허용" 플래그가 설정되지 않은 경우

다음을 실행해 보면 도움이 될 수 있습니다.

ActiveRecord::Base.connection.execute("BEGIN TRANSACTION; END;") 

에서: 루비:SQLite3::Busy예외:데이터베이스가 잠겨 있습니다:

이렇게 하면 시스템을 유지하는 모든 트랜잭션이 정리될 수 있습니다.

거래 시간이 초과되면 이런 일이 발생한다고 생각합니다.실제로 "실제" 데이터베이스를 사용해야 합니다.Drizzle이나 MySQL과 같은 것입니다.이전 두 가지 옵션보다 SQLite를 선호하는 이유가 무엇입니까?

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top