Solana 공동 창립자: Solana 상태 성장에 대한 해결책은 무엇인가요?
저자: toly, Solana 공동 창립자
편집: Felix, PANews
매일 약 100만 개의 새로운 계정이 Solana에 추가되며, 현재 총 상태는 5억 개를 초과하고 스냅샷 크기는 약 70GB입니다. 하드웨어의 개선으로 이러한 숫자는 완전히 관리 가능하지만, SVM 런타임의 목표는 가장 저렴한 하드웨어 접근 방식을 제공하는 것입니다. 이를 위해서는 현재 하드웨어 제한 내에서 상태와 메모리를 관리해야 합니다.
PCI 대역폭
2024년 기준, 최신 PCI 대역폭은 0.5 Tbs에서 1 Tb의 처리량에 도달할 수 있습니다. 즉, 초당 64GB에서 128GB입니다. 비록 큰 것처럼 들리지만, 하나의 tx가 128MB를 읽거나 쓸 경우, 128GBps의 PCI 대역폭은 체인의 TPS를 약 1000으로 제한합니다. 실제로 대부분의 tx는 최근에 로드되어 RAM에 캐시된 메모리에 접근합니다. 이상적인 설계는 128MB의 새로운 상태를 가진 1000개의 tx를 로드할 수 있도록 하고, 기존 캐시 상태를 읽고 쓰는 10k 이상의 tx를 추가하는 것입니다.
계정 인덱스
새로운 계정을 생성하려면 해당 계정이 현재 존재하지 않음을 증명해야 합니다. 이는 각 검증자에서 자동으로 수행되며, 각 검증자는 현재 모든 유효한 계정의 전체 인덱스를 가지고 있습니다. 계정 데이터가 로컬에 저장되지 않고 데이터의 해시만 저장되더라도, 5억 개의 계정은 32바이트의 키 + 32바이트의 데이터 해시로 구성되어 각 항목이 64바이트가 되어 32GB가 됩니다. 이는 RAM과 디스크의 분리를 보장하기에 충분합니다.
스냅샷 크기
일부 스냅샷 크기에서 네트워크의 일부가 하드웨어 고장을 겪을 경우, 새로운 시스템을 차가운 시작하는 데 필요한 시간은 최악의 경우 재시작 시간을 연장할 수 있습니다. 대역폭과 하드웨어의 개선으로 상황은 매일 변하고 있으며, Solana는 이 한계에 가까워지지 않았지만, 이 한계는 언제든지 존재합니다.
개요
메모리와 디스크는 서로 다른 성능 특성과 제한을 가지고 있습니다. SVM이 이를 구분하지 않으면 거래와 제한은 최악의 경우를 기준으로 가격이 책정되어 성능이 제한됩니다. 거래 실행 중 모든 계정 키는 최소한 사용 가능해야 하며, 총 계정 수는 RAM과 디스크 PCIi 대역폭 활용도에 영향을 미칩니다. 스냅샷은 임의로 증가할 수 없습니다. 이상적인 해결책은:
PCI 리소스가 필요 없는 tx를 블록에 더 많이 패킹할 수 있도록 허용
총 인덱스 크기와 스냅샷 크기를 관리
Chilly, Avocado, LSR. 나쁜 이름은 종종 훌륭한 소프트웨어 설계의 징후입니다. Anza와 Firedancer의 엔지니어들은 다음과 같은 솔루션을 생각해냈습니다.
Chilly
계정 런타임의 캐시는 모든 인스턴스에 의해 결정론적으로 관리됩니다. 더 높은 수준에서 이는 상태에 접근하기 위한 LRU 캐시입니다. 블록 구축 및 스케줄링 동안 이 구현은 계정을 쉽게 확인할 수 있으며, LRU 캐시를 잠그거나 반복할 필요가 없습니다. 캐시는 매우 간단한 카운터 메커니즘으로 구현됩니다.
총 로드 바이트는 Bank::loaded_bytes:u64로 추적됩니다.
각 계정은 사용 시 현재 실행 총계인 account::load_counter:u64로 표시됩니다.
계정을 로드할 때, 만약 Bank::loadedbytes - Account::loadcounter > CACHESIZE이면, 해당 계정은 차가운 계정으로 간주되며, 그 크기는 각 블록의 LOADLIMIT에 따라 계산됩니다.
새로운 계정의 load_counter는 0이므로 모든 새로운 계정은 차가운 계정입니다.
리더의 스케줄러는 LOAD_LIMIT를 수위로 사용하며, 이는 쓰기 잠금 CU 제한과 유사합니다.
이 설계의 절묘한 점은 현재의 스케줄러에 자연스럽게 적합하다는 것입니다. 사용자는 자신의 우선 수수료에 대해서만 걱정하면 됩니다. 스케줄러는 LOADLIMIT 및 계정 쓰기 잠금 제한 이하의 모든 tx를 백팩 문제에 넣어야 합니다. 가장 높은 우선 순위의 tx는 먼저 로드되고 LOADLIMIT를 사용할 수 있습니다. 이 제한에 도달하면 모든 다른 tx는 여전히 하나의 블록에 포함될 수 있습니다. 따라서 검증자는 tx의 캐시 지역성을 최대화할 수 있습니다.
Avocado
Avocado는 상태 압축과 인덱스 압축의 두 부분으로 구성됩니다. 먼저 해시로 계정 데이터를 대체한 다음, 계정 인덱스를 이진 트리/파트리샤 트리로 이동합니다. 새로운 계정은 그들이 "트리"에 존재하지 않음을 증명해야 합니다.
상태 압축
대략적인 설계는 다음과 같습니다:
할당 중 각 계정은 바이트당 X 개의 lamports에 바인딩됩니다.
만약 X < 현재 경제 바닥가라면, 해당 계정은 메모리에 유지되며, 해당 계정은 압축됩니다.
압축은 여러 단계의 과정으로, 하나의 epoch에서 실행됩니다.
계정 데이터는 해시 값(data)으로 대체됩니다.
계정 키는 여전히 상태에 있습니다.
압축된 계정을 참조하는 거래는 실패합니다.
압축 해제는 로더와 유사한 데이터를 업로드해야 합니다.
압축 해제의 비용은 새로운 계정을 할당하는 비용과 동일해야 합니다.
추정에 따르면 75%의 계정은 6개월 이상 접근되지 않았으며, 아마도 영원히 접근되지 않을 것입니다. 이를 압축하면 스냅샷 크기를 50% 절약할 수 있습니다.
인덱스 압축
이는 더 어려운 문제입니다. 상태 압축만으로는 검증자가 시스템 내의 모든 가능한 유효 계정을 여전히 보유하고 있습니다. 새로운 계정을 생성하려면 이 데이터베이스를 확인해야 합니다. 검증자가 이 데이터베이스를 저장하는 비용은 매우 높지만, 사용자가 새로운 계정을 생성하는 비용은 매우 낮습니다. 새로운 개인 키가 기존 계정과 충돌하지 않도록 보장해야 합니다.
이진 트리 채굴
이진 트리는 스냅샷의 일부로 추적됩니다.
추가 솔을 얻고자 하는 검증자는 거래를 생성하여 상태에서 압축된 계정 kv 쌍을 삭제하고 이를 이진 트리에 추가할 수 있습니다.
사용자는 압축 해제 과정에서 kv를 트리에서 제거하여 허용되지 않은 경우 이를 역으로 실행할 수 있습니다(이는 압축 계정을 백그라운드 서비스에서 압축할 때 더 쉽게 하기 위해 압축 해제 시 원자적 작업이 필요할 수 있습니다).
검증자에게는 kv 쌍의 수와 관계없이 트리 루트의 크기는 일정합니다.
zkp를 사용하면 각 tx는 약 30개의 계정을 압축할 수 있습니다.
각 블록에 하나만 있다고 가정하면, 5억 개의 계정을 압축하는 데 약 80일이 걸립니다.
이 과정의 핵심은 이를 수행하는 검증자가 보상을 받지만, 모든 검증자가 이를 수행해야 하는 것은 아니라는 것입니다. 모든 검증자가 이를 수행해야 한다면, 모든 검증자는 현재 이진 트리의 내용을 유지해야 하며, 이는 전체 상태가 스냅샷의 일부여야 함을 의미합니다. 전체 상태를 유지하려는 검증자는 인덱스에서 N개의 계정을 트리에 압축하는 거래를 제출해야 합니다.
새 계정 증명
새로운 계정을 생성하려면 사용자는 해당 계정이 트리에 존재하지 않음을 증명해야 합니다. 전체 상태를 유지하는 검증자는 계정이 트리에 없다는 증명을 생성할 수 있습니다. 이는 사용자에게 부담을 주며, 그들은 이러한 증명을 생성하기 위해 항상 대형 상태 제공자와 연결되어 있어야 합니다.
또는 사용자는 자신의 계정이 최근 PoH 해시로 생성되었음을 증명할 수 있습니다. 이를 지원하는 가장 간단한 방법은:
새로운 PKI 생성
계정 주소는 해시(최근 PoH 해시, PKI::public_key)입니다.
트리 내의 계정이 먼저 상태 압축을 수행해야 하므로, 이는 전체 epoch이 필요합니다. 트리 내의 어떤 계정도 최근 PoH 해시를 사용하여 주소를 생성할 수 없습니다.
지원할 수 있는 다른 방법은 PKI 생성 자체가 개인 키가 해시(사용자 숨겨진 비밀, 최근 PoH 해시)로 생성되었음을 증명하는 것입니다.
LSR
경량 단순 임대, 즉 덜 어리석은 임대. 새로운 계정을 할당하는 비용을 어떻게 가격 책정할 것인지, 그리고 오래된 폐기된 계정이 결국 압축되고 시스템의 전체 부담과 새로운 사용자의 가격을 줄이는 방법은 무엇일까요?
임대 제도를 복원할 필요가 있습니다. 임대는 현재 상태에서 계정이 X 달러/바이트/일의 비용을 지불해야 한다는 것을 의미하며, 이는 AWS에서 계정이 저장 비용을 지불하는 것과 같습니다.
임대 요율 결합 곡선
RentRate = K*(state_size)^N
현재 상태 크기가 작든 크든 관계없이, 작을 경우 요율은 낮아야 하고, 스냅샷 제한에 가까워질 경우 요율은 매우 높아야 합니다.
할당 최소 결합 가격
계정은 최소한 하나의 epoch 동안 존재해야 합니다. 할당은 계정을 핫 상태로 가져오는 데 필요합니다. 핫 계정은 캐시 기간 동안 존재해야 합니다.
New Account bond = Epoch Slots * RentRate * Account::size
새 계정의 잔액에는 최소한 이만큼의 lamports가 있어야 생성할 수 있습니다.
핫 계정 소각
lruturnverrate = 각 계정이 LRU 캐시에서 평균적으로 차지하는 시간, 최대값은 1 epoch입니다. 이 값은 상수일 수도 있고, 체외에서 계산되어 중위수 지분 가중 상수로 SVM에 보고될 수 있습니다.
압축
(current slot - account::creation_slot) * RentRate * account::size > account::lamports일 때, 계정을 압축하고 모든 lamports를 소각합니다.
위의 해결책은 시간이 지남에 따라 사용되지 않는 계정이 결국 lamports 0에 도달하고 압축될 것이기 때문에 상태를 매우 저렴하게 만들 것입니다. 따라서 데이터 오버헤드가 줄어들고, 심지어 인덱스 오버헤드도 줄어들어 현재 상태의 크기가 감소할 것입니다. 상태 크기를 줄이면 초이차 할당 비용이 낮아질 것입니다.