CodeGym /Java Course /All lectures for KO purposes /애플리케이션에서 ACID를 구현하는 방법: 실습

애플리케이션에서 ACID를 구현하는 방법: 실습

All lectures for KO purposes
레벨 1 , 레슨 889
사용 가능

8.1 트랜잭션 ID

XID 또는 TxID로 지정됩니다(차이가 있으면 알려주세요). 타임스탬프는 TxID로 사용할 수 있으며 모든 작업을 특정 시점으로 복원하려는 경우 사용할 수 있습니다. 타임스탬프가 충분히 세분화되지 않은 경우 문제가 발생할 수 있습니다. 그러면 트랜잭션이 동일한 ID를 얻을 수 있습니다.

따라서 가장 신뢰할 수 있는 옵션은 고유한 UUID 제품 ID를 생성하는 것입니다. 파이썬에서 이것은 매우 쉽습니다:

>>> import uuid 
>>> str(uuid.uuid4()) 
'f50ec0b7-f960-400d-91f0-c42a6d44e3d0' 
>>> str(uuid.uuid4()) 
'd15bed89-c0a5-4a72-98d9-5507ea7bc0ba' 

트랜잭션 정의 데이터 집합을 해시하고 이 해시를 TxID로 사용하는 옵션도 있습니다.

8.2 재시도

특정 함수나 프로그램이 멱등적이라는 것을 안다면 이는 오류가 발생한 경우 해당 호출을 반복할 수 있고 시도해야 한다는 것을 의미합니다. 그리고 우리는 일부 작업이 오류를 일으킬 것이라는 사실에 대비해야 합니다. 최신 응용 프로그램이 네트워크와 하드웨어에 분산되어 있다는 점을 감안할 때 오류는 예외가 아니라 표준으로 간주되어야 합니다. 오류는 서버 충돌, 네트워크 오류, 원격 응용 프로그램 정체로 인해 발생할 수 있습니다. 애플리케이션은 어떻게 작동해야 합니까? 맞습니다. 작업을 반복하십시오.

한 조각의 코드가 전체 단어 페이지보다 더 많은 것을 말할 수 있으므로 순진한 재시도 메커니즘이 이상적으로 작동하는 방식을 이해하기 위해 한 가지 예를 사용하겠습니다. Tenacity 라이브러리를 사용하여 이를 시연할 것입니다(너무 잘 설계되어 사용할 계획이 없더라도 반복 메커니즘을 설계할 수 있는 방법을 예제에서 보여주어야 함).

import logging
import random
import sys
from tenacity import retry, stop_after_attempt, stop_after_delay, wait_exponential, retry_if_exception_type, before_log

logging.basicConfig(stream=sys.stderr, level=logging.DEBUG)
logger = logging.getLogger(__name__)

@retry(
	stop=(stop_after_delay(10) | stop_after_attempt(5)),
	wait=wait_exponential(multiplier=1, min=4, max=10),
	retry=retry_if_exception_type(IOError),
	before=before_log(logger, logging.DEBUG)
)
def do_something_unreliable():
	if random.randint(0, 10) > 1:
    	raise IOError("Broken sauce, everything is hosed!!!111one")
	else:
    	return "Awesome sauce!"

print(do_something_unreliable.retry.statistics)

> 만일의 경우를 대비하여 \@retry(...)는 "데코레이터"라고 하는 특별한 Python 구문입니다. 다른 함수를 래핑하고 실행 전후에 작업을 수행하는 retry(...) 함수일 뿐입니다.

보시다시피 재시도는 창의적으로 설계할 수 있습니다.

  • 시간(10초) 또는 시도 횟수(5)로 시도를 제한할 수 있습니다.
  • 지수적일 수 있습니다(즉, 2 ** 일부 증가하는 숫자 n ). 또는 별도의 시도 사이의 시간을 늘리기 위해 다른 방법(예: 고정)을 사용합니다. 지수 변형은 "혼잡 붕괴"라고 합니다.
  • 특정 유형의 오류(IOError)에 대해서만 재시도할 수 있습니다.
  • 재시도 시도는 로그의 일부 특수 항목에 의해 선행되거나 완료될 수 있습니다.

