【问题标题】:How come the redis-benchmark command is not following the redis protocol?redis-benchmark命令怎么不遵循redis协议?
【发布时间】:2014-08-10 03:43:30
【问题描述】:

我在运行redis-benchmark 命令后直接从 tcp 连接读取数据,据我所知,redis-benchmark 没有遵循 redis 协议。

redis protocol 如其网站所述:

在 Redis 中使用 RESP 作为请求-响应协议的方式是 以下:

  • 客户端将命令作为批量字符串的 RESP 数组发送到 Redis 服务器。
  • 服务器根据命令实现回复其中一种 RESP 类型。

意味着正确的客户端实现必须始终发送 批量字符串的 RESP 数组。

如果这是真的,那么任何不以 * 开头的东西都被认为是语法错误(因为它不是 RESP 数组)。

因此,如果要向 redis 服务器发送 ping 命令,则必须将其作为长度为 1 的 resp 数组发送,其中包含 1 个包含单词 ping 的批量字符串。例如:

"*1\r\n$4\r\nPING\r\n"

但是,每当我直接收听 redis-benchmark 命令并读取它的 tcp 连接时,我都会得到:

“PING\r\n”

遵循 redis 协议。这是一个错误还是 redis 协议中隐含的某些东西使 pings 变得特别?据我所知,我找不到任何说 ping 很特别的东西,也找不到长度 1 命令很特别的东西。有人知道发生了什么吗?

要自己查看重现这些结果,您可以复制 my code 直接检查:

package main

import (
    "fmt"
    "log"
    "net"
)

func main() {
    RedisBenchmark()
}

func RedisBenchmark() {
    url := "127.0.0.1:6379"
    fmt.Println("listen: ", url)
    ln, err := net.Listen("tcp", url) //announces on local network
    if err != nil {
        log.Fatal(err)
    }
    for {
        conn, err := ln.Accept() //waits and returns the next connection to the listener
        if err != nil {
            log.Fatal(err)
        }

        tcpConn := conn.(*net.TCPConn)
        go HandleConnection(tcpConn)
    }
}

func HandleConnection(tcpConn *net.TCPConn) {
    b := make([]byte, 256) //TODO how much should I read at a time?
    n, err := tcpConn.Read(b)
    if err != nil {
        fmt.Println("n: ", n)
        log.Fatal(err)
    }
    fmt.Printf("+++++> raw input string(b): %q\n", string(b))
    msg := string(b[:n])
    fmt.Printf("+++++> raw input msg: %q\n", msg)
}

并使用 go with 运行它:

go run main.go

在不同的终端(或 tmux 窗格)上关注:

redis-benchmark

对于所有测试,或者如果您只想使用 1 个客户端运行 ping:

redis-benchmark -c 1 -t ping -n 1

你可以在http://redis.io/topics/benchmarkshttp://redis.io/topics/benchmarks处查看我如何使用标志运行它的详细信息

【问题讨论】:

    标签: tcp go redis


    【解决方案1】:

    这称为内联命令。查看 Redis 协议文章的Inline Commands 部分。

    【讨论】:

    • 当它停止遵循我在问题中指定的协议时,我还应该知道什么吗?
    • 我认为该文档中指定了所有内容,但如果您遇到奇怪的事情,请随时在此处或邮件列表中询问。
    • FWIW,我认为处理内联命令的代码不如以“*”开头的命令的代码有效。例如,我发现我的 REDIS 服务器发送“*1\r\n$4\r\nPING\r\n”比发送“PING\r\n”快 5-6%。对于任何可能认为使用内联命令可能会更有效的人来说,这没什么显着差异,但很有趣。
    【解决方案2】:

    内联命令和RESP的区别可以参考源码。

    readQueryFromClient
    |-->  if command begins with * --> processInlineBuffer()process it as RESP
    |
    |-->  if command not begins with * --> processMultibulkBuffer():process it as inline command 
    

    RESP 是解析 Redis 服务器命令的更有效方式

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2022-11-29
      • 2020-04-07
      • 1970-01-01
      • 1970-01-01
      • 2018-09-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多