Что нового в Go 1.23: Итераторы, Unique, Телеметрия, улучшения таймеров и другое

13 августа 2024 года вышел очередной релиз новой версии Golang - Go 1.23, включающий улучшения как в языке, так и в стандартной библиотеке.

Перед прочтением рекомендую подписаться на мой телеграмм канал, где вы сможете найти актуальные новости, примеры и хаки в мире разработки: @asanov_tech

Что нового в Go 1.23: Итераторы, Unique, Телеметрия, улучшения таймеров и другое


Итераторы: iter и slices

Введены итераторы для работы с пользовательскими последовательностями данных. Появился новый пакет iter, а также функции для работы с итераторами в пакетах slices и maps. Теперь можно, например, обрабатывать ключи карты с помощью итераторов.

Пример использования итераторов:

package main

import (
    "fmt"
    "golang.org/x/exp/maps"
    "golang.org/x/exp/slices"
)

func main() {
    // Создаём карту
    m := map[string]int{
        "apple":  5,
        "banana": 2,
        "cherry": 7,
    }

    // Получаем все ключи карты через итератор
    keys := maps.Keys(m)

    // Сортируем ключи
    sortedKeys := slices.Sorted(keys)

    // Выводим отсортированные ключи
    fmt.Println(sortedKeys)
}

Объяснение:


> maps.Keys(m) возвращает итератор по ключам карты m.

> slices.Sorted(keys) сортирует ключи.

> В результате программа выведет отсортированный список ключей: [apple banana cherry].


Этот код демонстрирует основные функции нового пакета iter, который используется для работы с коллекциями данных, например, картами и срезами.

Новый пакет unique

Позволяет “канонизировать” значения, создавая одну общую копию для одинаковых объектов, что помогает сократить использование памяти.

Пример использования пакета unique в Go 1.23:



package main

import (
   "fmt"
   "golang.org/x/exp/unique"
)

func main() {
   // Создаем объект для канонизации строк
   u := unique.Make[string]()
        
   // Канонизируем несколько строк
   handle1 := u.Handle("apple")
   handle2 := u.Handle("banana")
   handle3 := u.Handle("apple")
        
   // Сравниваем канонизированные строки
   fmt.Println(handle1 == handle3) // true
   fmt.Println(handle1 == handle2) // false
        
   // Выводим оригинальные значения
   fmt.Println(handle1.Value()) // "apple"
   fmt.Println(handle2.Value()) // "banana"
}

Объяснение:


Пакет unique позволяет “канонизировать” значения, то есть создавать общие объекты для одинаковых данных. В примере строка "apple" была канонизирована дважды, но handle1 и handle3 ссылаются на одну и ту же строку, что показывает эффективное использование памяти.

Функция u.Handle("apple") возвращает объект Handle[string], который используется для сравнения и доступа к значению.


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

Телеметрия в Go 1.23 / Telemetry

А вот это уже действительно интересно. Добавлена телеметрия — теперь можно добровольно отправлять анонимные данные об использовании инструментов Go, что поможет улучшить качество сборки и быстрее находить баги. Также появились новые команды, такие как

go env -changed
для отображения измененных переменных окружения.

Ниже подробнее расскажу на примерах как это использовать с практическими примерами.

Улучшение таймеров

Изменена реализация time.Timer и time.Ticker, что должно улучшить производительность. Тут с точки зрения интерфейса нового ничего нет, но под капотом разработчики гошки значительно увеличили скорость. Однако, я всё же приведу простой пример использования timer и tick: Пример: Повторяющийся таймер с time.Ticker


package main

import (
    "fmt"
    "time"
)

func main() {
    // Создаем тикер, который срабатывает каждые 500 миллисекунд
    ticker := time.NewTicker(500 * time.Millisecond)

    // Запускаем цикл для обработки событий тикера
    go func() {
        for t := range ticker.C {
            fmt.Println("Тик в:", t)
        }
    }()

    // Останавливаем тикер через 2 секунды
    time.Sleep(2 * time.Second)
    ticker.Stop()
    fmt.Println("Тикер остановлен")
}


Объяснение:


time.NewTicker создаёт тикер, который генерирует события каждые 500 миллисекунд.

Мы обрабатываем события из канала тикера ticker.C.

По истечении 2 секунд тикер останавливается с помощью ticker.Stop().

Поддержка новых платформ

Добавлена экспериментальная поддержка OpenBSD на RISC-V 64-bit.

Эти и другие обновления направлены на повышение удобства работы с языком, оптимизацию производительности и улучшение стандартной библиотеки. Полные подробности можно найти в релизных заметках Go 1.23 на официальном сайте.sd 

Как интегрировать обновелния телеметрии в Go 1.23 с Jaeger?

Чтобы интегрировать Go с OpenTelemetry и включить его в APM и Jaeger, можно следовать следующим шагам:


1. Установка OpenTelemetry для Go


Сначала нужно установить библиотеку OpenTelemetry для Go:



go get go.opentelemetry.io/otel
go get go.opentelemetry.io/otel/sdk
go get go.opentelemetry.io/otel/exporters/trace/jaeger
    


Эти пакеты предоставляют необходимые инструменты для работы с OpenTelemetry, включая SDK и экспортёры для отправки данных в Jaeger.


2. Пример настройки трейсинга с OpenTelemetry и отправки данных в Jaeger


package main

import (
    "context"
    "log"
    "time"

    "go.opentelemetry.io/otel"
    "go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp"
    "go.opentelemetry.io/otel/sdk/trace"
    "go.opentelemetry.io/otel/sdk/resource"
    semconv "go.opentelemetry.io/otel/semconv/v1.4.0"
)

