거래 및 기타

사용 가능

5.1 동시성의 문제

조금 먼 이론부터 시작합시다.

프로그래머가 만드는 모든 정보 시스템(또는 간단히 응용 프로그램)은 각각 필요한 기능의 일부를 제공하는 몇 가지 일반적인 블록으로 구성됩니다. 예를 들어, 캐시는 리소스 집약적인 작업의 결과를 기억하여 클라이언트가 데이터를 더 빨리 읽을 수 있도록 하고, 스트림 처리 도구를 사용하면 비동기 처리를 위해 다른 구성 요소에 메시지를 보낼 수 있으며, 일괄 처리 도구는 " 일정한 주기성을 가지고 축적된 데이터의 양을 긁어모으십시오. .

그리고 거의 모든 응용 프로그램에서 데이터베이스(DB)는 어떤 식으로든 관련되어 있으며 일반적으로 두 가지 기능을 수행합니다. 즉, 귀하로부터 데이터를 받을 때 데이터를 저장하고 나중에 요청 시 데이터를 제공합니다. 이미 많은 기성품 솔루션이 있기 때문에 누구나 자신의 데이터베이스를 만들려고 생각하는 사람은 거의 없습니다. 하지만 애플리케이션에 적합한 것을 어떻게 선택합니까?

따라서 이전에 저장한 집 주변의 작업 목록을 로드할 수 있는 모바일 인터페이스가 있는 애플리케이션을 작성했다고 가정해 보겠습니다. 즉, 데이터베이스에서 읽고 새 작업으로 보완하고 각 특정 작업의 우선 순위를 작업 - 1(최고)에서 3(최저)까지. 한 번에 한 사람만 모바일 애플리케이션을 사용한다고 가정해 보겠습니다. 하지만 이제 감히 어머니에게 자신의 창작물에 대해 이야기했고 이제 그녀는 두 번째 일반 사용자가 되었습니다. 동시에, 바로 같은 밀리초에 "창문 세척"과 같은 작업을 다른 우선 순위로 설정하기로 결정하면 어떻게 됩니까?

전문적인 용어로 귀하와 어머니의 데이터베이스 쿼리는 데이터베이스에 쿼리를 만든 2개의 프로세스로 간주할 수 있습니다. 프로세스는 하나 이상의 스레드에서 실행할 수 있는 컴퓨터 프로그램의 엔터티입니다. 일반적으로 프로세스에는 기계 코드 이미지, 메모리, 컨텍스트 및 기타 리소스가 있습니다. 즉, 프로세스는 프로세서에서 프로그램 명령을 실행하는 것으로 특징지을 수 있습니다. 귀하의 애플리케이션이 데이터베이스에 요청을 할 때, 우리는 귀하의 데이터베이스가 한 프로세스에서 네트워크를 통해 받은 요청을 처리한다는 사실에 대해 이야기하고 있습니다. 애플리케이션에 동시에 두 명의 사용자가 있는 경우 특정 시점에 두 개의 프로세스가 있을 수 있습니다.

일부 프로세스가 데이터베이스에 요청을 하면 특정 상태에 있는 것을 찾습니다. 상태 저장 시스템은 이전 이벤트를 기억하고 "상태"라고 하는 일부 정보를 저장하는 시스템입니다. 로 선언된 변수는 integer0, 1, 2 또는 42의 상태를 가질 수 있습니다. 뮤텍스 (상호 배제)에는 두 가지 상태가 있습니다. 잠금 또는 잠금 해제 이진 세마포어("필수" 대 "해제") 및 일반적으로 이진 (이진) 데이터 유형 및 변수는 1 또는 0의 두 가지 상태만 가질 수 있습니다.

상태의 개념을 기반으로 여러 수학적 및 공학적 구조가 기반으로 합니다. 예를 들어 유한 오토마톤(하나의 입력과 하나의 출력이 있고 매 순간 유한한 상태 세트 중 하나에 있는 모델)과 "상태"가 있습니다. ” 내부 상태에 따라 개체가 동작을 변경하는 디자인 패턴(예: 하나 또는 다른 변수에 할당된 값에 따라).

