redis-benchmark命令为什么不遵循redis协议?

I was reading in directly from a tcp connection after running the redis-benchmark command and as far as I can tell, redis-benchmark is NOT following the redis protocol.

The redis protocol is as stated in its website:

The way RESP is used in Redis as a request-response protocol is the following:

  • Clients send commands to a Redis server as a RESP Array of Bulk Strings.
  • The server replies with one of the RESP types according to the command implementation.

Meaning that a correct client implementation must always send RESP arrays of bulk strings.

If that is true, then, anything that does not start with a * is considered a syntax error (since its not an RESP array).

Thus, if one were to send a ping command to a redis-server, then it must be sent as a resp array of length 1 with 1 bulk string containing the word ping. For example:

"*1 $4 PING "

However, whenever I listen directly to the redis-benchmark command and read its tcp connection I get instead:

"PING "

which does not follow the redis protocol. Is that a bug or is there something implied in the redis protocol that makes pings special? As far as I could tell I couldn't find anything that said that pings were special, nor that length 1 commands were special. Does someone know whats going on?

To see reproduce these results yourself you can copy my code to inspect it directly:

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
", string(b))
    msg := string(b[:n])
    fmt.Printf("+++++> raw input msg: %q
", msg)
}

and run it using go with:

go run main.go

followed on a different terminal (or tmux pane):

redis-benchmark

for all the test or if you only want to run ping with 1 client:

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

you can see the details of how I am running it with the flags at: http://redis.io/topics/benchmarks

That is called an inline command. Check the Inline Commands section of the Redis Protocol article.

You can refer to the source code to find out the differences between inline command and RESP.

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

RESP is a more efficent way to parse the command for the Redis Server