<개요>

- Designing Data Intensive Applications 를 읽고 그 중 Transactions에 대한 내용을 정리.

- 기존에 일반적인 내용들 (e.g RDB기준), 새로 추가되는 개념들 (e.g NoSQL)을 포함하여 정리

 

<내용>

1. Transactions

- read/write 가 일어날때 논리적인 하나의 단위로 묶어서 생각해본다.

- application에서 database에 접근할때 프로그래밍을 좀더 단순화하는데 목적이 있다고 본다. (추상화)

 

2. ACID

Atomicity, Consistency, Isolation, Durability

위와 같은 것은 일반적으로 트랜잭션의 특성으로 보고 있으며, 실제 각 DBMS에서 구현하는 방법들은 조금씩 차이가 있다.

특히, 이 책에서는 수년간 사용해왔던 이 단어들에 역시 모호한 부분들이 존재하며, 관점에 따라 차이가 있음을 소개하고 있다.

 

Atomicity

- 통상적으로 더이상 나눌수 없는 단위로 본다. 그러나 그 세부의 이해에는 약간의 차이가 있다.

- 예를 들어서 멀티쓰레드 환경에서는 하나의 쓰레드가 atomic operation을 수행할때 다른 쓰레드에서는 그 중간값을 참조할 수 없음을 의미한다. 그러나 ACID내에서 Atomicity는 concurrency의미가 아니다. 이 개념은 Isolation에 포한된다.

- ACID내에서 Atomicity는 write가 수행될때 (내부적으로 process, network, disk등의 여러 에러가 발생할 수 있는 요인이 있지만) 성공 혹은 실패가 하나로 묶이는 것을 의미한다. (committed / aborted)

 즉, "어디까지는 성공하고 어디까지는 실패하고" 가 발생하지 않도록 하는 것이 그 의미에 가까워서 이 책에서는 abortability가 좀 더 의미적으로 가깝지 않나라고 이야기한다.

 

Consistency

- 역시 다양한 영역에서 혼용되어 사용하고 있다. 예를 들어서 eventual consistency, consistent hashing, CAP, 그리고 ACID내에서 같은 단어들이지만 다른의미를 가지고 있다.

- ACID내 C의 경우 invariants가 항상 참인것에 집중한다고 볼 수 있다. 그 예로 여러가지 constraint를 이야기하고 있는데 이 책에서는 이러한 영역이 database보다는 application이 보장해야하는 것으로 보고 있다.

Data에 어떤 내용을 담을 것인가는 결국 application 에서 정해지며 A,I,D는 database의 속성이지만 consistency는 그렇게 볼수 없다는 것이다. 

- 나도 여기에 동의하는 것이 최근 NoSQL에서는 한 application의 기능에서 다루는 단위(set)를 기준으로 데이터를 구성하는 것이 일반적이며(JOIN X), 그에 따라서 각 데이터의 key값에 대한 정합성을 보장하는 것은 응답속도나 reliability에 따라서 타협하여 구현하는 모습을 통해서 체감할 수 있다고 생각한다.

 

Isolation

- 같은 record에 대해 동시에 여러 clients가 접근하여 경합이 발생했을 때 어떻게 해결할 것인가.

- 특히 우리가 일반적으로 알고 있는 Isolation level과 비슷하면서도 다른 용어, 추가적인 개념설명으로 재미있었던 부분이었다.

 (e.g dirty write, read write skew 등)

- 용어에서 설명하듯이 기본적으로 여러 transactions이 동시에 수행되더라도 각각은 별도로 격리 되어야 한다는 것이 기본적인 원칙이다. 이 때 발생할 수 있는 여러가지 데이터 이상현상이 있으며 (DIRTY READ, NON REPETABLE READ, PHANTOM READ등) 각 현상을 제거할 수 있도록 Level을 조정하여 성능과 정합성을 타협하는 것이다.

- 다만 각 database가 정의하는 isolation level는 차이가 있으며, 그것을 구현하는 방법도 다르다는 내용을 소개하고 있다.

 (e.g snapshot isolation, Inno DB consistent read 등)

 

Durability

- 결국 모든 저장소 (File, Database, Storage)는 안전하게 데이터를 저장하는 것이 목적이다.

- single-node database 에서는 이것을 보장하기 위해서 저장공간 (hdd,ssd 등)에 데이터를 기록하고, write-ahead log를 기록하고 recover event하는 형태로 접근했으며

- replicated database 에서는 복제하여 다른 노드에 저장하고, 각 transaction이 이루어질 때 write / replication을 수행하는 형태로 관리하고 있다.

 

특히 여기에는 개발자들이 놓치는 문제들이 간혹 있는데 간단히 살펴보면 다음과 같다.

- Disk에 기록한뒤 다운될 경우 Data는 잃어버리지 않으며 접근이 불가능한 것으로 접근 가능한 다른 시스템으로 대체할 수도 있다.

- Memory에 저장된 데이터는 휘발성이기 때문에 Disk가 필요하다.