따라서 기계 세계의 대부분의 개체에는 시간이 지남에 따라 변경될 수 있는 상태가 있습니다. 큰 데이터 패킷을 처리하는 파이프라인은 오류를 발생시키고 실패하게 됩니다 . 계정, 급여 영수증 후 변경.

한 상태에서 다른 상태로의 전환("전환"), 즉 진행 중에서 실패 로 전환하는 것을 작업이라고 합니다. 아마도 모든 사람이 CRUD 작업 ( create, read, 또는 유사한 HTTPupdate 메서드 - , , , ) 을 알고 있을 것입니다 . 그러나 프로그래머는 종종 데이터베이스에서 특정 값을 읽는 것보다 작업이 더 복잡할 수 있기 때문에 코드에서 작업에 다른 이름을 지정합니다. 예를 들어, 누가 이러한 작업 기능을 수행합니까? 이미 설명한 프로세스.deletePOSTGETPUTDELETEvalidate()

조금 더, 내가 왜 그렇게 자세하게 용어를 설명하는지 이해하게 될 것입니다!

함수이거나 분산 시스템에서 다른 서버로 요청을 전송하는 모든 작업에는 호출 시간완료 시간(완료 시간) 이라는 두 가지 속성이 있습니다 . 이 속성은 호출 시간보다 훨씬 큽니다(Jepsen의 연구원). 이 두 타임스탬프 모두 가상의 완전히 동기화되고 전 세계적으로 사용 가능한 시계가 제공된다는 이론적 가정에서 진행하십시오.

할 일 목록 애플리케이션을 상상해 봅시다. 당신은 에서 모바일 인터페이스를 통해 데이터베이스에 요청을 하고 14:00:00.014, 당신의 어머니는 13:59:59.678(즉, 336밀리초 전) 같은 인터페이스를 통해 할 일 목록을 업데이트하여 설거지를 추가합니다. 네트워크 지연과 데이터베이스에 대한 가능한 작업 대기열을 고려하면, 귀하와 귀하의 어머니 외에 어머니의 모든 친구도 귀하의 응용 프로그램을 사용하는 경우 데이터베이스는 귀하의 요청을 처리한 후 어머니의 요청을 실행할 수 있습니다. 즉, 어머니의 여자 친구의 요청뿐만 아니라 두 개의 요청이 동시에(동시에) 동일한 데이터로 전송될 가능성이 있습니다.

따라서 우리는 데이터베이스 및 분산 응용 프로그램 분야에서 가장 중요한 용어인 동시성(concurrency)에 도달했습니다. 두 작업의 동시성은 정확히 무엇을 의미할 수 있습니까? 일부 작업 T1 및 일부 작업 T2가 제공되면 다음과 같습니다.

  • T1은 실행 시작 시간 T2 이전에 시작하고 T2 시작 및 종료 시간 사이에 완료할 수 있습니다.
  • T2는 T1의 시작 시간 이전에 시작하여 T1의 시작과 끝 사이에 완료할 수 있습니다.
  • T1 실행 시작 및 종료 시간 사이에 T1을 시작하고 완료할 수 있습니다.
  • T1과 T2가 공통 실행 시간을 갖는 다른 시나리오

이 강의의 틀 내에서 우리는 주로 데이터베이스에 들어가는 쿼리와 데이터베이스 관리 시스템이 이러한 쿼리를 인식하는 방법에 대해 이야기하고 있지만 동시성이라는 용어는 예를 들어 운영 체제의 맥락에서 중요합니다. 이 기사의 주제에서 너무 벗어나지는 않겠지 만 여기서 말하는 동시성은 동시성의 딜레마와 동시성의 딜레마와 그 차이점과 관련이 없다는 점을 언급하는 것이 중요하다고 생각합니다. 운영 체제 및 고성능 컴퓨팅. 병렬 처리는 다중 코어, 프로세서 또는 컴퓨터가 있는 환경에서 동시성을 달성하는 한 가지 방법입니다. 공통 데이터에 대한 서로 다른 프로세스의 동시 액세스라는 의미에서 동시성에 대해 이야기하고 있습니다.

