?

Log in

No account? Create an account
об одном баге, программистское - Поклонник деепричастий [entries|archive|friends|userinfo]
Anatoly Vorobey

[ website | Website ]
[ userinfo | livejournal userinfo ]
[ archive | journal archive ]

Links
[Links:| English-language weblog ]

об одном баге, программистское [окт. 19, 2007|06:18 pm]
Anatoly Vorobey
Последние несколько дней я упорно занимался поиском одного конкретного бага, и нашел его в результате. Проблема, которую я хотел решить, заключалась в том, что определенный процесс обработки данных, работающий с гигантским количеством исходных данных, выдающий на выходе другое гигантское количество результатов, и делающий все это одновременно на огромном количестве серверов - этот процесс оказался несколько недетерминистским. Это значит, что если его запустить два раза на абсолютно идентичных входных данных, на выходе получится почти то же самое, но с отдельными весьма редкими отличиями. Причем эти отличия появлялись в разных местах после разных запусков, и вообще вели себя довольно случайным образом.

Как в таком разбираться? В том, что процесс выдает наружу, невозможно почти ничего увидеть, кроме того, что есть разница между двумя запусками - чтобы понять, почему, надо понять, где эта разница возникает во время обработки данных в коде (которого, кстати, много, весь написан не мной, и если основные модули верхнего уровня я хорошо понимаю, есть также и библиотеки, о которых я почти ничего не знаю). Почти невозможно выводить какую-то полезную информацию в логи во время работы процесса, потому что для того, чтобы быть полезной для подробного анализа, ей нужно быть такой огромной по размерам, что с ней не справиться никак. Ведь во время обработки конкретных данных неизвестно, что именно на них в конце концов будет расхождение с другим запуском - это во многой степени случайно - так что пришлось бы писать что-то обо всех, а это нереально. Далее, запустить тот же процесс на гораздо меньшей части исходных данных тоже не получается - если ее как следует уменьшить, чтобы легко было анализировать происходящее, то эффект исчезает.

Я поступил так. Во-первых, все же уменьшил размер исходных данных настолько, чтобы эффект все еще всегда происходил и было довольно много примеров его, но, с другой стороны, один запуск всего процесса начал занимать не X времени, а Y времени, где Y намного меньше X. Во-вторых, вставил код, которых в определенные моменты работы процесса берет релевантные внутренние структуры, сериализует их в массив байтов, вычисляет его хэш, и уже только одно это хэш-значение пишет в некие лог-файлы, которые я потом могу проанализировать (эти файлы тоже оказываются огромными, но уже не гигантскими). Это позволило мне сделать два запуска и после этого убедиться, что в такой-то момент работы в них все еще было идентично... здесь тоже... а вот тут уже расхождение; ага, что у нас происходит между "здесь" и "тут"?

После нескольких сеансов такого сужения определился в общих чертах источник бага, и после этого уже просто внимательное изучение чужого для меня кода помогло найти конкретную проблему. Которая заключалась, кстати, в следующем. Определенная структура данных при создании не обнуляла все свои многочисленные поля, кроме одного: поля-сторожа, гарантирующего разумность всех остальных полей, и по умолчанию равного false. Только когда все остальное заполняется разумными данными, а не мусором, в него ставят true. Теперь представьте себе сочетание двух багов: одного, который в определенных редких обстоятельствах не обрабатывал эту структуру вообще, хотя должен был; и другого, который при обращении к структуре на предмет вытащить из нее полезные данные не проверял значение поля-сторожа... вот тебе, бабушка, и недетерминизм.

