Надежность среды выполнения Rust/Wasm требует обработки как паники, так и аварийного восстановления.
Как только общий экземпляр Wasm начнет принимать вызовы в течение длительного времени, сбой перерастет из единичного сбоя в проблему восстановления состояния и изоляции ошибок.
Поначалу Wasm можно легко рассматривать как уровень портирования: код можно запрограммировать, страницу можно запустить, производительность в порядке, и все, кажется, примерно то же самое. Действительно начинаются сложности, обычно после прохождения демо-версии. Как только такие модули, как редакторы, средства визуализации и анализаторы документов, перейдут от одностраничных экспериментов к долгосрочным резидентным средам выполнения, модели ошибок немедленно изменятся.
В настоящее время паника и прерывание больше не являются ветвями исключений на языковом уровне. Они решают следующее: может ли этот экземпляр продолжать получать последующую работу, загрязнено ли состояние в памяти, должен ли хост-уровень немедленно отбросить экземпляр и нужно ли заполнить пул экземпляров. Когда мобильная команда перемещает ядро, которое долгое время работало в собственных контейнерах, в Интернет, именно этот уровень изменений легче всего недооценить.
После прохождения демо-версии только начинается моделирование неисправности.
Сбои при одном вызове понять несложно. Нажатие кнопки запускает вызов Wasm. В случае неудачи для операции будет сообщено об ошибке. Обновите страницу и повторите попытку. Стоимость по-прежнему контролируема.
Проблема возникает после того, как среда выполнения начинает повторно использовать экземпляры. Когда один и тот же экземпляр Wasm непрерывно открывает несколько документов, получает несколько раундов входных событий и проходит через несколько вызовов моста JS, влияние паники и прерывания больше не ограничивается текущим действием. Неполный сбой может затянуть последующие запросы.
Такие риски зачастую не проявляются в первый день. На первом этапе вы обычно видите только разрозненные отчеты об ошибках: случайные сбои при рендеринге, определенный экспорт зависает, а определенный документ находится в неправильном состоянии после закрытия и повторного открытия. Если вы проверите дальше, подсказки постепенно сойдутся в одном и том же явлении: хотя сбой произошел в цепочке вызовов, ущерб остался в общем экземпляре.
На этом этапе в центре внимания обсуждения больше не вопрос «Вызовет ли код Rust панику», а «Готова ли эта среда выполнения продолжать обслуживать следующий вызов после паники».
Панику можно поймать, прерывание может только изменить экземпляры.
Самая важная вещь, которую следует разделить в Rust/Wasm, — это две семантики сбоя: паника и прерывание.
У паники также есть возможность вернуться к установленным границам. Пока уровень привязки и уровень хоста заранее согласовывают метод восстановления, текущий вызов может завершиться неудачей, и другие состояния экземпляра также могут быть сохранены. прерывание - это вообще не выход. Это означает, что текущее выполнение достигло невосстановимого состояния. Если вы продолжаете использовать один и тот же экземпляр для получения запросов, вы, по сути, делаете ставку на то, что память и ресурсы не будут повреждены на полпути.
Если они смешаны во время выполнения, при последующей обработке обязательно возникнут проблемы:
— Проглотите прерывание как обычное исключение, и пул экземпляров продолжит повторно использовать объекты, которые потеряли доверие.
- Относитесь ко всем паникам так, как будто экземпляр должен быть уничтожен, и пропускная способность будет излишне снижена.
- Хост JS знает только «вызов не выполнен», но не знает, следует ли повторить попытку, потерять экземпляр или прервать текущий сеанс.
Это также наиболее реалистичный аспект надежности среды выполнения Wasm: сначала необходимо определить семантику восстановления, прежде чем можно будет реализовать последующую изоляцию и планирование.
Если уровень привязки не обеспечивает семантику восстановления, уровень хоста примет плохое состояние и продолжит принимать работу.
Самое опасное место для такого рода проблем находится не в бизнес-коде, а на уровне привязки, о котором, кажется, «уже позаботились». Уровень хоста часто видит только объект выданной ошибки и записывает его как обычный сбой вызова. Журнал существует, и страница не аварийно завершает работу сразу, но система, возможно, оставила плохое состояние внутри экземпляра.
Что действительно необходимо исправить, так это не просто try/catch, а действия по обработке после сбоя. Логика, подобная следующей, только начала использоваться в проектировании надежности:
async function runWithRecovery(instance, input) {
try {
return await instance.exports.handle(input)
} catch (error) {
if (isAbort(error)) {
pool.replace(instance.id)
}
throw error
}
}
В центре внимания этого кода не синтаксис, а простое суждение: пометил ли текущий сбой этот экземпляр как ненадежный объект. Если ответ положительный, действие по восстановлению не должно останавливаться на выдаче ошибок, а должно продолжаться вплоть до устранения экземпляра, реконструкции ресурсов и сокращения потока запросов.
Пока этот уровень не определен четко, будет казаться, что система обрабатывает ошибки, но на самом деле она возвращает потенциально поврежденную среду выполнения обратно в производственный путь.
Общие экземпляры превратят проблему восстановления в проблему стратегии объединения
После внедрения Wasm в реальные продукты редко остается только «один экземпляр, пока страница не закроется». Более распространенными являются пулы экземпляров, рабочие пулы или документы приоритетного плана и фоновые задачи, совместно использующие набор ресурсов времени выполнения. На этом этапе затраты на восстановление, вызванные паникой и прерыванием, напрямую перепишут стратегию объединения.
Если инициализация экземпляра является дорогостоящей, система, естественно, будет стремиться использовать ее как можно чаще. Но как только повторное использование будет установлено, необходимо одновременно улучшить изоляцию неисправностей:
- Какие состояния можно повесить только за один вызов, и будут сброшены вместе с вызовом после сбоя
- Какие кеши разрешено сохранять между вызовами, а какие кеши должны быть полностью аннулированы при возникновении прерывания. — После замены экземпляра как будут переноситься задачи в очереди? Будет ли повторная попытка вызвать побочные эффекты дважды?
Это не ответы, которые языковой уровень отправит автоматически. Это проекты времени выполнения.
По этой причине, если обсуждение надежности Rust/Wasm ограничивается вопросом «можно ли подхватить панику?», проблему легко недооценить. Что действительно увеличивает разрыв в стоимости обслуживания, так это то, сможет ли пул экземпляров поддерживать четкую границу доверия после сбоя.
Применимые границы тесно связаны с жизненным циклом
Этот набор проектов реставрации требуется не для каждого проекта Wasm.
Если модуль представляет собой просто одноразовый автономный инструмент или весь экземпляр перезапускается при уничтожении страницы, то разница между паникой и прерыванием все равно будет существовать, но польза от восстановления будет намного меньше. Часто бывает достаточно напрямую обновить страницу и повторно запустить задачу.
Как только система приобретет следующие характеристики, семантика восстановления быстро изменится с «элемента оптимизации» на «элемент инфраструктуры»:
- Экземпляр находится в течение длительного времени и не уничтожается за один жизненный цикл страницы.
- Один и тот же экземпляр постоянно выполняет несколько раундов вызовов.
- Уровень хостинга должен использовать пул в обмен на время запуска и пропускную способность.
- Защита состояния сеанса, состояния кэша и задач в очереди после сбоя.
Когда мобильные команды переносят собственные возможности в Интернет, эта граница встречается чаще всего. Отношения изоляции, которые изначально были установлены по умолчанию в процессе приложения, часто приходилось заполнять заново после достижения границы хоста JS/Wasm.
Wasm упрощает ввод собственного кода в браузер, но не обеспечивает семантику восстановления во время выполнения. Как только система начинает совместно использовать экземпляры, повторно использовать состояние и принимать долгосрочные вызовы, паника и прерывание должны рассматриваться как два разных события во время выполнения. Первый заботится о том, как завершить текущий вызов, а второй — о том, сможет ли этот экземпляр продолжать жить в пуле. Если это решение не будет принято первым, то чем успешнее будет трансплантация кода, тем труднее будет справиться с последующими неудачами.
What to read next
Want more posts about iOS?
Posts in the same category are usually the best next step for reading more on this topic.
View same categoryWant to keep following #iOS?
Tags are useful for related tools, specific problems, and similar troubleshooting notes.
View same tagWant to explore another direction?
If you are not sure what to read next, return to the homepage and start from categories, topics, or latest updates.
Back home