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

Использование Redis в Golang позволяет улучшить производительность приложения за счет ускорения доступа к данным. Кроме того, Redis предоставляет множество возможностей, таких как кэширование результатов запросов к базе данных, сохранение промежуточных вычислений и хранение временных данных, что может существенно сократить нагрузку на сервер базы данных.

Стандартом де-факто для централизованного кэширования является Redis, но, популярные сегодня библиотеки и не поддерживают потоковую передачу данных, эффективных с точки зрения памяти. 

В моем телеграм вы найдете множество проектов с уроками, гайдами и кодом для Golang разработчиков

Еще я собрал полезную папку для Golang разработчиков, там находится все, что нужно Go программисту.

Вместо этого они предлагают []byte API, с которыми вы взаимодействуете следующим образом:

// В этом коде используется https://github.com/redis/go-redis, но те же
// ограничения действуют для Rueidis и Redigo.
func redisHandler(w http.ResponseWriter, r *http.Request) {
ctx := context.Background()
// Извлечение ключа из RequestURI
key := strings.TrimLeft(r.RequestURI, "/")

// Получить значение из Redis в виде байтового фрагмента
val, err := rdb.Get(ctx, key).Bytes()
if err == redis.Nil {
	http.Error(w, "Key not found in Redis", http.StatusNotFound)
	return
} else if err != nil {
	http.Error(w, err.Error(), http.StatusInternalServerError)
	return
}

_, err = w.Write(val)
if err != nil {
	http.Error(w, err.Error(), http.StatusInternalServerError)
}

}

Этот паттерн работает хорошо, если вы кэшируете небольшие объекты, но если вы кэшируете объекты размером более 1 кб, []байт-ориентированные API работют не так хорошо.

В протоколе Redis нет ничего такого, что мешало бы создать потоковый API. Поэтому передставляем redjet, библиотеку Redis, ориентированную на производительность

Redjet - это высокопроизводительная библиотека Go для Redis. Ее отличительной особенностью является потоковый API с низким распределением ресурсов. Более подробную информацию можно найти в разделе бенчмарков.

Установка библиотеки:

go get github.com/coder/redjet@latest

С помощью redjet вы можете написать приведенный выше код следующим образом:

func redisHandler(w http.ResponseWriter, r *http.Request) {
ctx := context.Background()
// Извлечение ключа из RequestURI
key := strings.TrimLeft(r.RequestURI, "/")

// Передаем значение непосредственно из Redis в ответ.
_, err := rdb.Command("GET", key).WriteTo(w)
if err != nil {
	http.Error(w, err.Error(), http.StatusInternalServerError)
}

}

Код стал проще и эффективнее.

Потоковая запись

Популярные библиотеки Redis страдают от одной и той же проблемы, когда дело доходит до записи значений в Redis. Они требуют, чтобы вы хранили все значение в памяти в виде []byte, прежде чем отправить его.

С помощью redjet вы можете передавать значения в Redis следующим образом:

fi := strings.NewReader("Содержимое файла")
err := rdb.Command("SET", "key", fi).Ok()
// обработка ошибки

Здесь есть важная оговорка. В протоколе Redis значения имеют префикс длины, поэтому мы не можем передавать потоковую запись через io.Reader. Я предполагаю, что это одна из основных причин, почему популярные библиотеки не поддерживают потоковую запись.

Чтобы обойти это, redjet необходим redjet.LenReader, который определяется как:

type LenReader interface {
  Len() int
  io.Reader
}

и может быть создаы с помощью redjet.NewLenReader:

Удобно, что некоторые типы в стандартной библиотеке, такие как bytes.Readerstrings.Reader и bytes.Buffer, неявно реализуют redjet.LenReader.

Бенчмарки

Redjetс сравнили с бенчмарками:

Время на операцию. Если рассматривать чтения размером 1 кб, то вот результаты

Все результаты бенчмарков доступны здесь.

Комментарии (3)


  1. alexdora
    14.01.2024 18:09

    Когда я баловался на nodejs было интересно потыкать редис, иногда даже он был палочкой-выручалочкой. Перейдя на Golang я про него забыл.

    Тот же вопрос кэширования я решаю прямо в RAM. Статья не заинтересовала решать это по другому. Только рекламу тг канала увидел и как пользоваться пакетом, о котором судя по всему все и так знают кому редис нужен.

    С удовольствием услышу про применение редисом не с целью «а так тупо легче», а где реально упрашает жизнь.


    1. Free_ze
      14.01.2024 18:09
      +9

      Простое решение про кэш в RAM не позволит шарить его между инстансами приложения, в отличие от.


      1. kirik
        14.01.2024 18:09
        +1

        Плюс не сможет пережить апдейт сервиса.