为什么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

相关问答

更多

单元格高度等于图像宽度(Cell height equal to image width)

你不能在heightForRowAtIndexPath调用单元格对象,因为它会在cellForRowAtIndexPath调用heightForRowAtIndexPath时创建无限循环。 其次,使用约束调整width因为函数名称清楚地表明它是高度。 如果您确定控件的高度,请使用此选项 return 90.0 //its optional if height is fixed 其他 为top , bottom , left , right , width和height约束添加约束,并使用> =...

使UItableview单元格高度等于其子UItableview(Make UItableview cell height equal to it's child UItableview)

首先看看我的ViewController,它有一个tableview(tblview)和UITableViewCell(CustomTableViewCell), class ViewController: UIViewController { @IBOutlet var tblview:UITableView! override func viewDidLoad() { super.viewDidLoad() self.tblview.deleg...

基于动态标签高度的iOS8动态单元格高度(iOS8 Dynamic Cell Height based on Dynamic Label height)

第一个问题:是的,确实如此。 您需要使用不同的水平压缩阻力优先级。 您可能还需要较低优先级的不等式来设置限制。 第二个问题:问题是你没有完全确定身高。 您必须从单元格的顶部到单元格的底部一直有约束,以便单元格的高度由其内部的内容严格确定。 First question: Yes, it is. You'll need to use different horizontal compression resistance priorities. You might also need a lower ...

UItableview每个单元格标签都要隐藏,高度应该更改(UItableview each cell label want to hide and height should be change)

是的,这是可能的。您必须根据方法cellForRowAtIndexPath的国家/地区名称应用条件。 喜欢这个 if(countryName isEqualToString @"Canada"){ countryInfoLabel.numberofLines=0; countryInfoLabel.text=[NSString stringWithFormat:@"Population:%@",populationFromService]]; } 根据国家/地区名称在coun...

无法设置表格视图单元格的动态高度?(Not able to set the dynamic height of table view cell?)

如果你已经做了一切正确的事情仍然无法获得所需的输出意味着问题将受到限制。 我做了一个简单的约束布局,使用这个骨架作为参考并重新约束你的单元格。 将(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. ...

如何使宽度单元格等于字符串长度?(How make width cell equal string length?)

对于这个问题,我创建了扩展: extension String { func widthWithConstrainedHeight(_ height: CGFloat, font: UIFont) -> CGFloat { let constraintRect = CGSize(width: CGFloat.greatestFiniteMagnitude, height: height) let boundingBox = self.bounding...

设置单元格的高度等于标签内容(Set height of cell equal to the label content)

如果您已正确设置约束并且应用程序的部署目标是> = iOS 8,则可以使用自动行高计算。 因此,您必须在viewDidLoad执行以下操作: tableView.estimatedRowHeight = 44 tableView.rowHeight = UITableViewAutomaticDimension 其中44应该是某种平均行高。 那么你根本不必实现estimatedRowHeight和heightForRow方法...... 你也可以实现heightForRow并执行以下操作: //...

如何根据其内容更改单元格高度?(How do I change cell height according to its content?)

这样做的方法是使用自动布局。 您需要从单元格的顶部到底部设置垂直约束: 单元格的上边缘与第一个标签的上边缘之间的距离。 从第一个标签的下边缘到图像视图的上边缘的距离。 从图像视图的下边缘到第二个标签的上边缘的距离。 等等 ... 自动布局将根据您在标签和图像视图中放置的内容的大小来确定单元格的大小。 您还应该记住将表视图上的estimatedRowHeight属性设置为一些有意义的值。 这将有助于表格视图将内容大小的某些计算推迟到用户开始滚动时。 另外,将表视图上的rowHeight属性设置为UI...

如何设置自定义单元格标签的约束?(How to set the constraints for custom cell label?)

Masonry提供了以编程方式添加约束的更简单方法。 LEt说你有一个UIView并且想要为它添加约束: UIView *superview = self; UIView *view1 = [[UIView alloc] init]; view1.translatesAutoresizingMaskIntoConstraints = NO; view1.backgroundColor = [UIColor greenColor]; [superview addSubview:view1];...

以编程方式设置collectionview单元格中标签约束的高度(Setting up height of label constraint in collectionview cell programatically)

有一种方便的方法来使用约束并在代码中更改它。 首先,声明一个约束属性: @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 co...

相关文章

更多

Redis Cookbook

Two years since its initial release, Redis already ...

Redis概述

什么是Redis Redis是Remote Dictionary Server的缩写, Redis是一 ...

redis 集群环境搭建-redis集群管理

集群架构 (1)所有的redis节点彼此互联(PING-PONG机制),内部使用二进制协议优化传输速度 ...

Redis 事务详解

Redis 事务可以一次执行多个命令, 并且带有以下两个重要的保证:事务是一个单独的隔离操作:事务中的 ...

redis从库只读设置-redis集群管理

默认情况下redis数据库充当slave角色时是只读的不能进行写操作,如果写入,会提示以下错误:REA ...

redis安装-redis集群管理

安装redis [root@master opt]# mkdir /opt/redis [root ...

redis sentinel.conf详解-redis集群管理

sentinel.conf详解 官方完整示例

基于linux下redis安装与配置

编译源程序:make install,复制可执行文件,Redis的启动,Redis随机启动

Redis配置文件详解

redis是一款开源的、高性能的键-值存储(key-value store),和memcached类似 ...

最新问答

更多

获取MVC 4使用的DisplayMode后缀(Get the DisplayMode Suffix being used by MVC 4)

我用Google搜索了一个解决方案。 “EnumDisplayModeProvider”是我自己设置网站的各种模式的枚举。 public EnumDisplayModeProvider GetDisplayModeId() { foreach (var mode in DisplayModeProvider.Instance.Modes) if (mode.CanHandleContext(HttpContext)) {

如何通过引用返回对象?(How is returning an object by reference possible?)

这相对简单:在类的构造函数中,您可以分配内存,例如使用new 。 如果你制作一个对象的副本,你不是每次都分配新的内存,而是只复制指向原始内存块的指针,同时递增一个也存储在内存中的引用计数器,使得每个副本都是对象可以访问它。 如果引用计数降至零,则销毁对象将减少引用计数并仅释放分配的内存。 您只需要一个自定义复制构造函数和赋值运算符。 这基本上是共享指针的工作方式。 This is relatively easy: In the class' constructor, you allocate m

矩阵如何存储在内存中?(How are matrices stored in memory?)

正如它在“熵编码”中所说的那样,使用Z字形图案,与RLE一起使用,在许多情况下,RLE已经减小了尺寸。 但是,据我所知,DCT本身并没有给出稀疏矩阵。 但它通常会增强矩阵的熵。 这是compressen变得有损的点:输入矩阵用DCT传输,然后量化量化然后使用霍夫曼编码。 As it says in "Entropy coding" a zig-zag pattern is used, together with RLE which will already reduce size for man

每个请求的Java新会话?(Java New Session For Each Request?)

你是如何进行重定向的? 您是否事先调用了HttpServletResponse.encodeRedirectURL()? 在这里阅读javadoc 您可以使用它像response.sendRedirect(response.encodeRedirectURL(path)); The issue was with the path in the JSESSIONID cookie. I still can't figure out why it was being set to the tomca

css:浮动div中重叠的标题h1(css: overlapping headlines h1 in floated divs)

我认为word-break ,如果你想在一个单词中打破行,你可以指定它,这样做可以解决问题: .column { word-break:break-all; } jsFiddle演示。 您可以在此处阅读有关word-break属性的更多信息。 I think word-break, with which you can specify if you want to break line within a word, will do the trick: .column { word-break

无论图像如何,Caffe预测同一类(Caffe predicts same class regardless of image)

我认为您忘记在分类时间内缩放输入图像,如train_test.prototxt文件的第11行所示。 您可能应该在C ++代码中的某个位置乘以该因子,或者使用Caffe图层来缩放输入(请查看ELTWISE或POWER图层)。 编辑: 在评论中进行了一次对话之后,结果发现在classification.cpp文件中错误地删除了图像均值,而在原始训练/测试管道中没有减去图像均值。 I think you have forgotten to scale the input image during cl

xcode语法颜色编码解释?(xcode syntax color coding explained?)

转到: Xcode => Preferences => Fonts & Colors 您将看到每个语法高亮颜色旁边都有一个简短的解释。 Go to: Xcode => Preferences => Fonts & Colors You'll see that each syntax highlighting colour has a brief explanation next to it.

在Access 2010 Runtime中使用Office 2000校对工具(Use Office 2000 proofing tools in Access 2010 Runtime)

你考虑过第三方拼写检查吗? 您可以将在C#中开发的自定义WinForms控件插入访问数据库吗? VB6控件怎么样? 如果你能找到一个使用第三方库进行拼写检查的控件,那可能会有效。 Have you considered a third party spell checker? Can you insert a custom WinForms controls developed in C# into an access database? What about a VB6 control? If

从单独的Web主机将图像传输到服务器上(Getting images onto server from separate web host)

我有同样的问题,因为我在远程服务器上有两个图像,我需要在每天的预定义时间复制到我的本地服务器,这是我能够提出的代码... try { if(@copy('url/to/source/image.ext', 'local/absolute/path/on/server/' . date("d-m-Y") . ".gif")) { } else { $errors = error_get_last(); throw new Exception($err

从旧版本复制文件并保留它们(旧/新版本)(Copy a file from old revision and keep both of them (old / new revision))

我不确定我完全明白你在说什么。 你能编辑你的帖子并包含你正在做的Subversion命令/操作的特定顺序吗? 最好使用命令行svn客户端,以便容易为其他人重现问题。 如果您只是想获取文件的旧副本(即使该文件不再存在),您可以使用如下命令: svn copy ${repo}/trunk/moduleA/file1@${rev} ${repo}/trunk/moduleB/file1 其中${repo}是您的存储库的URL, ${rev}是您想要的文件的版本。 这将恢复该文件的旧版本,包括最高版本