키워드 분류

기본

  1. 객체: Table, Index(B tree), View, Material View, Procedure, Function, Trigger, Sequence(+SCN), Synonym 등
  2. Statement: DML, DDL, TCL, DCL
  3. row type: NUMBER, VARCHAR2, NVARCHAR2, CLOB, NCLOB, BLOB
  4. Data Dictionary View: ALL_TABLES, ALL_USERS, DBA_TABLES, DBA_SEGMENTS, USER_CONSTRAINTS, V$SESSION 등
  5. DD(System Tables): 4번 DD View의 code를 조회하면 실제 테이블 이름이 나온다. tibero는 SYS._DD_TBL과 같은 이름이다.
  6. LOB segment

physical structure(file, disk)

  1. Database instance - Tablespace - Segment - Extent - Datablock - OS block
  2. Datafile / Controlfile
  3. Row Chaining, Row Migration, Chained Row Pieces
  4. Redo Log
  5. Undo Tablespace, ITL

logical structure(memory)

  1. SGA / PGA
  2. Buffer Cache, Large Pool
  3. Redo Log Buffer, undo retention

동작 방식

  1. DB instance 상태 (SHUTDOWN, NOMOUNT, MOUNT, OPEN)
  2. DB instance 종료 (NORMAL, TRANSACTIONAL, IMMEDIATE, ABORT)
  3. tx isolation level, ACID property
  4. DML lock, DDL lock (row lock, table lock // RS, RX, S, SRX, X)
  5. high water mark(HWM)

recovery

  1. instance recovery, media recovery
  2. roll forward, roll back
  3. incarnation number

'Oracle DB' 카테고리의 다른 글

DBMS의 LOB 저장 구조  (0) 2020.04.09
DB에 redo log가 필요한 이유  (0) 2020.04.06
SGA - DB buffer cache  (0) 2019.09.03
SGA - large pool, java pool, fixed SGA  (0) 2019.09.03
SGA - shared pool  (0) 2019.08.31
Posted by sjo200
,

Java JVM GC

면접 2021. 4. 18. 01:00

GC의 기본

GC는 '대부분의 객체는 생성되고 곧 쓰레기(Unreachable Object)가 된다'라는 가설을 전제로 만들어졌다.
GC는 모든 방법을 막론하고, 단계별로 minor GC, major GC, full GC로 나누어 조건에 따라 GC를 실행한다.
일반적으로 minor GC는 Young Generation를 대상으로 하고, major GC는 Old Generation을 대상으로 하여 GC를 실행한다. full GC는 STW(stop-the-world)로 실행중인 애플리케이션을 멈춘 뒤 모든 메모리 영역에 대해 GC를 실행한다.
GC의 방법에 따라 low latency 또는 high throughput를 추구하는 방향이 있다.

reference counting은 생각보다 오버헤드가 많다고 한다. 예를 들면 multi thread 환경일때 counting을 CAS operation을 사용해야 한다던가, 매 참조마다 카운팅 연산이 들어가기 때문이다. 그래서 사용하지 않는듯 하다.

기존 GC (G1 GC 등장 이전)

  • heap을 Eden, Survivor 0, Survivor 1, Old region으로 나눈다.
  • Eden과 Survivor 0, Survivor 1을 young generation이라고 하는데, Survivor 둘 중 하나에만 객체가 존재한다.
  • minor GC는 Eden과 사용중인 Survivor의 살아있는 객체들을 찾아서 사용중이지 않은 Survivor에 넣는 작업이다.
  • Survivor에서 threshold만큼 살아서 옮겨다닌 객체는 Old로 옮겨진다.
  • major GC는 mark and sweep 방식으로 Old region을 정리한다.
GC 방법 minor GC major GC 목표
Serial GC serial serial mark - sweep - compaction 싱글 프로세서
Parallel GC parallel parallel mark - sweep - compaction high throughput
CMS GC parallel concurrent mark - sweep low latency

Serial Garbage Collector

  • 메모리 사용량이 100MB 이하이고, 싱글 프로세서일때 사용한다. 모든 GC 과정이 STW를 수반한다.
  • tenured generation이 꽉 차면 major GC가 실행된다.

Parallel Garbage Collector

  • Serial GC의 minor, major GC를 parallel로 진행한다. 모든 GC 과정이 STW를 수반한다.
  • maximum pause time goal을 설정할 수 있다. default는 제한 없이 멈출 수 있어서 throughput이 가장 높지만, 이 값을 설정하면 그 이하로 줄이기 위해 collector가 GC와 관련된 파라미터 값을 조정한다.
  • throughput goal을 설정할 수 있다. default는 1%의 시간만 GC에 사용하도록 한다.
  • minimum footprint(프로그램이 실행되는 동안 사용하는 heap size) goal을 설정할 수 있다. 위 두 goal이 만족될 때, 이 goal도 고려해서 GC한다.

CMS Garbage Collector

  • major GC 전체 시간동안 STW를 하지 않고, 두 번의 작은 pause time만으로 수행한다. pause time을 최소화하고, reachable object trace와 sweep을 애플리케이션과 동시에 수행해서 latency를 줄인다.
    1. initial mark (root 바로 근처의 object를 mark, STW)
    2. concurrent mark (1에서 mark된 object가 참조하는 object들을 따라가서 확인)
    3. remark (새로 추가되거나 참조가 끊긴 객체를 확인, STW)
    4. concurrent sweep (쓰레기 정리)
  • 최근 히스토리에 따라 major GC를 수행해야할 시점을 예상하고 수행하는 방법(automatic pacing)도 있고, Old 영역이 일정 퍼센트 이상 차면 major GC를 수행하는 방법도 있다.
  • 사용 CPU, 메모리가 많고, compaction 과정이 기본적으로 없기 때문에 fragmentation이 일어난다. 그래서 compaction이 실행되면 다른 GC에 비해 STW 시간이 오래 걸린다.

G1 GC

CMS를 장기적으로 대체하기 위해 만들어졌다. CMS보다 GC pause를 더 짧게 가져가도록 만들어졌고, CMS보다 튜닝하기 쉽게 만들어졌다. default 설정은 high throughput과 low latency를 적절한 밸런스로 고려해서 수행한다.
또한, CMS를 튜닝하기 위해서는 여러 가지 옵션을 설정해야 한다. 또한, Old generation 기준으로 occupancy를 판단하는데, G1 GC는 전체 heap 기준으로 보기 때문에 더 직관적이다. 그 외에도, G1의 목표도 high throughput 또는 low latency 쪽으로 치우쳐서 goal을 만들 수도 있다. 다른 특징으로는 CMS보다도 메모리를 조금 더 쓴다는 점이 있다. Remember Set, Collection Set을 region마다 사용하기 때문이다.
G1 GC는 heap을 일정 크기의 block으로 나누고, 각 block마다 Eden, Survivor, Old, Humongous, Not allocated space 중 하나를 맡는다. 관리 방법이 달라지므로, minor GC, major GC 방법도 당연히 달라진다.

  • minor GC
    1. evacuation (STW)
    2. 통계 수집 (다음 minor GC를 언제 하는지에 따라 Eden, Survivor가 가져야할 크기를 계산)
    3. 계산대로 Eden, Survivor의 block 개수를 resize
  • major GC
    1. initial mark (minor GC의 evacuation과 같이 수행하기 때문에 STW가 필요없음)
    2. concurrent mark 및 liveness 계산
    3. remark (STW)
    4. 낮은 liveness를 가진 block부터 evacuation 수행(evacuation하는 동안 STW).
  • 대표적인 option
    1. MaxGCPauseMillis (목표로 하는 최대 pause time)
    2. InitiatingHeapOccupancyPercent (GC를 시작할 heap occupancy 지정)
    3. NewRatio, SurvivorRatio (명시적으로 young generation 크기를 지정함. 이 경우 통계 수집에 따라 resize 하지 않음)
    4. GCTimeRatio (default 9, = 90%를 애플리케이션에 쓰고 10%를 GC에 사용해도 된다)

참고

[1]https://docs.oracle.com/javase/8/docs/technotes/guides/vm/gctuning/toc.html

[2]https://d2.naver.com/helloworld/1329

[3]www.youtube.com/watch?v=bhVzCIk3-Q4&ab_channel=OracleLearning

[4]johngrib.github.io/wiki/jvm-memory/#garbage-first-garbage-collector

[5]perfectacle.github.io/2019/05/11/jvm-gc-advanced/

[6]stackoverflow.com/a/19303535

Posted by sjo200
,

Consistency

Data-centric consistency models에는 세 가지가 있다[1]. client-centric consistency models까지 덧붙여서 생각할 수도 있지만[2], 일단 NOSQL 특성에 주로 표현되는 것만 생각한다.

  1. eventual consistency: 복제를 언젠가는 마쳐서, 다같이 같은 값을 보는 일관성을 보장한다.(가장 약한 보장)
  2. causal consistency: 인과성이 있는 작업은 그 순서대로 보여야 한다.
  3. sequential consistency: 모든 연산이 특정 순서대로 실행된 것으로 보여야 한다.

2번에 추가적인 설명을 하자면, insert A=1 이후 update A=2 를 했다면 맨 마지막 A=2 만 보이거나, A=1이 보인 뒤 A=2가 보여야한다는 말이다. 1번만 보장하는 DB의 경우에는, 방금 두 연산이 node X에서 실행된다고 하면 node X에서는 A=2가 보이고, 데이터를 복제중인 node Y에서는 A=1이 보이는 상황이 가능하기 때문이다.
이 때 2번의 경우에는 insert B=3을 어느 시점에 하더라도, B=3이 어떤 때에 보이는지는 관계없다. 왜냐하면 서로 인과성이 없기 때문이다.(1번도 당연히 같다. 더 약한 보장이기 때문이다.)

단일 리더 복제는 선형적이 될 수 있으며, 설계/동시성 버그/split brain 등으로 인해 비선형적이 되기도 한다. 주키퍼는 합의 알고리즘을 통해 단일 리더를 선출하고 동작하므로 선형적이라고 한다.
다중 리더 복제는 충돌이 필연적으로 발생하므로, 충돌 해소가 필요하며 이 때문에 비선형적이다.
리더 없는 복제는 write와 read를 할 때, 공유하는 node들에게도 실행해서 선형적임을 보장받을 수 있다. 그러나 선택에 따라 비선형적이 될 수도 있는데 이에 대해 설명한다.

리더 없는 복제의 정책

리더 없는 복제는 Dynamo에 기반한 DB에서 사용한다. 정족수(quorum) 쓰기와 읽기를 한다. dynamoDB와 같은 NOSQL은 보통 eventual consistency를 기본으로 제공하고, 정족수를 사용해서 sequential consistency를 제공한다고 알려져있다.

정족수 읽기가 2 이상일 경우(r > 1), 여러 읽기 도중 오래된 값을 가진 node가 있다면 이를 복구해준다. 이를 읽기 복구(read repair)라고 한다. 오래된 값을 가진 node가 있는 지 백그라운드 프로세스가 지속적으로 찾는 것을 안티 엔트로피 처리라고 한다. 두 메커니즘을 모든 DB가 구현하는건 아니다.
쓰기 가용성을 높이기 위해 정족수 w를 만족하지 않아도 일단 연결할 수 있는 node에 기록하는 것을 느슨한 정족수, 나중에 끊어진 node가 연결되면 수용한 쓰기를 보내주는 것을 hinted handoff라고 한다. DB마다 선택할 수 있는 정책이다.

쓰기 충돌이 일어나면 LWW(last-write-wins)를 해소 방법으로 쓰거나, version vector를 사용해서 동시에 일어났는지 판단하고 정책에 따라 값을 정할 수 있다. LWW는 모든 머신간 시간 동기화를 하기 힘드므로 사실상 부정확한(비선형적) 충돌 해소 방법이다. version vector를 통해 동시에 값이 바뀐걸 확인하고, 두 값의 합집합을 취하면 손실없이 데이터를 병합할 수 있다(version clock과 version vector는 다르다고 하지만, 예시이다.[3, 4]).

리더 없는 복제가 선형성을 보장하려면, 정족수를 w + r > n으로 설정하고, read 시 read repair를 동기로 하고, write할 client는 쓰기 충돌을 막기 위해, write를 보낼 node들의 최신 상태를 알아야 한다. Cassandra는 read repair를 동기로 하지만, write시 LWW로 충돌해소를 하기 때문에 선형성을 보장할 수 없다. 사실상 리더 없는 복제는 비선형적이라고 가정하는게 안전하다.

다중 리더 복제와 리더 없는 복제는 결함 노드, 네트워크 중단, 지연 시간 급증에서 견고하지만 일관성을 보장하기 힘들다.

Cassandra의 tunable consistency

Cassandra는 CAP에서 C를 eventual consistency로 제공하지만, linearizable consistency도 제공할 수 있다고 주장한다[5]. 정족수를 파라미터로 설정해서 r + w > n 이면 후자를 보장할 수 있다고 하는데, 이론적으로 거의 가깝지만 앞서 확인했듯이 LWW를 사용하므로 완벽하다고 하기는 어렵다. 그 외에도 파라미터에 다양한 값을 줄 수 있고, 값에 따라 consistency를 "tune"할 수 있다고 하는데 큰 의미는 없어보인다.

인용

[1] https://en.wikipedia.org/wiki/Consistency_model#Data-centric_consistency_models
[2] https://sergeiturukin.com/2017/06/29/eventual-consistency.html
[3] https://levelup.gitconnected.com/distributed-systems-physical-logical-and-vector-clocks-7ca989f5f780
[4] https://riak.com/why-vector-clocks-are-easy/
[5] https://docs.datastax.com/en/cassandra-oss/3.x/cassandra/dml/dmlAboutDataConsistency.html
참고: 책 "데이터 중심 애플리케이션 설계"

'NoSQL' 카테고리의 다른 글

NoSQL SSTable, LSM tree의 구조  (0) 2021.03.02
Posted by sjo200
,