
솔라나 공동 창립자: 솔라나의 상태 증가 문제에 대한 해결책은 무엇인가?
저자: toly, Solana 공동 창립자
번역: Felix, PANews
매일 약 100만 개의 새로운 계정이 Solana에 추가되며, 현재 총 상태는 5억을 넘고 스냅샷 크기는 약 70GB이다. 하드웨어가 향상됨에 따라 이러한 수치 자체는 충분히 관리 가능하지만, SVM 런타임의 목표는 가장 저렴한 하드웨어 접근 방식을 제공하는 것이며 이를 달성하기 위해서는 현재 하드웨어 제한 내에서 상태와 메모리를 관리해야 한다.
PCI 대역폭
2024년 기준 최신 PCI 대역폭은 초당 0.5Tbps에서 1Tbps의 처리량, 즉 초당 64GB에서 128GB까지 도달할 수 있다. 상당히 큰 수치처럼 들리지만, 만약 하나의 트랜잭션이 128MB를 읽고 쓴다면, 128GB/s의 PCI 대역폭은 체인의 TPS를 약 1000 정도로 제한하게 된다. 실제로 대부분의 트랜잭션은 최근 로드되어 RAM에 캐싱된 메모리에 접근한다. 이상적인 설계는 128MB의 새 상태를 가진 1000개의 트랜잭션과 함께, 기존 캐시된 상태를 읽고 쓰는 10,000개 이상의 트랜잭션을 처리할 수 있도록 해야 한다.
계정 인덱스
새 계정을 생성하려면 해당 계정이 현재 존재하지 않는다는 것을 증명해야 한다. 이는 일반적으로 각 검증자가 현재 모든 유효한 계정의 전체 인덱스를 가지고 있기 때문에 각 검증기에서 자동으로 수행된다. 계정 데이터가 로컬에 저장되지 않고 데이터 해시만 저장되더라도, 5억 개의 계정은 32바이트 키 + 32바이트 데이터 해시, 즉 항목당 64바이트로 총 32GB가 된다. 이는 이미 RAM과 디스크를 분리할 만큼 충분한 용량이다.
스냅샷 크기
특정 스냅샷 크기에서는 네트워크 일부가 하드웨어 장애를 겪었을 때 새로운 시스템을 콜드 스타트하는 데 필요한 시간이 최악의 경우 재시작 시간을 연장할 수 있다. 대역폭과 하드웨어의 개선으로 상황은 매일 변화하고 있으며 Solana는 아직 이 한계에 가까워지지 않았지만, 어느 시점에서도 이 제한은 존재한다.
요약
메모리와 디스크는 서로 다른 성능 특성과 제한을 가진다. SVM이 이를 구분하지 않으면 트랜잭션과 제한은 최악의 경우에 맞춰 가격이 책정되어 성능이 제한된다. 트랜잭션 실행 중에는 모든 계정 키가 적어도 사용 가능해야 하며, 총 계정 수는 RAM과 디스크 PCI 대역폭 활용도에 영향을 미친다. 스냅샷은 임의로 커질 수 없다. 이상적인 해결책은 다음과 같다.
-
PCI 리소스를 필요로 하지 않는 더 많은 트랜잭션을 블록에 포함할 수 있도록 허용
-
총 인덱스 크기와 스냅샷 크기를 관리
Chilly, Avocado, LSR. 나쁜 이름은 종종 훌륭한 소프트웨어 설계의 징표다. Anza와 Firedancer의 엔지니어들이 아래의 방안을 고안했다.
Chilly
계정 런타임의 캐시는 모든 인스턴스에 의해 결정론적으로 관리된다. 고수준에서 보면 이것은 상태 접근을 위한 LRU 캐시이다. 블록 생성 및 스케줄링 중에 이 구현은 LRU 캐시를 잠그거나 반복하지 않고도 쉽게 계정을 확인할 수 있다. 캐시는 매우 간단한 카운터 메커니즘으로 구현된다.
-
총 로드 바이트는 Bank::loaded_bytes:u64로 추적된다
-
각 계정은 사용될 때 현재 실행 총합인 account::load_counter:u64로 태그 지어진다
-
계정을 로드할 때, Bank::loaded_bytes - Account::load_counter > CACHE_SIZE이면 그 계정은 콜드 계정으로 간주되며, 그 크기는 각 블록의 LOAD_LIMIT에 따라 계산된다
-
새 계정의 load_counter는 0이므로 모든 새 계정은 콜드 계정이다
-
리더의 스케줄러는 WRITE_LOCK CU 제한과 유사하게 LOAD_LIMIT를 워터마크로 취급한다
이 설계의 훌륭한 점은 현재 스케줄러에 자연스럽게 잘 맞는다는 것이다. 사용자는 단지 자신의 우선 순위 수수료만 신경 쓰면 된다. 스케줄러는 LOAD_LIMIT와 계정 쓰기 잠금 제한 모두를 충족하는 모든 트랜잭션을 배낭 문제처럼 처리해야 한다. 가장 높은 우선순위의 트랜잭션이 먼저 로드되고 LOAD_LIMIT를 사용할 수 있다. 이 제한에 도달하면 다른 모든 트랜잭션도 여전히 블록에 포함될 수 있다. 따라서 검증자는 트랜잭션들의 캐시 지역성을 극대화하여 완화할 수 있다.
Avocado
Avocado는 두 부분으로 구성된다: 상태 압축과 인덱스 압축. 먼저 계정 데이터를 해시로 대체한 후, 계정 인덱스를 Binary Trie / Patricia Trie로 마이그레이션한다. 새 계정은 자신이 'trie' 내에 존재하지 않는다는 것을 증명해야 한다.
상태 압축
대략적인 설계는 다음과 같다:
-
할당 시 각 계정은 바이트당 X 램포트(lamports)를 바인딩한다
-
X가 현재 경제적 밑값보다 작으면, 메모리에 있는 계정은 압축된다
-
압축은 에포크 기간에 걸쳐 실행되는 다단계 프로세스이다
-
계정 데이터는 해시(data)로 대체된다
-
계정 키는 여전히 상태 내에 존재한다
-
압축된 계정을 참조하는 트랜잭션은 실패한다
-
압축 해제는 로더와 유사한 데이터를 업로드해야 한다
-
압축 해제 비용은 새 계정을 할당하는 비용과 동일해야 한다
추정하기에 6개월 이상 접근되지 않은 계정의 약 75%는 앞으로도 거의 사용되지 않을 가능성이 높다. 이것들을 압축하면 스냅샷 크기를 50% 절감할 수 있다.
인덱스 압축
이는 해결하기 더 어려운 문제이다. 상태 압축만으로는 검증자들이 여전히 시스템 내 가능한 모든 유효한 계정을 보유하고 있다. 새 계정 생성은 이 데이터베이스를 확인해야 한다. 검증자가 이 데이터베이스를 저장하는 비용은 높지만, 사용자가 새 계정을 생성하는 비용은 낮다. 새 개인키가 기존 계정과 충돌하지 않도록 보장해야 한다.
Binary Trie 마이닝
-
Binary Trie는 스냅샷의 일부로 추적된다
-
추가 SOL을 얻고자 하는 검증자는 트랜잭션을 만들어 상태에서 압축된 계정 kv 쌍을 삭제하고 이를 Binary Trie에 추가할 수 있다
-
사용자는 압축 해제 과정에서 kv를 Trie에서 제거함으로써 허용되지 않은 상태에서 역작업을 수행할 수 있다(이 작업은 압축 해제 시 원자 연산이 필요할 수 있으며 백그라운드 서비스에서 계정 압축을 처리할 때 더 쉬워진다)
-
검증자 입장에서 Trie가 얼마나 많은 kv 쌍을 포함하든 상관없이 Trie 루트의 크기는 일정하다
-
zkp를 사용하면 각 트랜잭션은 약 30개의 계정을 압축할 수 있다
-
각 블록당 하나씩 있다고 가정하면, 5억 개의 계정을 압축하는 데 약 80일이 소요된다
이 과정의 핵심은 이 작업을 수행하는 검증자가 보상을 받지만, 모든 검증자가 반드시 수행할 필요는 없다는 점이다. 모든 검증자가 이 작업을 수행해야 한다면, 모든 검증자는 현재 Binary Trie의 내용을 유지해야 하며, 이는 전체 상태가 스냅샷의 일부여야 함을 의미한다. 전체 상태를 유지하고자 하는 검증자는 인덱스 내 N개의 계정을 Trie에 압축하는 트랜잭션을 제출해야 한다.
새 계정 증명
새 계정을 만들려면 사용자가 해당 계정이 Trie에 존재하지 않는다는 것을 증명해야 한다. 전체 상태를 유지하는 검증자는 계정이 Trie에 존재하지 않는다는 증명을 생성할 수 있다. 그러나 사용자는 이러한 증명을 생성하기 위해 항상 대규모 상태 제공자에 연결해야 하므로 부담이 된다.
또는 사용자는 자신의 계정이 가장 최근의 PoH 해시로 생성되었음을 증명할 수 있다. 이를 지원하는 가장 간단한 방법은 다음과 같다:
-
새 PKI 생성
-
계정 주소는 해시(최근 PoH 해시, PKI::public_key)이다
Trie 내 계정은 먼저 상태 압축을 거쳐야 하며, 이는 전체 에포크가 필요하다. 따라서 Trie 내 어떤 계정도 최근 PoH 해시를 사용해 주소를 생성할 수 없다.
지원 가능한 다른 방법으로는 PKI 생성 자체가 "비밀 값 + 최근 PoH 해시"로부터 개인키가 생성되었다는 증명을 제공할 수 있다.
LSR
Lightweight Simple Rent, 또는 Less Stupid Rent. 새 계정 할당 비용을 어떻게 정가해야 하며, 오래되고 폐기된 계정들이 궁극적으로 압축되어 시스템의 전반적 부하와 신규 사용자의 가격이 줄어들도록 보장할 수 있을까?
렌트(Rent) 제도를 복원해야 한다. Rent란 현재 상태의 계정이 AWS 계정이 저장 비용을 지불하듯이 X달러/바이트/일의 비용을 지불해야 한다는 의미이다.
Rent Rate bonding curve
RentRate = K*(state_size)^N
현재 상태 크기가 얼마이든, 작으면 요금은 낮아야 하고, 스냅샷 제한에 가까우면 요금은 매우 높아야 한다.
할당 최소 바인딩 가격
계정은 적어도 한 에포크는 존재해야 한다. 할당은 계정을 Hot 상태로 가져와야 한다. 핫 계정은 캐시 기간 동안 존재해야 한다.
새 계정 바인딩 = 에포크 슬롯 수 * RentRate * Account::size
새 계정 생성 시 잔액에 위 금액 이상의 램포트가 있어야 한다.
Hot Account Burn
lruturnverrate = LRU 캐시 내 각 계정의 평균 점유 시간, 최대 1 에포크. 이 값은 상수일 수 있으며, 체인 외부에서 계산되어 중앙값 권한 가중 상수로서 SVM에 보고될 수 있다.
압축
(현재 슬롯 - account::creation_slot) * RentRate * account::size > account::lamports 일 때, 계정을 압축하고 모든 램포트를 소각한다.
위 솔루션은 사용되지 않는 계정이 시간이 지남에 따라 결국 램포트가 0이 되어 압축되므로 상태를 저렴하게 유지할 수 있다. 따라서 데이터 오버헤드가 감소하고 인덱스 오버헤드도 감소하며, 이는 현재 상태 크기를 줄인다. 상태 크기 감소는 초-이차적인 할당 비용을 낮춘다.
TechFlow 공식 커뮤니티에 오신 것을 환영합니다
Telegram 구독 그룹:https://t.me/TechFlowDaily
트위터 공식 계정:https://x.com/TechFlowPost
트위터 영어 계정:https://x.com/BlockFlow_News














