首页 \ 问答 \ 为什么redis-benchmark命令不遵循redis协议?(How come the redis-benchmark command is not following the redis protocol?)

为什么redis-benchmark命令不遵循redis协议?(How come the redis-benchmark command is not following the redis protocol?)

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

redis协议如其网站所述:

RESP在Redis中用作请求 - 响应协议的方式如下:

  • 客户端将命令作为Bulk Strings的RESP数组发送到Redis服务器。
  • 服务器根据命令实现回复一种RESP类型。

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

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

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

“* 1 \ r \ n $ 4 \ r \ nPING \ r \ n”

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

“PING \ r \ n”

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

要查看自己重现这些结果,您可以复制我的代码以直接检查它:

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运行它:

go run main.go

跟随在不同的终端(或tmux窗格):

redis-benchmark

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

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

你可以在http://redis.io/topics/benchmarks看到有关我如何运行它的详细信息


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\r\n$4\r\nPING\r\n"

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

"PING\r\n"

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


原文:https://stackoverflow.com/questions/25225333
更新时间:2023-01-16 08:01

最满意答案

如果您已正确设置约束并且应用程序的部署目标是> = iOS 8,则可以使用自动行高计算。 因此,您必须在viewDidLoad执行以下操作:

tableView.estimatedRowHeight = 44
tableView.rowHeight = UITableViewAutomaticDimension

其中44应该是某种平均行高。 那么你根本不必实现estimatedRowHeightheightForRow方法......

你也可以实现heightForRow并执行以下操作:

// if cell is of kind textview cell
return UITableViewAutomaticDimension
// else
return some static value

if you have setup your constraints correctly and your app's deployment target is >= iOS 8 you can use the automatic row height calculation. therefore you have to do the following in viewDidLoad:

tableView.estimatedRowHeight = 44
tableView.rowHeight = UITableViewAutomaticDimension

where 44 should be some kind of average rowheight. then you do not have to implement the methods estimatedRowHeight and heightForRow at all...

you can also implement heightForRow and do something like the following:

// if cell is of kind textview cell
return UITableViewAutomaticDimension
// else
return some static value

相关问答

