Go for Devs – Telegram
Go for Devs
1.07K subscribers
49 photos
17 videos
64 links
По сотрудничеству пишите в личные сообщения канала.
Download Telegram
🗑 Сборщик мусора в Go. Часть 3: Управление скоростью GC

Команда Go for Devs подготовила перевод статьи о том, как в Go устроено управление скоростью работы сборщика мусора.

TL;DR: даже при тысячах горутин GC подстраивается под нагрузку, выбирая между меньшим числом долгих пауз и большим числом коротких.

Итог — разработчику почти не нужно вручную «крутить» настройки, рантайм сам находит оптимальный ритм.

📚 Подробности на Хабр: https://habr.com/ru/articles/953426/

Первая статья из серии.
Вторая статья из серии.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5🔥31
🪲 Cloudflare нашли редчайший баг — прямо в компиляторе Go для ARM64!

Да, это не опечатка: не рантайм, не race condition в их коде, а чистый косяк в сгенерированном машинном коде Go. И баг был настолько редким, что проявиться он мог только в инфраструктуре масштаба Cloudflare — при 84 миллионах HTTP-запросов в секунду.

На ARM64-машинах Cloudflare стали вылезать странные паники вроде traceback did not unwind completely — ошибка, указывающая на повреждённый стек при попытке раскрутки. Поначалу инженеры списали это на баг в старом коде с panic/recover, потом — на библиотеку Go Netlink. Но когда даже без неё паники продолжились, стало ясно: проблема глубже.

После недель отладки выяснилось: краш происходит при асинхронном вытестении (введённом в Go 1.14), когда рантайм прерывает горутину между двумя машинными инструкциями, корректирующими указатель стека. В этот момент стек оказывается в «разрезанном» состоянии — раскрутчик стека получает некорректный указатель и падает.

Инженеры написали минимальный Go-пример, где функция с большим стеком (>64 КБ) порождает тот самый двойной ADD. После пары минут работы программа стабильно умирала с SIGSEGV. Без сторонних библиотек. Только чистый Go.

package main

import (
"runtime"
)

//go:noinline
func big_stack(val int) int {
var big_buffer = make([]byte, 1 << 16)

sum := 0
// предотвращаем оптимизацию стека компилятором
for i := 0; i < (1<<16); i++ {
big_buffer[i] = byte(val)
}
for i := 0; i < (1<<16); i++ {
sum ^= int(big_buffer[i])
}
return sum
}

func main() {
go func() {
for {
runtime.GC()
}
}()
for {
_ = big_stack(1000)
}
}

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

Go-команда признала баг и исправила его в версиях go1.23.12, go1.24.6 и go1.25.0.

Получается, даже компиляторы ошибаются) Просто чтобы поймать такой баг, нужно немного — пара сотен дата-центров и десятки миллионов запросов в секунду.

Источник

@go_for_devs
👍10🔥9🤯61
Как структурировать маршруты в Gin

При разработке веб-API у вас часто бывает множество конечных точек, логически связанных между собой. Например, один набор маршрутов — для управления пользователями, другой — для работы с товарами, третий — для обработки заказов. Без должной организации ваш код быстро превращается в хаотичный набор маршрутов, который трудно читать, сопровождать и развивать.


r.GET("/books", getBooks)
r.POST("/books", createBook)
r.GET("/members", getMembers)
r.POST("/members", createMember)


Здесь на помощь приходит группировка маршрутов. Она позволяет объединять связанные маршруты под общим префиксом пути. Представьте, что вы создаёте «папки» для маршрутов: каждая группа содержит набор конечных точек, которые относятся друг к другу. Это не только повышает читаемость кода, но и упрощает применение общего поведения (например, middleware) к определённым группам маршрутов.


package main

import (
"github.com/gin-gonic/gin"
)

func main() {
r := gin.Default()

// Grouping book-related routes
bookGroup := r.Group("/books")
{
bookGroup.GET("/", getBooks)
bookGroup.POST("/", createBook)
}

// Grouping member-related routes
memberGroup := r.Group("/members")
{
memberGroup.GET("/", getMembers)
memberGroup.POST("/", createMember)
}

r.Run()
}