Young Fighter 과정을 완료하고 애플리케이션 측면에서 트랜잭션 작업에 필요한 기본 빌딩 블록을 알았으므로 이제 분산 시스템에서 트랜잭션을 구현할 수 있는 두 가지 방법에 대해 알아보겠습니다.

8.3 거래 애호가를 위한 고급 도구

이 주제는 별도의 큰 기사에 합당하기 때문에 상당히 일반적인 정의만 제공하겠습니다.

2단계 커밋(2pc) . 2pc에는 준비 단계와 커밋 단계의 두 단계가 있습니다. 준비 단계 동안 모든 마이크로 서비스는 원자적으로 수행할 수 있는 일부 데이터 변경을 준비하라는 요청을 받습니다. 모두 준비되면 커밋 단계에서 실제 변경 사항을 적용합니다. 프로세스를 조정하려면 필요한 객체를 잠그는 글로벌 코디네이터가 필요합니다. 즉, 코디네이터가 잠금을 해제할 때까지 변경 사항에 액세스할 수 없게 됩니다. 특정 마이크로 서비스가 변경 준비가 되지 않은 경우(예: 응답하지 않음) 코디네이터는 트랜잭션을 중단하고 롤백 프로세스를 시작합니다.

이 프로토콜이 좋은 이유는 무엇입니까? 원자성을 제공합니다. 또한 쓰고 읽을 때 격리를 보장합니다. 즉, 코디네이터가 변경 사항을 커밋할 때까지 한 트랜잭션의 변경 사항이 다른 트랜잭션에 표시되지 않습니다. 그러나 이러한 속성에는 단점도 있습니다. 이 프로토콜은 동기식(차단)이기 때문에 시스템 속도가 느려집니다(RPC 호출 자체가 상당히 느리다는 사실에도 불구하고). 그리고 다시 상호 차단의 위험이 있습니다.

사가 _ 이 패턴에서 분산 트랜잭션은 연결된 모든 마이크로 서비스에서 비동기 로컬 트랜잭션에 의해 실행됩니다. 마이크로서비스는 이벤트 버스를 통해 서로 통신합니다. 마이크로 서비스가 로컬 트랜잭션을 완료하지 못하면 다른 마이크로 서비스가 보상 트랜잭션을 수행하여 변경 사항을 롤백합니다.

Saga의 장점은 차단된 개체가 없다는 것입니다. 그러나 물론 단점도 있습니다.

Saga는 특히 많은 마이크로 서비스가 관련된 경우 디버깅하기 어렵습니다. Saga 패턴의 또 다른 단점은 읽기 격리가 없다는 것입니다. 즉, ACID에 표시된 속성이 우리에게 중요하다면 Saga는 우리에게 그다지 적합하지 않습니다.

이 두 기술에 대한 설명에서 무엇을 알 수 있습니까? 분산 시스템에서 원자성 및 격리에 대한 책임은 애플리케이션에 있습니다. ACID 보장을 제공하지 않는 데이터베이스를 사용할 때도 마찬가지입니다. 즉, 충돌 해결, 롤백, 커밋 및 공간 확보와 같은 작업은 개발자의 어깨에 있습니다.

8.4 ACID 보증이 필요한 시기를 어떻게 알 수 있습니까?

특정 사용자 또는 프로세스 집합이 동일한 데이터에서 동시에 작업할 가능성이 높은 경우 .

진부해서 미안하지만 전형적인 예는 금융 거래입니다.

거래가 실행되는 순서가 중요한 경우.