- 비동기로 복제하는 시스템에서는 Leader의 상태에 따라서 최근 변경사항이 누락될 수 있다.

- Storage에도 버그나 문제는 존재하며 완벽은 없다. (e.g 정전, 펌웨어 버그 등)

- Disk는 생각보다 자주 망가진다. 갑자기 죽기도 하지만.. 천천히 망가지기도 한다. (bad sector!) 물리적인 매체가 망가진다는 것은 replicas, backup도 손상되는 것을 의미하고, 그래서 historical backup전략이 존재한다.

- 특히 SSD는 빠르지만 불량블록이 생각보다 자주 발생하고, HDD는 갑자기 죽기도 한다.
- SSD는 전원이 공급되지 않으면 온도에 따라서도 손실이 발생한다고 한다!?


결국 절대적인 보장은 이세상에 존재 하지않기 때문에 우리는 여러 기술을 복합적으로 사용하는 것이다.

 

<정리>

-  ACID는 과거부터 쭉 사용해온 용어이지만 Computing Area가 다양해지면서 비슷한 용어들의 모호함이 존재한다.

- Database에서 보장해야하는 개념들은 결국 각 벤더마다 다를 수도 있다. 

  즉 JDBC 드라이버의 실제 구현은 내가 생각하고 기대한 것과는 다를 수 있다. (과거에 update 쿼리실행 후 결과값이 변경된 건수로 나와야 하는데 0으로 나왔던 기억이 있다.)

- Consistency는 application의 영역으로 보는 것이 어떨까 라는 의견이 있다.

 (유효성을 위한 제약조건 같은 기능들은 Database가 제공할 수 있지만 결국 어떤값을 기록하는가는 Application에 달려있다.)

- 우리는 물리적인 세상에서 살고 있기 때문에 100% 보장이라는 것은 있을 수 없다.

 

Transcation에 대해서 대략적으로 살펴보았으며 다음 글에는 Atomicity와 Isolation에 대해서 좀 더 자세히 정리하도록 하겠다.

<개요>

Apache Hive는 HDFS에 저장되어 있는 파일데이터를  SQL 기반으로 처리할 수 있도록 하는 오픈소스이다. (모든 SQL을 지원하는 것은 아니며, 파일시스템 특성상 UPDATE, DELETE는 권장하지 않는다. )

그러나 지속적으로 DataWareHouse  트랜잭션 처리에 대한 요구사항이 꾸준히 생겨서 Hive에서도 트랜잭션을 지원하기 위한 기능이 개발되었다.

이에 대해서 내부구조를 간략히 살펴본다. (원문해석 + 개인이해/경험추가 )


<ACID>

database transaction의 4대 속성이라고도 하는데 다음과 같다.

https://ko.wikipedia.org/wiki/ACID


Atomicity(원자성)

트랜잭션과 관련된 작업들이 부분적으로 실행되다가 중단되지 않는 것을 보장하는 능력이다. 예를 들어, 자금 이체는 성공할 수도 실패할 수도 있지만 보내는 쪽에서 돈을 빼 오는 작업만 성공하고 받는 쪽에 돈을 넣는 작업을 실패해서는 안된다. 원자성은 이와 같이 중간 단계까지 실행되고 실패하는 일이 없도록 하는 것

Consistency(일관성)

트랜잭션이 실행을 성공적으로 완료하면 언제나 일관성 있는 데이터베이스 상태로 유지하는 것을 의미한다. 무결성 제약이 모든 계좌는 잔고가 있어야 한다면 이를 위반하는 트랜잭션은 중단

Isolation(고립성)

트랜잭션을 수행 시 다른 트랜잭션의 연산 작업이 끼어들지 못하도록 보장하는 것을 의미한다. 이것은 트랜잭션 밖에 있는 어떤 연산도 중간 단계의 데이터를 볼 수 없음을 의미한다. 은행 관리자는 이체 작업을 하는 도중에 쿼리를 실행하더라도 특정 계좌간 이체하는 양 쪽을 볼 수 없다. 공식적으로 고립성은 트랜잭션 실행내역은 연속적이어야 함을 의미한다. 성능관련 이유로 인해 이 특성은 가장 유연성 있는 제약 조건이다

Durability(지속성)

공적으로 수행된 트랜잭션은 영원히 반영되어야 함을 의미한다. 시스템 문제, DB 일관성 체크 등을 하더라도 유지되어야 함을 의미한다. 전형적으로 모든 트랜잭션은 로그로 남고 시스템 장애 발생 전 상태로 되돌릴 수 있다. 트랜잭션은 로그에 모든 것이 저장된 후에만 commit 상태로 간주될 수 있다.


<Hive-ACID>

Hive 0.13이전에는 원자성, 일관성, 지속성에 대해서는 파티션 레벨로 지원하기 시작했으며, 고립성에 대해서는 Zookeeper나 메모리상에서 지원하는 locking 메커니즘 수준으로 제공되었으나 이제는 row level로는 ACID를 만족시킬 수 있다.