func initTracer() func() {
    // Настраиваем экспортёр OTLP для отправки в Elastic APM
    exporter, err := otlptracehttp.New(context.Background(),
        otlptracehttp.WithEndpoint("your-apm-server-url:8200"), // Укажите URL вашего Elastic APM
        otlptracehttp.WithInsecure(),                            // Если используете HTTP, уберите для HTTPS
    )
    if err != nil {
        log.Fatal(err)
    }

    tp := trace.NewTracerProvider(
        trace.WithBatcher(exporter),
        trace.WithResource(resource.NewWithAttributes(
            semconv.SchemaURL,
            semconv.ServiceNameKey.String("your-service-name"),
        )),
    )

    otel.SetTracerProvider(tp)

    return func() {
        if err := tp.Shutdown(context.Background()); err != nil {
            log.Fatal(err)
        }
    }
}

func main() {
    cleanup := initTracer()
    defer cleanup()

    tracer := otel.Tracer("example-tracer")

    // Пример использования трейсинга
    ctx, span := tracer.Start(context.Background(), "example-operation")
    time.Sleep(1 * time.Second)
    span.End()

    log.Println("Telemetry sent to Elastic APM")
}
        


3. Включение OpenTelemetry в APM (например, Datadog или другие)


OpenTelemetry может работать с разными APM системами. Для этого достаточно изменить экспортёр на нужную платформу (например, Datadog или Zipkin). Используйте нужный экспортёр OpenTelemetry, который интегрирован с вашей APM платформой. Для Datadog, например, можно использовать экспортёр datadog/opentelemetry-exporter.


4. Конфигурация Jaeger


Jaeger можно запустить локально через Docker для тестирования:



docker run -d --name jaeger \
  -e COLLECTOR_ZIPKIN_HTTP_PORT=9411 \
  -p 5775:5775/udp \
  -p 6831:6831/udp \
  -p 6832:6832/udp \
  -p 5778:5778 \
  -p 16686:16686 \
  -p 14268:14268 \
  -p 14250:14250 \
  -p 9411:9411 \
  jaegertracing/all-in-one:1.22        
        

Как интегрировать обновелния телеметрии в Go 1.23 с APM от Elastic?


1. Настройка Elastic APM


Elastic APM поддерживает OpenTelemetry, что делает интеграцию более гибкой. Прежде чем начать, убедитесь, что Elastic APM настроен и работает, и что у вас есть доступ к Elastic APM серверу.


2. Установка OpenTelemetry для Go


Go 1.23 включает встроенную телеметрию, но для отправки данных в Elastic APM нам нужно воспользоваться OpenTelemetry. Установите необходимые библиотеки OpenTelemetry:



go get go.opentelemetry.io/otel
go get go.opentelemetry.io/otel/sdk
go get go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp    
    


3. Конфигурация экспорта телеметрии в Elastic APM через OpenTelemetry


Elastic APM поддерживает протокол OTLP, который используется OpenTelemetry для отправки трейсингов и метрик. Настроим экспорт данных телеметрии из Go в Elastic APM:



package main

import (
    "context"
    "log"
    "time"

    "go.opentelemetry.io/otel"
    "go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp"
    "go.opentelemetry.io/otel/sdk/trace"
    "go.opentelemetry.io/otel/sdk/resource"
    semconv "go.opentelemetry.io/otel/semconv/v1.4.0"
)

func initTracer() func() {
    // Настраиваем экспортёр OTLP для отправки в Elastic APM
    exporter, err := otlptracehttp.New(context.Background(),
        otlptracehttp.WithEndpoint("your-apm-server-url:8200"), // Укажите URL вашего Elastic APM
        otlptracehttp.WithInsecure(),                            // Если используете HTTP, уберите для HTTPS
    )
    if err != nil {
        log.Fatal(err)
    }

    tp := trace.NewTracerProvider(
        trace.WithBatcher(exporter),
        trace.WithResource(resource.NewWithAttributes(
            semconv.SchemaURL,
            semconv.ServiceNameKey.String("your-service-name"),
        )),
    )

    otel.SetTracerProvider(tp)

    return func() {
        if err := tp.Shutdown(context.Background()); err != nil {
            log.Fatal(err)
        }
    }
}

func main() {
    cleanup := initTracer()
    defer cleanup()

    tracer := otel.Tracer("example-tracer")

    // Пример использования трейсинга
    ctx, span := tracer.Start(context.Background(), "example-operation")
    time.Sleep(1 * time.Second)
    span.End()

    log.Println("Telemetry sent to Elastic APM")
}    
    


4. Запуск Elastic APM серверов и просмотр трейсингов


1. Убедитесь, что Elastic APM сервер работает и настроен для приёма данных OTLP.

2. После запуска приложения, данные трейсинга будут отправляться в Elastic APM. Вы сможете их просматривать в разделе APM в Kibana.


5. Включение телеметрии Go 1.23


Для активации встроенной телеметрии Go 1.23 можно использовать команду:


go telemetry on


Заключение


Интеграция Elastic APM с Go 1.23 через OpenTelemetry позволяет не только использовать встроенные функции телеметрии Go, но и отправлять данные в Elastic для глубокого анализа производительности и ошибок.


Подпишитесь на мой телеграмм канал, где вы сможете найти актуальные новости, примеры и х

аки в мире разработки: https://t.me/asanov_tech

Комментарии

Популярные сообщения из этого блога

Как преобразовать строку в массив в ClickHouse / How to transform string to array in ClickHouse

Как разложить массив на несколько строк в ClickHouse

Экспорт одной таблицы базы данных или mysqldump одной таблицы (MySQL)