Сравнение индексаторов: Zaino и Ztreamer
Zaino и Ztreamer — два индексатора, поддерживающие протокол lightwallet gRPC — API, который лёгкие кошельки Zcash используют для синхронизации. На этой странице приведено независимое воспроизводимое сравнение: возвращают ли они одинаковые ответы, сколько времени занимает построение их индекса и насколько быстро они обслуживают кошельки.
Кратко
- Оба индексатора возвращают корректные данные цепочки. Каждый ответ, который можно было сверить с Zebra, совпал, поэтому кошельки могут использовать любой из них.
- Выявленные различия относятся к соглашениям и граничным случаям: коды ошибок, порядок байтов одного хеша, способ подсчёта дублирующегося адреса и несколько форм JSON-RPC-ответов.
- Ztreamer строит свой индекс примерно в 6 раз быстрее на том же CPU. Zaino начинает отвечать через 6 секунд, перенаправляя запросы в Zebra во время построения.
- Ztreamer обслуживает быстрее во всех измеренных сценариях: в 13–17 раз больше блоков в секунду при полной загрузке кошелька.
- Значительная часть задержки Zaino вызвана одной отсутствующей настройкой сокета (
TCP_NODELAY), которая добавляет примерно 40 мс ко многим запросам. Это исправляется одной строкой.
Что сравнивалось
| Сборка | Базовый узел | Почему |
|---|
| Zaino 0.10.1 | Zebra 6.4.2 (бэкенд direct) | Последний стабильный релиз Zaino |
| Zaino 0.9.0 | Zebra 6.4.2 (бэкенд direct) | Версия, измеренная в собственном опубликованном сравнении Ztreamer |
| Ztreamer v0.1.0 | Встроенный узел Zakura | Последний тег Ztreamer |
| Ztreamer master | Встроенный Zakura 1.5.1 | То, что собирают инструкции по установке Ztreamer |
Эти два решения используют разные архитектуры:
- Zaino работает как отдельный процесс рядом с полным узлом Zebra, читает состояние Zebra и поддерживает собственный индекс. Это индексатор в стеке Z3. См. Zaino.
- Ztreamer встраивает узел Zakura (форк Zebra) в тот же процесс и поддерживает индекс компактных блоков.
Как проводились измерения
- Одинаковые данные для всех. Каждая сборка начиналась с одного и того же снимка testnet Zcash Foundation, зафиксированного на высоте 4 382 897, поэтому все они индексировали в точности одну и ту же цепочку.
- Любой может это повторить. Всё запускается на бесплатных раннерах, размещённых GitHub: сделайте форк репозитория и запустите один workflow.
- Три запуска для каждой сборки, каждый с пустого индекса. Сервер и генератор нагрузки работали на отдельных ядрах CPU.
- Совместимость: все 20 gRPC-методов протокола lightwallet (274 тестовых случая) сравнивались побайтно между сборками и проверялись по JSON-RPC Zebra. Также были проверены 28 методов JSON-RPC, обслуживаемых Zaino.
- Производительность: время и ресурсы для построения индекса, задержка каждого запроса, пропускная способность диапазонов блоков, от 1 до 128 одновременных клиентов и полная загрузка кошелька от активации Sapling до вершины цепочки.
Результаты
Построение индекса
Медианы трёх запусков:
| Сборка | Индекс готов | Первый ответ | Размер индекса на диске |
|---|
| Zaino 0.10.1 | 1 395 с | 6 с | 22,06 GiB |
| Zaino 0.9.0 | 1 211 с | 6 с | 22,06 GiB |
| Ztreamer v0.1.0 | 216 с | 210 с | 1,44 GiB |
| Ztreamer master | 159 с | 158 с | 1,44 GiB |
Zaino становится пригодным к использованию почти сразу, поскольку перенаправляет запросы в Zebra во время построения. Ztreamer не обслуживает ничего, пока его индекс не будет готов. На той же модели CPU Zaino 0.10.1 работал в 6–6,5 раза дольше, чем Ztreamer v0.1.0, и использовал в 7,5–8 раз больше процессорного времени (включая Zebra).
Обслуживание
Медианы трёх запусков, в блоках в секунду, если не указано иное:
| Сценарий | Zaino 0.10.1 | Ztreamer v0.1.0 |
|---|
| Диапазон из 1 000 блоков | 11 414 | 179 486 |
| Полная загрузка кошелька (280 000 → вершина) | 11 124 | 189 041 |
| Диапазон из 1 000 блоков, 128 клиентов | 110 093 | 229 527 |
| Один блок, 128 клиентов (запросов/с) | 6 843 | 11 044 |
При 128 клиентах разрыв сокращается примерно до 2 раз, поскольку оба сервера были ограничены двумя ядрами CPU.
Минимум в 40 мс
На Zaino шесть из двенадцати RPC имеют медианную задержку около 40 мс, а каждый RPC имеет 99-й перцентиль около 41 мс. Причина заключается в том, как Zaino настраивает свой gRPC-слушатель: параметр сокета TCP_NODELAY никогда не включается, поэтому операционная система задерживает небольшие ответы на срок до 40 мс.
Включение параметра извне, без изменения бинарного файла Zaino, устранило этот минимум. Например, GetTreeState снизился с 40,3 мс до 0,75 мс (Ztreamer: 0,63 мс). Потоковая передача больших объёмов блоков не изменилась, поэтому приведённый выше разрыв в пропускной способности реален.
Различия совместимости
- Zaino 0.9.0 по умолчанию включает прозрачные данные в
GetBlock, хотя протокол указывает, что по умолчанию должны включаться только защищённые данные. Это исправлено в версии 0.10.1.
GetSubtreeRoots: поле completingBlockHash использует противоположный порядок байтов в двух индексаторах. Текущие кошельки не считывают это поле.
- Коды ошибок: Zaino возвращает
INTERNAL для некорректного ввода; Ztreamer возвращает INVALID_ARGUMENT или NOT_FOUND.
- Дублирующиеся адреса в
GetTaddressBalanceStream учитываются дважды, за исключением Ztreamer master.
- JSON-RPC: Zaino в режиме
getrawtransaction с подробностью 0 возвращает объект вместо шестнадцатеричной строки, в отличие от Zebra и zcashd.
Ограничения
- Только testnet. Блоки testnet меньше, чем в mainnet, поэтому абсолютные значения времени и размера не являются показателями mainnet. Сравнение относительное, на идентичных входных данных.
- Общие CI-машины с несколькими моделями CPU. В полном отчёте для основных показателей приведены сравнения на одинаковых CPU.
- Не измерялось: реорганизации, следование за вершиной живой цепочки, нагрузка mempool и TLS.
Где узнать больше