그리고 실제로 순전히 이론적으로 무엇이 잘못될 수 있습니까?

공유 데이터에 대해 작업할 때 "경쟁 조건"이라고도 하는 동시성과 관련된 수많은 문제가 발생할 수 있습니다. 첫 번째 문제는 프로세스가 수신해서는 안 되는 데이터(불완전, 임시, 취소 또는 "잘못된" 데이터)를 수신할 때 발생합니다. 두 번째 문제 는 프로세스가 오래된 데이터, 즉 데이터베이스의 마지막 저장된 상태에 해당하지 않는 데이터를 받는 경우입니다. 몇 밀리 초 전에 발생한 마지막 인출을 고려하지 않고 데이터베이스가 애플리케이션에 계정 상태를 반환했기 때문에 일부 애플리케이션이 잔액이 0 인 사용자 계정에서 돈을 인출했다고 가정 해 보겠습니다. 상황이 너무 좋지 않습니까?

5.2 트랜잭션이 우리를 구했습니다

이러한 문제를 해결하기 위해 논리적으로 단일 작업인 데이터베이스를 사용한 일련의 순차적 작업(상태 변경) 그룹인 트랜잭션의 개념이 등장했습니다. 거래의 개념이 분명히 돈을 다루는 맥락에서 정확하게 나타 났기 때문에 우연히가 아니라 은행에 대한 예를 다시 들겠습니다. 거래의 전형적인 예는 한 은행 계좌에서 다른 은행 계좌로 돈을 이체하는 것입니다. 먼저 원본 계좌에서 금액을 인출한 다음 대상 계좌에 입금해야 합니다.

이 트랜잭션을 수행하려면 애플리케이션이 데이터베이스에서 발신인의 잔액 확인, 발신인 계정의 금액 차단, 수신인 계정에 금액 추가, 발신자로부터 금액 차감과 같은 여러 작업을 수행해야 합니다. 그러한 거래에는 몇 가지 요구 사항이 있습니다. 예를 들어, 애플리케이션은 잔액에 대한 오래되었거나 잘못된 정보를 수신할 수 없습니다. 예를 들어 동시에 병렬 트랜잭션이 중간에 오류로 종료되고 자금이 계정에서 인출되지 않은 경우 애플리케이션이 이미 정보를 수신했습니다. 자금이 상각되었다는 것입니다.

이 문제를 해결하기 위해 "격리"와 같은 트랜잭션의 속성이 호출되었습니다. 트랜잭션은 동시에 수행되는 다른 트랜잭션이 없는 것처럼 실행됩니다. 우리의 데이터베이스는 동시 작업을 순차적 으로 하나씩 실행하는 것처럼 수행합니다. 사실 가장 높은 격리 수준은 Strict Serializable 입니다 . 예, 가장 높음은 여러 수준이 있음을 의미합니다.

"그만"이라고 말합니다. 말을 잡아요.

각 작업에는 호출 시간과 실행 시간이 있다고 설명했던 것을 기억해 봅시다. 편의상 호출과 실행을 2개의 작업으로 고려할 수 있습니다. 그런 다음 모든 호출 및 실행 작업의 정렬된 목록을 데이터베이스의 기록이라고 할 수 있습니다. 그런 다음 트랜잭션 격리 수준은 일련의 기록입니다. 우리는 격리 수준을 사용하여 어떤 스토리가 "좋음"인지 결정합니다. 이야기가 "연재 가능성을 깨뜨린다" 또는 "연재할 수 없다"라고 말할 때 우리는 그 이야기가 일련화 가능한 이야기 ​​세트에 없다는 것을 의미합니다.

