본문 바로가기
블록체인/블록체인이란?

이더리움 프루닝

by 제이제이_은재 2022. 6. 29.
반응형

 

💡이더리움에서의 프루닝

 

이더리움에서는 프루닝을 State Trie Pruning이라고 한다. State Trie Pruning은 현재 상태를 Prefix Tree의 일종인 Modified Merkle Partricia (MPT, 상태전이 일반 머클 확장 페트리샤 트리)로 저장한다. 이더리움에서 상태란, Account의 상태(Account state)이다. 그리고, 이 상태들이 모여 Global State를 이루고, 이는 Key-Value의 데이터 구조로 저장하고 있다.

 

key : value = 32 byte Address : Account state

 

사용자가 늘어나게 되면 당연히 이더리움의 어카운트가 계속 늘어나고, 수정 사항이 늘어나자 이는 계산이 버거워지고 느려지는 것으로 이어졌다. 이를 위해 머클 트리를 도입하여 기존의 값을 변경하는 것은 어느 정도 해소하였지만, 새로운 노드를 추가하거나 삭제하는 것은 아직도 머클 트리의 정렬을 다시 계산해야 하는 복잡한 작업이다. 이에, 이더리움에서는 몇 가지의 기능을 추가하여 머클트리를 보완했고, 그 머클 트리가 바로 Modified Merkle Patricia Trie(MPT, 상태전이 일반 머클 확장 페트리샤 트리) 이다. MPT는 State Root의 Hash를 계산하기 위해 전체를 볼 필요가 없다. 수정된 브랜치의 Hash만 다시 계산하기 때문에 빠르게 root Hash 를 찾을 수 있다.

 

 

 

MPT는 새로 삽입되는 노드의 수를 최소화한다. 예를 들어, 위의 그림에서 Block N 과 Block N + 1 의 차이는 A 의 오른쪽 자식의 값이 10에서 20으로 변경된 것 뿐이다. 이 경우 10에서 20으로 변경된 노드의 부모 외의 다른 노드는 기존의 노드를 재활용할 수 있다. 따라서 푸른색으로 그려진 3개의 노드만 새로 추가하면 된다. 그렇다고 해서 더는 접근할 필요가 없는 노드들을 지울 수는 없다. 이더리움은 Finality를 보장하지 않기 때문이다. 언제든지 Block N + 1 이 Block N 으로 Retract 될 수 있다. 게다가 Web3 API 를 통해서 과거의 State에 접근하는 것도 가능하기 때문에 현재 상태에서 안 쓰이는 노드를 바로 지울 수는 없다.

 

그렇다고 해서 영원히 남겨둘 수 있는 것도 아니다. 현재 이더리움에서 최신 State의 크기는 약 25GB 정도지만, 과거 State를 전부 저장하면 300GB를 넘어간다. 게다가 이 크기는 점점 커질 것이기 때문에 이를 전부 저장하면 300GB가 넘어간다. 게다가 이 크기는 점점 커질 것이기 때문에 이를 전부 저장하는 것은 현실적이지 못하다. 이더리움은 접근할 수 있는 과거 State를 127개로 제한하여 그보다 오래된 State에만 포함된 노드는 지워도 되도록 했다. 하지만 지워도 된다는 것과 지울 수 있다는 것은 별개의 문제이다. DB에 저장돼있는 노드 중 최근 127개의 노드에서 접근할 수 없는 노드를 찾아 지우는 것은 쉬운 문제가 아니다.

 

✓ 이더리움 프루닝의 문제

 

이 문제는 컴퓨터 과학에서 오랫동안 풀어 온 Automatic Memory Management 문제와 비슷하다. 실제로 비탈릭 부테린이 쓴 State Tree Pruning은 Reference Counting을 언급하고 있다. 하지만 이더리움의 State Trie Pruning은 일반적인 Memory Management 와 다른 점이 있다. 일반적인 Automatic Memory Management는 휘발성이 있는 자원을 다룬다. 따라서 프로그램이 비정상 종료되는 상황을 고려하지 않아도 된다. 프로그램이 종료되면 관리해야 할 자원이 남아 있지 않기 때문이다. 하지만 State Trie의 노드는 DB에 저장되는 Persistence 메모리이다. 프로그램의 비정상 종료로 인해 State Trie 가 비정상적인 상태가 되면 복구할 방법이 없다. 비탈릭 부테린이 제시한 State Tree Pruning이 메인 넷에 들어가지 못한 것도 이러한 이유 때문이다.

 

Reference Counting이 아닌 다른 방법으로 State Trie Pruning을 구현할 수도 있다. 예를 들어 Trace를 이dyd하는 방법도 Tracing Garbage Collection 도 Automatic Memory Management 에서 흔히 사용되는 기법이다. 하지만 Trace에 필요한 추가적인 메모리나 Stop-the-world에 의해 생기는 성능 문제 등이 먼저 해결돼야 한다. 이러한 문제들로 현재 Go-Ethereum 에서는 매우 한정적으로 State Trie Pruning을 한다. State Trie 에 대해 캐시를 사용하는데, 이 캐시에만 저장된 노드에 대해서는 Pruning 을 하고 DB에 저장딘 노드는 Pruning 을 하지 않는 방식이다. 캐싱된 노드는 서버가 정상적으로 종료되거나, 생선된지 128 block이 지났거나, 캐시 크기를 넘겼거나, 마지막으로 캐시된 노드가 DB에 저장된지 5분이 지나면 DB에 저장한다. 즉, 위의 조건을 만족하기 전에 캐시에서 삭제된 노드는 DB에 저장하지 않는다.

 

하지만 생성된 지 5분이 지나지 않아서 삭제되는 노드는 그리 많지 않다. 따라서 대부분의 삭제됐어야 할 노드는 여전히 DB에 남아 있다. 이에 대해 이더리움에서는 State Pruning을 구현하는 것을 계속 시도하고 있다. 하지만 State Trie Pruning이 실제로 구현되기 전에는 Fast Sync를 사용하여 다음과 같은 방법을 사용하기로 권장한다. 다음의 세 과정을 거치면, 새 노드에서는 Fast Sync로 동기화된 상태까지의 Garbage Node 없이 유효한 노드만 관리할 수 있다.

 

1. 세 클라이언트를 띄운다.

2. 기존 클라이언트에서 새 클라인언트로 Fast Sync를 받는다.

3. 기존 클라이언트를 지운다.

 

언뜻 보기에는 주먹구구식 방식으로 보이지만, 위험 부담이 있는 Garbage Collection 을 구현하는 것보다 안전하고 현실적인 해결책이다. 이더리움에 Garbage Collection이 구현되기 전까지는 계속 위와 같은 방식을 이용해야 할 것이다.

반응형

댓글