Наконец-то выбрался из леса, а это значит, что скоро будут новые посты
🥰6🔥4🏆4💅2👏1🕊1
Небольшой интересный факт о gRPC.
При реализации gRPC сервера, нельзя указать в приложении алгоритм сжатия отправляемого сообщения.
Алгоритм сжатия берется из заголовка запроса
То есть алгоритм сжатия определяет клиент.
При реализации gRPC сервера, нельзя указать в приложении алгоритм сжатия отправляемого сообщения.
Алгоритм сжатия берется из заголовка запроса
grpc-encoding (документация) (код).То есть алгоритм сжатия определяет клиент.
😱5✍4🤓3💅1
Мебибайты и кибибайты.
Меня достаточно давно смущало:
Приставки из СИ (Système international) это степени числа 10
То есть:
10^3 это кило
10^6 это мега
Но когда мы говорим про 1 килобайт, мы говорим про 1024 байт, а не про 1000 байт.
К примеру — код pprof, в исходном коде Go:
И вот, некоторая путаница cуществует с 60-х годов
— Понятия бит введено в 1948 году ( A Mathematical Theory of Communication ).
— В 1950 впервые используется приставка кило для бит, в качестве 1000 бит.
— В 1964 использование приставки K в качестве степени 2 ( A Time-Shared Computer for Real-Time Information Processing ).
Для решения этой путаницы в августе 1995 года добавляют новые приставки, которых нет в СИ:
В вики указан 1998, это когда МЭК ввел
Которые уже обозначают степени числа 2 (2^10, 2^20...).
То есть:
В итоге: спустя 30 лет, после появления приставок степени двойки, путаницы еще больше, уже в течении 60 лет (!!!).
— Проводник в Windows показывает размер в KB, когда на самом деле KiB.
— Внутри Go где-то правильное использование приставок, а где-то нет.
— Приложения GNU вроде (не все проверял) корректно дружат (parted, ls).
— Grafana знает про приставки степени двойки.
— Международное бюро мер и весов (создатели СИ) в брошюре 2019 года написали о том что: приставки СИ сугубо степени числа 10, а приставки степени числа 2 это не СИ не стоит их путать.
Меня достаточно давно смущало:
Приставки из СИ (Système international) это степени числа 10
То есть:
10^3 это кило
10^6 это мега
Но когда мы говорим про 1 килобайт, мы говорим про 1024 байт, а не про 1000 байт.
К примеру — код pprof, в исходном коде Go:
{"kB", []string{"kb", "kbyte", "kilobyte"}, float64(1 << 10)}И вот, некоторая путаница cуществует с 60-х годов
— В 1950 впервые
— В 1964 использование приставки K в качестве степени 2 (
Для решения этой путаницы в августе 1995 года добавляют новые приставки, которых нет в СИ:
kibi (Ki), mebi (Mi), gibi (Gi) and tebi (Ti)
Которые уже обозначают степени числа 2 (2^10, 2^20...).
То есть:
14 КB (килобайт) = 14*10^3 = 14_000 байт
14 KiB (кибибайт) = 14*2^10 = 14_336 байт
В итоге: спустя 30 лет, после появления приставок степени двойки, путаницы еще больше, уже в течении 60 лет (!!!).
— Проводник в Windows показывает размер в KB, когда на самом деле KiB.
— Внутри Go где-то правильное использование приставок, а где-то нет.
— Приложения GNU вроде (не все проверял) корректно дружат (parted, ls).
— Grafana знает про приставки степени двойки.
— Международное бюро мер и весов (создатели СИ) в брошюре 2019 года написали о том что: приставки СИ сугубо степени числа 10, а приставки степени числа 2 это не СИ не стоит их путать.
💅3✍2🐳2
Кажется что в Go скоро появятся новые директивы:
Они будут нужны для новой миграционной тулзы:
На сколько я понял:
А c
К примеру:
Меняется на:
Как по мне, выглядит несколько странно.
P.S.
Не совсем понятно как будет решаться проблема с пересечением скоупа.
Кажется тогда код с которым осуществляется работа может стать максимально некрасивым :с
//go:fix inline
//go:fix forward
Они будут нужны для новой миграционной тулзы:
go fix, которая переписывает на новый API после обновления Go (подробнее можно почитать тут).На сколько я понял:
//go:fix forward — просто меняет обратно совместимую сущность.А c
//go:fix inline чуть муторнее, go fix будет просто инлайнить тело функцииК примеру:
package a
func f() {
One() // want `inline call of a.One`
new(T).Two() // want `inline call of \(a.T\).Two`
}
type T struct{}
//go:fix inline
func One() int { return one } // want One:`goFixInline a.One`
const one = 1
//go:fix inline
func (T) Two() int { return 2 } // want Two:`goFixInline \(a.T\).Two`
Меняется на:
package a
func f() {
_ = one // want `inline call of a.One`
_ = 2 // want `inline call of \(a.T\).Two`
}
type T struct{}
//go:fix inline
func One() int { return one } // want One:`goFixInline a.One`
const one = 1
//go:fix inline
func (T) Two() int { return 2 } // want Two:`goFixInline \(a.T\).Two`
Как по мне, выглядит несколько странно.
P.S.
Не совсем понятно как будет решаться проблема с пересечением скоупа.
Кажется тогда код с которым осуществляется работа может стать максимально некрасивым :с
GitHub
cmd/fix: automate migrations for simple deprecations · Issue #32816 · golang/go
(I've mentioned this in passing on #32014 and #27248, but I don't see an actual proposal filed yet — so here it is!) Over time, the author of a package may notice certain patterns in the us...
👍4✍1❤1👨💻1👀1💅1👾1
Является ли число Pi корректным destination для ping?
PI=3.14159265 ping ${PI}
PI=3.14159265 ping ${PI}
Anonymous Quiz
62%
✅ Да
38%
❌ Нет
🤨3🍌1💅1👾1
Постом выше спрашивал про
А вот и ответ:
🥁🥁🥁
Число
Почему?
Ping использует функцию inet_aton().
И man, говорит про эту функцию следующее:
В итоге, пингануть
🤯 🤯 🤯
Откуда это все пошло:
- 1983,
- 1990,
- 1999,
- 2004,
- 2005,
- 2020,
ping.А вот и ответ:
🥁🥁🥁
Число
Pi для команды ping является корректным аргументом.Почему?
Ping использует функцию inet_aton().
И man, говорит про эту функцию следующее:
a.b.c.d
Each of the four numeric parts specifies a byte of the address; the bytes are assigned in left-to-right order to produce the binary address.
a.b.c
Parts a and b specify the first two bytes of the binary address. Part c is interpreted as a 16-bit value that defines the rightmost two bytes of the binary address. This notation is suitable for specifying (outmoded) Class B network addresses.
a.b
Part a specifies the first byte of the binary address. Part b is interpreted as a 24-bit value that defines the rightmost three bytes of the binary address. This notation is suitable for specifying (outmoded) Class C network addresses.
a
The value a is interpreted as a 32-bit value that is stored directly into the binary address without any byte rearrangement.
В итоге, пингануть
127.0.0.1 можно просто через ping 127.1 или через 0x7F.1, или через 2130706433...Откуда это все пошло:
- 1983,
4.2BSD. Первое появление подобной логики, в функции inet_addr().- 1990,
4.3BSD-Reno. Появление функции inet_aton().- 1999,
Networking Services (XNS) Issue 5.2. Описывает inet_addr(), с подобным синтаксисом.- 2004,
POSIX. Взятое из XNS ассоциация IEEE добавляет в POSIX функции: inet_addr(), inet_ntoa(), сохраняя поведение (link, и через поиск этих функций).- 2005,
RFC 3986, Запрещает подобный синтаксис для URI, хотя в chromium based браузерах оно работает http://2915189091 (ссылка не работает на этом тексте, так что только через ^c ^v).- 2020,
Golang. Создано issue с предложением добавить описанную выше логику в пакет net, спустя почти пять лет (4 декабря 2024) закрывают issue как "not planned".Please open Telegram to view this post
VIEW IN TELEGRAM
✍3👍2🔥2👾2❤🔥1😁1😱1💅1
Please open Telegram to view this post
VIEW IN TELEGRAM
go.dev
Go 1.24 Release Notes - The Go Programming Language
🔥10👏3❤1✍1👌1💅1
Ранее писал про новую директиву
Alan Donovan из Go team недавно сделал PR, в котором добавил в пакеты
Здесь выглядит симпатично, *НО* это сделал инженер из Go team, а какое качество будет у разработчиков сторонних библиотек?
В целом, я буду делать по старинке, через
Как мне кажется, лучше было бы через
//go:fix inline.Alan Donovan из Go team недавно сделал PR, в котором добавил в пакеты
ioutil и reflect эту директиву для некоторых функций.Здесь выглядит симпатично, *НО* это сделал инженер из Go team, а какое качество будет у разработчиков сторонних библиотек?
В целом, я буду делать по старинке, через
golangci-lint искать deprecated функции и руками буду править.Как мне кажется, лучше было бы через
go vet предупреждение сделать, а не править так исходный код.✍5🔥1💅1💘1👾1
Недавно вспоминал о своем докладе: "Почему Docker написан на Go", который я готовил год назад для подлодки.
В этом докладе вас ждет:
- 🕵️ Теория заговора
- 📅 История контейнеризации с 1979 года
- 💔 Почему K8s отказался от Docker (спойлер: не совсем отказался)
- 📑 Не совсем публичные слайды команды dotCloud (ex Docker, inc)
📺 Смотреть
P.S. Все еще актуально, как и год назад!👀
В этом докладе вас ждет:
- 🕵️ Теория заговора
- 📅 История контейнеризации с 1979 года
- 💔 Почему K8s отказался от Docker (спойлер: не совсем отказался)
- 📑 Не совсем публичные слайды команды dotCloud (ex Docker, inc)
P.S. Все еще актуально, как и год назад!
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥9❤5🥰2
Ранее говорил о
И вот в новой версии Go (1.25) уже не понадобится библиотека github.com/uber-go/automaxprocs, так как
Уже даже документация обновлена для
GOMAXPROCS и cgroup.И вот в новой версии Go (1.25) уже не понадобится библиотека github.com/uber-go/automaxprocs, так как
cgroup для GOMAXPROCS будет учитываться "из коробки".Уже даже документация обновлена для
master ветки.🔥10✍3❤2🍓1💅1
Я пропустил что в Go 1.22 добавили работу с относительно новой сущностью Linux
Зачем это в Linux?
Работа с
- Получаем
- Процесс умирает,
- ОС создает новый процесс, переиспользуя
- В итоге мы работаем с совершенно другим процессом.
Это причина уязвимостей: CVE-2019-6133, CVE-2019-15790... А так же причина одного из issue у Go .
Решение
В Linux 5.1 появился системный вызов
Дальше (вплоть до ядра 6.5) добавили и другие методы получения
Что в Go?
И уже в Go 1.23 в методах и функциях, которые относятся к процессу используется по возможности
pidfd.Зачем это в Linux?
Работа с
PID по сути всегда гонка: - Получаем
PID процесса (например, PID=100);- Процесс умирает,
- ОС создает новый процесс, переиспользуя
PID=100;- В итоге мы работаем с совершенно другим процессом.
Это причина уязвимостей: CVE-2019-6133, CVE-2019-15790... А так же причина одного из issue у Go .
Решение
В Linux 5.1 появился системный вызов
pidfd_open(pid_t pid, unsigned int flags). Он даёт ссылку на конкретный процесс, а не на PID, который может быть переиспользован. Дальше (вплоть до ядра 6.5) добавили и другие методы получения
pidfd.Что в Go?
И уже в Go 1.23 в методах и функциях, которые относятся к процессу используется по возможности
pidfd.🔥9👍4🍾2👨💻2😁1💅1
В последнее время довольно часто приходится работать напрямую с TCP/UDP, а иногда и по SSH.
В таких случаях особенно важно использовать connection pool и следить, чтобы соединение не "умерло" - - так мы избегаем накладных расходов на рукопожатие (особенно важно если в протоколе есть дополнительные "телодвижения").
Отлично в этом помогает библиотека от jackc -- puddle (автор, кстати, того же pgx).
Грубо говоря, это
Примеры использования вне README можно посмотреть в исходниках pgx (файл pgxpool/pool.go) и ch-go (файл chpool/conn.go).
Ну и небольшой пример из README:
В таких случаях особенно важно использовать connection pool и следить, чтобы соединение не "умерло" - - так мы избегаем накладных расходов на рукопожатие (особенно важно если в протоколе есть дополнительные "телодвижения").
Отлично в этом помогает библиотека от jackc -- puddle (автор, кстати, того же pgx).
Грубо говоря, это
sync.Pool{}, только не для памяти, а для ресурсов, причём с возможностью ограничить количество создаваемых экземпляров. Если лимит достигнут, попытка получить новый ресурс блокируется до появления свободного -- что помогает контролировать нагрузку и избегать перерасхода соединений.Примеры использования вне README можно посмотреть в исходниках pgx (файл pgxpool/pool.go) и ch-go (файл chpool/conn.go).
Ну и небольшой пример из README:
func main() {
constructor := func(context.Context) (net.Conn, error) {
return net.Dial("tcp", "127.0.0.1:8080")
}
destructor := func(value net.Conn) {
value.Close()
}
maxPoolSize := int32(10)
pool, err := puddle.NewPool(&puddle.Config[net.Conn]{Constructor: constructor, Destructor: destructor, MaxSize: maxPoolSize})
if err != nil {
log.Fatal(err)
}
// Acquire resource from the pool.
res, err := pool.Acquire(context.Background())
if err != nil {
log.Fatal(err)
}
// Use resource.
_, err = res.Value().Write([]byte{1})
if err != nil {
log.Fatal(err)
}
// Release when done.
res.Release()
}
👍9🔥7
Уххх!
В Go начали завозить
То есть, возможно, можно будет вызывать SIMD инструкции напрямую, прямо из Go кода.
Для теста можно подтянуть ветку через
Правда, пока что поддержка только для amd64, так что локально потыкать у меня не получится :(
Как только появится arm -- обязательно сделаю бенчмарки и поделюсь результатами.
Кратко о текущем состоянии -- в комментарии Cherry Mui: https://github.com/golang/go/issues/73787#issuecomment-3208178910
В Go начали завозить
intrinsics для SIMD.То есть, возможно, можно будет вызывать SIMD инструкции напрямую, прямо из Go кода.
Для теста можно подтянуть ветку через
gotip:go install golang.org/dl/gotip@latest # если ещё не установлено
gotip download dev.simd # собираем ветку dev.simd
Правда, пока что поддержка только для amd64, так что локально потыкать у меня не получится :(
Как только появится arm -- обязательно сделаю бенчмарки и поделюсь результатами.
Кратко о текущем состоянии -- в комментарии Cherry Mui: https://github.com/golang/go/issues/73787#issuecomment-3208178910
GitHub
simd/archsimd: architecture-specific SIMD intrinsics under a GOEXPERIMENT · Issue #73787 · golang/go
Update (02/11/2026): The AMD64 low-level SIMD package is now available in Go 1.26 under GOEXPERIMENT=simd. There were minor bug fixes since the RC2. We'll continue the development for Go 1.27 o...
🔥3❤1👏1🍓1💅1👾1
В Go завезли поддержку valgrind -- утилиты, которая может обнаруживать утечки памяти.
Это, конечно, круто, но зачем?
На этот вопрос ответил автор CL, а также security team lead в Golang -- Roland Bracewell Shoemaker.
Основная цель -- находить функции, которые выполняются не за константное время.
Тут у кого-то может возникнуть вопрос:
SECURITY team lead .
В криптографии очень важно, чтобы функции выполнялись за константное время.
Если передавать разные входные данные и замерять время выполнения, можно провести timing oracle attack.
Тривиальный и упрощённый пример:
Мы побайтово сравниваем два хеша и при первом несовпадении выходим из функции раньше.
Тогда атакующий может подбирать хеш, ориентируясь на время выполнения запроса:
если оно немного замедлилось -- значит, один символ уже верный.
Чтобы предотвратить это, нужно, чтобы доступ к памяти и ветвление кода были одинаковыми для всех входных данных.
Для проверки этого как раз и нужен valgrind -- он отслеживает, какие области памяти и регистры используются в каждой ветке исполнения.
Подробнее про использование valgrind в рамках поиска функции, которые выполняются не за константное время можно почитать тутрепозиторию аж 15 лет .
Это, конечно, круто, но зачем?
На этот вопрос ответил автор CL, а также security team lead в Golang -- Roland Bracewell Shoemaker.
Основная цель -- находить функции, которые выполняются не за константное время.
Тут у кого-то может возникнуть вопрос:
Зачем нам функции, которые работают за константное время? Разве мы не хотим, чтобы они выполнялись как можно быстрее?А тут стоит посмотреть на роль того, кто добавил CL
В криптографии очень важно, чтобы функции выполнялись за константное время.
Если передавать разные входные данные и замерять время выполнения, можно провести timing oracle attack.
Тривиальный и упрощённый пример:
Мы побайтово сравниваем два хеша и при первом несовпадении выходим из функции раньше.
Тогда атакующий может подбирать хеш, ориентируясь на время выполнения запроса:
если оно немного замедлилось -- значит, один символ уже верный.
Чтобы предотвратить это, нужно, чтобы доступ к памяти и ветвление кода были одинаковыми для всех входных данных.
Для проверки этого как раз и нужен valgrind -- он отслеживает, какие области памяти и регистры используются в каждой ветке исполнения.
Подробнее про использование valgrind в рамках поиска функции, которые выполняются не за константное время можно почитать тут
🔥9✍3👾2💅1
Telegram
Lasiar работает 💡
Я пропустил что в Go 1.22 добавили работу с относительно новой сущностью Linux pidfd.
Зачем это в Linux?
Работа с PID по сути всегда гонка:
- Получаем PID процесса (например, PID=100);
- Процесс умирает,
- ОС создает новый процесс, переиспользуя PID=100;…
Зачем это в Linux?
Работа с PID по сути всегда гонка:
- Получаем PID процесса (например, PID=100);
- Процесс умирает,
- ОС создает новый процесс, переиспользуя PID=100;…
https://t.me/LasiarAtWork/50
А вот и добавили возможность использование
А вот и добавили возможность использование
pidfd напрямую.cmd.Process.WithHandle(func(handle uintptr) {
// работа с дескриптором процесса.
}✍4🤓2🔥1💅1