Репликация AccountsDB для служб RPC
Проблема
Валидаторы отстают от сети, когда перегружены большой нагрузкой RPC. По-видимому, это связано с комбинацией нагрузки на ЦП и состязаниями за блокировки, вызванными обслуживанием запросов RPC. Самые дорогие RPC-запросы связаны со сканированием учетных записей.
Обзор решения
«Реплики» AccountsDB, которые запускаются отдельно от основного валидатора, могут использоваться для разгрузки запросов на сканирование учетных записей. Реплики будут только: запрашивать и извлекать обновления учетной записи из валидатора, обслуживать запросы RPC состояния учетной записи клиента и управлять очисткой + сжатием AccountsDb и AccountsBackgroundService.
Реплика взаимодействует с основным валидатором через новый механизм RPC для получения метаданных о репликации и обновлении учетных записей от валидатора. Основной валидатор поддерживает только один узел-реплику. Узел реплики может передавать информацию одной или нескольким другим репликам, формирующим дерево репликации.
При начальном запуске узла-реплики он загружает последний снимок из валидатора и создает из него банк и AccountsDb. После этого он запрашивает у своего основного валидатора новые слоты и просит валидатор отправить обновленные учетные записи для этого слота и обновить его собственный AccountsDb.
Один и тот же механизм репликации RPC может использоваться между репликами и другими репликами. Это требует, чтобы реплика обслуживала как клиент, так и сервер в модели репликации.
На стороне обслуживания клиентского RPC JsonRpcAccountsService отвечает за обслуживание клиентских вызовов RPC для информации, связанной с учетными записями, аналогичной существующей JsonRpcService.
Реплика также будет периодически делать моментальные снимки, чтобы ее можно было быстро запустить после перезапуска, если моментальный снимок не слишком старый.
Подробное решение
В следующих разделах содержится более подробная информация о конструкции.
Модель согласованности
Информация AccountsDb реплицируется асинхронно от основного валидатора к реплике. Когда делается запрос к AccountsDb реплики, реплика может не иметь последней информации о последнем слоте. В этом отношении он в конечном итоге будет последовательным. Однако для конкретного слота предоставленная информация согласуется с информацией его равноправного валидатора для подтвержденных и завершенных уровней обязательств. Для версии 1 мы поддерживаем запросы только на этих двух уровнях.
Узел реплики Solana
Будет введен новый узел с именем solana-replica-node, основной обязанностью которого является поддержка реплики AccountsDb. Узел RPC или узел реплики используются в этом документе взаимозаменяемо. Это будет отдельный исполняемый файл от валидатора.
Реплика состоит из следующих основных компонентов:
ReplicaSlotConfirmationRequestor
: эта служба отвечает за периодическую отправку запроса ReplicaSlotConfirmationRequest
своему одноранговому валидатору или реплике для последних слотов.
Он указывает последний слот (last_replicated_slot), для которого реплика уже получила информацию об учетных записях. Это поддерживает ReplWorkingSlotSet и управляет жизненным циклом BankForks, BlockCommitmentCache (для самого высокого подтвержденного слота) и оптимистически подтвержденного банка.
ReplicaSlotConfirmationServer
: эта служба отвечает за обслуживание ReplicaSlotConfirmationRequest
и отправляет ReplicaSlotConfirmationResponse
обратно запрашивающей стороне.
Ответ состоит из вектора новых слотов, о которых известно валидатору, которые позже, чем указанный last_replicated_slot. Этот сервис также работает в основном валидаторе. Этот сервис получает слоты для репликации от BankForks, BlockCommitmentCache и OpmiscallyConfirmBank.
ReplicaAccountsRequestor
: эта служба отвечает за отправку запроса ReplicaAccountsRequest
своему одноранговому валидатору или реплике для ReplicaAccountInfo
для слота, для которого не была завершена репликация базы данных учетных записей. ReplicaAccountInfo содержит ReplicaAccountMeta, Hash и AccountData. ReplicaAccountMeta
содержит информацию о существующей AccountMeta
в дополнение к длине данных учетной записи в байтах.
«ReplicaAccountsServer»: эта служба отвечает за обслуживание «ReplicaAccountsRequest» и отправляет «ReplicaAccountsResponse» запрашивающей стороне. Ответ содержит счетчик ReplAccountInfo и вектор ReplAccountInfo. Эта служба работает как в валидаторе, так и в реплике, передающей информацию о репликации. Сервер может передавать информацию об учетной записи из своего AccountCache или из хранилища, если оно уже очищено. Это похоже на создание пакета моментальных снимков из AccountsDb с той разницей, что хранилище не нужно сбрасывать на диск перед потоковой передачей клиенту. Если данные учетной записи находятся в кеше, их можно передавать напрямую. Необходимо соблюдать осторожность, чтобы избежать очистки данных учетной записи для слота во время обслуживания потоковой передачи. При попытке репликации слота, если слот уже очищен с данными учетных записей, очищенными в результате обновления в более поздних корневых слотах, реплика должна отказаться от этого слота и попробовать более поздний неочищенный корневой слот.
Во время репликации нам также необходимо реплицировать информацию об учетных записях, которые были очищены из-за нулевых лампортов, т. е. мы должны иметь возможность определить разницу между учетной записью в данном слоте, которая не была обновлена и, следовательно, не имеет записи в хранилище в этом слот, и тот, который содержит 0 лэмпортов и был очищен в истории. Мы можем записать это через какой-нибудь механизм "Tombstone" - запись удаленных мертвых учетных записей для слота. Сами надгробия могут быть удалены по истечении срока хранения, выраженного в эпохах. Любая попытка реплицировать слоты с удаленными надгробиями потерпит неудачу, и реплика должна пропустить этот слот и попробовать более поздние.
JsonRpcAccountsService
: это служба RPC, обслуживающая клиентские запросы на информацию об учетной записи. Существующий JsonRpcService обслуживает другие клиентские вызовы, кроме AccountsDb.
Узел реплики обслуживает только вызовы AccountsDb.
Существующему JsonRpcService требуются BankForks, OptimisticallyConfirmedBank и BlockCommitmentCache для загрузки банка. Службе JsonRpcAccountsService потребуется использовать информацию, полученную из ReplicaSlotConfirmationResponse, для создания AccountsDb.
AccountsBackgroundService
: эта служба также работает в реплике, которая отвечает за периодическое создание моментальных снимков, сжатие AccountsDb и очистку учетных записей.
Существующий код также использует BankForks, которые нам нужно сохранить в реплике.
Вопросы совместимости
Из соображений совместимости протокола все запросы имеют версию репликации, которая изначально установлена на 1. В качестве альтернативы мы можем использовать версию валидатора. Сторона сервера RPC должна проверить версию запроса и завершиться ошибкой, если она не поддерживается.
Настройка репликации
Чтобы ограничить неблагоприятное воздействие на валидатор и реплику из-за репликации, их можно настроить со списком узлов реплики, которые могут образовывать с ним пару репликации. И узел реплики настроен с валидатором, который может обслуживать его запросы.
Отказоустойчивость
Основная ответственность за обеспечение устойчивости репликации к ошибкам лежит на реплике. В случае неудачных запросов реплика должна повторить запросы.
Интерфейс
Ниже приведены клиентские API-интерфейсы RPC, поддерживаемые узлом реплики в JsonRpcAccountsService.
- getAccountInfo
- getBlockCommitment
- getMultipleAccounts
- getProgramAccounts
- getMinimumBalanceForRentExemption
- getInflationGovenor
- getInflationRate
- getEpochSchedule
- getRecentBlockhash
- getFees
- getFeeCalculatorForBlockhash
- getFeeRateGovernor
- getLargestAccounts
- getSupply
- getStakeActivation
- getTokenAccountBalance
- getTokenSupply
- getTokenLargestAccounts
- getTokenAccountsByOwner
- getTokenAccountsByDelegate
Следующие API не включены:
- getInflationReward
- getClusterNodes
- getRecentPerformanceSamples
- getGenesisHash
- getSignatueStatuses
- getMaxRetransmitSlot
- getMaxShredInsertSlot
- sendTransaction
- simulateTransaction
- getSlotLeader
- getSlotLeaders
- minimumLedgerSlot
- getBlock
- getBlockTime
- getBlocks
- getBlocksWithLimit
- getTransaction
- getSignaturesForAddress
- getFirstAvailableBlock
- getBlockProduction
Пункты действий
- Создайте структуру реплики и исполняемый файл
- Интегрируйте код восстановления моментального снимка для начальной загрузки AccountsDb.
- Разработайте код интерфейса ReplicaSlotConfirmationRequestor и ReplicaSlotConfirmationServer.
- Разработайте подробные реализации ReplicaSlotConfirmationRequestor и ReplicaSlotConfirmationServer: управление жизненным циклом ReplEligibleSlotSet: добавление к нему новых корней и удаление корней. И интерфейсы, управляющие интерфейсом ReplWorkingSlotSet: добавление и удаление. Разработать компонент, синтезирующий информацию из BankForks, BlockCommitmentCache и OptimistcallyConfirmedBank на стороне сервера и поддерживающий информацию на стороне клиента.
- Разработайте код интерфейса для ReplicaAccountsRequestor и ReplicaAccountsServer.
- Разработайте подробную реализацию для ReplicaAccountsRequestor и ReplicaAccountsServer и разработайте сериализатор и десериализатор хранилища учетных записей репликации.
- Разработать код интерфейса JsonRpcAccountsService
- Подробная реализация JsonRpcAccountsService, код рефакторинга для совместного использования с частью JsonRpcService.
- Интеграция с AccountsBackgroundService в реплике для сжатия, очистки и моментальных снимков.
- Метрики и тестирование производительности