Заметьте, насколько чище стало: все маршруты, связанные с книгами, сгруппированы под /books, а все, связанные с читателями, — под /members. Это упрощает навигацию по коду и понимание его структуры.

📚 Подробности на Хабр: https://habr.com/ru/articles/955802/
Please open Telegram to view this post
VIEW IN TELEGRAM
👍74🔥2🤯1
🫢 А вы знали, что у Go есть свой ML-фреймворк?

И называется он GoMLX, развивается с 2023 года — и, внимание, всё ещё жив! Последний коммит был пару недель назад.

GoMLX — это полноценный фреймворк на чистом Go, без Python и C++ под капотом. Он умеет всё, что должен уметь взрослый AI-инструмент: автодифф, готовые слои вроде LSTM и Attention, оптимизаторы (SGD, Adam), визуализацию, чекпоинты и даже метрики обучения.

За скорость отвечает OpenXLA/PJRT — тот же движок, что крутит JAX и TensorFlow. А если хочется поиграть — можно запустить модели прямо в браузере через WASM.

Разработчик уже показал демки: классификатор “кошки против собак”, diffusion-модель и даже AlphaZero-бот, который играет в настольную игру Hive. Всё это — на Go.

Конечно, GoMLX пока не собирается отбирать хлеб у PyTorch (будем честны, и не смог бы), но сам факт впечатляет: язык, который когда-то ассоциировался с микросервисами и горутинами, теперь присутствует и на территории машинного обучения.

GitHub
Туториал
Сравнение с Python
Попробовать

@go_for_devs
10👍7🔥5
⚡️ 1 000 000 узлов в Kubernetes

Кажется, кто-то снова решил побить рекорды: проект k8s-1m замахнулся на кластер из миллиона узлов.

Если вкратце:

1. Команда проекта разделила данные по степени важности. Критически важная информация сохраняется надёжно, а временные данные — такие как сигналы активности узлов — обрабатываются в упрощённом режиме, без избыточных гарантий. Это позволило значительно повысить производительность при большом числе операций.

2. Сетевой уровень построен на IPv6, что устраняет необходимость в NAT и дополнительной маршрутизации. Вместо одного централизованного планировщика используется распределённая схема: несколько независимых компонентов обрабатывают свои части кластера и передают результаты агрегатору. Такой подход снижает нагрузку и ускоряет распределение задач между узлами.

3. Основное ограничение выявилось не в самом Kubernetes, а в используемом хранилище данных. Стандартный etcd оказался узким местом при высокой частоте обновлений. В проекте его заменили на более лёгкую in-memory реализацию, что позволило увеличить скорость обработки и снизить задержки.

Главный вывод — масштаб системы определяется не количеством узлов, а скоростью и эффективностью работы с данными. При росте инфраструктуры важно разграничивать типы нагрузок, оптимизировать хранение и использовать горизонтальное масштабирование вместо усложнения отдельных компонентов.

Полный обзор на Хабр
Инструкция по запуску

@go_for_devs
🔥5🤯42
💥 Как memory maps (mmap) обеспечивают в 25 раз более быстрый доступ к файлам в Go

Одно из самых медленных действий, которое можно совершить в приложении, — это системный вызов. Они медленные, потому что требуют перехода в ядро, а это дорогостоящая операция. Что делать, если нужно выполнять много операций ввода-вывода с диском, но при этом важна производительность? Один из вариантов — использовать memory maps.

Memory maps — это современный механизм Unix, позволяющий «включить» файл в виртуальную память. В контексте Unix «современный» означает появившийся где-то в 1980-х или позже. У вас есть файл с данными, вы вызываете mmap, и получаете указатель на участок памяти, где эти данные находятся. Теперь, вместо того чтобы делать seek и read, вы просто читаете по этому указателю, регулируя смещение, чтобы попасть в нужное место.

Производительность

Ниже сравнение производительности при чтении файла через memory map и через ReaderAt. ReaderAt использует системный вызов pread(), совмещающий seek и read, а mmap просто читает напрямую из памяти.


Случайное чтение (ReaderAt): 416.4 ns/op
Случайное чтение (mmap): 3.3 ns/op
---
Итерация (ReaderAt): 333.3 ns/op
Итерация (mmap): 1.3 ns/op


