Please enable JavaScript.
Coggle requires JavaScript to display documents.
go (Многопоточность, Язык, Ошибки, Правильные мысли, Папки, Контекст,…
go
Многопоточность
Термины
-
-
Виды многозадачности
-
-
В Go используется смешанный подход. В момент компиляции определяется эвристически кто когда будет выполняться. А во время выполнения всё делает планировщик
-
-
Структура Runtime Go (Схема)
-
-
G - Гоурутина
-
Это структура, которая выполняет переданную функцию
-
-
-
-
-
-
Канал - это очередь сообщений, которая работает в многопоточной среде
Работа с каналом
-
Открываются через ch := make(chan тип значений, вместительность буфера)
-
Вместимость буфера задаёт размер буфера канала. По-умолчанию он 0. Если N, то канал не блокирует запись до тех пор, пока полон этот буфер
Можно перебирать через range. Если после перебора канал не закрыт в рутине, возникает deadlock
Закрытие канала
Закрывает канал тот, кто в него пишет
Если много продюсеров, то закрывает канал тот, кто создаёт продюсеров
Не закрытый канал жрёт ресурсы, нужно их закрывать явно. Их не видит планировщик
-
-
-
-
-
-
-
-
Библиотеки
-
-
-
-
Условия, на которые должны реагировать рутины sync.Cond (в основном это решают через каналы)
-
Поток
-
-
-
Типы работ потока
CPU-Bound - это вычисления, которые никогда не будут прерваны
IO-Bound: это работа, которая заставляет потоки переходить в состояние ожидания
-
-
Счетчик команд - также (instruction pointer) (IP) позволяет потоку отслеживать следующую команду для выполнения
В go число в конце при трассировке stack_trace/example1/example1.go:13 +0x39
- это смещение значения IP от вершины соответствующей функции
-
Переключение контекста - процесс переключения планировщиком ОС потоков между собой и смены их состояния
-
-
Язык
Типы
-
-
-
-
array
a := [6]int{2, 3, 5, 7, 11, 13}
Можно объявлять без размерности и компилятор сам посчитает:
a := [...] {1, 2, 3}
-
-
можно создавать через make([]int, len, cap)
-
-
-
-
fn - функции
-
-
Если аргументы функции не исользуются, их переменные можно не указывать. Если хоть один аргумент используется, то нужно использовать _
-
Интерфесы
interface
-
Типизация в go называется duck typing. Если наш тип крякает как утка, то значит это и есть утка
-
-
-
-
-
Встроенные
Интерфейсы пакетов
-
Marshaler\Unmarshaler
MarshalJSON() ([]byte, error)
-
-
-
-
-
-
Если есть шанс ошибки, её можно перехватить через
val, ok := i.(нужный тип)
-
Методы
Можно передавать как ссылку на объект, так и его копию
Методы - это функции, аргументом которых является объект
-
-
-
-
func Index[T comparable](s []T, x T) int
-
Ошибки
Создание error
-
Если нужно подставить переменную, то fmt.Errorf(текст, переменная)
errors.Wrap(РОДИТЕЛЬСКАЯ_ОШИБКА, СООБЩЕНИЕ)
-
-
errors.Is(err, ОЖИДАЕМАЯ_ОШИБКА)
-
Бизнесовые ошибки стоит хранить в pkg/errors для того, чтобы их можно было переиспользовать извне
Правильные мысли
-
-
Указатели нужно использовать тогда, когда объект имеет состояние, иначе лучше передавать копию
-
internal
Код, видимый только внутри модуля
-
pkg
Код, видимый снаружи модуля
Контекст
ctx, cancel := context.WithTimeout(baseContext, таймаут)
-
cancel - это функция, вызвав которую можно отменить выполнение
ctx.Done() - возвращает канал, который сообщает о завершении таймаута
Если нужен контекст там, где нет доступа к верхним контекстам, можно детачнуть текущий через
detachedCtx := ctx.Detach(ctx)
-
-
-
JSON
аннотации json:"ключВJSON,обработчик"
виды обработчиков
omitempty - пропустить, если nil
-
ключВJSON если без обработчика и равен -, то поле игнорируется
-
Наследование
В Go нет наследование, но есть композиция за счёт вкладывания типов в друг-друга
Чтобы вложить, нужно указать название целевого в теле подчинённого
-
-
-
Логгирование (урок 15)
-
Библиотеки
uber-go/zap
-
Подключение к GELF-серверу:
gelf "github.com/snovichkov/zap-gelf"
gelfCore, err := gelf.NewCore(АДРЕС, УРОВЕНЬ)
Можно сделать вывод сразу в двух местах через пакет tee:
notSugaredLogger := zap.New(zapcore.NewTee(consoleCore, gelfCore))
Настройка:
consoleCore := zapcore.NewCore(...)
sugaredLogger := zap.New(consoleCore)
logger.SetLogger(sugaredLogger)
Установить логгер с информативными префиксом:
logger.SetLogger(sugaredLogger.With("service", cfg.Project.ServiceName))
Логгирование в режиме дебага:
logger.DebugKV(ctx, СООБЩЕНИЕ)
-
-
-
-
-
-
Трассировка
-
-
Термины
Span - содержит имя операции, время, логи, теги и контекст (родитель, traceId, ...)
-
-
Покрывать трейсами стоит обращения к БД, микросервисам и обработку Kafka
-
Библиотеки
pgx
Рекомендуется только если используется PostgreSQL и не используется другими библиотеками database/sql
-
-
Миграции
Goose
-
Миграции нужно разбивать таким образом, чтобы они выполнялись быстро
Чтобы отключить транзакции, нужно добавить * goose NO TRANSACTION
Чтобы не залипало на проде, нужно добавлять таймаут:
set lock_timeout = "5s";
5s - максимум
-
database/sql
-
Запросы
-
-
-
Нужно передавать контекст, чтобы можно было прервать соединение с БД после прерывания процесса
Prepared statement
stmt, err := db.Prepare(ЗАПРОС)
defer stmt.Close()
_, err := stmt.Exec(ПАРАМЕТРЫ)
Транзакции
tx, err := db.BeginTx(ctx, nil)
// Работа с tx как с db
err := tx.Commit()
-
-
-
-
-
Query builder
squirrel
-
Чтобы везде не задавать PlaceholderFormat можно сделать так:
var psql = sq.StatementBuilder.PlaceholderFormat(sq.Dollar)
и перевызывать psql
-
-
-
Приложения\Технологии
Protocol Bufers
-
-
-
-
В протобуфере нельзя отличить значения по-умолчанию от отсутствующего значения. Это обходится путём обявления вложенного сообщения. Тогда получится отличить
-
Как хранятся сообщения
Каждое поле задаётся четырмя частями в бинарном виде: идентификатор тега(1,2,3), тип, длина значения и значение
-
-
-
Метрики (16 урок)
Уровни метрик
-
Service level objectives (SLO) - желаемое, целевое значение SLI (или группы SLI)
Service level agreement (SLA) - установленное бизнесом внешнее обязательство по доступности сервиса перед клиентами
Prometheus
Структура
Pushgateway - собирает метрики с приложения. Испольуется редко, поскольку много сложностей с ним (Единая точка отказа, нет мониторинга жизни приложения и хранит данные не эффективно)
-
-
-
Термины
-
Time series - состоит из имени метрики, лейблов и значений
Формат: <metric name>{<label name>=<label value>, ...} <sample>
Пример: api_http_requests_total{method="POST", handler="/messages"} 123
-
-
В лейблах лучше не использовать очень разные значения, поскольку лимит в 50
-
Типы данных
-
String - не используется, устарело
-
-
PromQL
Пример:
http_requests_total{environment=~"staging|testing|development",method!="GET"}[5m]
Операторы
= простые сравнения «равно»
!= простые сравнения «не-равно»
=~ regex-сравнение «равно»
!~ regex-сравнение «не-равно»
Функции аггрегирования
sum by (ПРИЛОЖЕНИЕ*, ГРУППА) (МЕТРИКА) - сумма по группировке
sum by (application, group) (http_requests_total)
sum without (instance) (http_requests_total) - сумма по группировке, только исключая instance
-
Библиотека для go:
go get github.com/prometheus/client_golang/prometheus
go get github.com/prometheus/client_golang/prometheus/promauto
go get github.com/prometheus/client_golang/prometheus/promhttp
Мониторинг HTTP-сервера:
http.Handle("/metrics", promhttp.Handler())
Типы метрик
Counter - счётчик, значение которого может только увеличиться
-
var metricProcessedOpsTotal = promauto.NewCounter(prometheus.CounterOpts{
Name: "myapp_processed_ops_total",
Help: "The total number of processed events",
})
metricProcessedOpsTotal.Inc()
Dec()
Gauge - измеритель, значение которого может как падать, так и повышаться
-
-
Histogram - когда нужно считать большое количество значений, выводя только их сумму или итог. Квантилии (бакеты) помогают понять данные в граничных случаях
Данные дробятся по
_bucket{..., le="0.22"} - среднее значение данных, которое меньше или равно 0.22
_sum
_count
-
-
rate(prometheus_http_request_duration_seconds_sum[5m] / rate(prometheus_http_request_duration_seconds_count[5m])
histogram_quantile(0.9, rate(http_request_duration_seconds_bucket[10m])) - Подсчет 90-го процентиля времени выполнения запроса за последние 10m
histogram = promauto.NewHistogram(prometheus.HistogramOpts{...})
...
histogram.Observe(rand.Float64() * 10)
Summary (сводка) - тоже самое, что и Histogram, но менее рекомендуеая к использованию
-
Grafana
-
Можно настраивать свои графики, задавая метрики на PromQL напрямую в настройках графика
-
-
Можно сделать динамичную легенду из лейбела, добавив вместо названия название label: {{status}}
-
Библиотеки\Пакеты
Readers
Читает методом r.Read(byte): количество считанных байтов, error
-
net
http
HTTP-клиент
http.Get(url) (resp, err)
-
HTTP-сервер
http.ListenAndServe(ХОСТ_С_ПОРТОМ,ХАНДЛЕР)
-
http.HandleFunc(ПУТЬ, ХАНДЛЕР) - регистрация хандлера
-
-
-
-
-
Полезные функции
strconv.ParseInt(num, 2, 64) - конвертирует число в другую систему исчисления
strings.Repeat(ТЕКСТ, КОЛИЧЕСТВО)
strconv.FormatInt(n, 2) - конвертирует число в бинарную строку
Дальше
-
-
Рекомендую следующие книги: Learning Go by Joe Bodner и классический текст The Go Programming Language (хорош в качестве второй книги про Golang).
-
Наработки озона
database.WithTx(ctx, db, fn(ctx, tx *sql tx)...)
-
-