Как бы вы себя чувствовали, если бы я сказал вам, что когда я брал здесь интервью, вопрос на собеседовании был таким? Предполагается, что обычные люди не войдут в яму. Однако я в деле. Потому что я думаю, что такого рода технические проблемы забавны. Это все. Иначе работа будет скучной.
предисловие
- На самом деле вам нет необходимости исправлять этот баг, потому что у многих отечественных компаний версия выходит каждую неделю, поэтому они вообще не в курсе о существовании этого бага.
- На самом деле вам не нужно исправлять эту ошибку, потому что вы пишете сценарий автоматического перезапуска по расписанию и тихо перезапускаете его глубокой ночью.
- На самом деле вам не надо решать этот баг, потому что Baidu тоже начал поддерживать сео системы спа, чего вы до сих пор так усердно работаете над тем, чтобы сделать там дрянной сср.
Если вам так же скучно, как и мне, то читайте дальше. Правильно или нет не знаю. Во всяком случае, в моем локальном тесте большинство проблем были нокаутом.
В связи со сменой работы
Во время интервью интервьюер задал такой вопрос: в их системе наблюдалось странное явление: система SSR на основе Vue испытывала медленный подъем ЦП и время от времени приходилось перезагружаться. Спросите меня, какое решение?
Эм? Процессор поднимается?Есть ли утечка памяти? Он возвращается при каждом запросе? Существуют ли блокировки операций ввода-вывода? Если это экспресс, все ли выполняет возврат? Медленный подъем, какой величины? Что такое QPS? Нагрузка на сервер нормальная?
Потом я успешно получил оффер, и второй задачей, которая была поставлена передо мной после присоединения, было решение этой технической проблемы. Когда вы видите это, вы думаете, что меня обманывают? Ха-ха-ха, но я просто люблю вызов. Это весело, иначе работа была бы скучной. Однако такое техническое расследование трудно дать результат в короткие сроки, да и для меня это очень опасно. И, гм. . . . . . Также есть возможность разгрузить мельницу и убить осла. Кто знает. В любом случае, это весело. какая разница.
Проблема действительно такая, как описано?
При решении технической проблемы мы часто получаем производительность, описанную человеком, столкнувшимся с проблемой, а производительность реальной проблемы не обязательно совпадает с тем, что сказал описатель.
Когда мы сталкиваемся с проблемами производительности, нам нужно полностью понять природу проблемы? Это просто процессор медленно растет? Современные фреймворки SPA имеют серьезные проблемы с потреблением ресурсов процессора.Недостаточно ли кластера серверов? Сопровождается ли это утечкой памяти? Есть ли ожидающие запросы, которые не возвращаются? Эти вопросы снова и снова крутились в моей голове.
Пока я не увидел систему, не увидел исходный код, не зашел на сервер и не увидел различные данные мониторинга сервера, молодец. Интересно, меня это еще больше возбуждает.
вопрос:
- Процессор периодически растет, иногда падает, но в целом тенденция к росту. Цикл достигает более 80% загрузки примерно за 2 недели.
- Каждый день происходит небольшое количество утечек памяти, очень мало. Также будут релизы. Общая тенденция составляет около 500 миллионов в день.
- Ежедневный объем доступа сильно колеблется при наличии активности, но в целом ситуация относительно стабильна, однако система журналов сохраняет журналы только за последние 7 дней, что затрудняет анализ причин из журналов. Данные за дни проблемы пропали.
- Для серверной системы на уровне кода, если нет серьезных проблем с логикой кода, улучшение производительности, вызванное оптимизацией кода, ограничено.
первый обход
Судя по логу доступа и проблеме, описанной дескриптором, пики доступа бывают в дни высокой загрузки ЦП. И использование ЦП также значительно снижается при уменьшении трафика. Поэтому по пользовательскому трафику в часы пик CPU в те дни следует судить о том, что нагрузка на сервер была недостаточной и не выдержала пик трафика. Вот я и пошел к Лидеру с этим результатом опроса. Лидер тоже согласился. В конце концов, это имеет смысл с уровня данных. И я посоветовался с коллегами по эксплуатации и техническому обслуживанию с этой стороны, и они тоже почувствовали то же самое. И действительно, в то время был большой всплеск трафика, который длился несколько часов.
Тем не менее, в следующие несколько дней было замечено, что когда трафик не был таким огромным, все еще будет наблюдаться медленный восходящий тренд, но он будет медленнее, чем в период пикового трафика. Итак, первые выводы были признаны ошибочными.
второй обход
Согласно эмпирическому анализу, такое явление, как медленное увеличение ЦП и не может быть значительно уменьшено, в основном связано с тем, что некоторые фрагменты кода приостановлены и не могут быть освобождены. Для Nodejs есть не что иное, как несколько типов: 1 setTimeout, 2 block IO, 3 express не вызывает res.end() для завершения запроса.
Начал делать обзор кода и обнаружил, что весь проект был построен на основе официальной версии vue-hackernews2.0. С кодом проблем нет. Так может блокировка IO?
Поэтому я попросил своего однокурсника по эксплуатации и техническому обслуживанию рассказать, как просматривать активные сетевые ссылки и проводить стресс-тестирование в локальной среде. Затем остановитесь и проверьте состояние ссылки через полчаса (поскольку операционная система не освободит ссылку сразу после завершения операции, чтобы оптимизировать использование io, поэтому вам придется подождать некоторое время).
После стресс-теста результаты были очень шокирующими: из-за крайне низкой производительности внутреннего интерфейса тестовой среды было приостановлено слишком много запросов. В это время также много заблокированных ссылок на сокеты, память взлетает, а процессор не сильно упал. Хахаха проблема найдена (радоваться рано).
Поэтому я отправился в отдел эксплуатации и обслуживания, чтобы договориться о том, есть ли средства для установки и отключения долговременно не отвечающего канала на сервере. Эксплуатация и обслуживание очень беспомощны. . . . . .
Отлично. Вы должны прийти сами. Почему столько ссылок висит? Поискав данные, я обнаружил, что есть такое явление: при перегрузке сервера, из-за того, что он не может ответить, сокет клиента будет приостановлен и все время находиться в состоянии подключения.
Я пошел спросить ответственного за разработку проекта и сказал, что они установили тайм-аут, который не вызовет эту ситуацию. . . . . .
Но я четко видел много запросов, которые были возвращены после более чем 200 секунд в журнале. . . . . . Это означает, что установленный нашим кодом таймаут не работает. Так что мне нужно найти достаточно улик, чтобы убедить его.
Иногда, когда мы общаемся, другая сторона не доверяет вашей точке зрения, но это потому, что ваши доказательства недостаточны.В это время вам нужно найти достаточно убедительных доказательств, чтобы доказать свою точку зрения.
Поэтому я копался в документации Nodejs, следил за кодом проекта и обнаружил, что есть проблема с этой реализацией axios:
if (config.timeout) {
timer = setTimeout(function handleRequestTimeout() {
req.abort();
reject(createError('timeout of ' + config.timeout + 'ms exceeded', config, 'ECONNABORTED', req));
}
}
Этот код выглядит нормально, это типичное решение для обработки тайм-аута во внешней обработке.
Поскольку в Nodejs ссылка io будет блокировать обработку таймера, поэтому этот setTimeout не будет срабатывать вовремя, и будут случаи, когда он вернется через более чем 10 секунд.
Вроде бы проблема решена, огромный трафик и заблокированные соединения приводят к скоплению запросов, сервер не справляется, а процессор не выходит из строя.
Это упоминается в официальной документации Nodejs:
If req.abort() is called before the connection succeeds, the following events will be emitted in the following order:
- socket
- (req.abort() called here)
- abort
- close
- error with an error with message Error: socket hang up and code ECONNRESET
Так что я даюаксиос поднял PR, решение состоит в том, чтобы использовать обработку тайм-аута для подключения в сокете, чтобы заменить setTimeout, который будет заблокирован в Nodejs для обработки запроса тайм-аута. Эта проблема также существует в node-request. И после множества локальных тестов выясняется, что ЦП и память находятся в пределах нормы при высокой нагрузке. Думал все ок.
if (config.timeout) {
// Sometime, the response will be very slow, and does not respond, the connect event will be block by event loop system.
// And timer callback will be fired, and abort() will be invoked before connection, then get "socket hang up" and code ECONNRESET.
// At this time, if we have a large number of request, nodejs will hang up some socket on background. and the number will up and up.
// And then these socket which be hang up will devoring CPU little by little.
// ClientRequest.setTimeout will be fired on the specify milliseconds, and can make sure that abort() will be fired after connect.
req.setTimeout(config.timeout, function handleRequestTimeout() {
req.abort();
reject(createError('timeout of ' + config.timeout + 'ms exceeded', config, 'ECONNABORTED', req));
}
}
Однако. . . . . . Я снова ошибся.
Однажды я забыл выключить компьютер, а локальная среда стресс-теста все еще работала, а на следующий день я с удивлением обнаружил, что все ресурсы приостановленных сокетов были освобождены. Однако память и ЦП по-прежнему не переработаны. На данный момент я проверил с моими коллегами по эксплуатации и обслуживанию, и действительно, операционная система будет автоматически обрабатывать эти долгосрочные неактивные ссылки. Хотя я решил проблему, изменив исходный код axios, кажется, что основная причина проблемы неверна.
Случайно обнаружил "дерзкую" обработку в vue-router
Я действительно понятия не имею.Похоже, я не уловил первопричину проблемы после нескольких дней траты, хотя проблема была решена по ошибке. Но этот способ решения проблемы будет иметь некоторую неопределенность в отношении того, сможет ли он искоренить проблему.
Используйте проверку для повторного анализа памяти системы.Поскольку онлайн-трафик очень велик, но утечка памяти и ЦП очень мала, и воспроизвести такой большой объем доступа локально сложно, поэтому очень сложно воспроизвести локально, плюс метод GC JS, очень сложно исследовать. Только один запрос и один запрос можно многократно сравнивать с образом памяти, чтобы найти хоть малейшую подсказку.
Что касается ЦП, то отследить его еще сложнее, а ежедневный прирост ЦП онлайн составляет около 0,02 в час. Это означает, что влияние среднего запроса на утечку ЦП минимально, и после выполнения крупномасштабного теста запроса отслеживание памяти становится неточным.
Возможно, на этот раз преимущество старых программистов, которые могут затаить дыхание и искать проблемы. Иногда для решения технической проблемы не требуется, насколько вы сильны, способ решения проблемы и главное терпение.
При случайном обнаружении после выполнения запроса в образе памяти всегда будет отображаться таймер. Затем при следующем захвате образа памяти сбрасывается другой таймер. Что за фкс? Что за черт.
И этот таймер не имеет очевидной информации, чтобы сказать мне, где он был создан. Сбой снова.
Может ли это быть источником утечки памяти? Таймер занимает очень мало ресурсов, он асинхронный и не блокирует систему, поэтому он не заставит ЦП работать на высоком уровне в течение длительного времени, как бесконечный цикл. Кажется, что этот таймер является источником проблемы.
К счастью, все API-интерфейсы Nodejs реализованы на js, поэтому код отслеживания прерывается прямо в setTimeout. . . . . . Это действительно чудо. Нашел операцию Sao в vue-router
function poll (
cb, // somehow flow cannot infer this is a function
instances,
key,
isValid
) {
if (instances[key]) {
cb(instances[key]);
} else if (isValid()) {
setTimeout(function () {
console.log('vue-router poll');
poll(cb, instances, key, isValid);
}, 16);
}
}
Да, верно, это таймер бесконечного цикла. Что такое экземпляры? Код доступа должен быть соответствующим экземпляром асинхронного компонента, а ключ — значением ключа соответствующего компонента в массиве экземпляров. Условий выхода всего два: 1. Асинхронный компонент загружается и 2. Маршрут меняется.
Но в сценарии ssr изменение маршрута не будет происходить в процессе каждого запроса. Таким образом, условие выхода оставляет только загрузку асинхронного компонента завершенной. Но по какой-то причине он не загружался успешно. Это приводит к тому, что таймер попадает в бесконечный цикл. И предпосылка заключается в том, что в компоненте должна быть реализована защитная функция beforeRouteEnter.
Потому что реализация кода vue-router слишком шумная. Помочь может только всемогущий гитхаб. нашел этоissue
Это точно соответствует моей ситуации. Но я был немного охладел к ответу члена. Проблему можно отлично воспроизвести через простые настройки сабжа. Команда закрыла его на том основании, что «упрощенная копия вместо целого приложения поможет выявить проблему, спасибо». . . . . .
И еще более раздражает:
> A boiled down repro instead of a whole app would help to identify the problem, thanks
if you have an infinite loop, it's probably next not being called without arguments 《= 以为我们都是傻子吗?不知道调next?
Отлично. Кажется, что раз уж он на пиратском корабле, то может рассчитывать только на себя. После того, как я пообщался с владельцем темы, я начал пытаться решить проблему. Но после нескольких дней напряженной работы тема сдалась. но я. . . . . . Я также решил сдаться (не думайте, что я такой высокий, если честно, я несколько дней читал исходный код vue-router. Я действительно не нашел хорошего решения, в основном потому, что я буду много изменять вещей.).
решение
Причины утечек памяти и процессора в vue-ssr в настоящее время две:
- Ожидающие сокеты вызывают временную блокировку
- Таймер в vue-router в некоторых случаях застревает в бесконечном цикле.
- Много шаблонной компиляции, много памяти будет занято строками в памяти
Итак, как решить эту проблему?
- Удалите обработку beforeRouteEnter в компоненте. Перенесите сюда обработку в другие места и анализируйте с уровня кода vue-router, чтобы не попасть в бесконечный цикл таймера.
- Замените метод setTimeout в nodejs для обработки времени ожидания запроса на стороне сервера и используйте дескриптор события времени ожидания http.request для его обработки. Запретить io блокировать обработку таймера.
- Если требования SEO не слишком высоки, используется метод рендеринга страницы скелета для рендеринга страницы скелета клиенту, а затем внешний интерфейс напрямую инициирует запрос ajax для извлечения данных сервера. Избегайте выполнения запросов на стороне сервера на стороне nodejs. Некоторые ссылки приостановлены из-за блокировки, вызванной невосприимчивостью фона на стороне сервера. (Цикл событий nodejs отличается от браузера, хотя он основан на движке V8. Это также распространенный метод применения большинства отечественных интернет-компаний в разделе vue-ssr)
может быть также
Я изучаю vue-ssr всего 2 недели, если у вас есть какие-либо вопросы по вышеизложенному, пожалуйста, напомните мне, чтобы я вовремя исправил это.