Шесть фундаментальных принципов, которые служат строительными блоками архитектуры REST API:
Please open Telegram to view this post
VIEW IN TELEGRAM
👍8❤3
This media is not supported in your browser
VIEW IN TELEGRAM
Компилятор shell-скриптов, который превращает их в безопасные, переносимые и статические бинарные файлы.
В отличие от других инструментов, Bunster не просто упаковывает ваш скрипт в бинарник — он компилирует его в автономные программы, не зависящие от оболочки.
👉 https://github.com/yassinebenaid/bunster
👉 @juniorGolang | #ресурсы
В отличие от других инструментов, Bunster не просто упаковывает ваш скрипт в бинарник — он компилирует его в автономные программы, не зависящие от оболочки.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5❤2🌚1
Буферизированные каналы как семафоры для ограничения выполнения горутин
Когда нам нужно управлять тем, сколько горутин могут одновременно получить доступ к ресурсу, использование семафора — надежный подход.
Мы можем создать семафор с помощью буферизированного канала, где размер канала определяет, сколько горутин может выполняться одновременно. Вот как это работает:
🔹 Горутин отправляет значение в канал, занимая одну ячейку.
🔹 После завершения своей задачи он извлекает значение, освобождая тем самым эту ячейку для другой горутины.
В этом примере:
🔹
🔹
Если нужен более аккуратный способ управления этим процессом, можно рассмотреть создание типа
Использование такого пользовательского типа Semaphore упрощает управление доступом к ресурсам в наших функциях.
Также существует реализация семафора в пакете golang.org/x/sync/semaphore, которая представляет собой взвешенный семафор.
Взвешенный семафор позволяет горутине занимать более одной ячейки, что полезно в сценариях, когда задачи требуют разного объема ресурсов.
Например, при управлении пулом подключений к базе данных, где некоторые операции могут одновременно потребовать несколько подключений.
👉 @juniorGolang | #tip
Когда нам нужно управлять тем, сколько горутин могут одновременно получить доступ к ресурсу, использование семафора — надежный подход.
Мы можем создать семафор с помощью буферизированного канала, где размер канала определяет, сколько горутин может выполняться одновременно. Вот как это работает:
В этом примере:
wg.Add(10) — мы подготавливаемся к завершению 10 горутин.make(chan struct{}, 3) — это создает семафор, позволяющий одновременно работать только 3 горутинам.Если нужен более аккуратный способ управления этим процессом, можно рассмотреть создание типа
Semaphore, который будет обрабатывать все действия, связанные с семафором.Использование такого пользовательского типа Semaphore упрощает управление доступом к ресурсам в наших функциях.
Также существует реализация семафора в пакете golang.org/x/sync/semaphore, которая представляет собой взвешенный семафор.
Взвешенный семафор позволяет горутине занимать более одной ячейки, что полезно в сценариях, когда задачи требуют разного объема ресурсов.
Например, при управлении пулом подключений к базе данных, где некоторые операции могут одновременно потребовать несколько подключений.
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
👍11❤1
https://github.com/StarFleetCPTN/GoMFT
Please open Telegram to view this post
VIEW IN TELEGRAM
👍8❤1
Настройка GOMAXPROCS для контейнерных сред (Kubernetes, Docker и др.)
⚠️ (Внимание: длинный и скучный материал)
Что такое GOMAXPROCS?
По умолчанию Go может запускать до 10 000 потоков одновременно, но фактическое количество потоков, выполняющихся параллельно, определяется важным параметром — GOMAXPROCS.
GOMAXPROCS устанавливает ограничение на количество потоков ОС, которые могут одновременно исполнять пользовательский Go-код (не просто конкуррентно, а именно параллельно).
Значение по умолчанию соответствует количеству логических ядер CPU, которое видит ОС (
Например, на моем MacOS это 8 ядер, а значит, Go будет одновременно выполнять до 8 потоков.
Запуск Go в контейнерах (Docker и Kubernetes)
В контейнеризированных средах, таких как Kubernetes, можно задать ограничения по CPU для каждого контейнера. Это означает, что контейнеру разрешено использовать только определённое количество процессорных ресурсов.
Пример:
🔹
🔹
Но проблема в том, что Go не видит эти ограничения. Он по-прежнему определяет количество доступных CPU на уровне хост-машины, а не контейнера.
(Хост-машина или нода может содержать несколько подов.)
Из-за этого Go-приложение может пытаться использовать больше процессорных ресурсов, чем ему выделено.
❓ "Но почему? Ведь чем больше CPU, тем лучше!"
Вот несколько причин, почему это может быть проблемой:
— Контекстные переключения – если потоков больше, чем ядер, ОС вынуждена чаще переключаться между ними.
— Неэффективное планирование – планировщик Go создаёт больше готовых к выполнению горутин, чем CPU может реально обработать, что приводит к избыточной конкуренции за процессорное время.
— Неэффективное выполнение CPU-bound задач – Go-программы часто CPU-bound, а значит, лучше работают, когда каждое ядро загружено ровно одним потоком без необходимости ожидания.
Если GOMAXPROCS больше, чем реально выделенные CPU-ресурсы, Go-рантайм планирует больше потоков, чем есть доступных ядер, что приводит к неэффективному выполнению.
✅ Решение
Если хочется автоматизировать настройку, можно использовать uber-go/automaxprocs. Эта библиотека корректирует GOMAXPROCS в соответствии с ограничением CPU контейнера.
(Если интересно, как работает uber-go/automaxprocs под капотом — просто скажите.)
Если вы понимаете спецификацию деплоя/пода, можно вручную задать переменную окружения
Но с точки зрения DevOps лучше вовсе избегать CPU-лимитов, а вместо них устанавливать только CPU requests (об этом подробнее ниже). Это касается не только Go-сервисов.
Задумайтесь об этом, если в вашем контейнере не задан лимит CPU.
Полезные ссылки:
— Почему не стоит использовать CPU-лимиты в Kubernetes
— Kubernetes CPU Limits и Go
👉 @juniorGolang | #tip
Что такое GOMAXPROCS?
По умолчанию Go может запускать до 10 000 потоков одновременно, но фактическое количество потоков, выполняющихся параллельно, определяется важным параметром — GOMAXPROCS.
GOMAXPROCS устанавливает ограничение на количество потоков ОС, которые могут одновременно исполнять пользовательский Go-код (не просто конкуррентно, а именно параллельно).
Значение по умолчанию соответствует количеству логических ядер CPU, которое видит ОС (
runtime.NumCPU()).Например, на моем MacOS это 8 ядер, а значит, Go будет одновременно выполнять до 8 потоков.
Запуск Go в контейнерах (Docker и Kubernetes)
В контейнеризированных средах, таких как Kubernetes, можно задать ограничения по CPU для каждого контейнера. Это означает, что контейнеру разрешено использовать только определённое количество процессорных ресурсов.
Пример:
limit: 250m = 1/4 ядраlimit: 1 = 1 полное ядроНо проблема в том, что Go не видит эти ограничения. Он по-прежнему определяет количество доступных CPU на уровне хост-машины, а не контейнера.
(Хост-машина или нода может содержать несколько подов.)
Из-за этого Go-приложение может пытаться использовать больше процессорных ресурсов, чем ему выделено.
Вот несколько причин, почему это может быть проблемой:
— Контекстные переключения – если потоков больше, чем ядер, ОС вынуждена чаще переключаться между ними.
— Неэффективное планирование – планировщик Go создаёт больше готовых к выполнению горутин, чем CPU может реально обработать, что приводит к избыточной конкуренции за процессорное время.
— Неэффективное выполнение CPU-bound задач – Go-программы часто CPU-bound, а значит, лучше работают, когда каждое ядро загружено ровно одним потоком без необходимости ожидания.
Если GOMAXPROCS больше, чем реально выделенные CPU-ресурсы, Go-рантайм планирует больше потоков, чем есть доступных ядер, что приводит к неэффективному выполнению.
Если хочется автоматизировать настройку, можно использовать uber-go/automaxprocs. Эта библиотека корректирует GOMAXPROCS в соответствии с ограничением CPU контейнера.
(Если интересно, как работает uber-go/automaxprocs под капотом — просто скажите.)
Если вы понимаете спецификацию деплоя/пода, можно вручную задать переменную окружения
GOMAXPROCS в соответствии с лимитом.Но с точки зрения DevOps лучше вовсе избегать CPU-лимитов, а вместо них устанавливать только CPU requests (об этом подробнее ниже). Это касается не только Go-сервисов.
Задумайтесь об этом, если в вашем контейнере не задан лимит CPU.
Полезные ссылки:
— Почему не стоит использовать CPU-лимиты в Kubernetes
— Kubernetes CPU Limits и Go
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
👍11❤2
https://github.com/openbao/openbao
Please open Telegram to view this post
VIEW IN TELEGRAM
GitHub
GitHub - openbao/openbao: OpenBao exists to provide a software solution to manage, store, and distribute sensitive data including…
OpenBao exists to provide a software solution to manage, store, and distribute sensitive data including secrets, certificates, and keys. - openbao/openbao
❤4👍2
Оптимизируйте множественные вызовы с помощью singleflight
Допустим, у вас есть функция, которая получает данные по сети или выполняет ввод-вывод, и её выполнение занимает около 3 секунд:
Эта функция выдаёт новое значение каждые 10 секунд.
🔹 Если вызвать эту функцию 3 раза подряд, общее время ожидания составит примерно 9 секунд.
🔹 Если использовать 3 горутины, общее время ожидания может сократиться до 3 секунд, но функция всё равно будет вызвана 3 раза для получения одного и того же результата (~99%).
Здесь на помощь приходит пакет singleflight, который доступен по ссылке:
👉 golang.org/x/sync/singleflight.
Этот пакет позволяет выполнить функцию только один раз, независимо от того, сколько раз она была вызвана за эти 3 секунды, и возвращает один общий результат.
Это отлично подходит для оптимизации функций, работающих долго или потребляющих много ресурсов.
Как это работает?
1️⃣ Создаём объект
2️⃣ Передаём в метод
Метод
Параметр
Зачем нужен аргумент
Ключ (
Если поступает несколько запросов с одним и тем же ключом,
Пример работы: Go Playground
С этим подходом, если функция вызывается несколько раз одновременно, фактически выполняется только один её вызов. А результат этого единственного вызова разделяется между всеми ожидающими
👉 @juniorGolang | #tip
Допустим, у вас есть функция, которая получает данные по сети или выполняет ввод-вывод, и её выполнение занимает около 3 секунд:
Эта функция выдаёт новое значение каждые 10 секунд.
Здесь на помощь приходит пакет singleflight, который доступен по ссылке:
Этот пакет позволяет выполнить функцию только один раз, независимо от того, сколько раз она была вызвана за эти 3 секунды, и возвращает один общий результат.
Это отлично подходит для оптимизации функций, работающих долго или потребляющих много ресурсов.
Как это работает?
singleflight.Groupgroup.Do() функцию, которая выполняет дорогостоящие вычисления.Метод
group.Do() возвращает:(result any, err error, shared bool)
Параметр
shared показывает, был ли результат разделён между несколькими вызовами.Зачем нужен аргумент
key?Ключ (
key) — это идентификатор запроса.Если поступает несколько запросов с одним и тем же ключом,
singleflight понимает, что они запрашивают одно и то же.Пример работы: Go Playground
С этим подходом, если функция вызывается несколько раз одновременно, фактически выполняется только один её вызов. А результат этого единственного вызова разделяется между всеми ожидающими
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
👍10❤2
https://github.com/goipay/goipay
Please open Telegram to view this post
VIEW IN TELEGRAM
GitHub
GitHub - goipay/goipay: A lightweight crypto payment processor microservice, written in Golang, designed for creating and processing…
A lightweight crypto payment processor microservice, written in Golang, designed for creating and processing cryptocurrency invoices via gRPC. - goipay/goipay
👍6❤2
Разбор DNS: от основ до создания DNS-сервера на Go
Статья объясняет основы DNS, процесс разрешения доменных имен и создание собственного DNS-сервера на Go.
Автор рассматривает работу DNS-запросов и делится проектом DNS-сервера с веб-интерфейсом на GitHub.
Полезно для изучающих сети и Go
👉 Читать
👉 @juniorGolang | #cтатья
Статья объясняет основы DNS, процесс разрешения доменных имен и создание собственного DNS-сервера на Go.
Автор рассматривает работу DNS-запросов и делится проектом DNS-сервера с веб-интерфейсом на GitHub.
Полезно для изучающих сети и Go
Please open Telegram to view this post
VIEW IN TELEGRAM
👍6❤3🤔1
https://github.com/Vein05/nomnom
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4❤1🔥1😁1
Фильтрация без лишних аллокаций
При фильтрации слайсов в Go стандартный подход — создание нового слайса для отфильтрованных элементов.
Однако такой метод приводит к дополнительным аллокациям памяти.
Более эффективный способ — фильтровать «на месте», используя исходный массив слайса.
Как это работает:
•
• Добавляя
Таким образом, мы не выделяем новую память, а заполняем уже существующий массив.
Этот метод особенно полезен, когда:
•
• Критична производительность, особенно при работе с большими объемами данных.
👉 @juniorGolang | #tip
При фильтрации слайсов в Go стандартный подход — создание нового слайса для отфильтрованных элементов.
Однако такой метод приводит к дополнительным аллокациям памяти.
Более эффективный способ — фильтровать «на месте», используя исходный массив слайса.
Как это работает:
•
filtered := numbers[:0] создаёт новый слайс filtered, который ссылается на тот же массив, что и numbers, но имеет нулевую длину, сохраняя емкость numbers. • Добавляя
num в filtered, мы избегаем лишних аллокаций, так как просто изменяем содержимое numbers (или его базового массива).Таким образом, мы не выделяем новую память, а заполняем уже существующий массив.
Этот метод особенно полезен, когда:
•
numbers больше не нужен после фильтрации.• Критична производительность, особенно при работе с большими объемами данных.
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
👍16🔥7❤3👎1
https://github.com/yusing/godoxy
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5❤3
Leak and Seek: A Go Runtime Mystery
Статья описывает расследование команды Cyolo, связанное с утечкой памяти в приложении на языке Go. После сообщений клиентов о проблемах с производительностью команда обнаружила, что утечка связана с объектами SqliteRows, SqliteStmt и SqliteConn в драйвере SQLite3.
Они исследовали возможность циклических ссылок и проблемы с механизмом финализаторов в Go, но выяснили, что причиной была блокировка горутины финализатора из-за функции Close в пакете go-smb2, выполняющей потенциально блокирующие операции ввода-вывода.
Это приводило к задержке освобождения памяти и утечке ресурсов. В результате команда предложила улучшения для мониторинга финализаторов и сообщила о найденных проблемах сообществу Go
👉 Читать
👉 @juniorGolang | #cтатья
Статья описывает расследование команды Cyolo, связанное с утечкой памяти в приложении на языке Go. После сообщений клиентов о проблемах с производительностью команда обнаружила, что утечка связана с объектами SqliteRows, SqliteStmt и SqliteConn в драйвере SQLite3.
Они исследовали возможность циклических ссылок и проблемы с механизмом финализаторов в Go, но выяснили, что причиной была блокировка горутины финализатора из-за функции Close в пакете go-smb2, выполняющей потенциально блокирующие операции ввода-вывода.
Это приводило к задержке освобождения памяти и утечке ресурсов. В результате команда предложила улучшения для мониторинга финализаторов и сообщила о найденных проблемах сообществу Go
Please open Telegram to view this post
VIEW IN TELEGRAM
👍9❤2😁2