更多
  • 你不能在heightForRowAtIndexPath调用单元格对象,因为它会在cellForRowAtIndexPath调用heightForRowAtIndexPath时创建无限循环。 其次,使用约束调整width因为函数名称清楚地表明它是高度。 如果您确定控件的高度,请使用此选项 return 90.0 //its optional if height is fixed 其他 为top , bottom , left , right , width和height约束添加约束,并使用> = cond ...
  • 首先看看我的ViewController,它有一个tableview(tblview)和UITableViewCell(CustomTableViewCell), class ViewController: UIViewController { @IBOutlet var tblview:UITableView! override func viewDidLoad() { super.viewDidLoad() self.tblview.delegate = ...
  • 第一个问题:是的,确实如此。 您需要使用不同的水平压缩阻力优先级。 您可能还需要较低优先级的不等式来设置限制。 第二个问题:问题是你没有完全确定身高。 您必须从单元格的顶部到单元格的底部一直有约束,以便单元格的高度由其内部的内容严格确定。 First question: Yes, it is. You'll need to use different horizontal compression resistance priorities. You might also need a lower prior ...
  • 是的,这是可能的。您必须根据方法cellForRowAtIndexPath的国家/地区名称应用条件。 喜欢这个 if(countryName isEqualToString @"Canada"){ countryInfoLabel.numberofLines=0; countryInfoLabel.text=[NSString stringWithFormat:@"Population:%@",populationFromService]]; } 根据国家/地区名称在countryIn ...
  • 如果你已经做了一切正确的事情仍然无法获得所需的输出意味着问题将受到限制。 我做了一个简单的约束布局,使用这个骨架作为参考并重新约束你的单元格。 将(W:20,H:20)添加到[img]。 确保将行数设置为0,以及所有其他自动尺寸的东西。 IB约束截图。 输出: If u have done everything correct and still u r unable the get desired output means the issue will be with constraints. I hav ...
  • 对于这个问题,我创建了扩展: extension String { func widthWithConstrainedHeight(_ height: CGFloat, font: UIFont) -> CGFloat { let constraintRect = CGSize(width: CGFloat.greatestFiniteMagnitude, height: height) let boundingBox = self.boundingRect( ...
  • 如果您已正确设置约束并且应用程序的部署目标是> = iOS 8,则可以使用自动行高计算。 因此,您必须在viewDidLoad执行以下操作: tableView.estimatedRowHeight = 44 tableView.rowHeight = UITableViewAutomaticDimension 其中44应该是某种平均行高。 那么你根本不必实现estimatedRowHeight和heightForRow方法...... 你也可以实现heightForRow并执行以下操作: // if c ...
  • 这样做的方法是使用自动布局。 您需要从单元格的顶部到底部设置垂直约束: 单元格的上边缘与第一个标签的上边缘之间的距离。 从第一个标签的下边缘到图像视图的上边缘的距离。 从图像视图的下边缘到第二个标签的上边缘的距离。 等等 ... 自动布局将根据您在标签和图像视图中放置的内容的大小来确定单元格的大小。 您还应该记住将表视图上的estimatedRowHeight属性设置为一些有意义的值。 这将有助于表格视图将内容大小的某些计算推迟到用户开始滚动时。 另外,将表视图上的rowHeight属性设置为UITable ...
  • Masonry提供了以编程方式添加约束的更简单方法。 LEt说你有一个UIView并且想要为它添加约束: UIView *superview = self; UIView *view1 = [[UIView alloc] init]; view1.translatesAutoresizingMaskIntoConstraints = NO; view1.backgroundColor = [UIColor greenColor]; [superview addSubview:view1]; UIE ...
  • 有一种方便的方法来使用约束并在代码中更改它。 首先,声明一个约束属性: @IBOutlet weak var labelHeight: NSLayoutConstraint! 其次,将它绑定在XIB或Stroyboard中: 最后,您可以通过编程方式更改它: self.labelHeight.constant = 130 There is a convenience way to use constraint and change it in code. First, declare a constra ...

相关文章

更多

最新问答

更多
  • 如何在Laravel 5.2中使用paginate与关系?(How to use paginate with relationships in Laravel 5.2?)
  • linux的常用命令干什么用的
  • 由于有四个新控制器,Auth刀片是否有任何变化?(Are there any changes in Auth blades due to four new controllers?)
  • 如何交换返回集中的行?(How to swap rows in a return set?)
  • 在ios 7中的UITableView部分周围绘制边界线(draw borderline around UITableView section in ios 7)
  • 使用Boost.Spirit Qi和Lex时的空白队长(Whitespace skipper when using Boost.Spirit Qi and Lex)
  • Java中的不可变类(Immutable class in Java)
  • WordPress发布查询(WordPress post query)
  • 如何在关系数据库中存储与IPv6兼容的地址(How to store IPv6-compatible address in a relational database)
  • 是否可以检查对象值的条件并返回密钥?(Is it possible to check the condition of a value of an object and JUST return the key?)
  • GEP分段错误LLVM C ++ API(GEP segmentation fault LLVM C++ API)
  • 绑定属性设置器未被调用(Bound Property Setter not getting Called)
  • linux ubuntu14.04版没有那个文件或目录
  • 如何使用JSF EL表达式在param中迭代变量(How to iterate over variable in param using JSF EL expression)
  • 是否有可能在WPF中的一个单独的进程中隔离一些控件?(Is it possible to isolate some controls in a separate process in WPF?)
  • 使用Python 2.7的MSI安装的默认安装目录是什么?(What is the default installation directory with an MSI install of Python 2.7?)
  • 寻求多次出现的表达式(Seeking for more than one occurrence of an expression)
  • ckeditor config.protectedSource不适用于editor.insertHtml上的html元素属性(ckeditor config.protectedSource dont work for html element attributes on editor.insertHtml)
  • linux只知道文件名,不知道在哪个目录,怎么找到文件所在目录
  • Actionscript:检查字符串是否包含域或子域(Actionscript: check if string contains domain or subdomain)
  • 将CouchDB与AJAX一起使用是否安全?(Is it safe to use CouchDB with AJAX?)
  • 懒惰地初始化AutoMapper(Lazily initializing AutoMapper)
  • 使用hasclass为多个div与一个按钮问题(using hasclass for multiple divs with one button Problems)
  • Windows Phone 7:检查资源是否存在(Windows Phone 7: Check If Resource Exists)
  • 无法在新线程中从FREContext调用getActivity()?(Can't call getActivity() from FREContext in a new thread?)
  • 在Alpine上升级到postgres96(/ usr / bin / pg_dump:没有这样的文件或目录)(Upgrade to postgres96 on Alpine (/usr/bin/pg_dump: No such file or directory))
  • 如何按部门显示报告(How to display a report by Department wise)
  • Facebook墙贴在需要访问令牌密钥后无法正常工作(Facebook wall post not working after access token key required)
  • Javascript - 如何在不擦除输入的情况下更改标签的innerText(Javascript - how to change innerText of label while not wiping out the input)
  • WooCommerce / WordPress - 不显示具有特定标题的产品(WooCommerce/WordPress - Products with specific titles are not displayed)