Второй день недели, а я просто в каком-то безумии нахожусь.
Предыстория: мы в MapReduce обрабатываем просто тучу данных и понятное дело, что не обходится без странных машин каждый день. Чтобы от этого хоть как-то спастись, в shuffle сессии мы пишем чексуммы при записи из Map, а при чтении из Reduce мы их читаем и сравниваем. Если какие-то чексуммы не совпадают, ну что поделать, машина была побитая, удалим машину и перезапустим шард для исполнения снова. Такие падения исчисляются единицами в день, но в целом забавно смотреть как им мозги отказывают.
Конечно же команда по Silent Data Corruption настроила мониторинг на это дело. И тут вот после нескольких месяцев тестирования решили выкатить новые процессоры :). Угадайте какая метрика равномерно для всех пользователей повысилась. Падения всё ещё редки, но достаточно повысились, чтобы бить тревогу.
Слышал байку, что мы тут в Google дизайним системы, чтобы они были устойчивы к багам в CPU. Конечно же, это неправда. В общем, даже процессоры не работают в этом мире, ничего, блин, не работает в этом мире. Уже два дня пытаюсь понять в чём дело, а ещё убедить себя, что компьютеры всё же были ошибкой.
Своими глазами я повидал:
1. Данные на диске были записаны правильно, кроме одной 4кб страницы -- были записаны нулями. Root cause: скорее всего при использовании DIRECT_IO кто-то решил почитать данные из того же файла до close(), воспроизводилось раз на 4 тысячи машин
2. Команда побайтового сравнения вернула, что какие-то байты разные, по факту записаны были одни и те же байты. Root cause: непонятен, но спустя 2 недели у машины совсем отказали мозги, и она умерла
3. Битфлипы всех видов, в том числе детерминированные: машина работала корректно, но при сжатии посылаемых данных один бит был другим, чем на реплике. Root cause: не ясно
4. Cамокорректирующиеся AES -- decode(encode(x)) на машине давал x, а на другой decode от закодированной на первой выдавал ерунду. Root cause: одна инструкция ошибалась "правильно", процессор отправился на свалку
5. Падения инструкций, которые обещают не читать кое-какие данные, но всё же их читают. Root cause: баг в процессоре, был починен вендором
Мои коллеги из Google [1] также рассказывали о:
1. Битфлип, влияющий на сборку мусора в Java, где крутились холодные пользовательские данные. Результат: потеря данных из-за того, что система не обращалась к данным.
2. Повреждения таблицы страниц в ядре, в результате чего процесс и ядро были несогласованы и ломались в очень непредсказуемых местах
3. Два треда зашли в критическую секцию, нарушилась базовая гарантия Mutex, результат -- поломанные пользовательские данные
Что помогало, и что я привнёс(у):
1. Проверять чексуммы с битфлипами, если обнаружилось несовпадение, посвапать биты один за другим и пересчитать чексуммы. Честно украл идею, когда работал в поиске, много ловит и отсекает "простые" случаи
2. Как ни странно, алгоритмы сжатия типа LZ4, Snappy и даже ZSTD тоже хорошо находят битфлипы. В том плане, что если записана чексумма разжатых данных, и битфлип произошёл в сжатом формате, иногда битфлипы сохраняются и в разжатом виде. Особенно для не очень хорошо сжимаемых данных. Это очень нетривиальный факт, но я умею доказывать какие-то свойства про него.
3. Использовать алгоритмы сжатия, которые умеют в диагностику, в каком бите формат данных поломался. В это умеют LZ4 и ZSTD. Snappy и zlib не умеют.
4. Искать большую последовательность нулей, особенно большую степень двойки+-1. Тоже отсекает проценты понятных поломок.
5. Если данные важны в каждом бите, делайте кворумные джобы, запускайте 3 реплики и пока 2 не договорятся, никакого удаления/пересчёта денег не происходит.
Если 1-4 ничего не нашли, на это стоит смотреть глазами. 5 работает примерно всегда.
Возьму пару дней погулять. Ощущение, что ничего не работает после таких дебагов. Но зато они интересные, весь стек надо понимать.
[1] Cores that don't count. Lessons from silent data corruption at Google
[2] ClickHouse тоже писал про "Checksum does not match"
[3] Silent data corruptions at Facebook
Предыстория: мы в MapReduce обрабатываем просто тучу данных и понятное дело, что не обходится без странных машин каждый день. Чтобы от этого хоть как-то спастись, в shuffle сессии мы пишем чексуммы при записи из Map, а при чтении из Reduce мы их читаем и сравниваем. Если какие-то чексуммы не совпадают, ну что поделать, машина была побитая, удалим машину и перезапустим шард для исполнения снова. Такие падения исчисляются единицами в день, но в целом забавно смотреть как им мозги отказывают.
Конечно же команда по Silent Data Corruption настроила мониторинг на это дело. И тут вот после нескольких месяцев тестирования решили выкатить новые процессоры :). Угадайте какая метрика равномерно для всех пользователей повысилась. Падения всё ещё редки, но достаточно повысились, чтобы бить тревогу.
Слышал байку, что мы тут в Google дизайним системы, чтобы они были устойчивы к багам в CPU. Конечно же, это неправда. В общем, даже процессоры не работают в этом мире, ничего, блин, не работает в этом мире. Уже два дня пытаюсь понять в чём дело, а ещё убедить себя, что компьютеры всё же были ошибкой.
Своими глазами я повидал:
1. Данные на диске были записаны правильно, кроме одной 4кб страницы -- были записаны нулями. Root cause: скорее всего при использовании DIRECT_IO кто-то решил почитать данные из того же файла до close(), воспроизводилось раз на 4 тысячи машин
2. Команда побайтового сравнения вернула, что какие-то байты разные, по факту записаны были одни и те же байты. Root cause: непонятен, но спустя 2 недели у машины совсем отказали мозги, и она умерла
3. Битфлипы всех видов, в том числе детерминированные: машина работала корректно, но при сжатии посылаемых данных один бит был другим, чем на реплике. Root cause: не ясно
4. Cамокорректирующиеся AES -- decode(encode(x)) на машине давал x, а на другой decode от закодированной на первой выдавал ерунду. Root cause: одна инструкция ошибалась "правильно", процессор отправился на свалку
5. Падения инструкций, которые обещают не читать кое-какие данные, но всё же их читают. Root cause: баг в процессоре, был починен вендором
Мои коллеги из Google [1] также рассказывали о:
1. Битфлип, влияющий на сборку мусора в Java, где крутились холодные пользовательские данные. Результат: потеря данных из-за того, что система не обращалась к данным.
2. Повреждения таблицы страниц в ядре, в результате чего процесс и ядро были несогласованы и ломались в очень непредсказуемых местах
3. Два треда зашли в критическую секцию, нарушилась базовая гарантия Mutex, результат -- поломанные пользовательские данные
Что помогало, и что я привнёс(у):
1. Проверять чексуммы с битфлипами, если обнаружилось несовпадение, посвапать биты один за другим и пересчитать чексуммы. Честно украл идею, когда работал в поиске, много ловит и отсекает "простые" случаи
2. Как ни странно, алгоритмы сжатия типа LZ4, Snappy и даже ZSTD тоже хорошо находят битфлипы. В том плане, что если записана чексумма разжатых данных, и битфлип произошёл в сжатом формате, иногда битфлипы сохраняются и в разжатом виде. Особенно для не очень хорошо сжимаемых данных. Это очень нетривиальный факт, но я умею доказывать какие-то свойства про него.
3. Использовать алгоритмы сжатия, которые умеют в диагностику, в каком бите формат данных поломался. В это умеют LZ4 и ZSTD. Snappy и zlib не умеют.
4. Искать большую последовательность нулей, особенно большую степень двойки+-1. Тоже отсекает проценты понятных поломок.
5. Если данные важны в каждом бите, делайте кворумные джобы, запускайте 3 реплики и пока 2 не договорятся, никакого удаления/пересчёта денег не происходит.
Если 1-4 ничего не нашли, на это стоит смотреть глазами. 5 работает примерно всегда.
Возьму пару дней погулять. Ощущение, что ничего не работает после таких дебагов. Но зато они интересные, весь стек надо понимать.
[1] Cores that don't count. Lessons from silent data corruption at Google
[2] ClickHouse тоже писал про "Checksum does not match"
[3] Silent data corruptions at Facebook