우리가 어떤 종류의 이야기를 하고 있는지 명확히 하기 위해 예를 들어 보겠습니다. 예를 들어, 그런 종류의 기록이 있습니다. 중간 읽기 . 이는 트랜잭션 A가 실행 중인 다른 트랜잭션 B에 의해 수정되고 아직 커밋되지 않은("커밋되지 않음") 행에서 데이터를 읽을 수 있을 때 발생합니다. 트랜잭션 B이며 언제든지 취소할 수 있습니다. 예를 들어 중단된 읽기는 취소된 인출 트랜잭션의 예일 뿐입니다.

몇 가지 가능한 이상이 있습니다. 즉, 변칙은 데이터베이스에 경쟁적으로 액세스하는 동안 발생할 수 있는 일종의 바람직하지 않은 데이터 상태입니다. 그리고 특정 원치 않는 상태를 방지하기 위해 데이터베이스는 서로 다른 수준의 격리, 즉 원치 않는 상태로부터 서로 다른 수준의 데이터 보호를 사용합니다. 이러한 수준(4개)은 ANSI SQL-92 표준에 나열되었습니다.

일부 연구자들에게는 이러한 수준에 대한 설명이 모호해 보이며 자체적이고 보다 상세한 분류를 제공합니다. 이미 언급한 Jepsen과 MySQL 또는 PostgreSQL과 같은 특정 DBMS에서 제공하는 격리 수준을 정확히 명확히 하는 것을 목표로 하는 Hermitage 프로젝트에 주의를 기울이는 것이 좋습니다. 이 리포지토리에서 파일을 열면 특정 이상에 대해 데이터베이스를 테스트하는 데 사용하는 SQL 명령 시퀀스를 볼 수 있으며 관심 있는 데이터베이스에 대해 유사한 작업을 수행할 수 있습니다. 다음은 관심을 끌 수 있는 저장소의 한 가지 예입니다.

-- Database: MySQL

-- Setup before test
create table test (id int primary key, value int) engine=innodb;
insert into test (id, value) values (1, 10), (2, 20);

-- Test the "read uncommited" isolation level on the "Intermediate Reads" (G1b) anomaly
set session transaction isolation level read uncommitted; begin; -- T1
set session transaction isolation level read uncommitted; begin; -- T2
update test set value = 101 where id = 1; -- T1
select * from test; -- T2. Shows 1 => 101
update test set value = 11 where id = 1; -- T1
commit; -- T1
select * from test; -- T2. Now shows 1 => 11
commit; -- T2

-- Result: doesn't prevent G1b

동일한 데이터베이스에 대해 일반적으로 여러 유형의 격리 중 하나를 선택할 수 있음을 이해하는 것이 중요합니다. 가장 강력한 단열재를 선택하지 않겠습니까? 컴퓨터 과학의 모든 것과 마찬가지로 선택한 격리 수준은 우리가 할 준비가 된 절충안과 일치해야 합니다. 이 경우 실행 속도의 절충안입니다. 격리 수준이 강할수록 요청 속도가 느려집니다. 처리. 필요한 격리 수준을 이해하려면 응용 프로그램의 요구 사항을 이해하고 선택한 데이터베이스가 이 수준을 제공하는지 이해하려면 설명서를 살펴봐야 합니다. 대부분의 응용 프로그램에서는 이것으로 충분하지만 특히 엄격한 요구 사항이 있는 경우 Hermitage 프로젝트의 사람들이 수행하는 것과 같은 테스트를 준비하는 것이 좋습니다.

5.3 ACID의 "I" 및 기타 문자

격리는 기본적으로 사람들이 일반적으로 ACID에 대해 이야기할 때 의미하는 것입니다. 그리고 이 개념을 설명하려는 사람들이 일반적으로 하는 것처럼 순서대로 진행하지 않고 이 두문자어를 분리하여 분석하기 시작한 것이 바로 이러한 이유 때문입니다. 이제 나머지 세 글자를 살펴보겠습니다.

