[sqlite] SQLite 동시 액세스

SQLite3는 동일한 DB에서 여러 프로세스를 읽고 쓰는 동시 액세스를 안전하게 처리합니까? 그것에 대한 플랫폼 예외가 있습니까?



답변

이러한 동시 액세스의 대부분이 읽기 (예 : SELECT)이면 SQLite가이를 잘 처리 할 수 ​​있습니다. 그러나 동시에 쓰기를 시작하면 잠금 경합이 문제가 될 수 있습니다. SQLite 엔진 자체가 매우 빠르며 경합을 최소화하기 위해 많은 영리한 최적화가 있기 때문에 파일 시스템의 속도에 따라 많은 것이 좌우됩니다. 특히 SQLite 3.

대부분의 데스크톱 / 노트북 / 태블릿 / 전화 응용 프로그램의 경우 동시성이 충분하지 않으므로 SQLite가 빠릅니다. (Firefox는 책갈피, 기록 등에 SQLite를 광범위하게 사용합니다.)

서버 응용 프로그램의 경우, 어떤 사람은 하루 전에 100K 미만의 페이지를 일반적인 시나리오 (예 : 블로그, 포럼)에서 SQLite 데이터베이스로 완벽하게 처리 할 수 ​​있다고 말했지만 그 반대 증거는 아직 보지 못했습니다. 실제로 최신 디스크와 프로세서를 사용하면 웹 사이트와 웹 서비스의 95 %가 SQLite와 잘 작동합니다.

정말로 빠른 읽기 / 쓰기 액세스를 원한다면 메모리 내 SQLite 데이터베이스를 사용하십시오 . RAM은 디스크보다 몇 배 빠릅니다.


답변

