haeinsa deview _최종
TRANSCRIPT
Haeinsa
HBase Transaction Library
김영목
VCNC
이 발표에서는 해인사를 소개합니다.
Between은 HBase를 사용하고있습니다.
발표자: 김영목 VCNC
여기는 봉은사
비트윈에서는 HBase를 사용합니다
HBase(Cluster)
ELB(HTTP)
API #1
API #2
HTTP
ELB #1(TCP)
ELB #2(TCP)
ZooKeeper
TCP
API #3
ELB #3(TCP)
비트윈의 시스템 아키텍처
Linearly Scalable Fault Tolerant Write Throughput
HBase를 쓰는 메신저 서비스
HBase의 좋은점
Row단위 ACID만 지원
Document 단위 ACID만 지원
Row 단위 ACID만 지원
그러나 NoSQL 데이터베이스트랜잭션이없다
T1 T2
bobBal = Read(bob,bal) bobBal = Read(bob,bal)
joeBal = Read(joe,bal) aliceBal = Read(alice,bal)
Write(bob, bobBal - $7) Write(alice, aliceBal - $2)
Write(joe, joeBal +$7) Write(bob, bobBal + $2)
• Bob은 $10, Joe는 $2, Alice는 $8가 있다고해봅시다.
• 아래 트랜잭션의결과는 어떻게 될까요?
트랜잭션이없으면 불편한점
Multi-Row ACID 지원!
하지만, Google에는 트랜잭션이있다!
Row단위 ACID만 지원
Document 단위 ACID만 지원
Row 단위 ACID만 지원
Full ACID Support
+
Linearly Scalable Fault Tolerant Write Throughput
모든 Hbase의 장점뿐만아니라
트랜잭션도지원해야한다!
NoSQL 트랜잭션, 어떤 특징들을 가져야하는가?
1. Multi-row, Multi-table 트랜잭션지원
2. Linearly scalable
3. Failure tolerant
4. Low overhead
Haeinsa의 특징
Haeinsa는 HBase에서 트랜잭션을 제공합니다.
1. HBase에 대한수정은전혀없습니다.
2.따라서현재운영중인 HBase 클러스터에쉽게적용가능
합니다.
Haeinsa의 특징
Haeinsa는 클라이언트 라이브러리입니다.
Application
Haeinsa
HBase Client Library
Haeinsa의 특징
Haeinsa는 이미 비트윈에 적용되어 사용되고 있습니다!
1. 2개월간아무문제없이돌아가고있습니다.
2.하루에 3억건의트랜잭션을처리하고있습니다.
Haeinsa의 특징
Haeinsa는 오픈소스 입니다.
https://github.com/vcnc/haeinsa
Haeinsa 이름의 유래
Haeinsa는 정말로 해인사에서 따온 이름입니다.
1.해인사에는팔만대장경이보존되어있습니다.
2.팔만대장경은 81,258개의목판본으로이루어져있습니다.
3.오탈자없이,52,382,960글자가새겨져있습니다.
4. 800년가까이아무문제없이보존되었습니다.
5.개발시작당시 VCNC의사무실이봉은사옆에있었습니다.
분산시스템에서의 트랜잭션 구현
T1
T2
T3
T4
Write Set:Transaction Timeline:
R1, R2
R2, R3
R1, R2, R3
R4
트랜잭션관리하기
동시에 실행되는트랜잭션은
어떻게 관리해야할까요?
T1
T2
T3
T4
Transaction Timeline:
트랜잭션관리하기
가장 단순한 방법은 한번에 하나씩만실행하기입니다.
하지만 동시성이떨어져 성능은 좋지 않습니다.
T1
T2
T3
T4
Transaction Timeline:
트랜잭션관리하기
동시에 실행해도되는 것들은
동시에 실행하는것이 좋습니다!
T1
T2
T3
T4
Write Set:Transaction Timeline:
R1, R2
R2, R3
R1, R2, R3
R4
트랜잭션관리하기
일단 트랜잭션을실행하다가커밋시에
충돌하는트랜잭션을실패시키면됩니다
• 동시성을위해 더 작은 단위의 Locking이 필요
• Row 단위나 Column단위로 Locking을 해야 함
• 이를 위해 2PC와 같은 프로토콜이필요!
트랜잭션동시성 향상 시키기
Coordinator
Participant
Participant
Prepared!
Prepared!
Prepared!
Voting Phase에서는 각 Participant들을 준비시킵니다.
2-Phase Commit
Voting Phase
Coordinator
Participant
Participant
Commited!
Commited!
Commited!
Commit Phase에서는 각 Participant를 Commit시킵니다.
Commit Phase
2-Phase Commit
• Haeinsa에서 트랜잭션의상태를 저장하기위한 특수 칼럼
• Row 단위 칼럼이 하나씩 존재
• 읽기/쓰기시마다 확인
Row key bal lock
Bob4: $33: $10
State:PREWRITTENCommitTimestamp:6PrewriteTimestamp:4Secondaries:[Joe]
Joe 3: $2State:STABLECommitTimestamp:3
Lock Column
Stable
CommittedPrewritten
Stable
AbortedPrewritten
트랜잭션성공시 트랜잭션실패시
Lock Column State Diagram
각 Row의 상태 변화는 다음과 같습니다.
3.구현
BeginTransaction()
bobBalance = Read(Bob, balance)
Write(Bob, balance, bobBalance-$7)
joeBalance = Read(Joe, balance)
Write(Joe, balance, joeBalance+$7)
Commit()
아래 예제를 통해서 Haeinsa의 동작을알아봅시다.
How it works
𝐶
𝑅𝐵𝑜𝑏
𝑅𝐽𝑜𝑒
Get(Bob, lock)Get(Bob, bal)
bobBal = Read(Bob,bal)
How it works
𝐶
𝑅𝐵𝑜𝑏
𝑅𝐽𝑜𝑒
Write(Bob, bobBal - $7)
How it works
𝐶
𝑅𝐵𝑜𝑏
𝑅𝐽𝑜𝑒
joeBal = Read(Joe,bal)
Get(Joe, lock)Get(Joe, bal)
How it works
𝐶
𝑅𝐵𝑜𝑏
𝑅𝐽𝑜𝑒
Write(Joe, joeBal + $7)
How it works
𝐶
𝑅𝐵𝑜𝑏
𝑅𝐽𝑜𝑒
Commit()
How it works
3개 Row 트랜잭션의커밋을 살펴봅시다.
𝑅𝑃𝑟𝑖𝑚𝑎𝑟𝑦
𝑅𝑆𝑒𝑐𝑜𝑛𝑑𝑎𝑟𝑦1 𝑅𝑆𝑒𝑐𝑜𝑛𝑑𝑎𝑟𝑦2
PREWRITTEN
COMMITTED
STABLE
Commit Operation
𝑐𝑜𝑚𝑚𝑖𝑡()
Primary Row부터 prewrite 합니다.
𝑅𝑃𝑟𝑖𝑚𝑎𝑟𝑦
𝑅𝑆𝑒𝑐𝑜𝑛𝑑𝑎𝑟𝑦1 𝑅𝑆𝑒𝑐𝑜𝑛𝑑𝑎𝑟𝑦2
PREWRITTEN
COMMITTED
STABLE
Commit Operation
𝑝𝑟𝑒𝑤𝑟𝑖𝑡𝑒(𝑅𝑝𝑟𝑖𝑚𝑎𝑟𝑦)
나머지 두 개의 Secondary Row들도 차례로 Prewrite합니다.
𝑅𝑃𝑟𝑖𝑚𝑎𝑟𝑦
𝑅𝑆𝑒𝑐𝑜𝑛𝑑𝑎𝑟𝑦1 𝑅𝑆𝑒𝑐𝑜𝑛𝑑𝑎𝑟𝑦2
PREWRITTEN
COMMITTED
STABLE
Commit Operation
𝑝𝑟𝑒𝑤𝑟𝑖𝑡𝑒(𝑅𝑠𝑒𝑐𝑜𝑛𝑑𝑎𝑟𝑦1)
𝑅𝑃𝑟𝑖𝑚𝑎𝑟𝑦
𝑅𝑆𝑒𝑐𝑜𝑛𝑑𝑎𝑟𝑦1 𝑅𝑆𝑒𝑐𝑜𝑛𝑑𝑎𝑟𝑦2
PREWRITTEN
COMMITTED
STABLE
Commit Operation
𝑝𝑟𝑒𝑤𝑟𝑖𝑡𝑒(𝑅𝑠𝑒𝑐𝑜𝑛𝑑𝑎𝑟𝑦2)
나머지 두 개의 Secondary Row들도 차례로 Prewrite합니다.
𝑅𝑃𝑟𝑖𝑚𝑎𝑟𝑦
𝑅𝑆𝑒𝑐𝑜𝑛𝑑𝑎𝑟𝑦1 𝑅𝑆𝑒𝑐𝑜𝑛𝑑𝑎𝑟𝑦2
PREWRITTEN
COMMITTED
STABLE
Commit Operation
𝑐𝑜𝑚𝑚𝑖𝑡(𝑅𝑝𝑟𝑖𝑚𝑎𝑟𝑦)
Primary Row를 Commit 상태로원자적으로변경합니다.
이 이후에는문제가발생해도이 트랜잭션은성공한것으로처리합니다.
우선 Secondary Row들부터 Stable상태로 만듭니다.
𝑅𝑃𝑟𝑖𝑚𝑎𝑟𝑦
𝑅𝑆𝑒𝑐𝑜𝑛𝑑𝑎𝑟𝑦1 𝑅𝑆𝑒𝑐𝑜𝑛𝑑𝑎𝑟𝑦2
PREWRITTEN
COMMITTED
STABLE
Commit Operation
𝑚𝑎𝑘𝑒𝑆𝑡𝑎𝑏𝑙𝑒(𝑅𝑠𝑒𝑐𝑜𝑛𝑑𝑎𝑟𝑦1)
𝑅𝑃𝑟𝑖𝑚𝑎𝑟𝑦
𝑅𝑆𝑒𝑐𝑜𝑛𝑑𝑎𝑟𝑦1 𝑅𝑆𝑒𝑐𝑜𝑛𝑑𝑎𝑟𝑦2
PREWRITTEN
COMMITTED
STABLE
Commit Operation
𝑚𝑎𝑘𝑒𝑆𝑡𝑎𝑏𝑙𝑒(𝑅𝑠𝑒𝑐𝑜𝑛𝑑𝑎𝑟𝑦2)
우선 Secondary Row들부터 Stable상태로 만듭니다.
𝑅𝑃𝑟𝑖𝑚𝑎𝑟𝑦
𝑅𝑆𝑒𝑐𝑜𝑛𝑑𝑎𝑟𝑦1 𝑅𝑆𝑒𝑐𝑜𝑛𝑑𝑎𝑟𝑦2
PREWRITTEN
COMMITTED
STABLE
Commit Operation
𝑚𝑎𝑘𝑒𝑆𝑡𝑎𝑏𝑙𝑒(𝑅𝑝𝑟𝑖𝑚𝑎𝑟𝑦)
마지막으로 Primary를 Stable로 만듭니다.
이로써 트랜잭션은처리가완료되었습니다.
𝐶
𝑅𝐵𝑜𝑏
𝑅𝐽𝑜𝑒
아래 주황색 영역에 대해서 각 Row에 새로운 값이 쓰였는지를 확인
쓰여있지 않으면 동시에 Row들을 잠금
Summary
𝐶
𝑅𝐵𝑜𝑏
𝑅𝐽𝑜𝑒
아래 녹색부분 동안 각 Row들이 잠겨있음
Summary
𝐶
𝑅𝐵𝑜𝑏
𝑅𝐽𝑜𝑒
파란색 부분 이후부터는 이 트랜잭션이성공한 것으로 인식하게 됨
Summary
실패시 동작
𝐶
𝑅𝐵𝑜𝑏
𝑅𝐽𝑜𝑒
트랜잭션이진행되면서각 단계에서 실패가날 수 있습니다.
가능한 모든 경우를 고려해야합니다.
실패시 동작
𝐶
𝑅𝐵𝑜𝑏
𝑅𝐽𝑜𝑒
특히 커밋시 진행되는각 단계에서
실패가 나는 경우에 대해 살펴봐야합니다.
𝐶
𝑅𝐵𝑜𝑏
𝑅𝐽𝑜𝑒
이 단계를 실패 시켜 보겠습니다.
실패!
실패시 동작
𝑅𝑃𝑟𝑖𝑚𝑎𝑟𝑦
𝑅𝑆𝑒𝑐𝑜𝑛𝑑𝑎𝑟𝑦1 𝑅𝑆𝑒𝑐𝑜𝑛𝑑𝑎𝑟𝑦2
PREWRITTEN
COMMITTED
STABLE
실패시 동작
Secondary2에 Prewrite 실패시 이 상태가 됩니다
𝑅𝑃𝑟𝑖𝑚𝑎𝑟𝑦
𝑅𝑆𝑒𝑐𝑜𝑛𝑑𝑎𝑟𝑦1 𝑅𝑆𝑒𝑐𝑜𝑛𝑑𝑎𝑟𝑦2
a𝑏𝑜𝑟𝑡(𝑅𝑝𝑟𝑖𝑚𝑎𝑟𝑦)
PREWRITTEN
COMMITTED
STABLE
ABORTED
실패시 동작
일단 Primary를 Abort상태로 바꿉니다
𝑅𝑃𝑟𝑖𝑚𝑎𝑟𝑦
𝑅𝑆𝑒𝑐𝑜𝑛𝑑𝑎𝑟𝑦1 𝑅𝑆𝑒𝑐𝑜𝑛𝑑𝑎𝑟𝑦2
PREWRITTEN
COMMITTED
STABLE
ABORTED
실패시 동작
𝑚𝑎𝑘𝑒𝑆𝑡𝑎𝑏𝑙𝑒(𝑅𝑠𝑒𝑐𝑜𝑛𝑑𝑎𝑟𝑦1)
이미 Pewritten상태인
Secondary1을 Stable로 바꿉니다
𝑅𝑃𝑟𝑖𝑚𝑎𝑟𝑦
𝑅𝑆𝑒𝑐𝑜𝑛𝑑𝑎𝑟𝑦1 𝑅𝑆𝑒𝑐𝑜𝑛𝑑𝑎𝑟𝑦2
PREWRITTEN
COMMITTED
STABLE
ABORTED
실패시 동작
마지막으로 Primary를 Stable로 만듭니다.
이로써 트랜잭션은복구가완료되었습니다.
𝑚𝑎𝑘𝑒𝑆𝑡𝑎𝑏𝑙𝑒(𝑅𝑝𝑟𝑖𝑚𝑎𝑟𝑦)
어떻게 변경사항을취소하는가?
Row key Bal lock
Bob4: $33: $10
State:PREWRITTENCommitTimestamp:6PrewriteTimestamp:4Secondaries:[Joe]
Joe4: $93: $2
State:PREWRITTENCommitTimestamp:6PrewriteTimestamp:4Primary:Bob
Alice 7:$10State:STABLECommitTimestamp:7
데이터를 여러 Timestamp에 걸쳐
여러 버전을 저장해 둡니다.
어떻게 변경사항을취소하는가?
Row key Bal lock
Bob4: $33: $10
State:PREWRITTENCommitTimestamp:6PrewriteTimestamp:4Secondaries:[Joe]
Joe4: $93: $2
State:PREWRITTENCommitTimestamp:6PrewriteTimestamp:4Primary:Bob
Alice 7:$10State:STABLECommitTimestamp:7
PrewriteTimestamp이 가리키는
버전을 지우면 변경사항을 취소할 수 있습니다.
어떻게 변경사항을취소하는가?
Row key Bal lock
Bob4: $33: $10
State:PREWRITTENCommitTimestamp:6PrewriteTimestamp:4Secondaries:[Joe]
Joe4: $93: $2
State:STABLECommitTimestamp:6
Alice 7:$10State:STABLECommitTimestamp:7
PrewriteTimestamp이 가리키는
버전을 지우면 변경사항을 취소할 수 있습니다.
어떻게 변경사항을취소하는가?
Row key Bal lock
Bob4: $33: $10
State:PREWRITTENCommitTimestamp:6PrewriteTimestamp:4Secondaries:[Joe]
Joe 3: $2State:STABLECommitTimestamp:6
Alice 7:$10State:STABLECommitTimestamp:7
PrewriteTimestamp이 가리키는
버전을 지우면 변경사항을 취소할 수 있습니다.
𝐶
𝑅𝐵𝑜𝑏
𝑅𝐽𝑜𝑒
이번엔 이 단계를 실패 시켜 보겠습니다.
실패시 동작
실패!
𝑅𝑃𝑟𝑖𝑚𝑎𝑟𝑦
𝑅𝑆𝑒𝑐𝑜𝑛𝑑𝑎𝑟𝑦1 𝑅𝑆𝑒𝑐𝑜𝑛𝑑𝑎𝑟𝑦2
PREWRITTEN
COMMITTED
STABLE
실패시 동작
𝑚𝑎𝑘𝑒𝑆𝑡𝑎𝑏𝑙𝑒(𝑅𝑠𝑒𝑐𝑜𝑛𝑑𝑎𝑟𝑦1)
실패한 경우 이 상태가 됩니다.
𝑅𝑃𝑟𝑖𝑚𝑎𝑟𝑦
𝑅𝑆𝑒𝑐𝑜𝑛𝑑𝑎𝑟𝑦1 𝑅𝑆𝑒𝑐𝑜𝑛𝑑𝑎𝑟𝑦2
PREWRITTEN
COMMITTED
STABLE
실패시 동작
𝑚𝑎𝑘𝑒𝑆𝑡𝑎𝑏𝑙𝑒(𝑅𝑠𝑒𝑐𝑜𝑛𝑑𝑎𝑟𝑦2)
우선 Secondary Row들부터 Stable상태로 만듭니다.
𝑅𝑃𝑟𝑖𝑚𝑎𝑟𝑦
𝑅𝑆𝑒𝑐𝑜𝑛𝑑𝑎𝑟𝑦1 𝑅𝑆𝑒𝑐𝑜𝑛𝑑𝑎𝑟𝑦2
PREWRITTEN
COMMITTED
STABLE
실패시 동작
𝑚𝑎𝑘𝑒𝑆𝑡𝑎𝑏𝑙𝑒(𝑅𝑝𝑟𝑖𝑚𝑎𝑟𝑦)
마지막으로 Primary를 Stable로 만듭니다.
이로써 트랜잭션은복구가완료되었습니다.
4.성능
0
5000
10000
15000
20000
25000
30000
35000
40000
45000
50000
0 10 20 30 40 50 60
Tx/S
ec
# of Region Server
Haeinsa
HBase
Practical Performance (Throughput)
메시지 전송 (3 rows, 3 gets, 6 puts)
0
5
10
15
20
25
30
35
0 10 20 30 40 50 60
ms
# of Region Server
Haeinsa
HBase
Practical Performance (Latency)
메시지 전송 (3 rows, 3 gets, 6 puts)
0
20000
40000
60000
80000
100000
120000
0 10 20 30 40 50 60
Tx/S
ec
# of Region Server
Haeinsa
HBase
Worst Case Performance (Throughput)
3 rows, 1 gets, 2 puts
0
5
10
15
20
25
30
0 10 20 30 40 50 60
ms
# of Region Server
Haeinsa
HBase
Worst Case Performance (Latency)
3 rows, 1 gets, 2 puts
5.비트윈 서비스에 적용 사례
그냥 적용해 봤습니다
HBase(Cluster)
Between테스트서버
비트윈클라이언트 Haeinsa
적용
• HBase의 기본 연산을 모두 제공합니다.
• Lock Column만 추가하면기존 HBase클러스터에 쉽게 적용
이 가능합니다.
• 일반적인경우의 충돌 비율: 0.004% ~ 0.010%
• 하지만 유저가 의도적으로많은 요청을보낼 때에는충돌이 자
주 나는 현상이 발생하였습니다.
그냥 적용했을때의문제점
HBase(Cluster)
Between테스트서버
비트윈클라이언트 요청을의도적으로
많이보내는경우,충돌이자주남
• 특정 유저의 연산을 특정 쓰레드가처리하도록구현
• 결과적으로한 유저에대해서는 Serial Scheduling이 되어 한
유저가 의도적으로요청을많이 보내도 Conflict이 나지 않음
특정 쓰레드로 요청을스케쥴링
비트윈 서버내 쓰레드풀
비트윈클라이언트
• 만약 Conflict이 나게 되면 요청을 처음 부터 다시 시작
• 다시 충돌이 나는 경우를 방지하기위해적당히 Backoff를 함
• Conflict Rate가 크게 줄었음: 0.0003%~0.0010%
Conflict Rate를 더욱 낮추기 위해서 재시도를함
비트윈클라이언트
HBase(Cluster)
Conflict발생시
다시재시도
6.정리
정리
• Haeinsa는 HBase상에서 트랜잭션을지원하면서 Lineary
Scalable한 클라이언트라이브러리입니다.
• 비트윈 서비스에서 2달간 적용되어안정성을확보하였습니다.
• 다른 트랜잭션 라이브러리에비해 성능이 뛰어나고 HBase보
다 더 좋은 성능을 내기도합니다.
Multi-Row ACID 지원!
정리
Document 단위 ACID만 지원
Row 단위 ACID만 지원
Haeinsa를 통해Multi-Row ACID 지원
정리
http://github.com/vcnc/haeinsa
THANK YOU
Q&A
There is rows representing balance of Bob and Joe.Let’s track how Haeinsa works by studying the transaction that Bob giving the $7 to Joe.
HBase-side
Row key Bal Lock
Bob 3: $10State:STABLECommitTimestamp:3
Joe 3: $2State:STABLECommitTimestamp:3
BeginTransaction()bobBal = Read(Bob, bal)Write(Bob, bal, bobBal-$7)joeBal = Read(Joe, bal)Write(Joe, bal, joeBal+$7)Commit()
Client-side
Appendix A: How it works?
<< Before Transaction >>
Nothing to do
HBase-side
Row key bal lock
Bob 3: $10State:STABLECommitTimestamp:3
Joe 3: $2State:STABLECommitTimestamp:3
BeginTransaction()bobBal = Read(Bob, bal)Write(Bob, bal, bobBal-$7)joeBal = Read(Joe, bal)Write(Joe, bal, joeBal+$7)Commit()
Client-side
State of Transaction
Writes = []Locks = {}
Read Bob’s Lock column first. And then read Bob’s Balance column.
HBase-side
Row key bal lock
Bob 3: $10State:STABLECommitTimestamp:3
Joe 3: $2State:STABLECommitTimestamp:3
Client-side
State of Transaction
Writes = []Locks[Bob] = (STABLE, 3)
BeginTransaction()bobBal = Read(Bob, bal)Write(Bob, bal, bobBal-$7)joeBal = Read(Joe, bal)Write(Joe, bal, joeBal+$7)Commit()
Bob’s new balance put into writes. Store on client-side memory. It will be write on Hbase on commit.
HBase-side
Row key bal lock
Bob 3: $10State:STABLECommitTimestamp:3
Joe 3: $2State:STABLECommitTimestamp:3
Client-side
State of Transaction
Writes = [(Bob, bal, $3)]Locks[Bob] = (STABLE, 3)
BeginTransaction()bobBal = Read(Bob, bal)Write(Bob, bal, bobBal-$7)joeBal = Read(Joe, bal)Write(Joe, bal, joeBal+$7)Commit()
Read Joe’s Lock column first. And then read Joe’s Balance column.
HBase-side
Row key bal lock
Bob 3: $10State:STABLECommitTimestamp:3
Joe 3: $2State:STABLECommitTimestamp:3
Client-side
State of Transaction
Writes = [(Bob, bal, $3)]Locks[Bob] = (STABLE, 3)Locks[Joe] = (STABLE, 3)
BeginTransaction()bobBal = Read(Bob, bal)Write(Bob, bal, bobBal-$7)joeBal = Read(Joe, bal)Write(Joe, bal, joeBal+$7)Commit()
Joe’s new balance put into writes.
HBase-side
Row key bal lock
Bob 3: $10State:STABLECommitTimestamp:3
Joe 3: $2State:STABLECommitTimestamp:3
BeginTransaction()bobBal = Read(Bob, bal)Write(Bob, bal, bobBal-$7)joeBal = Read(Joe, bal)Write(Joe, bal, joeBal+$7)Commit()
Client-side
State of Transaction
Writes = [(Bob, bal, $3),(Joe, bal, $9)]Locks[Bob] = (STABLE, 3)Locks[Joe] = (STABLE, 3)
Prewrite value on primary row. Primary row is selected by particular algorithm by Haeinsa.
HBase-side
Row key bal lock
Bob4: $33: $10
State:PREWRITTENCommitTimestamp:6PrewriteTimestamp:4Secondaries:[Joe]
Joe 3: $2State:STABLECommitTimestamp:3
BeginTransaction()bobBal = Read(Bob, bal)Write(Bob, bal, bobBal-$7)joeBal = Read(Joe, bal)Write(Joe, bal, joeBal+$7)Commit()
Client-side
State of Transaction
Writes = [(Bob, bal, $3),(Joe, bal, $9)]Locks[Bob] = (PREWRITTEN, 6, 4, [Joe])Locks[Joe] = (STABLE, 3)
Prewrite value on secondary row. Secondary row is the row which is not primary row.
HBase-side
Row key bal lock
Bob4: $33: $10
State:PREWRITTENCommitTimestamp:6PrewriteTimestamp:4Secondaries:[Joe]
Joe4: $93: $2
State:PREWRITTENCommitTimestamp:6PrewriteTimestamp:4Primary:Bob
BeginTransaction()bobBal = Read(Bob, bal)Write(Bob, bal, bobBal-$7)joeBal = Read(Joe, bal)Write(Joe, bal, joeBal+$7)Commit()
Client-side
State of Transaction
Writes = [(Joe, bal, $9)]Locks[Bob] = (PREWRITTEN, 6, 4, [Joe])Locks[Joe] = (PREWRITTEN, 6, 4, , Bob)
If prewrite all succeed, change state of primary row to COMMITED. The transaction can be treated as succeed at this moment.
HBase-side
Row key bal lock
Bob4: $33: $10
State:COMMITTEDCommitTimestamp:6Secondaries:[Joe]
Joe4: $93: $2
State:PREWRITTENCommitTimestamp:6PrewriteTimestamp:4Primary:Bob
BeginTransaction()bobBal = Read(Bob, bal)Write(Bob, bal, bobBal-$7)joeBal = Read(Joe, bal)Write(Joe, bal, joeBal+$7)Commit()
Client-side
State of Transaction
Writes = []Locks[Bob] = (COMMITTED, 6, , [Joe])Locks[Joe] = (PREWRITTEN, 6, 4, , Bob)
Change state of secondary row to STABLE.
HBase-side
Row key bal lock
Bob4: $33: $10
State:COMMITTEDCommitTimestamp:6Secondaries:[Joe]
Joe4: $93: $2
State:STABLECommitTimestamp:6
BeginTransaction()bobBal = Read(Bob, bal)Write(Bob, bal, bobBal-$7)joeBal = Read(Joe, bal)Write(Joe, bal, joeBal+$7)Commit()
Client-side
State of Transaction
Writes = []Locks[Bob] = (COMMITTED, 6, , [Joe])Locks[Joe] = (STABLE, 6)
Change state of primary row to STABLE.
HBase-side
Row key bal lock
Bob4: $33: $10
State:STABLECommitTimestamp:6
Joe4: $93: $2
State:STABLECommitTimestamp:6
BeginTransaction()bobBal = Read(Bob, bal)Write(Bob, bal, bobBal-$7)joeBal = Read(Joe, bal)Write(Joe, bal, joeBal+$7)Commit()
Client-side
State of Transaction
Writes = []Locks[Bob] = (STABLE, 6)Locks[Joe] = (STABLE, 6)
Transaction completed. All rows are in stable state.
HBase-side
Row key bal lock
Bob4: $33: $10
State:STABLECommitTimestamp:6
Joe4: $93: $2
State:STABLECommitTimestamp:6
BeginTransaction()bobBal = Read(Bob, bal)Write(Bob, bal, bobBal-$7)joeBal = Read(Joe, bal)Write(Joe, bal, joeBal+$7)Commit()
Client-side
State of Transaction
Writes = []Locks={}