Почти как магия. Возможно кто-то из вас помнит Varnish Cache – ускоритель HTTP, разработанный для динамических веб-сайтов с большим количеством контента. В 2006 году именно эта возможность делала его настолько быстрым при выдаче контента. Varnish Cache использовал memory maps, чтобы доставлять данные с невероятной скоростью.

Кроме того, поскольку можно работать с указателями на память, выделенную memory map, снижается нагрузка на память и уменьшается общая задержка.

Обратная сторона memory maps

Недостаток memory maps в том, что по сути в них нельзя писать. Причина кроется в устройстве виртуальной памяти.
Когда вы пытаетесь записать в область виртуальной памяти, которая не отображена на физическую, процессор вызывает page fault. Современный CPU отслеживает, какие страницы виртуальной памяти соответствуют каким физическим страницам. Если вы пишете в страницу, которая не сопоставлена, процессору нужна помощь.

При page fault операционная система:

1. Выделяет новую страницу памяти.
2. Считывает содержимое файла по нужному смещению.
3. Записывает это содержимое в новую страницу.
4. Затем управление возвращается приложению, и оно перезаписывает эту страницу новыми данными.

Можно просто поаплодировать тому, насколько это неэффективно. Думаю, можно с уверенностью сказать: писать через memory map — плохая идея, если важна производительность, особенно если есть риск, что файл ещё не загружен в физическую память.

Вот несколько бенчмарков:

Запись через mmap, страницы не в памяти: 1870 ns/op
Запись через mmap, страницы в памяти: 79 ns/op
WriterAt: 303 ns/op


Как видно, наличие страниц в кэше критически влияет на производительность. WriterAt, использующий системный вызов pwrite, даёт куда более предсказуемые результаты.

Тем не менее, в начале Varnish Cache действительно писал через memory map. Как-то это срабатывало — в основном потому, что конкуренты тогда были гораздо хуже.

Источник

@go_for_devs
👍84🔥3👎2
💥 Google представил Green Tea GC — сборщик мусора, который экономит до 40% CPU

Новый сборщик мусора в Go – Green Tea GC – уже тестируют в продакшене Google, и результаты ошеломляют — до 40% меньше времени на сборку мусора.

Исследование провели инженеры Google — Michael Knyszek и Austin Clements. Их цель: адаптировать Go GC под современные многоядерные процессоры, где традиционные алгоритмы просто застревают в ожидании кэш-памяти. Green Tea дебютировал в Go 1.25 как эксперимент (через GOEXPERIMENT=greenteagc), и уже в Go 1.26 его планируют включить по умолчанию.

Главные инсайты:
🟣 Green Tea переходит от сканирования объектов к сканированию страниц памяти — это резко ускоряет обработку
🟣 В процессе сборки мусора теперь происходит меньше случайных обращений к памяти
🟣 В среднем — на 10% меньше CPU времени на GC, максимум — до 40% экономии
🟣 На новых CPU с AVX-512 ожидается ещё +10% ускорения благодаря векторным инструкциям
🟣 Уже к Go 1.26 это будет дефолтный GC (с возможностью откатить через GOEXPERIMENT=nogreenteagc)

Green Tea не появился из ниоткуда, он стал результатом многолетней командной работы. Идея родилась ещё в 2018-м, обрела форму в 2024-м, когда прототип писали в японских кафе за чашкой матча, и превратилась в продакшн-технологию в 2025-м (см. картинку). Это пример того, как одно простое инженерное озарение становится революцией, когда за ним стоит сообщество.

Источник

@go_for_devs
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥11👍54🤔1🤯1
This media is not supported in your browser
VIEW IN TELEGRAM
🥳 Go исполнилось 16 лет: главное о развитии языка и экосистемы

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

Вот главное, что произошло вокруг именинника за последнее время:

🟣 К одному из самых заметных прорывов относится новый сборщик мусора Green Tea, который снижает накладные расходы на 10–40%. Для продакшн-сервисов это означает меньше пауз, стабильнее задержки и ощутимый выигрыш без каких-либо доработок в коде. Подробнее про него мы писали тут.