예, SQLite는 동시성을 잘 처리하지만 성능 측면에서 최고는 아닙니다. 내가 알 수있는 것에서 예외는 없습니다. 자세한 내용은 SQLite 사이트 ( https://www.sqlite.org/lockingv3.html)에 있습니다.

이 설명은 흥미 롭다 : “pager 모듈은 한 번에 모든 변경이 이루어 지도록하거나, 모든 변경이 발생하거나 전혀 수행되지 않도록하며, 둘 이상의 프로세스가 동시에 호환되지 않는 방식으로 데이터베이스에 액세스하려고하지 않도록합니다”


답변

그렇습니다. 이유를 알아 봅시다

SQLite는 트랜잭션입니다

SQLite의 단일 트랜잭션 내의 모든 변경 사항은 완전히 발생하거나 전혀 발생하지 않습니다.

동시 읽기 / 쓰기뿐만 아니라 이러한 ACID 지원은 두 가지 방식으로 제공됩니다. 이른바 저널링 ( ” 이전 방식 “이라고 함) 또는 미리 쓰기 로깅 ( ” 새로운 방식 “이라고 함)

저널링 (오래된 방식)

이 모드에서 SQLite는 DATABASE-LEVEL 잠금을 사용 합니다. 이것이 이해해야 할 중요한 포인트입니다.

즉, 무언가를 읽고 쓸 때마다 먼저 ENTIRE 데이터베이스 파일 에 대한 잠금을 획득 합니다. 여러 독자가 동시에 공존하고 무언가를 읽을 수 있음

쓰기 중에는 독점 잠금을 확보하고 다른 프로세스가 동시에 읽기 / 쓰기를 하지 않으므로 쓰기가 안전합니다.

이것은 왜 여기 가 SQLite는 구현 말을하는지 직렬화 거래

근심거리

매번 전체 데이터베이스를 잠글 필요가 있고 쓰기 동시성이 처리되는 프로세스를 기다리는 모든 사람이 대기하기 때문에 동시 쓰기 / 읽기의 성능이 상당히 낮습니다.

롤백 / 정지

데이터베이스 파일에 무언가를 쓰기 전에 SQLite는 먼저 임시 파일에서 변경되도록 청크를 저장합니다. 데이터베이스 파일에 쓰는 중에 충돌이 발생하면이 임시 파일을 가져 와서 변경 사항을 되돌립니다.

미리 쓰기 로깅 또는 WAL (새로운 방법)

이 경우 모든 쓰기는 임시 파일 ( write-ahead log )에 추가되고이 파일은 원래 데이터베이스와 주기적으로 병합됩니다. SQLite가 무언가를 검색 할 때 먼저이 임시 파일을 확인하고 아무것도 발견되지 않으면 주 데이터베이스 파일로 진행하십시오.

결과적으로 독자는 작가와 경쟁하지 않으며 올드 웨이에 비해 성능이 훨씬 좋습니다.

경고

SQlite는 기본 파일 시스템 잠금 기능에 크게 의존하므로주의해서 사용해야 합니다.

특히 저널링 모드에서 데이터베이스 잠금 오류가 발생 했을 가능성이 높 으므로이 오류를 염두에두고 앱을 설계해야합니다.


답변

아무도 WAL (Write Ahead Log) 모드를 언급하지 않은 것 같습니다. 트랜잭션이 올바르게 구성되고 WAL 모드가 설정된 상태에서 업데이트가 진행되는 동안 사람들이 내용을 읽는 동안 데이터베이스를 잠글 필요는 없습니다.

유일한 문제는 어떤 시점에서 WAL을 주 데이터베이스에 다시 통합해야한다는 것입니다. 데이터베이스에 대한 마지막 연결이 닫힐 때이 작업이 수행됩니다. 사용량이 많은 사이트를 사용하면 모든 연결이 닫히는 데 몇 초가 걸리지 만 하루에 100K의 조회수는 문제가되지 않습니다.


답변

2019 년에는 아직 출시되지 않았지만 별도의 지점에서 사용할 수있는 두 가지 새로운 동시 쓰기 옵션이 있습니다.

“PRAGMA journal_mode = wal2”

일반 “wal”모드에 비해이 저널 모드의 장점은 작성자가 한 wal 파일에 계속 쓰는 반면 다른 wal 파일은 체크 포인트됩니다.

시작 동시 -상세 문서 링크

BEGIN CONCURRENT 향상 기능은 시스템이 여전히 COMMIT 명령을 직렬화하더라도 데이터베이스가 “wal”또는 “wal2″모드 인 경우 여러 작성자가 쓰기 트랜잭션을 동시에 처리 할 수 ​​있도록합니다.

“BEGIN CONCURRENT”로 쓰기 트랜잭션을 열면 실제로 데이터베이스 잠금은 COMMIT가 실행될 때까지 지연됩니다. 이는 BEGIN CONCURRENT로 시작된 많은 수의 트랜잭션이 동시에 진행될 수 있음을 의미합니다. 시스템은 낙관적 인 페이지 레벨 잠금을 사용하여 충돌하는 동시 트랜잭션이 커미트되지 않도록합니다.

그것들은 begin-concurrent-wal2 또는 각각 별도의 브랜치에 있습니다.


답변

SQLite에는 데이터베이스 수준에 대한 독자-작성기 잠금이 있습니다. 여러 프로세스 (다른 프로세스가 소유하고있을 수 있음)는 동일한 데이터베이스에서 동시에 데이터를 읽을 수 있지만 하나만 데이터베이스에 쓸 수 있습니다.

SQLite는 무제한의 동시 판독기를 지원하지만 한 번에 한 명의 작성자 만 허용합니다. 많은 상황에서 이것은 문제가되지 않습니다. 라이터 큐업 각 응용 프로그램은 데이터베이스가 빠르게 작동하고 계속 진행하며 수십 밀리 초 이상 동안 잠금이 지속되지 않습니다. 그러나 더 많은 동시성이 필요한 일부 응용 프로그램이 있으며 해당 응용 프로그램은 다른 솔루션을 찾아야 할 수도 있습니다. – SQLite는 @ SQLite.org에 적합한 용도

독자-작성기 잠금은 독립적 인 트랜잭션 처리를 가능하게하며 데이터베이스 레벨에서 독점 및 공유 잠금을 사용하여 구현됩니다.

연결이 데이터베이스에서 쓰기 조작을 수행하기 전에 독점 잠금을 확보해야합니다. 단독 잠금이 확보되면 잠금이 다시 해제 될 때까지 다른 연결의 읽기 및 쓰기 작업이 모두 차단됩니다.

동시 쓰기의 경우 구현 세부 사항

SQLite에는 쓰기 작업 중에 가능한 한 늦게 데이터베이스를 잠그는 데 도움이되는 잠금 테이블이있어 최대의 동시성을 보장합니다.

초기 상태는 UNLOCKED이며이 상태에서는 연결이 데이터베이스에 아직 액세스하지 않았습니다. 프로세스가 데이터베이스에 연결되어 있고 트랜잭션이 BEGIN으로 시작된 경우에도 연결은 여전히 ​​잠금 해제 상태입니다.

UNLOCKED 상태 후 다음 상태는 SHARED 상태입니다. 데이터베이스에서 데이터를 읽거나 쓰지 않으려면 먼저 SHARED 잠금을 가져 와서 연결이 SHARED 상태가되어야합니다. 여러 연결이 동시에 SHARED 잠금을 확보하고 유지할 수 있으므로 여러 연결이 동일한 데이터베이스에서 동시에 데이터를 읽을 수 있습니다. 그러나 하나의 SHARED 잠금 만 해제되어 있으면 연결이 데이터베이스에 대한 쓰기를 완료 할 수 없습니다.

연결이 데이터베이스에 쓰려면 먼저 예약 된 잠금을 가져와야합니다.

한 번에 하나의 RESERVED 잠금 만 활성화 될 수 있지만 여러 개의 SHARED 잠금이 단일 RESERVED 잠금과 공존 할 수 있습니다. 예약 된 잠금이있는 동안 새 공유 잠금을 획득 할 수 있다는 점에서 예약 됨과 보류 중이 다릅니다. – 파일 잠금과 동시성에서 SQLite는 버전 3 @ SQLite.org

연결이 RESERVED 잠금을 확보하면 데이터베이스 수정 조작 처리를 시작할 수 있지만 이러한 수정은 실제로 디스크에 기록되지 않고 버퍼에서만 수행 될 수 있습니다. 판독 내용에 대한 수정은 메모리 버퍼에 저장됩니다. 연결이 수정 (또는 트랜잭션)을 제출하려는 경우 예약 된 잠금을 독점 잠금으로 업그레이드해야합니다. 자물쇠를 얻으려면 먼저 자물쇠를 PENDING 자물쇠로 들어야합니다.

PENDING 잠금은 잠금을 보유한 프로세스가 가능한 빨리 데이터베이스에 쓰려고하고 독점 잠금을 얻을 수 있도록 현재 공유 된 모든 잠금을 지울 때까지 대기하고 있음을 의미합니다. PENDING 잠금이 활성화 된 경우 기존 SHARED 잠금을 계속할 수 있지만 데이터베이스에 대해 새로운 SHARED 잠금이 허용되지 않습니다.

데이터베이스 파일에 쓰려면 독점 잠금이 필요합니다. 파일에는 하나의 EXCLUSIVE 잠금 만 허용되며 어떤 종류의 다른 잠금도 EXCLUSIVE 잠금과 공존 할 수 없습니다. 동시성을 최대화하기 위해 SQLite는 독점 잠금이 유지되는 시간을 최소화합니다. – 파일 잠금과 동시성에서 SQLite는 버전 3 @ SQLite.org

따라서 SQLite는 단순히 지원하지 않기 때문에 동일한 DB에 쓰는 여러 프로세스의 동시 액세스를 안전하게 처리한다고 말할 수 있습니다! 재시도 제한에 도달 하면 두 번째 작성자를 얻 SQLITE_BUSY거나 받게됩니다 SQLITE_LOCKED.


답변

이 스레드는 오래되었지만 sqlite에서 수행 한 테스트 결과를 공유하는 것이 좋을 것이라고 생각합니다 .EXCLUSIVE 잠금 및 시간 초과가 설정된 트랜잭션 내에서 SELECT 및 UPDATE sql 명령을 실행하는 2 개의 Python 프로그램 인스턴스 (다른 프로세스가 동일한 프로그램)를 실행했습니다. 10 초 동안 잠금을 설정하면 결과가 실망 스러웠습니다. 모든 인스턴스는 10000 단계 루프에서 수행했습니다.

  • 독점 잠금으로 DB에 연결
  • 카운터를 읽으려면 한 행을 선택하십시오
  • 카운터가 1 씩 증가하는 것과 같은 새 값으로 행을 업데이트하십시오.
  • db와의 밀접한 연결

sqlite가 트랜잭션에 독점 잠금을 부여하더라도 실제로 실행 된 총주기 수는 20 000과 같지 않았지만 두 프로세스에 대해 계산 된 단일 카운터에 대한 총 반복 횟수입니다. 파이썬 프로그램은 거의 단일 예외를 던지지 않았습니다 (20 번 실행을 선택하는 동안 한 번만). 테스트 시점의 sqlite 개정은 3.6.20 및 python v3.3 CentOS 6.5입니다. 내 의견으로는 이러한 종류의 작업에 대해보다 안정적인 제품을 찾거나 sqlite에 대한 쓰기를 단일 고유 프로세스 / 스레드로 제한하는 것이 좋습니다.