은행 송금으로 우리의 예를 다시 생각해보십시오. 한 계정에서 다른 계정으로 자금을 이체하는 거래에는 첫 번째 계정에서의 인출 작업과 두 번째 계정에서의 보충 작업이 포함됩니다. 두 번째 계정의 보충 작업이 실패한 경우 첫 번째 계정에서 인출 작업이 발생하지 않도록 할 수 있습니다. 즉, 트랜잭션이 완전히 성공하거나, 전혀 발생하지 않지만 일부만 이루어질 수는 없습니다. 이 속성을 "원자성"이라고 하며 ACID에서 "A"입니다.

트랜잭션이 실행되면 다른 작업과 마찬가지로 데이터베이스를 하나의 유효한 상태에서 다른 상태로 전송합니다. 일부 데이터베이스는 예를 들어 기본 또는 보조 키, 인덱스, 기본값, 열 유형 등과 관련하여 저장된 데이터에 적용되는 규칙인 소위 제약 조건을 제공합니다. 따라서 트랜잭션을 수행할 때 이러한 모든 제약 조건이 충족되는지 확인해야 합니다.

이 보증을 "일관성"이라고 하며 ACID의 문자입니다 C(나중에 설명할 분산 응용 프로그램 세계의 일관성과 혼동하지 말 것). ACID의 의미에서 일관성에 대한 명확한 예를 들겠습니다. 온라인 상점용 애플리케이션은 orders테이블에 행을 추가하려고 하고 테이블의 ID는 열에 product_id표시됩니다 .productsforeign key

예를 들어 제품이 구색에서 제거되고 그에 따라 데이터베이스에서 제거되면 행 삽입 작업이 발생하지 않아야 하며 오류가 발생합니다. 내 생각에 이 보장은 다른 것들과 비교할 때 다소 설득력이 없습니다. 데이터베이스에서 제약 조건을 적극적으로 사용한다는 것은 데이터에 대한 책임을 이전하는 것을 의미하기 때문입니다. CHECK와 같은 제약 조건) 애플리케이션에서 데이터베이스로, 지금 말하는 것처럼 그렇습니다.

그리고 마지막으로 D"저항"(내구성)이 남아 있습니다. 시스템 오류 또는 기타 오류로 인해 트랜잭션 결과 또는 데이터베이스 콘텐츠가 손실되어서는 안 됩니다. 즉, 데이터베이스에서 트랜잭션이 성공했다고 응답하면 데이터가 비휘발성 메모리(예: 하드 디스크)에 기록되었음을 의미합니다. 그건 그렇고, 다음 읽기 요청에서 데이터를 즉시 볼 수 있다는 의미는 아닙니다.

저번에 AWS(Amazon Web Services)에서 DynamoDB로 작업을 하다가 저장용으로 데이터를 보냈는데 답장(OK)을 받고 확인을 하기로 했는데 못봤습니다 HTTP 200. 다음 10초 동안 데이터베이스의 데이터. 즉, DynamoDB가 내 데이터를 커밋했지만 모든 노드가 데이터의 최신 복사본을 가져오기 위해 즉시 동기화되지는 않았습니다(캐시에 있었을 수도 있음). 여기서 우리는 다시 분산 시스템의 맥락에서 일관성의 영역으로 올라갔지만 아직 그것에 대해 이야기할 시간은 오지 않았습니다.

이제 우리는 ACID 보증이 무엇인지 알게 되었습니다. 그리고 우리는 그것들이 왜 유용한지도 알고 있습니다. 그러나 모든 응용 프로그램에 정말 필요합니까? 그렇지 않다면 정확히 언제입니까? 모든 DB가 이러한 보장을 제공합니까? 그렇지 않은 경우 대신 무엇을 제공합니까?

코멘트
  • 인기
  • 신규
  • 이전
코멘트를 남기려면 로그인 해야 합니다
이 페이지에는 아직 코멘트가 없습니다