Я последнее время активно юзаю Obsidian для конспектирования любой полезной инфы, и доклад выше не стал исключением. Чтобы эти заметки пылились не только у меня в базе знаний, ниже - конспект интересных моментов и тезисов.
Очевидно, что отладка параллельного кода сильно сложнее, чем отладка последовательного кода, выполняющегося в одном потоке. Самая большая при такой отладке - он часто имеет не повторяющееся поведение при одинаковых входных данных и параметрах железа, где он запускается.
Пакет https://github.com/xiegeo/coloredgoroutine подсвечивает вывод каждой горутины отдельным цветом, что может быть полезно при отладке.
Использование флага GODEBUG=schedtrace позволит вывести отладочную информацию про то, как планировщик управляет горутинами:
➜ GODEBUG=schedtrace=5000 ./main
SCHED 0ms: gomaxprocs=10 idleprocs=8 threads=3 spinningthreads=1 needspinning=0 idlethreads=0 runqueue=1 [0 0 0 0 0 0 0 0 0 0]
Еще один полезный лайфхак для отладки горутин - это добавление в них меток. Например, запускаем код, где поднимаются несколько воркеров:
func main() {
go func() {
// some work...
}()
go func() {
// some work...
}()
go func() {
// some work...
}()
В любом отладчике горутина будет помечена номером, обозначающим порядковый номер, под которым эта горутина запустилась. Но чтобы понять, какой именно воркер соответствует какому именно номеру, можно добавить теги:
func main() {
go func() {
labels := pprof.Labels("fetcher", "main_goroutine")
pprof.Do(ctx, labels, func(ctx context.Context) {
// some work
})
}()
go func() {
labels := pprof.Labels("worker_1", "main_goroutine")
pprof.Do(ctx, labels, func(ctx context.Context) {
// some work
})
}()
go func() {
labels := pprof.Labels("worker_2", "main_goroutine")
pprof.Do(ctx, labels, func(ctx context.Context) {
// some work
})
}()
// ...
}
И затем, в отладчике можно вывести горутину по конкретному тегу:
(dlv) goroutines -l -with label fetcher
Goroutine 21 - User: ./main.go:20 main.main.func1.1 (0x1003befcc) [chan send]
Labels: "fetcher":"main_goroutine"
[1 goroutines]
Хорошая статья, где описывается как это сделать более подробно и где автор показывает ряд других решений для добавления меток в горутины: https://blog.jetbrains.com/go/2020/03/03/how-to-find-goroutines-during-debugging/#using-a-custom-library-to-enable-debugging-labeling
Вторая часть доклада - про deadlock'и и про то, как с ними бороться.
Из полезного, либа, которая помогает найти дедлоки - https://github.com/sasha-s/go-deadlock
К примеру, автор этой библиотеки с помощью нее же нашел потенциальные дедлоки в коде cockroach db: https://github.com/cockroachdb/cockroach/issues/7972