TGViewer
Бодрый кодер Бодрый кодер @bodrcoder · 576 subscribers
Post #522 527
В комментарии к прошлому посту, попросили поделиться подробнее про pipline.

Часто кэш читают/пишут «в лоб» — по одному запросу. Но основная цена Redis в проде — это RTT (туда-обратно по сети). Pipeline позволяет отправить пачку команд за один сетевой раунд — сервер выполнит их по порядку, а ответы придут одной очередью.

Что такое pipeline (и чем он НЕ является)
- Pipeline не делает операции атомарными. Это просто «упаковка» команд в один раунд-трип.
- Для атомарности нужен MULTI/EXEC (**TxPipeline** в go-redis) или Lua-скрипт, либо WATCH + TxPipelined.
- Команды в pipeline выполняются по очереди на сервере, но клиент не ждёт ответ после каждой — экономим RTT.

---

Когда использовать
- Серии однотипных чтений/записей (например, 50 ключей GET / `HGETALL`).
- Смешанные операции, где ответы предыдущих команд не нужны для формирования следующих.
- Интеграции «на пути» запроса (критично снижать задержку).

Когда не стоит:
- Когда следующая команда зависит от результата предыдущей → делайте двумя фазами.
- Огромные пакеты (тысячи команд) — растёт задержка одной пачки и риск таймаутов. Лучше батчить.

---

Простой пример на Go.


package main

import (
"context"
"encoding/json"
"fmt"
"time"

"github.com/redis/go-redis/v9"
)

type Post struct {
ID, Author, Title, Content string
}

func main() {
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
defer cancel()

rdb := redis.NewClient(&redis.Options{Addr: "127.0.0.1:6379"})

// 1) Запись: тело поста + счётчики одним pipeline
post := Post{ID: "42", Author: "alice", Title: "Pipeline 101", Content: "…"}
body, _ := json.Marshal(post)

_, err := rdb.Pipelined(ctx, func(p redis.Pipeliner) error {
p.Set(ctx, "post:42:body", body, 10*time.Minute) // TTL у тела
p.HSet(ctx, "post:42:counters", "views", 0, "likes", 0) // счётчики отдельно
p.Persist(ctx, "post:42:counters") // живут дольше тела
return nil
})
if err != nil {
panic(err)
}

// 2) Чтение: тело + счётчики за 1 RTT
var (
bodyCmd = rdb.Get(ctx, "post:42:body")
ctrCmd = rdb.HGetAll(ctx, "post:42:counters")
)
// Внимание: без Pipelined() мы сделали 2 команды, но они уйдут подряд на одном соединении.
// Для явного пайплайна:
pipe := rdb.Pipeline()
bodyCmd = pipe.Get(ctx, "post:42:body")
ctrCmd = pipe.HGetAll(ctx, "post:42:counters")
if _, err := pipe.Exec(ctx); err != nil && err != redis.Nil {
panic(err)
}

var p Post
if b, err := bodyCmd.Bytes(); err == nil && len(b) > 0 {
_ = json.Unmarshal(b, &p)
}
counters := ctrCmd.Val()
fmt.Println("title:", p.Title, "views:", counters["views"])
}
  • 👍 4
  • 🔥 2
More from @bodrcoder
  1. Sep 25, 2026Всех с пятницей. #пятничныйюмор
  2. Sep 24, 2026Думаю что сейчас будут все более популярны те сервисы, которые поддерживают MCP. Скоро Нов…
  3. Sep 22, 2026Разбирал вещи, очень сильно обрадовался что нашел сокровище. Но правда оказалась печальнее…
  4. Sep 17, 2026Купился на новый инференс uzu - который обещал гипер скорость на маке. Но я когда затащил…
  5. Sep 17, 2026Post #812
  6. Sep 17, 2026Кто каким стулом пользуется для работы? У меня в свое время самый удобный стул был - за 10…
Threads Profile ViewerView any public Threads profile without an account.Open ThreadLook →Writing with AI? Make it sound human.Metric37 rewrites AI drafts so they read naturally. Free AI detector, 1,500 words free.Try Metric37 →