IT技术之家

首页 > Java

Java

性能优化 | Wireshark抓包告诉你为什么Redis Pipeline可以明显提升性能_Java小海._redis wireshark

发布时间:2022-10-24 18:31:14 Java 0次 标签:spring java-ee java
就本人目前所接触过的系统而言, 大部分系统性能瓶颈还是在IO。举个例子, 原本在内网表现压测表现正常的系统了,上了预发布环境后进行压力测试系统整体性能表现特别拉胯, 经过排查后发现 耗时主要集中MySQL与Redis查询/更新这一块, 排查数据库日志发现并没有特别离谱慢查询, 可以确定耗时基本上在IO这一块。排查出问题之后, 立马开始对系统采取了以下优化措施:需要使用到数据库数据的地方尽可能一次性查询出来 使用CASE WHEN机制一次性更新多条数据优化之后性能有所提升, 但表现还是不佳,...

就本人目前所接触过的系统而言, 大部分系统性能瓶颈还是在IO。

举个例子, 原本在内网表现压测表现正常的系统了,上了预发布环境后进行压力测试系统整体性能表现特别拉胯, 经过排查后发现 耗时主要集中MySQL与Redis查询/更新这一块, 排查数据库日志发现并没有特别离谱慢查询, 可以确定耗时基本上在IO这一块。

排查出问题之后, 立马开始对系统采取了以下优化措施:

需要使用到数据库数据的地方尽可能一次性查询出来使用CASE WHEN机制一次性更新多条数据

优化之后性能有所提升, 但表现还是不佳, 最后定位到部分接口(排行榜类的)有以下行为:

由于缓存数据分散在多个zset中, 查询出多少条用户数据就会调用多少次zscore以及zrevrank来获取用户的积分或排名

以上行为造成了接口的主要耗时全部集中在了IO上, 虽然平均执行一条指令耗时大概在1ms(从发出请求到接收到返回数据), 但架不住积少成多。

由此, 我们引入了Redis的pipeline机制对系统中的缓存读取的部分进行了优化。

Redis Pipeline

我们知道典型的Redis是典型的C/S架构, 并且是请求/响应模型, 即:

在同一个TCP连接上, 客户端按顺序发出请求A, B, C, 服务端按照顺序返回A, B, C的响应, 大多数客户端的实现方式是发出请求A后会等待到响应返回才发出下一个请求。

与之形成对比的是HTTP2, 该协议支持在同一个TCP连接上发出多个请求, 并且响应是可以无序到达的

需要注意的是, Redis Pipeline 并不是像set,get之类的命令, 而是客户端将命令打包在一起,然后发送给Redis服务端处理。说白了就是Redis服务端如果检测到了客户端同时发了多条命令过来, 会启用pipline机制, 将命令的响应保存到响应队列中, 处理完之后打包回给客户端。

以下Demo使用Go编写一个简单的pipline程序, 并记录了抓包数据:

package main

import (
	"context"
	"fmt"
	"github.com/go-redis/redis/v8"
)

func main() {
	rdb := redis.NewClient(&redis.Options{
		Addr:     "192.168.0.15:6379",
		Password: "", // no password set
		DB:       0,  // use default DB
	})
	ctx := context.Background()
	pipe := rdb.Pipeline()
	for i := 0; i < 64; i++ {
		pipe.ZRank(ctx, "rank", fmt.Sprintf("u%d", i))
	}
	cmds, err := pipe.Exec(ctx)
	if err != nil && err != redis.Nil {
		panic(err)
	}
	for _, cmd := range cmds {
		resp := cmd.(*redis.IntCmd)
		rank, err := resp.Result()
		if err != nil && err != redis.Nil {
			panic(err)
		}
		fmt.Printf("%d\n", rank)
	}
}

复制代码

如下图红框标注的报文所示, 客户端并没有发送pipline之类啥的字符串, 而是直接将命令打包在一起发送给服务端, 由于数据量较大被拆成了两个包。

Redis 服务端的响应报文如下所示

那么如果我们不使用Pipeline呢? WireShark截图如下所示(读者可以自行修改以上代码并进行验证)

以上行为可能你在内网开发的时候没有什么感觉, 因为业务服务器和Redis服务器之间的RTT很小, 甚至有可能在同一机子上。可如果上了生产环境, 业务服务器和Redis服务一般都是单独部署,这么多网络请求带来的耗时就很可观了。

总结

Redis Pipeline是Redis提供的一种批处理机制, 而不是一条命令使用 Redis Pipeline机制可以有效减少网络请求次数,减少多次IO带来的消耗从而提供性能通过合并IO操作(减少IO次数)带来性能提升是非常明显的


作者:kovogo
链接:https://juejin.cn/post/7031567422402330654
来源:稀土掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。