🟣 Не менее значимый апдейт — flight recorder для диагностики: он сохраняет последние миллисекунды жизни сервиса и позволяет понять, что случилось, даже если проблема проявилась спустя часы. Подробнее про него мы писали тут.

🟣 А ещё Go уверенно заходит в эпоху ИИ: официальный MCP SDK и интеграции в gopls формируют прочный фундамент для разработки агентных систем и инструментов прямо на Go.

Команда обещает, что это только начало — и обороты они точно снижать не собираются.

@go_for_devs
Please open Telegram to view this post
VIEW IN TELEGRAM
👍11👏4🔥21
Forwarded from AI for Devs
😬 TOON: новый формат на смену JSON для более эффективного взаимодействия с LLM?

TOON — это ещё один способ записать те же самые JSON-данные, но компактнее и понятнее для моделей. Вместо  "key": "value" он использует отступы как YAML и табличную запись для массивов объектов: шапка с названиями полей, дальше строки с данными.

Пример из README: вместо обычного JSON с пользователями — строка users[2]{id,name,role}: и две строки 1,Alice,admin и 2,Bob,user. Структура при этом не теряется: объекты, массивы и примитивы остаются теми же, формат — просто «другая запись» того же JSON.

Главная идея — экономия токенов и более предсказуемое поведение LLM на больших массивах данных. Помните, мы даже рассказывали про то, что от формата напрямую может зависеть результат генерации.

В бенчмарках TOON даёт порядка 30–60% экономии токенов на больших ровных массивах объектов по сравнению с форматированным JSON и заметно меньше, но всё равно ощутимо — против compact JSON. На ряде задач TOON показывает чуть более высокую точность ответов, чем обычный JSON при меньшем числе токенов.

При этом авторы честно фиксируют зоны, где TOON не выгоден.

Если структура сильно вложенная, неравномерная и почти не подходит под табличный вид, компактный JSON в тестах иногда оказывается короче. Если данные вообще чисто табличные и плоские, CSV по-прежнему даёт минимальный размер, а TOON добавляет небольшой оверхед ради явной структуры и валидации.


То есть формат заточен именно под «много однотипных объектов с примитивными полями», а не под любые данные подряд.

Для использования уже есть CLI через npx @toon-format/cli и TypeScript-библиотека @toon-format/toon.

@ai_for_devs
😁7👍3🔥3
🐘 Kafka реально быстрая, но я возьму Postgres

Перевели довольно длинный, но приземлённый разбор: зачем большинству проектов вообще тащить Kafka и пять разных баз, если тот же Postgres спокойно закрывает типичные нагрузки. Автор не просто рассуждает — он гоняет бенчмарки и смотрит, насколько далеко можно уехать на одном Postgres в сценариях pub/sub и очередей.

Если коротко, то по мир можно поделить на два лагеря:

🟣 Первый — «резюме-дривен девелопмент»: берём модные стеки, потому что «так делают большие компании» и «это спрашивают на собесах», даже если реальная нагрузка — пара мегабайт в секунду.

🟣 Второй — те, кто начинают с базовых вещей и считают не только RPS, но и организационные издержки: новые системы надо изучать, мониторить, обновлять, поддерживать, и это обходится дороже, чем кажется. На этом фоне логика «просто используйте Postgres, пока не упрётесь в реальные лимиты» выглядит вполне рационально.

В бенчмарках Postgres выступает как и pub/sub, и очередь: десятки тысяч сообщений в секунду, мегабайты входящего/исходящего трафика, на относительно скромных инстансах и без экзотического тюнинга. Да, Kafka и спецочереди по-прежнему лучше оптимизированы под свои задачи и выигрывают на очень больших масштабах. Но до этих масштабов большинство систем просто не доходит — и в подавляющем числе кейсов упираться будете не в базу, а в продукт, команду или деньги.

Вместо «архитектуры как у Google» лучше думать в терминах минимально жизнеспособной инфраструктуры: взять Postgres и использовать его максимально просто и добавлять новые технологии только тогда, когда они реально нужны. Чем меньше компонентов — тем меньше точек отказа и меньше клейкого кода между ними.

