Haeinsa deview _최종

Preview:

Citation preview

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

jobs@vcnc.co.kr

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={}