Go без тормозов: 11 промтов для конкурентности, gRPC и профилирования высоконагруженных сервисов
Go создавался в Google как язык для сетевых сервисов, которые должны держать нагрузку и не падать под ней. Горутины, каналы, сборщик мусора с низкими паузами, встроенный pprof — всё это есть в стандартной библиотеке и работает без сторонних фреймворков. Проблема в другом: даже аккуратный код на Go легко превращается в источник утечек горутин, гонок данных и неожиданных аллокаций. По данным официальной документации Go, net/http/pprof и runtime/pprof дают доступ к CPU-, heap-, goroutine-, mutex- и block-профилям, но мало кто открывает их регулярно.
Эта подборка — про то, как использовать LLM как второго инженера рядом с вами. Промты ниже покрывают полный цикл: проектирование конкурентных паттернов, генерация gRPC-сервисов, поиск утечек горутин, чтение pprof-профилей, оптимизация аллокаций и безопасный рефакторинг горячего пути. Каждый промт — копипаст-реди, с пояснением задачи и примером. Ссылки на первоисточники (go.dev, pkg.go.dev, grpc.io) прилагаются, чтобы вы могли проверить каждое утверждение.
1. Генерация конкурентного паттерна под конкретную задачу
Задача: когда нужно выбрать между worker pool, fan-out/fan-in, errgroup или pipeline — и получить сразу рабочий каркас.
Ты senior Go-инженер. Мне нужно обработать N задач с ограничением параллелизма.
Контекст:
- Go 1.22+, доступны context, errgroup (golang.org/x/sync/errgroup)
- Задачи: <опиши, например, HTTP-вызовы с таймаутом 2s>
- Требования: отмена по context, сбор первой ошибки, ограничение воркеров
Выдай: 1) выбор паттерна и почему, 2) полный код с комментариями,
3) как тестировать через go test -race, 4) подводные камни.
Пример использования: обработка 10 000 URL с лимитом 50 одновременных запросов. Модель предложит worker pool на канале задач + errgroup.WithContext. Проверяйте результат командой go test -race ./... — гонки данных ловятся именно так.
2. Аудит кода на утечки горутин
Задача: найти горутины, которые никогда не завершатся.
Проанализируй код ниже на утечки горутин и блокировки.
Ищи: горутины без выхода, запись в небуферизованный канал без читателя,
отсутствие select с ctx.Done(), забытый cancel().
Формат ответа: таблица
| строка | проблема | почему утечка | фикс |
Затем покажи исправленную версию.
Пример: функция, которая пишет в канал results после возврата из функции — классика. Правильный фикс: буферизованный канал или select с ctx.Done(). Встроенный go test с goleak (github.com/uber-go/goleak) в TestMain ловит такие утечки автоматически.
3. Проектирование gRPC-сервиса с .proto и интерсепторами
Задача: сгенерировать proto-файл и серверную обвязку с логированием, метриками и таймаутами.
Спроектируй gRPC-сервис на Go (grpc-go) для <домен>.
Дай: 1) .proto с proto3, полями и RPC-методами;
2) сервер с unary-интерсепторами: логирование, recovery, таймаут;
3) клиент с retry и keepalive;
4) команду protoc (protoc-gen-go, protoc-gen-go-grpc).
Учти context propagation и deadline.
Пример команды генерации: protoc --go_out=. --go-grpc_out=. proto/service.proto. Интерсепторы регистрируются через grpc.ChainUnaryInterceptor. Официальные примеры — на github.com/grpc/grpc-go.
4. Поиск узкого места по CPU-профилю pprof
Задача: превратить profile в список конкретных мест для оптимизации.
Вот вывод go tool pprof -top (вставь текст).
Объясни: 1) какие функции — горячие и почему;
2) что можно исправить без изменения архитектуры;
3) какие аллокации убрать;
4) как проверить эффект через benchstat.
Дай конкретные патчи.
Пример: если в топе runtime.mallocgc и strings.Split — вы аллоцируете на каждом запросе. Фикс: strings.Builder или sync.Pool. Документация: pkg.go.dev/net/http/pprof.
5. Чтение heap-профиля и борьба с аллокациями
Задача: понять, куда уходит память и почему GC работает часто.
Покажи, как снять heap-профиль в работающем сервисе:
1) через net/http/pprof (debug=1 и debug=0);
2) сравнить два профиля: go tool pprof -base old.prof new.prof;
3) интерпретировать inuse_space vs alloc_space;
4) предложить 5 типовых оптимизаций для Go 1.22.
Пример: go tool pprof -http=:8080 http://localhost:6060/debug/pprof/heap. Разница inuse_space (живая память) и alloc_space (всего аллоцировано) критична: первая показывает утечки, вторая — давление на GC.
6. Настройка GOGC и GOMEMLIMIT под нагрузку
Задача: подобрать параметры сборщика мусора без перезапуска сервиса.
У меня сервис на Go с нагрузкой <RPS>, heap ~<размер>, latency SLA <p99>.
Объясни влияние GOGC и GOMEMLIMIT (Go 1.19+).
Дай: 1) как выставить через runtime/debug.SetMemoryLimit;
2) как метрики runtime.MemStats читать в Prometheus;
3) как проверить эффект через нагрузочный тест.
Пример: GOGC=100 (значение по умолчанию) означает, что heap удваивается перед сборкой. GOMEMLIMIT=4GiB заставляет GC работать агрессивнее при приближении к лимиту. Официальный гайд: go.dev/doc/gc-guide.
7. Генерация нагрузочного теста и бенчмарка
Задача: получить воспроизводимый бенчмарк с реалистичным профилем.
Напиши Go-бенчмарк для функции <имя>.
Требования: b.ReportAllocs(), b.ResetTimer(), table-driven cases,
запуск через go test -bench=. -benchmem -count=10.
Дополнительно — пример запуска ghz или k6 для gRPC-эндпоинта.
Пример: go test -bench=BenchmarkHandler -benchmem -cpuprofile=cpu.prof. Для gRPC есть ghz — реальный инструмент с открытым исходником.
8. Диагностика гонок данных по race detector
Задача: разобрать вывод -race и не сломать логику фиксом.
Вот вывод go test -race (вставь). Объясни:
1) какие две горутины конфликтуют и на какой переменной;
2) почему это гонка, а не ложное срабатывание;
3) предложи минимум 2 варианта фикса (mutex / atomic / channel) и trade-offs;
4) покажи патч.
Пример: race detector — часть тулчейна (go test -race), не сторонний плагин. Он ловит реальные обращения к памяти, но не заменяет проектирование.
9. Оптимизация горячего пути и escape analysis
Задача: понять, почему объект уходит в heap.
Покажи вывод go build -gcflags=-m (вставь фрагмент).
Объясни, какие переменные escaped to heap и почему.
Предложи изменения: передача по значению, уменьшение размера структуры,
избегание интерфейсов в горячем цикле.
Пример: go build -gcflags='-m -m' ./... печатает решения компилятора. Частая причина escape — возврат указателя на локальную переменную или передача в interface{}.
10. Рефакторинг с сохранением поведения
Задача: переписать код так, чтобы тесты остались зелёными.
Отрефактори <функция> для снижения аллокаций и упрощения.
Ограничения: публичный API не менять, тесты должны пройти без правок.
Дай: diff, объяснение каждого изменения, команду для проверки
(go test ./... -race -count=1).
Пример: замена fmt.Sprintf на strconv.AppendInt в горячем пути экономит аллокации. Проверяйте через benchstat до/после.
11. Генерация observability-обвязки
Задача: подключить метрики, трейсинг и профилирование в один сервис.
Покажи, как подключить к Go-сервису:
1) Prometheus (prometheus/client_golang);
2) OpenTelemetry (go.opentelemetry.io/otel);
3) net/http/pprof на отдельном порту;
4) health-check /healthz и /readyz.
Дай полный main.go и объясни, почему pprof не должен быть на публичном порту.
Пример: pprof на :6060 в отдельной internal-сети — стандартная практика. Публичный доступ к /debug/pprof — риск утечки информации и DoS.
| Промт | Что решает | Ключевой инструмент |
|---|---|---|
| 1 | Паттерн конкурентности | errgroup, context |
| 2 | Утечки горутин | goleak |
| 3 | gRPC-сервис | protoc, grpc-go |
| 4 | CPU-профиль | pprof -top |
| 5 | Heap-профиль | pprof -base |
| 6 | Настройка GC | GOGC, GOMEMLIMIT |
| 7 | Нагрузка | ghz, k6 |
| 8 | Гонки | go test -race |
| 9 | Escape analysis | -gcflags=-m |
| 10 | Рефакторинг | benchstat |
| 11 | Observability | Prometheus, OTel |
Что дальше
Промты не заменяют чтение исходников и профилирование на реальных данных. Используйте их как ускоритель: сначала получите каркас и гипотезы от модели, затем проверьте pprof, -race и бенчмарками. Официальные точки входа — go.dev/doc, pkg.go.dev/net/http/pprof, grpc.io/docs/languages/go. Если хотите системно закрыть темы конкурентности, gRPC и профилирования — начните с одного промта из списка на своём коде и доведите его до измеримого результата: latency p99, число аллокаций, размер heap. Такой цикл даёт больше, чем десяток прочитанных статей.
Comments