Краткий вывод от статьи такой: начните с Postgres, держите стек простым, а к Kafka и прочим тяжёлым системам приходите только тогда, когда у вас действительно появятся проблемы их масштаба. Всё остальное — из серии «преждевременная оптимизация».

@go_for_devs
Please open Telegram to view this post
VIEW IN TELEGRAM
👍175🔥3🤔2
🫡 Gemini 3 Pro стала доступна в JetBrains IDE

Думаю все уже слышали, что вчера вышла Gemini 3 Pro Preview – флагманская модель от Google, SOTA практически по всем известным бенчмаркам.

Исключением как раз является SWE-бенч. В нём Claude Sonnet 4.5 остался лидером.

JetBrains добавили Gemini 3 Pro в свои IDE. Теперь она доступна в AI Chat, а скоро доберётся до Junie, фирменного агента от JetBrains.

@go_for_devs
👍6🔥63🤔1
📊 Экосистема Go сегодня: что изменилось в 2025 году

Перевели подробный разбор того, как эволюционировала экосистема Go к 2025 году — от фреймворков и тестовых библиотек до инструментов для DevOps и AI-редакторов.

Общее впечатление после прочтения такое: за пять лет Go стал заметно популярнее, инструментов стало больше, AI-редакторов — тоже, но принципиально почти ничего не поменялось. Подходы остаются прежними.

Мы всё так же используем gin, net/http и GoLand. Разве что значительно выросла доля тех, кто предпочитает встроенный пакет testing — теперь им пользуются 60% разработчиков против 35% пять лет назад.

Интересы Go-сообщества тоже практически не изменились: те же Kubernetes, те же базы данных, те же сервисы для логирования.

И, пожалуй, это скорее плюс. Экосистема растёт вместе с количеством разработчиков, но без резких поворотов и кардинальных перемен, которые обычно вносят хаос и заставляют команды перестраивать процессы.

@go_for_devs
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
👍10🔥42
💡 Почему маленькие интерфейсы делают Go-код ощутимо лучше

Подготовили разбор о том, почему огромные интерфейсы в Go — это тихий архитектурный антипаттерн, который портит тесты, замедляет разработку и делает код хрупким. Автор идёт от практики: берёт реальный код, смотрит, как широкие контракты тянут за собой ненужные зависимости, и показывает, почему принцип разделения интерфейсов (тот самый ISP из SOLID) в Go работает почти автоматически — если ему не мешать.

Автор показывает всё на конкретном коде: сначала простой FileStorage, который вроде бы удобен… пока не нужно протестировать функцию, использующую всего один метод. Потом — S3-клиент из AWS SDK, где желание «обернуть всё интерфейсом» быстро приводит к монстру из десятков методов, который привязывает весь проект к одному определению.

Статья объясняет, как Go естественным образом подталкивает к маленьким интерфейсам: вы определяете контракт рядом с потребителем, оставляете только нужное поведение и получаете код, который проще тестировать, легче менять и труднее сломать случайным обновлением зависимостей.

Коротко: широкие интерфейсы — это технический долг, который маскируется под «архитектурную зрелость». Маленькие интерфейсы — это практичный, Go-шный путь к читаемому и поддерживаемому коду.

📚 Читать на Хабр: https://habr.com/ru/articles/967730/
Please open Telegram to view this post
VIEW IN TELEGRAM
👍9🔥32
🔥 Самая важная новость недели)

Git 3.0 по умолчанию будет создавать ветку main!

Через 16 лет после появления master Git меняет дефолтную ветку на main, чтобы точно не задеть ни чьи чувства 😊

История вопроса тянется давно. Software Freedom Conservancy ещё в 2020 году заявила о планах отказаться от master в пользу более нейтрального названия.

Через несколько месяцев этот шаг сделал GitHub, автоматически создавая main во всех новых репозиториях. Но сам Git до сегодняшнего дня сохранял старое поведение, перекладывая ответственность на пользователя.

Git 2.52 уже закрепил это в патч-нотах, а к релизу 3.0 (где-то в 2026) проект ждут и другие апгрейды: переход на SHA-256, новый формат хранения и даже чуть-чуть Rust под капотом.

Ушла эпоха)

@go_for_devs
😢13👍5😁4😱1