Расходы после переноса на Go зависят от нагрузки
Расходы после переноса на Go снижаются, когда память, параллельность и соединения позволяют покупать меньше ресурсов для прежней нагрузки.

Перенос системы на Go может снизить счет за инфраструктуру, но само название языка в манифесте развертывания ничего не экономит. Экономия появляется, когда новая программа хранит меньше живых данных, создает меньше временного мусора, осознанно ограничивает прием работы, повторно использует соединения и позволяет держать меньше экземпляров при прежнем уровне сервиса. Если эти механизмы не изменились, счет тоже может остаться прежним.
Я видел, как команды радовались бинарному файлу, который в тесте разработчика занимал вчетверо меньше памяти, а затем обнаруживали, что в рабочей среде по-прежнему нужно прежнее число экземпляров. Ограничением оказывалось время завершения пакетного задания, лимит соединений с базой данных или правило доступности, а не heap. Поэтому убедительное экономическое обоснование начинается с четырех отдельных величин: память на экземпляр, полное время пакетного задания, соединения на экземпляр и необходимое число экземпляров. Назначайте им цену только после измерения всех четырех.
Счет меняется только вместе с ограничением
Расходы снижаются, когда измеренное сокращение ресурса пересекает границу закупки. Снижение резидентной памяти с 1,8 ГБ до 900 МБ имеет значение, если сервис можно перенести с конфигурации на 4 ГБ на конфигурацию на 2 ГБ, разместить на узле вдвое больше процессов или убрать экземпляры. Прямой денежной выгоды нет, если правила по-прежнему выделяют 4 ГБ, в кластере есть свободное место или стоимость определяет лицензируемая зависимость.
Сначала найдите ограничение самой нагрузки. Онлайн-сервис может упираться в задержку при пиковом потоке запросов. Ночное расчетное задание может зависеть от крайнего срока завершения. Перенесенный в контейнеры сервер из настольной системы может зависеть от состояния каждой сессии и правила, по которому каждый экземпляр обязан выдерживать отказ соседнего. Это разные задачи расчета мощности, даже если исходный репозиторий один.
Разделяйте потребление и выделение. Счета за облако и контейнеры обычно отражают запрошенную или предоставленную мощность, а не минимальное число в профилировщике. Процесс может использовать 600 МБ, но запрашивать 2 ГБ и занимать 2 ГБ в модели планировщика. После переноса кто-то должен изменить requests, limits, пороги автоматического масштабирования и правила размещения на узлах. Иначе техническая победа останется неиспользуемой мощностью.
Сравнивать нужно стоимость завершенной единицы работы при одинаковой цели: запрос в том же процентиле задержки, правильно рассчитанный полис или задание, завершенное до того же срока. Сравнение простаивающих процессов почти ничего не доказывает. Сравнение разных требований надежности еще хуже, ведь более дешевая система может просто иметь меньший запас.
Стройте исходную точку по счетам и конфигурации, а не по памяти. Запишите типы экземпляров, минимальное число реплик, верхние границы масштабирования, запросы памяти и CPU, резервирование узлов, уровни базы данных и длительность заданий. Пометьте каждую статью как переменную, ступенчатую или фиксированную. Переменная стоимость следует за использованием, ступенчатая меняется лишь на границе тарифа, фиксированное обязательство не меняется до конца срока. Такая классификация не дает бездумно перенести процент улучшения одной метрики в бюджет.
После измерения важен ответственный за изменение. Команда переноса может доказать безопасность меньшего request, но стандартами контейнеров управляет владелец платформы, а резервированием управляют финансисты. Запишите изменение конфигурации, владельца и ближайшую дату закупки в тот же документ приемки, что и результаты теста. Иначе все согласятся с ростом свободной мощности, но никто не изменит покупаемую единицу.
Меньше памяти требует хранить меньше состояния
Go часто снижает память на экземпляр, когда вместо тяжелой среды выполнения и объемного графа объектов новая версия использует компактные структуры данных и четкие границы владения. Дело не в какой-то особой дешевизне памяти в Go. Новый сервис может загружать меньше конфигурации, раньше освобождать данные запросов, обрабатывать записи потоком вместо полной загрузки и представлять предметные значения без слоев объектов фреймворка.
Измеряйте три показателя: живой heap после сборки мусора, всю резидентную память процесса и working set контейнера или операционной системы. Живой heap показывает объем доступных из программы данных Go. Резидентная память также включает стеки goroutine, метаданные среды выполнения, отображение исполняемого файла, нативные выделения и страницы, которые система еще не вернула. Модель закупки только по HeapAlloc даст слишком оптимистичный результат.
Стеки Go изначально малы и растут по мере надобности. Это помогает при большом числе одновременных, но в основном ожидающих операций. Однако goroutine не бесплатны. Каждый заблокированный запрос может удерживать стек, буферы и ссылки на большой граф объектов. Сервис без ограничения приема превратит всплеск в тысячи ожидающих goroutine и сохранит гораздо больше памяти, чем показывал профиль стабильной нагрузки.
Наряду с живым объемом важна скорость выделения. Обработчик может выделить 20 МБ, затем все освободить и оставить небольшой живой heap, но часто запускать сборщик мусора и тратить CPU. Повторное использование рабочих буферов иногда помогает, однако глобальный sync.Pool не задает политику хранения. Его объекты могут исчезнуть при сборке мусора, а слишком большие буферы делают удержание памяти непредсказуемым. Ограничьте размер всего, что возвращается в пул.
Используйте GOMEMLIMIT как защитное ограничение среды выполнения, а не как обещание удержать резидентную память ниже указанного числа. Документация Go описывает его как мягкий предел памяти, которой управляет среда выполнения. Нативные библиотеки, отображаемые файлы и другие страницы процесса в этот расчет не входят. Установите значение ниже лимита контейнера, оставьте место для этих страниц и следите за CPU сборщика под настоящей нагрузкой. Слишком жесткий предел заменит аварийное завершение непрерывной сборкой мусора и плохой задержкой.
Память нужно измерять на рабочем трафике
Для показательного результата нужны рабочая смесь запросов, прогретые кэши и время, достаточное для обнаружения удержания. Синтетические запросы по одному успешному пути пропускают большие отчеты, редкие конфигурации клиентов, тела повторных запросов и медленных клиентов, удерживающих буферы ответа. Воспроизведите записанный трафик, если это разрешают правила, или подготовьте очищенный набор с сохранением размеров и частоты маршрутов.
Проводите измерения в определенные моменты: после запуска, после прогрева кэша, при длительной обычной нагрузке, на пике и после возврата к обычной нагрузке. Последняя точка обнаруживает удержание. Если живой heap уменьшился, а резидентная память осталась высокой, среда может хранить пригодные для повторного использования страницы. Если heap не уменьшился, код все еще достигает данных. Исправлять эти случаи нужно по-разному.
Небольшой сценарий делает проверку объективнее:
curl -s http://127.0.0.1:6060/debug/pprof/heap > heap.pb.gz
go tool pprof -top -sample_index=inuse_space ./service heap.pb.gz
cat /sys/fs/cgroup/memory.current
В выводе профиля перечислены функции с прямым и накопленным числом используемых байтов. Файл cgroup выводит одно целое число в байтах. Рядом запишите request памяти развертывания, потому что именно его учитывает планировщик и часто счет. Если пути cgroup v2 нет, возьмите метрику working set контейнера вашей платформы и зафиксируйте ее определение.
Не открывайте net/http/pprof на общедоступном listener. Привяжите диагностику к закрытому административному endpoint или собирайте профиль через аутентифицированный механизм платформы. Профиль heap может раскрыть имена типов, схемы выделения и фрагменты состояния процесса. Относитесь к нему как к эксплуатационным данным, а не как к безобидной диаграмме.
Сравнивайте профили по маршруту и фазе нагрузки, а не только по крупнейшему источнику выделений. Большое выделение при запуске может господствовать в накопленном представлении, но не иметь отношения к росту на пике. Метки через pprof.Do разделяют этапы пакета или классы запросов и показывают, какая работа держит память у лимита.
Для удержанной памяти нужен граф выделений, а не автоматическая очистка кэша. Проследите пути к корням и найдите map, channel, timer или goroutine, сохраняющие доступность данных. Пропущенный вызов отмены может удержать весь контекст запроса. Метка метрики из пользовательского ввода может создать неограниченную карту рядов. Кэш может ограничивать число записей, но не байты, и несколько огромных значений разрушат расчет. Исправьте правило владения и повторите ту же фазу.
Тест должен захватить периодические задачи. Перезагрузка сертификатов, построение отчетов, уплотнение и ежедневное обновление справочников могут установить уровень выше, чем час воспроизведения запросов. Если есть еженедельная обработка или закрытие месяца, измерьте ее отдельно и учитывайте правила этого события. Усреднение с обычным трафиком скрывает пик, который вызывает остановку или экстренное масштабирование.
Быстрое пакетное задание требует ограниченного параллелизма
Go сокращает пакетное окно, когда старая программа оставляет CPU или ввод и вывод без работы, а новая совмещает независимые операции, не перегружая следующую систему. Замена последовательного цикла COBOL, PL/SQL или настольной программы на goroutine может открыть параллелизм, но неограниченный запуск часто замедляет работу.
Правильный предел определяется самым узким общим ресурсом: сессиями базы данных, пропускной способностью хранилища, квотой удаленного сервиса, CPU или конкуренцией блокировок. Используйте фиксированное число workers либо семафор, измеряйте ожидание отдельно от выполнения и отменяйте группу, когда задание уже не может завершиться успешно. Так оператор получает понятный регулятор.
Например, сверка может независимо читать разделы счетов, но писать через одну индексированную таблицу проводок. Рост с четырех workers до шестнадцати сократит чтение. Двести workers могут насытить базу, увеличить ожидание блокировок и удлинить каждую операцию. Программа одновременно удержит больше строк, буферов и стеков, поэтому попытка ускорения увеличит и время, и память.
Время пакета включает запуск, контрольные точки, повторы и завершение. Тест только внутреннего цикла может показать большой выигрыш при неизменном крайнем сроке. Измеряйте от разрешения планировщика до момента безопасного использования результата следующими системами. Сохраняйте одинаковыми объем входа и проверки правильности.
Сохраните поведение при перезапуске. Если старое задание фиксирует каждый раздел, а новое только все сразу в конце, чистый запуск выглядит быстрее, но поздняя ошибка требует полного повтора. Ожидаемые расходы зависят от частоты сбоев и повторной работы. Идемпотентная запись, надежные контрольные точки и ограниченный бюджет повторов управляют производительностью, потому что определяют объем переделки.
Некоторые пакеты почти не ускорятся. Задание, уже насытившее канал хранилища, не обгонит этот канал из-за управляющего кода на Go. Лицензированный поток с мейнфрейма может выдавать вход в фиксированное время. Следующая система может принимать только один файл. Перенос улучшит сопровождение и восстановление без сокращения окна, и финансовая модель должна говорить об этом прямо.
Проверяйте эффективность CPU отдельно. Worker Go, декодирующий текст, преобразующий десятичные числа и создающий короткоживущие structs, может потратить больше CPU, хотя за счет параллелизма закончит раньше. Измерьте CPU-секунды полного пакета и реальное время. Реальное время показывает соблюдение срока, CPU-секунды показывают потребление общей вычислительной мощности. Один показатель может улучшиться, а другой ухудшиться.
Ограничивайте память обратным давлением между этапами. Если читатели опережают писателей, безразмерный channel незаметно превращается в копию входа в памяти. Рассчитайте вместимость каждой очереди по размеру элемента и допустимому буферу. При заполнении блокируйте производителей или сбрасывайте данные в надежное хранилище. Показывайте глубину очереди и время блокировки. Пик станет предсказуемым, а метрики покажут, поможет ли еще один worker или только перенесет ожидание.
Работа с соединениями может уничтожить выигрыш
Пулы превращают число экземпляров в нагрузку на базы данных и удаленные сервисы. Небольшой процесс может стоить дороже, если каждая копия открывает слишком много соединений. database/sql и net/http.Transport повторно используют их, но значения по умолчанию не заменяют расчет мощности. Операторы должны установить лимиты по общему размеру парка и поведению внешней системы.
Для SQL считайте SetMaxOpenConns бюджетом всего парка. Если база разрешает 400 прикладных сессий, а сервис может вырасти до 20 экземпляров, максимум в 20 на экземпляр исчерпает все до миграций, администрирования и резерва на отказ. Берите максимально возможное число экземпляров, а не среднее сегодня. SetMaxIdleConns задает готовые сессии процесса, а SetConnMaxLifetime и SetConnMaxIdleTime со временем выводят их из обращения.
Низкий предел открытых соединений создает очередь внутри процесса. Это может быть правильно, но следите за DB.Stats(): WaitCount и WaitDuration показывают ожидание свободного места. Если задержка растет там, новые экземпляры могут ухудшить очередь базы, ведь каждый добавит пул. Исправьте запрос, длительность транзакции или мощность базы, прежде чем масштабировать симптом.
У HTTP есть своя ловушка. Новый http.Client или Transport для каждого запроса исключает повторное использование и вызывает постоянную смену соединений. Используйте один настроенный transport, закрывайте тела ответов на всех путях, читайте или опустошайте их, когда это нужно для повторного использования. Задайте пределы простоя для хоста, timeout заголовков и общий срок операции. Большой пул простаивающих соединений на множестве экземпляров может держать тысячи sockets при умеренном потоке.
Смена соединений стоит ресурсов и вне процесса. TLS handshakes используют CPU, короткие sockets накапливаются в таблицах системы, база аутентифицирует тут же исчезающие сессии. Поэтому сервис Go может использовать меньше heap, а CPU базы вырастет и число экземпляров не снизится из-за худшей хвостовой задержки.
Транзакции усложняют расчет. Обработчик, который открывает транзакцию, вызывает удаленный сервис и затем фиксирует изменения, держит сессию во время ожидания сети. Двадцать соединений обслужат сотни быстрых запросов или лишь двадцать зависших транзакций. Где позволяет правильность, вынесите удаленные вызовы из транзакций, задайте сроки и записывайте длительность без чувствительных аргументов. Увеличение пула не исправит слишком широкую транзакционную границу.
При проверке failover наблюдайте за штормом соединений. Когда меняется endpoint базы или сервер закрывает простаивающие sockets, все экземпляры могут подключиться одновременно. Частые повторы умножают аутентификацию и обнаружение во время восстановления. Применяйте ограниченную экспоненциальную задержку со случайным разбросом, соблюдайте срок вызывающей стороны и ограничивайте одновременные подключения. Измеряйте восстановление и внешнюю нагрузку при максимальном парке: один процесс не покажет синхронную волну.
Число экземпляров задают поток и правила отказа
Необходимое число равно наибольшему из требований по пропускной способности, памяти, задержке и доступности, округленному вверх с явным запасом. Не делите старую память на новую и не называйте результат коэффициентом уплотнения. Такой расчет не учитывает, справится ли один экземпляр с потоком и выдержит ли парк потерю участника.
Создайте короткую карточку мощности для каждого важного сервиса. В ней нужны пиковая частота запросов, безопасная пропускная способность экземпляра до нарушения задержки, working set на этом уровне, максимум соединений и число отказавших экземпляров, которое требует выдерживать политика. Храните исходные измерения рядом с выбранными значениями, чтобы было видно место запаса.
Если пик равен 1 200 запросам в секунду, а экземпляр безопасно обслуживает 275 с нужной задержкой, требуется ceil(1200/275) = 5 экземпляров. Если при этом нужно пережить отказ одного, разверните не менее шести. Эти числа лишь показывают арифметику, а не обещают производительность Go. Измеряйте свою величину непосредственно перед выходом задержки или ошибок за цель.
Автоматическое масштабирование не отменяет эту работу. Цель по CPU иногда подходит обработчику с ограничением CPU, но пропустит сервис, который ждет насыщенный пул. Цель по памяти может отреагировать поздно, так как удержанная память уменьшается медленно. Выберите сигнал самого ограничения, например задержку очереди или число одновременных операций, и включите запуск в резерв. Маленький бинарный файл, который несколько минут греет большой кэш, все равно требует запасных экземпляров до пика.
Размещение на узлах создает еще одну границу. Меньшие requests памяти экономят деньги в фиксированном кластере, только если планировщик разместит достаточно нагрузок, чтобы убрать узел или отложить следующий. Раздробленные requests CPU и памяти оставляют непригодные пробелы. Переразместите весь пул на бумаге, затем проверьте работу планировщика и только после этого учитывайте экономию.
Используйте разные числа для обычной работы, failover и развертывания. При постепенном развертывании старые и новые реплики могут работать вместе. При эвакуации региона трафик попадет на парк, обычно обслуживающий половину потока. Если модель рассчитана лишь на спокойное состояние, первое развертывание или отказ нарушит цель либо заставит вернуть прежние лимиты. Временная мощность может быть дешевой, но должна входить в квоты и прогноз.
Не доверяйте средним значениям в многопользовательской системе. Два экземпляра могут иметь одинаковый средний CPU, хотя один держит клиента с огромным working set, а другой много небольших. До снижения памяти воспроизведите самую тяжелую разрешенную смесь или запретите совместное размещение крупных клиентов. Если договор не ограничивает размер клиента, нужны правила приема или обоснованное выделение для худшего случая.
Некоторые переносы не снижают счет
Экономии нет, когда инфраструктура составляет малую или фиксированную часть стоимости либо новый проект без изменений наследует старое ограничение. Перенос все равно может быть правильным решением, но неподтвержденная экономия вычислений ослабит предложение.
Самые очевидные случаи:
- Минимальная доступность уже требует два или три экземпляра, а нагрузка поместилась бы на одном на любом языке.
- В счете господствует база данных, брокер, лицензия поставщика или зарезервированный узел.
- Нагрузка почти все время ждет неизменившуюся последовательную зависимость.
- Правила размещения или изоляции данных требуют отдельной среды каждому клиенту независимо от использования.
- Трафик настолько редок, что важнее тарификация serverless, время запуска или минимальная плата платформы.
Cgo и нативные библиотеки могут уменьшить разницу в памяти, потому что их выделения находятся вне heap Go. Перенос оболочки вокруг того же вычислительного ядра изменит оркестрацию, но не дорогую работу. Разделение монолита тоже может размножить кэши, transports, буферы телеметрии и минимальные реплики. Весь парк способен занять больше памяти, хотя каждый процесс выглядит компактным.
Наблюдаемость тоже может стоить заметно. Метки высокой кардинальности, неограниченные очереди трассировки и подробные журналы содержимого потребляют память, сеть и хранилище на любом языке. Если новая версия добавила телеметрию, которой раньше не было, сравнивайте равные возможности или честно запишите новую стоимость. Не прячьте ее в сравнении языков.
Еще одна причина разочарования связана с транслитерацией. Воспроизведение каждой старой границы процесса и таблицы в памяти сохраняет архитектуру, создавшую прежнее потребление. Исполняемый файл может стать меньше, но система загрузит те же данные, будет ждать те же блокировки и запустит столько же копий. Для изменения счета должен измениться хотя бы один механизм.
Цены единиц могут действовать против технического результата. Управляемая платформа может брать за несколько крупных экземпляров больше, чем за существующие зарезервированные типы. Сетевые расходы вырастут, если разделенные сервисы пересекают зоны для вызовов, прежде остававшихся внутри процесса. Новый Postgres может заменить уже оплаченную лицензию заметной строкой управляемого сервиса. Рассчитывайте саму целевую топологию, а не умножайте старые цены на желаемый коэффициент.
Рабочее время команды нужно отделять от инфраструктуры, хотя оба фактора входят в решение. Более простое развертывание, быстрая диагностика и отказ от редких языков могут дать основную отдачу. Оценивайте их отдельной моделью и подходящими доказательствами. Если смешать их с завышенной экономией вычислений, хорошая модернизация потеряет доверие после первого счета облака.
Тест паритета должен идти рядом с нагрузочным
Результаты производительности имеют смысл, только если новая система сохраняет деловое поведение. Самая дешевая программа бесполезна, если иначе округляет деньги, меняет стабильность сортировки, теряет повтор или по-другому обрабатывает пустое поле. Проверяйте правильность и мощность на одном наборе, чтобы одно нельзя было незаметно обменять на другое.
Запишите входы и видимые снаружи выходы текущей системы, удалите или защитите чувствительные данные, затем воспроизведите набор в обеих версиях. Сравните статусы, важные заголовки, нормализованные тела, изменения в базе и события. Значения, которые должны различаться, например идентификаторы и время, нормализуйте по именованным проверенным правилам. Любое необъясненное различие блокирует заявление о производительности.
Для онлайн-трафика повышайте нагрузку до нарушения цели, а не до падения процесса. На каждой ступени собирайте пропускную способность, распределение задержки, ошибки, working set, скорость выделения, CPU сборщика, ожидание пулов и внешнюю нагрузку. Для пакетов воспроизведите несколько размеров и запишите время этапов, контрольные точки, повторную работу и окончательную готовность.
Храните конфигурацию эксперимента вместе с результатом. Она должна указывать сборку, настройки runtime, пределы CPU и памяти, число workers, лимиты пулов, входной набор и версии внешних систем. Без этих данных результат нельзя повторить, и на бюджетной проверке он станет преданием.
После обычных ступеней проведите намеренный тест насыщения. Его задача не в рекордном максимуме, а в проверке ограниченности перегрузки: очереди должны перестать расти, вызывающие стороны должны получать контролируемые ошибки или обратное давление, память должна стабилизироваться, а система восстанавливаться без перезапуска. Запишите первое достигнутое ограничение. Оно входит в карточку мощности и определяет сигнал масштабирования.
Повторите безопасную ступень на нескольких свежих экземплярах. Прогрев runtime, конкуренция на узле и порядок набора могут изменить отдельный запуск. Покажите разброс и сохраните исходные временные ряды. Нужен не декоративный балл, а повторяемые данные для выбора requests и числа реплик, которым эксплуатация поверит в два часа ночи.
При переносе унаследованной системы CodeHero проверяет паритет по записанному рабочему трафику, а затем модернизирует архитектуру вместо транслитерации. Для расчета расходов это правильный порядок: зафиксировать поведение, изменить механизмы и измерить эксплуатационную границу, которая формирует счет.
Учитывайте экономию после изменения ресурсов
Подтвержденное сокращение становится финансовым, когда его отражают конфигурация и закупочная модель. Уменьшите requests памяти, скорректируйте CPU, настройте пределы масштабирования, сократите бюджеты пулов, где позволяет расчет, и проверьте отказ при новом минимуме. Затем наблюдайте полный деловой цикл, включая самый тяжелый пакет и доступный пик онлайна.
Ведите реестр до и после с предоставленной мощностью и ценами единиц, а не процентами из профилировщика. Включите уровни базы, передачу данных, хранилище наблюдаемости и действующие резервирования. Если трехлетнее резервирование нельзя сократить, назовите ближайший результат освобожденной мощностью и укажите, когда появится денежная экономия. Финансисты понимают разницу, а выдуманная немедленная выгода создаст проблемы позже.
Сильное предложение дает диапазон. Консервативный вариант применяет измеренные улучшения экземпляра, но сохраняет минимумы и фиксированные сервисы. Ожидаемый меняет типы экземпляров или число узлов после успешных тестов нагрузки и отказа. Верхний остается в приложении, пока его не подтвердит настоящий трафик. Каждый вариант называет ограничение, которое должно измениться.
Go дает разработчикам хорошие средства для компактных сервисов, контролируемого параллелизма и повторного использования соединений. Он не отменяет очереди, пределы внешних систем и правила доступности. Если расчет мощности не связывает меньший heap, короткий пакет или небольшой пул с меньшим числом покупаемых единиц, продолжайте работу над проектом и пока не учитывайте экономию.
Вопросы
Всегда ли перенос на Go снижает расход памяти?
Нет. Память снижается, если новый проект хранит меньше состояния, создает меньше временных данных или убирает нагрузку фреймворка. Cgo, дублированные кэши и прежняя модель объектов могут оставить резидентную память на том же или большем уровне.
Можно ли рассчитывать контейнер Go по HeapAlloc?
Нет. HeapAlloc не включает стеки goroutine, метаданные, нативные выделения и другие резидентные страницы. Берите working set контейнера на показательном пике и оставляйте место между GOMEMLIMIT и лимитом контейнера.
Как доказать экономию от меньшего процесса Go?
Покажите, что меньший working set меняет request памяти, тип экземпляра, число узлов или другую покупаемую единицу. Если выделение не меняется, вы освободили мощность, но пока не снизили счет.
Почему дополнительные goroutine замедлили пакет?
Workers, вероятно, превысили общий предел сессий базы, хранилища или блокировок. Ограничьте параллелизм на этом ресурсе и измеряйте ожидание отдельно от выполнения.
Что должен включать тест пакетного задания?
Измеряйте от разрешения планировщика до безопасного использования результата. Учитывайте запуск, контрольные точки, повторы, завершение и правильность, а не только внутренний цикл.
Сколько соединений дать каждому экземпляру Go?
Разделите бюджет прикладных сессий между максимальным парком и оставьте резерв для отказа, миграций и администрирования. Проверьте DB.Stats(), поскольку ожидание показывает низкий лимит или слишком долгие транзакции.
Заменяет ли автоматическое масштабирование тест мощности?
Нет. Ему нужен сигнал настоящего ограничения и время на запуск полезной мощности. Цель по CPU не обнаружит сервис, остановившийся за пулом базы данных.
Когда перенос на Go не экономит инфраструктуру?
Прямой выигрыш будет мал, если стоимость задают минимальные реплики, отдельные среды, лицензии или последовательная зависимость. Восстановление и сопровождение могут улучшиться, но оценивать их нужно честно.
Как справедливо сравнить старую систему и Go?
Используйте одинаковый трафик, правила правильности, цель сервиса и резерв отказа. Запишите лимиты runtime, workers, пулы и версии внешних систем, чтобы другой инженер повторил результат.
Когда финансисты могут признать экономию?
После изменения предоставленной мощности и проверки на показательном деловом цикле. Действующие резервирования могут задержать денежную выгоду, поэтому до изменения обязательств показывайте освобожденную мощность отдельно.