회사가 FunnyYellowChat 메신저에서 FunnyRedChat 메신저로 전환하려고 한다고 상상해보세요. 왜냐하면 FunnyRedChat에서는 gif를 보낼 수 있지만 FunnyYellowChat에서는 불가능하기 때문입니다. 그러나 당신은 단순히 메신저를 바꾸는 것이 아니라 한 메신저에서 다른 메신저로 회사의 서신을 마이그레이션하는 것입니다. 프로그래머가 중앙 어딘가에 프로그램과 프로세스를 문서화하는 데 너무 게을러서 대신 메신저의 다른 채널에 모든 것을 게시했기 때문에 이렇게 합니다. 예, 영업 사원이 같은 위치에 협상 및 계약 세부 정보를 게시했습니다. 요컨대, 회사의 전체 수명이 거기에 있고 문서화를 위해 모든 것을 서비스로 옮길 시간이 없고 인스턴트 메신저 검색이 잘 작동하기 때문에 잔해를 치우는 대신 단순히 모든 것을 복사하기로 결정했습니다. 메시지를 새 위치로 보냅니다. 메시지의 순서가 중요합니다

그건 그렇고, 메신저의 서신의 경우 일반적으로 순서가 중요하지만 두 사람이 동시에 같은 채팅에서 무언가를 쓸 때 일반적으로 누구의 메시지가 먼저 표시되는지는 그다지 중요하지 않습니다. 따라서 이 특정 시나리오에서는 ACID가 필요하지 않습니다.

또 다른 가능한 예는 생물 정보학입니다. 나는 이것을 전혀 이해하지 못하지만 인간 게놈을 해독할 때 순서가 중요하다고 생각합니다. 그러나 생물 정보학자는 일반적으로 모든 작업에 일부 도구를 사용한다고 들었습니다. 아마도 자체 데이터베이스가 있을 수 있습니다.

사용자에게 제공하거나 오래된 데이터를 처리할 수 없는 경우.

그리고 다시 - 금융 거래. 솔직히 말해서 다른 예가 생각나지 않았습니다.

보류 중인 트랜잭션이 상당한 비용과 관련된 경우. 데이터베이스가 트랜잭션을 격리할 수 없기 때문에 의사와 간호사가 동시에 환자 기록을 업데이트하고 서로의 변경 사항을 지울 때 발생할 수 있는 문제를 상상해 보십시오. 의료 시스템은 금융 외에 ACID 보증이 중요한 경향이 있는 또 다른 영역입니다.

8.5 언제 ACID가 필요하지 않습니까?

사용자가 자신의 개인 데이터 중 일부만 업데이트하는 경우.

예를 들어 사용자가 웹 페이지에 댓글이나 스티커 메모를 남깁니다. 또는 서비스 제공업체의 개인 계정에서 개인 데이터를 편집합니다.

사용자가 데이터를 전혀 업데이트하지 않고 새 데이터로 보완(추가)만 하는 경우.

예를 들어, 실행 데이터를 저장하는 실행 중인 애플리케이션: 실행 시간, 시간, 경로 등. 각각의 새 실행은 새 데이터이며 이전 데이터는 전혀 편집되지 않습니다. 아마도 데이터를 기반으로 분석을 얻을 수 있으며 NoSQL 데이터베이스만 이 시나리오에 적합합니다.

비즈니스 로직이 트랜잭션이 수행되는 특정 순서에 대한 필요성을 결정하지 않는 경우.

아마도 다음 생방송에서 신작 제작을 위해 기부금을 모으는 유튜브 블로거에게는 누가, 언제, 어떤 순서로 돈을 던 졌는지가 그다지 중요하지 않을 것입니다.

사용자가 몇 초 또는 심지어 몇 분 동안 같은 웹 페이지나 애플리케이션 창에 머물게 되므로 어떻게든 오래된 데이터를 보게 될 것입니다.

이론적으로 이들은 모든 온라인 뉴스 매체 또는 동일한 Youtube입니다. 또는 "하브르". 불완전한 트랜잭션이 시스템에 일시적으로 저장될 수 있다는 것이 중요하지 않은 경우 손상 없이 무시할 수 있습니다.

많은 소스에서 데이터를 집계하고 높은 빈도로 업데이트되는 데이터(예: 적어도 5분마다 변경되는 도시의 주차 공간 점유 데이터)를 집계하는 경우 이론상으로는 큰 문제가 되지 않습니다. 어떤 시점에서 주차장 중 하나에 대한 거래가 진행되지 않는 경우 귀하를 위해. 물론 이 데이터로 정확히 무엇을 하려는지에 따라 다릅니다.

코멘트
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION