Автор этой статьи: Защитите нашу сторону Ли Юаньфан
Для коммерческих перепечаток, пожалуйста, свяжитесь с автором для получения разрешения, а для некоммерческих перепечаток, пожалуйста, укажите источник.
феномен неисправности
Онлайн-машина отчетов о скрытых точках иногда вызывает тревогу о чрезмерном использовании памяти. ssh на вершину машины и обнаружил, что основная память занята скрытой службой. Я перезагружался несколько раз, но через некоторое время по-прежнему появляется сигнал об использовании памяти. Ниже приведены сведения о тревоге.
[P1][PROBLEM][ali-e-xxx-service03.bj][][ all(#3) mem.memfree.percent 4.19575<5][O3 >2019-10-28 10:20:00]
вывод проблемы
Служба скрытых точек в основном получает запрос отчета, сжатый клиентом, распаковывает данные запроса и доставляет их в kafka.Логическая функция относительно проста. Первоначальное подозрение состоит в том, что некоторые ресурсы не освобождаются, что приводит к утечкам памяти или утечкам подпрограмм.
Устранение неполадок
Поскольку код не поддерживается нашей деловой стороной, мы сначала запросили разрешение на код у соответствующего отдела. После прочтения исходного кода весь выпуск ресурсов управляется отсрочкой, и ни один очевидный ресурс не освобождается.
1. Измените конфигурацию онлайн-среды и откройте порт трассировки.
Перед отладкой и анализом проблемы студенты, знакомые с go, знают, что Golang предоставляет очень удобный инструмент диагностики производительности go tool trace; go tool trace — это убийца производительности в golang, который может выявить все события времени выполнения и использование памяти в операции Wait. Это один из самых полезных инструментов в экосистеме Go для диагностики проблем с производительностью, таких как задержка, распараллеливание и исключения гонки.
Поскольку все они используют базовую библиотеку компании, базовая библиотека специально инкапсулирует go trace. Просто измените файл конфигурации на онлайн-машине, отправьте информацию о трассировке на указанный порт в файле конфигурации, а затем используйте инструмент go для анализа.
Затем я использовал инструмент go tool локально и обнаружил, что сеть недоступна.Я проверил и обнаружил, что порт трассировки не привязан к 0.0.0.0 [собачья голова].
Затем используйте прокси-инструмент, чтобы изменить порт прокси-сервера 9900 на порт 9999, а затем используйте инструмент go, чтобы построить график нормального использования памяти. Как показано ниже
2020-01-18-18-11-23.jpg
2. Подождите, пока произойдет сбой
Ожидание — долгий процесс, он может занять дни или месяцы, если вам не повезет. Сохраните здесь десятки тысяч слов x#@#@$@!%?@^!. . .
3. То, что должно прийти, все еще здесь
Через несколько дней получил еще одно оповещение сервера, на этот раз немного раньше, чем предыдущие, из-за роста qps. Выполните верхнюю часть памяти сразу после получения предупреждения
go tool pprof -alloc_space http://{addr}/debug/pprof/heap
Showing top 20 nodes out of 55
flat flat% sum% cum cum%
2.76GB 59.76% 59.76% 2.76GB 59.76% compress/flate.NewReader
0.45GB 9.73% 69.49% 0.45GB 9.73% net/http.newBufioWriterSize
0.29GB 6.33% 75.82% 3.05GB 66.09% compress/gzip.(*Reader).Reset
0.25GB 5.35% 81.17% 0.25GB 5.35% net/http.newBufioReader
0.13GB 2.85% 84.01% 0.13GB 2.85% runtime.rawstringtmp
0.11GB 2.31% 86.32% 0.11GB 2.31% bytes.makeSlice
0.10GB 2.26% 88.58% 0.10GB 2.26% runtime.hashGrow
Каждая строка представляет информацию о функции. Первые два столбца представляют память, используемую функцией, и процентное соотношение; третий столбец — долю текущей памяти, используемой всеми функциями; четвертый и пятый столбцы — память и долю (также известную как кумулятивное значение), занимаемую функциями. функция и ее подфункции, кумулятивный), должен быть больше или равен значению первых двух столбцов, последний столбец — это имя функции. Если у приложения есть проблемы с производительностью, приведенная выше информация должна сказать нам, на выполнение каких функций тратится память, и анализ процессорного времени pprof аналогичен.
pprof может не только распечатать место, занимающее больше всего памяти (вверху), но также перечислить код функции и соответствующие данные выборки (список), код сборки и соответствующие данные выборки (disasm), а также может выводить в различных стилях, Например, svg, gv, callgrind, png, gif и т. д.
Видно, что большая часть памяти занята этими Ридерами.
4. Перечитайте код с вопросами
Ранее мы провели предварительный анализ занятости и обнаружили, что функция Fcuntion, занимающая много памяти, является плоской. форматы. Итак, мы берем проблему и снова находим соответствующую реализацию исходного кода Вот несколько ключевых определений:
var Gzip GzipPool
func GetReader(src io.Reader) (*gzip.Reader, error) {
return Gzip.GetReader(src)
}
func PutReader(reader *gzip.Reader) {
Gzip.PutReader(reader)
}
// GzipPool manages a pool of gzip.Writer.
// The pool uses sync.Pool internally.
type GzipPool struct {
readers sync.Pool
writers sync.Pool
}
Здесь sync.Pool используется для оптимизации GC. Чтобы убедиться, что вся память находится в пуле, мы использовали веб-инструмент, предоставляемый инструментом go, для проверки использования памяти в пуле. Конечно, большая часть использования находится в бассейне. Давно это было, в этот раз без фото. . .
5. Что такое sync.Pool?
Пакет синхронизации предоставляет базовые инструменты параллельного программирования golang. Согласно описанию официальной документации:
Pool's purpose is to cache allocated but unused items for later reuse, relieving pressure on the garbage collector. That is, it makes it easy to build efficient, thread-safe free lists. However, it is not suitable for all free lists.
Обычно мы используем golang для создания приложений в сценариях с высокой степенью параллелизма, но поскольку встроенный в golang механизм GC будет влиять на производительность приложения, чтобы уменьшить GC, golang предоставляет механизм повторного использования объектов, то есть синхронизацию. Пул объектов пула. sync.Pool является масштабируемым и безопасным параллелизмом. Его размер ограничен только размером памяти, и его можно рассматривать как контейнер для значений многократно используемых объектов. Целью проекта является хранение объектов, которые были выделены, но не используются временно, и напрямую берутся из пула, когда они необходимы. Видя это, я считаю, что у многих студентов, знакомых с ГК, уже есть в душе догадки: может быть, это связано с ГК.
Итак, каково время запуска GC в Golang?
Реализация GC для Golang GC 1.13 представляет собой проблему с трехцветным маркером, барьером записи и вспомогательным GC. Есть два основных триггерных условия:
- Превышен порог размера памяти
- время от времени
Порог управляется переменной gcpercent, которая срабатывает, когда соотношение вновь выделенной памяти к уже используемой памяти превышает gcpercent.
Например, после завершения перезапуска использование памяти составляет 5 МБ, тогда время следующего перезапуска наступает, когда выделение памяти достигает 10 МБ. То есть дело не в том, что чем больше памяти выделено, тем выше частота сборки мусора. Что делать, если пороговое значение размера памяти никогда не достигается? В это время GC будет запускаться по времени.Например, если он не достиг 10M, то GC будет запускаться в обычное время (по умолчанию запускается каждые 2 минуты), чтобы обеспечить восстановление ресурсов .
Поэтому, когда использование памяти медленно увеличивается, количество триггеров GC будет уменьшаться и приближаться к 2 мин. Без GC объекты в пуле не будут восстановлены, что приведет к постепенному увеличению использования памяти.
Активировать GC для проверки
Измените код, ограничьте rlimit и используйте горутину для активного вызова gc каждые 30 секунд, а затем после тестирования подключайтесь к сети. Затраты времени на онлайн-интерфейс существенно не изменились, система работает нормально, а тревога использования памяти больше никогда не срабатывала.
краткое изложение проблемы
В начале я не обращал особого внимания на периодически возникающие сигналы памяти. Было много случайностей, но объективно проблемы всегда существовали. Только своевременно обнаруживая проблемы и регулярно обобщая их, мы можем продолжать совершенствоваться и расти. Старайтесь избегать перезапуска, как только возникает проблема, чтобы не стать SRB (Service ReBoot Boy😁).
Справочная документация
[1] анализ памяти golang/динамическое отслеживание
[2] golang GC