Что мне не нравится во всем этом - это то, что такие занятия - нахождение сложных багов в слабознакомом мне коде - мне слишком нравится (ну, если код не безобразный, конечно). Я получаю наслаждение от самого процесса быстрого вникания в незнакомый мне код, перемалывания его концепций и допущений у себя в голове, методично-шерлокхолмсовского вычленения того места, где есть проблема, и отбрасывания тех мест, где нет, погони за багом прыжками по болотным кочкам, с отладчиком наперевес (не в этом случае, но вообще говоря). Это дуэль - даже не с самим багом, который в итоге всегда незначителен, а с хитро спрятавшей его суть окружающей реальностью, дуэль с целью заставить ее объяснить, в чем дело. Мне слишком нравится побеждать в этой дуэли - и этот факт мне не нравится; лучше бы я с большим рвением стремился писать нужное новое свое, чем методично анализировать уже существующее. Конечно, преувеличивать проблему тоже не надо - я очень люблю и свое писать, и пишу; да и баг, который я таким образом нашел, вполне мог бы иначе натворить много чего нехорошего. Это вопрос баланса; но существующий баланс меня не очень устраивает, и я намереваюсь его несколько сдвинуть.
СсылкаОтветить

Comments:
Страница 1 из 3
<<[1] [2] [3] >>
[User Picture]From: rasteehead
2007-10-19 05:21 pm
House M.D. не смотрели? :)
(Ответить) (Thread)
[User Picture]From: avva
2007-10-19 05:24 pm
Не только смотрел, еще и люблю и как раз недавно 3-й сезон досмотрел, пару дней назад :)
(Ответить) (Parent) (Thread) (Развернуть)
[User Picture]From: _foreseer
2007-10-19 05:22 pm
А в style guide у вас не рекомендуют все поля инициализировать, получается?
(Ответить) (Thread)
[User Picture]From: avva
2007-10-19 05:26 pm
У нас очень хороший style guide, который мне не хотелось бы обсуждать подробно, если Вы не против ;) Не стоит пытаться обобщать на основании одного случая, который я к тому же специально описал довольно туманно, и скрыл/исказил всякие идентифицирующие подробности.
(Ответить) (Parent) (Thread) (Развернуть)
[User Picture]From: deadkittten
2007-10-19 05:26 pm
Я в таких случаях всё же предпочитаю гигантские логи, которые потом можно переработать awk-ом...
(Ответить) (Thread)
[User Picture]From: avva
2007-10-19 05:27 pm
Понимаете, есть гигантские, а есть гигантские.
(Ответить) (Parent) (Thread)
[User Picture]From: taganay
2007-10-19 05:35 pm
С хешем идея очень понравилась, возьму на вооружение.
(Ответить) (Thread)
[User Picture]From: scolar
2007-10-19 05:48 pm
Если бы не любовь именно к этому занятию, Вы были бы либо хорошим учёным, либо плохим программистом.
(Ответить) (Thread)
From: saccovanzetti
2007-10-19 06:12 pm
вы забыли про хороших инженеров.
(Ответить) (Parent) (Thread)
[User Picture]From: _glav_
2007-10-19 05:51 pm
>После нескольких сеансов такого сужения
Вы несколько раз применяли хэш-функцию к результатам работы хэш функции? экспоненциально уменьшая количество выводимых данных? или к нескольким разным участкам кода применяли её по одному разу за весь тест?
(Ответить) (Thread)
[User Picture]From: avva
2007-10-19 06:04 pm
Я использовал наиболее простой и быстрый способ получить ответ на следующий вопрос: "вот место в коде, которое я хочу зафиксировать, и через которое проходят все исходные данные. Как мне получить инвариант всей важной внутренней информации, которой код оперирует на данный момент?"

Предположим, обрабатывая очередную порцию исходных данных, код сделал с ней много всяких операций, и записывает сейчас промежуточные результаты во внутреннюю хэш-таблицу, у которой ключи - строки, а значения - что-то еще. Тогда я допишу к этому несколько строк кода, которые вытащат все внутреннее состояние из этой хэш-таблицы в вектор, отсортируют его по порядку ключей, в цикле добавят все ключи в один большой буфер (и значения тоже, если их легко сериализовать), вычислят хэш этого буфера и отошлют в лог-файл, вместе с хэшем этой порции исходных данных. То же самое я сделаю еще в нескольких ключевых местах, когда код создает другие важные промежуточные структуры. Обычно таким образом я применял хэш-функцию к массиву байтов, в который я сериализовал какую-то внутреннюю структуру, но иногда получалось так, что я из нескольких таких хэшей составлял еще одну строку и брал еще один хэш - подробности не столь важны, важно, чтобы это был инвариант внутреннего состояния, отражающий точный смысл данных, а не случайности их расположения в памяти (поэтому, например, нужен шаг "отсортируют его по порядку ключей" выше).
(Ответить) (Parent) (Thread) (Развернуть)
From: 9000
2007-10-19 06:11 pm