그러나 아직은 제약사항이 좀 있다.


1. 제약사항

- BEGIN, COMMIT, ROLLBACK을 지원하지 않는다. 모두다 auto-commit이다

그렇다 보니 Spring과 연계하여 사용할 때 약간의 불편함이 있다. Spring 에서 지원하는 @JdbcTest 를 사용할 경우 단위테스트 작성시 rollback기능등을 이용하여 각 메소드별 테스트시 데이터정합성이 깨지지 않도록 보장해주는 기능이 있는데 해당 기능이 사용불가능 하다. 



- ORC포멧만 지원한다. 

- Bucket설정이 되어야 한다. 또한 External Table의 경우 compactor가 제어할 수 없기 때문에 ACID테이블로 만들 수 없다.


- non-ACID session에서는 ACID Table에 대한 읽기/쓰기를 할 수 없다. 

  어찌보면 당연하다. ACID를 사용하기 위해서는 org.apache.hadoop.hive.ql.lockmgr.DbTxnManager 로 hive transaction manager를 변경해야 한다.


- Dirty read, read committed, repeatable read, serializable의 isolation level은 지원하지 않는다.

- 기존의 zookeeper나 in-memory 락 메커니즘은 호환불가능



2. 기본 설

처음에 이야기한 것처럼 HDFS는 오직 통으로 움직이는 것을 좋아한다.

그래서 transaction들의 특징을 만족시키기 위해서 아래와 같이 설게되었다.


테이블이나 파티션은 Base 파일의 집합으로 저장하고, 새로운 레코드나 update, delete에 대해서는 Delta 파일로 저장한다. 델타파일들의 집합이 만들어지면 읽는 시점에 합친다.



<Compactor>

ACID를 지원하기 위해서 Meatastore에서 수행되고 있는 background processes들을 compactor라고 한다.


Hive는 Base File과 Delta File을 이용한 Compaction으로 ACID를 지원하기 때문에  Table을 생성할때 


STORED AS ORC 와 

CLUSTERED BY XXX INTO N BUCKETS  를 반드시 추가해야 한다.


apache orc 사이트에 가면 Hive ACID를 어떤 형태로 Support 하고 있는지 상세하게 설명이 되어있다.


<그림 1 : Hive Table>



<그림 2 : Major & Minor compaction>



Delta파일들이 늘어나게 되면 성능을 위해서 compaction을 수행하게 되는데 유형은 다음과 같다.


- minor compaction : Delta파일들을 모아서 Bucket당 하나의 Delta파일로 rewrite한다.

- major compaction : 하나이상의 Delta파일과 Bucket당 Base파일을 가지고 Bucket당 새로운 Base파일로 rewrite한다. 


실제로 YARN 에서 조회하면 UPDATE,DELETE를 수행할때마다 YARN Application이 수행되지는 않으며

주기적으로 수행되는 compactor작업을 확인할 수 있다.



<Transaction/Lock Manager>

추후 상세설명



3. Configuration

Client Side

Server Side (Metastore)



4. Table Properties

ACID를 사용하기 위해서는 (update,delete) "transactional=true" 를 설정해야 한다.

그리고 한번 ACID테이블로 생성하면 되돌릴 수 없으니 주의해야 한다.

또한 hive-sitem.xml등에서 hive.txn.manager=org.apache.hadoop.hive.ql.lockmgr.DbTxnManager 로 지정해야 하며 이 txManager가 없이는 ACID테이블을 사용할 수 없다.



Example: Set compaction options in TBLPROPERTIES at table level
CREATE TABLE table_name (
  id                int,
  name              string
)
CLUSTERED BY (id) INTO 2 BUCKETS STORED AS ORC
TBLPROPERTIES ("transactional"="true",
  "compactor.mapreduce.map.memory.mb"="2048",     -- specify compaction map job properties
  "compactorthreshold.hive.compactor.delta.num.threshold"="4",  -- trigger minor compaction if there are more than 4 delta directories
  "compactorthreshold.hive.compactor.delta.pct.threshold"="0.5" -- trigger major compaction if the ratio of size of delta files to
                                                                   -- size of base files is greater than 50%
);



그리고 2번에서 설명한 것처럼 compaction으로 ACID를 지원하기 때문에 compator에 대한 많은 상세설정이 있으며 compactor에 대한 설정은 ALTER문을 통해서 변경할 수 있다.


Example: Set compaction options in TBLPROPERTIES at request level
ALTER TABLE table_name COMPACT 'minor' 
   WITH OVERWRITE TBLPROPERTIES ("compactor.mapreduce.map.memory.mb"="3072");  -- specify compaction map job properties
ALTER TABLE table_name COMPACT 'major'
   WITH OVERWRITE TBLPROPERTIES ("tblprops.orc.compress.size"="8192");         -- change any other Hive table properties




<참고사이트>

https://cwiki.apache.org/confluence/display/Hive/Hive+Transactions

https://orc.apache.org/docs/acid.html


+ Recent posts