Про хэши ловко!

Что может быть лучше работы, которая в кайф? :)
(Ответить) (Thread)
From: saccovanzetti
2007-10-19 06:14 pm
муки творчества, если получится что-нибудь путное.
(Ответить) (Parent) (Thread) (Развернуть)
[User Picture]From: igorlord
2007-10-19 06:12 pm
Да, детерминистическая серия хэшей состояния системы -- это мно тоще первым пришло в голову. Но, в общем, Вам крупно повезло что система скорее всего была последовательная.

Мне иногда приходилось искать таких жучков в параллельных системах. Там такая штука как "а теперь мы сделаем хэш на всех структурах в памяти" не только "технически сложный процесс" но и очень вероятно может "починить" программку (что обидно). :)
(Ответить) (Thread)
[User Picture]From: salas
2007-10-19 06:58 pm
А если от промежуточной синхронизации оно "починится", то, может быть, можно так с этой синхронизацией и оставить? Понятно, что производительность теряется, но на практике часто ли настолько, чтоб баг не становился менее критичным?

P.S. Я параллельных систем не делал, кроме игрушечных, мне просто любопытно.
(Ответить) (Parent) (Thread) (Развернуть)
[User Picture]From: sleeping_death
2007-10-19 06:46 pm
познавательно, спасибо :)
(Ответить) (Thread)
[User Picture]From: dzz
2007-10-19 07:05 pm
Думаю, с балансом всё нормально, просто сыграл роль элемент новизны - своё, хоть и родное, но до некоторой степени - рутина, чужое - незнакомое и интригующее, особенно, при столь нетривиальном баге ;)

Если посадить тебя в качестве тестера-дебаггера, через пару месяцев отлова блох баланс опять "сместится".
(Ответить) (Thread)
[User Picture]From: loislo
2007-10-19 07:11 pm
Мне тоже доставляет изрядное удовольствие раскопать какую-нибудь багу. Эксплорер по натуре. Мне это тоже не всегда нравится но причину этого я вижу с том что результат получается бысто. Т.е. сделать новый продукт стоит допустим 3 месяца, а заловить сложную багу когда все опустили руки стоит в среднем неделю. Сатисфакция выше. Для борьбы с этим я стараюсь резать новые куски на короткие работающие фрагменты чтобы получать такое ощущение от каждого этапа разработки. Пытаюсь таким образом регулярно менять контекст.

Тема с хешами классная. Но подходящих задач нет. :)
(Ответить) (Thread)
[User Picture]From: alta_voce
2007-10-19 07:41 pm
У меня был вопрос, но ты уже ответил.
(Ответить) (Thread)
[User Picture]From: nice_beaver
2007-10-19 08:47 pm
Я хотел оставить комментарий, но вы мениа опередили
(Ответить) (Parent) (Thread)
[User Picture]From: slobin
2007-10-19 11:25 pm
А где проблема? По-моему, творцов нового (причём хороших творцов, без иронии) и так избыток, а вот людей, умеющих эффективно искать баги в таких вот чужих больших системах -- кот наплакал. А если это занятие ещё и нравится...

... То крылом волны касаясь (по техническим причинам) ...

(Ответить) (Thread)
[User Picture]From: juan_gandhi
2007-10-20 12:01 am
protobuffers нуждаются в радикальном лечении. Это всё такие 90-е...
(Ответить) (Thread)
[User Picture]From: azzo27
2007-10-20 12:48 am
>Что мне не нравится во всем этом - это то, что такие занятия - нахождение сложных багов в слабознакомом мне коде - мне слишком нравится

Совместить приятное с полезным - написать программу, которая будет делать все это автоматически. Конечно, это намного труднее ...
(Ответить) (Thread)
Страница 1 из 3
<<[1] [2] [3] >>