Redis-03-性能测试及工具性能_redis evalsha 性能-程序员宅基地

技术标签: java  redis  

一、慢查询

Redis慢查询分析

与mysql一样:当执行时间超过阈值,会将发生时间耗时命令记录。
redis命令生命周期:发送,排队,执行,返回。
慢查询只统计第3个执行步骤时间。

慢查询阈值

1.动态设置6379:> config set slowlog-log-slower-than 10000 //10毫秒
使用config set完后,若想将配置持久化保存到redis.conf,要执行config rewrite
2.redis.conf修改:找到slowlog-log-slower-than 10000,修改保存即可。
注意:slowlog-log-slower-than=0记录所以命令 -1命令都不记录。

慢查询原理

慢查询记录也是存在队列里的,slow-max-len存放的记录最大条数,比如设置的slow-max-len=1000(正式线上设置也为1000基本够用了,基本涵盖了所有慢查询语句了),当有第1001条慢查询命令插入时,队列的第一条命令就会出列,第1001条入列到慢查询队列中,可以config set动态设置,也可以修改redis.conf完成配置。

慢查询命令

获取队列里慢查询的命令:slowlog get
获取慢查询列表当前的长度:slowlog len //以上只有1条慢查询,返回1;
1,对慢查询列表清理(重置):slowlog reset //再查slowlog len 此时返回0 清空;
2,对于线上slow-max-len配置的建议:线上可加大slow-max-len的值,记录慢查询存长命令时redis会做截断,不会占用大量内存,线上可设置1000以上
3,对于线上slowlog-log-slower-than配置的建议:默认为10毫秒,根据redis并发量来调整,对于高并发比建议为1毫秒
4,慢查询是先进先出的队列,访问日志记录出列丢失,需定期执行slowlog get,将结果存储到其它设备中(如mysql)

二、Redis-cli详解

./redis-cli -r 3 -h 127.0.0.1 -a 123456 ping //返回pong表示127.0.0.1:6379能通,r代表次数
./redis-cli -h 127.0.0.1 -a 123456 -r 100 -i 1 info |grep used_memory_human //每秒输出内存使用量,输100次,i代表执行的时间间隔
./redis-cli -p 6379 -h 127.0.0.1 -a 123456
对于我们来说,这些常用指令以上可满足,但如果要了解更多
执行redis-cli --help, 可百度

三、Redis-server详解

./redis-server ./redis.conf & //指定配置文件启动,无论开什么服务都要带& 表示在后台运行。
./redis-server --test-memory 1024 //检测操作系统能否提供1G内存给redis, 常用于测试,想快速占满机器内存做极端条件的测试,可使用这个指令在redis上线前,做一次测试。

四、Redis-benchmark:基准性测试,测试redis的性能

1、redis-benchmark -h 192.168.42.111 -p 6379 -c 100 -n 100000
100个并发连接,100000个请求,检测host为localhost 端口为6379的redis服务器性能 。
2、redis-benchmark -h 192.168.42.111 -p 6379 -q -d 100
测试存取大小为100字节的数据包的性能。

3、redis-benchmark -h 192.168.42.111 -t set,lpush -n 100000 -q
只测试 set,lpush操作的性能,-q只显示每秒钟能处理多少请求数结果。

4、redis-benchmark -h 192.168.42.111 -n 100000 -q script load “redis.call(‘set’,‘foo’,‘bar’)”

只测试某些数值存取的性能, 比如说我在慢查询中发现,大部分为set语句比较慢,我们自己可以测一下Set是不是真的慢。

五、Pipeline详解

pipeline出现的背景:
redis客户端执行一条命令分4个过程:
发送命令-〉命令排队-〉命令执行-〉返回结果
这个过程称为Round trip time(简称RTT, 往返时间),mget mset有效节约了RTT,但大部分命令(如hgetall,并没有mhgetall)不支持批量操作,需要消耗N次RTT ,这个时候需要pipeline来解决这个问题。
1.未使用pipeline执行N条命令
在这里插入图片描述
2.使用pipeline执行N条命令
在这里插入图片描述

3.使用pipeline和未使用pipeline的性能对比:

在这里插入图片描述
小总结:使用pipeline执行速度比逐条执行要快,客户端与服务端的网络延迟越大,性能体现越明显。

4.原生的批命令(mset, mget等)与pipeline的对比:
A.原生批命令是原子性,pipeline是非原子性, (原子性概念:一个事务是一个不可分割的最小工作单位,要么都成功要么都失败。原子操作是指你的一个业务逻辑必须是不可拆分的. 处理一件事情要么都成功要么都失败,其实也引用了生物里概念,分子-〉原子,原子不可拆分)。
B.原生批命令一命令多个key, 但pipeline支持多命令(存在事务),非原子性。
C. 原生批命令是服务端实现,而pipeline需要服务端与客户端共同完成。

5.pipeline正确使用方式:
使用pipeline组装的命令个数不能太多,不然数据量过大,增加客户端的等待时间,还可能造成网络阻塞,可以将大量命令的拆分多个小的pipeline命令完成

		Jedis jedis  = new Jedis("127.0.0.1",6379);//只是创建了个对象

		//使用pipeline一次性将命令提交
		final Pipeline pipelined = jedis.pipelined();
		pipelined.set("a", "a");
		pipelined.sadd("b", "b", "bb");
		pipelined.mget("a");
		pipelined.sync(); //获取返回数据

		jedis.close();

六、Redis事务(弱事务性)

pipeline是多条命令的组合,为了保证它的原子性,redis提供了简单的事务,什么是事务?事务是指一组动作的执行,这一组动作要么成功,要么失败。
1.redis的简单事务,将一组需要一起执行的命令放到multi和exec两个命令之间,其中multi代表事务开始,exec代表事务结束。
注:在multi前set user:age 4 //初始化值
在这里插入图片描述
2.停止事务discard
在这里插入图片描述
3.命令错误,语法不正确,导致事务不能正常结束
在这里插入图片描述
4.运行错误,语法正确,但类型错误,事务可以正常结束
在这里插入图片描述
可以看到redis不支持回滚的。

5.watch命令
在这里插入图片描述
redis提供了简单事务,之所以说简单,不支持事务回滚。

七、LUA语言与Redis

因为redis的本身弱事务性,所以本身的事务就有点鸡肋。所以引入了LUA脚本。
LUA脚本语言是C开发的,类似存储过程。

使用脚本的好处如下:

1.减少网络开销:本来5次网络请求的操作,可以用一个请求完成,原先5次请求的逻辑放在redis服务器上完成。使用脚本,减少了网络往返时延。
2.原子操作:Redis会将整个脚本作为一个整体执行,中间不会被其他命令插入。
3.复用:客户端发送的脚本会永久存储在Redis中,意味着其他客户端可以复用这一脚本而不需要使用代码完成同样的逻辑。

语法格式:

6379>eval “return redis.call(‘get’,KEYS[1])” 1 name //eval+脚本+KEYS[1]+键个数+键
eval script numkeys key [key …]

//下面是简单语法,具体可以上对应官网
//语法1:
local int sum = 0
local int i =0
while i <= 100
do sum = sum+i
   i = i+1
end
print(sum)

//语法2:
local tables myArray={
    “james”,”java”,false,34} //定义
local int sum = 0
print(myArray[3])  //返回false
for i = 1,100
do
   sum = sum+1
end
print(sum)
for j = 1,#myArray   //遍历数组
do 
   print(myArray[j])
   if myArray[j] == “james” 
then
  print(true)
  break
else
  print(false)
end
end

案列实现

访问频率限制: 实现访问者 $ip 127.0.0.1在一定的时间 $time 20S内只能访问 $limit 10次.使用JAVA语言实现:

private boolean accessLimit(String ip, int limit,
 int time, Jedis jedis) {
    
    boolean result = true;

    String key = "rate.limit:" + ip;
    if (jedis.exists(key)) {
    
        long afterValue = jedis.incr(key);
        if (afterValue > limit) {
    
            result = false;
        }
    } else {
    
        Transaction transaction = jedis.multi();
        transaction.incr(key);
        transaction.expire(key, time);
        transaction.exec();
    }
    return result;
}

以上代码有两点缺陷 :
可能会出现竞态条件: 解决方法是用 WATCH 监控 rate.limit:$IP 的变动, 但较为麻烦;
以上代码在不使用 pipeline 的情况下最多需要向Redis请求5条指令, 传输过多.
使用lua脚本来处理,包括了原子性:如下
./redis-cli -h 127.0.01 -p 6379 -a 12345678 --eval ipCount.lua rate.limit:127.0.0.1 ,10 20

其中 逗号分开key值和参数 逗号两边都要有空格,不然参数会解析错误。, keys[1] = rate.limit:127.0.0.1 argv[1]=10次, argv[2]=20S失效
ipCount.lua内容:

local key =  KEYS[1]
local limit = tonumber(ARGV[1])
local expire_time = ARGV[2]

local is_exists = redis.call("EXISTS", key)
if is_exists == 1 then
    if redis.call("INCR", key) > limit then
        return 0
    else
        return 1
    end
else
    redis.call("SET", key, 1)
    redis.call("EXPIRE", key, expire_time)
    return 1
end

执行逻辑:使用redis-cli --eavl时,客户端把lua脚本字符串发给redis服务端,将结果返回客户端,如下图:
在这里插入图片描述
如果是直接在命令行输入lua脚本内容的:
语法格式: EVAL script numkeys key [key …] arg [arg …]
<1> script: 你的lua脚本
<2> numkeys: key的个数
<3> key: redis中各种数据结构的替代符号
<4> arg: 你的自定义参数

例子:eval “return {KEYS[1],KEYS[2],ARGV[1],ARGV[2]}” 2 key1 key2 bruce 20

redis对lua脚本的管理

1 ./redis-cli -h 127.0.0.11 -a 12345678 script load “$(cat random.lua)” //将LUA脚本内容加载到redis, 得到 返回的sha1值:afe90689cdeec602e374ebad421e3911022f47c0
在这里插入图片描述
执行脚本:evalsha afe90689cdeec602e374ebad421e3911022f47c0 1 bruce 1
通过 lget bruce获取值。
只是修改脚本,没有加载到redis上,调用这个脚本还是修改之前的脚本。

// random.lua脚本,随机一个值保存入key中
for i=1, ARGV[1],1 do
 redis.call("lpush", KEYS[1], math.random()); 
end
return true

2 6379〉script exists afe90689cdeec602e374ebad421e3911022f47c0 //检查sha1值的LUA脚本是否加载到redis中, 返回1 已加载成功。
在这里插入图片描述
3 6379〉script flush //清空加载的lua脚本内容。

4 6379〉script kill //杀掉正在执行的LUA脚本,比如LUA比较耗时阻塞,杀掉。
在这里插入图片描述

八、 发布订阅模式

redis提供了“发布、订阅”模式的消息机制,其中消息订阅者与发布者不直接通信,发布者向指定的频道(channel)发布消息,订阅该频道的每个客户端都可以接收到消息。
在这里插入图片描述

redis主要提供发布消息、订阅频道、取消订阅以及按照模式订阅和取消订阅。
1.发布消息
publish channel:test “hello world”
2.订阅消息
subscrible channel:test
此时另一个客户端发布一个消息:publish channel:test “james test”
当前订阅者客户端会收到如下消息:
在这里插入图片描述

九、从mysql中导入数据到redis

语句:mysql -utest(用户) -ptest(密码) test(数据库) --default-character-set=utf8 --skip-column-names(跳过列名) --raw(将后面的sql语句贴到mysql的命令框) < order.sql | redis-cli -h 192.168.42.111 -p 6379 -a 123456 --pipe(通过管道传输)

oreder.sql的文件内容:确实就是将数据改为redis能识别的RESP协议格式内容。

SELECT CONCAT(
 '*10\r\n', //表示下面有10行数据(实际时候,删除注释,下同)
   '$', LENGTH(redis_cmd), '\r\n', redis_cmd, '\r\n',  //表示命令的长度和命令名字
   '$', LENGTH(redis_key), '\r\n', redis_key, '\r\n',  //表示key的长度和key的名字
   '$', LENGTH(hkey1),'\r\n',hkey1,'\r\n', //第一个字段的长度和第一个字段名
   '$', LENGTH(hval1),'\r\n',hval1,'\r\n', //第一个字段的值长度和第一个字段的值
   '$', LENGTH(hkey2),'\r\n',hkey2,'\r\n', //第二个字段的长度和第二个字段名
   '$', LENGTH(hval2),'\r\n',hval2,'\r\n', //第二个字段的值长度和第二个字段的值
   '$', LENGTH(hkey3),'\r\n',hkey3,'\r\n',
   '$', LENGTH(hval3),'\r\n',hval3,'\r\n',
   '$', LENGTH(hkey4),'\r\n',hkey4,'\r\n',
   '$', LENGTH(hval4),'\r\n',hval4,'\r'
)
FROM (
 SELECT
 'HSET' AS redis_cmd,
 CONCAT('order:info:',orderid) AS redis_key,
 'ordertime' AS hkey1, ordertime AS hval1,
 'ordermoney' AS hkey2, ordermoney AS hval2,
 'orderstatus' AS hkey3, orderstatus AS hval3,
 'version' AS hkey4, `version` AS hval4
 FROM `order`
) AS t

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/weixin_43561060/article/details/114970965

智能推荐

kaggle數據集下載到colab上并且解压_colab 解压缩包-程序员宅基地

文章浏览阅读2.9k次。一个Google colab的实例最长可以持续12小时,窗口关闭后只会继续跑90分钟。!pip install -U -q kaggle!mkdir -p ~/.kaggle!echo '{"username":"pupil3","key":"a56f1ff7585ceb0a1d98f25d7bd514d3"}' > ~/.kaggle/kaggle.json!chmod ..._colab 解压缩包

Go语言学习笔记—gorm(三)_withpreload gorm-程序员宅基地

文章浏览阅读631次。对象关系映射(Object-Relationl Mapping,简称ORM)模式是一种为了解决面向对象和关系数据库(如mysql数据库)存在的互相不匹配的现象的技术。_withpreload gorm

locate: can not stat () `/var/lib/mlocate/mlocate.db': No such file or directory-程序员宅基地

文章浏览阅读269次。安装好CentOS后,第一次进入系统使用locate命令,结果出现:locate: can not stat () `/var/lib/mlocate/mlocate.db': No such file or directory解决办法运行updatedb命令即可,如下图所示:转载于:https://www.cnblogs.com/Richard-xie/p/47074..._/var/lib/plocate/plocate.db: no such file or directory

webpack5 + vite2 入门_webpack5、vite2-程序员宅基地

文章浏览阅读1k次。Webpack笔记从使用 webpack 的角度来说,搞清楚 webpack 的配置即可安装需要 node 14+ 和 npm(安装 node 时自动安装)。全局安装npm install webpack webpack-cli -g局部安装(推荐)npm init -y-D 表示安装的开发依赖。加不加并不影响,但是推荐加,这样项目 package.json 会整洁些。npm install webpack webpack-cli -D基本使用在新建项目的时候使用 webpack _webpack5、vite2

python包导入细节(attempted relative import beyond top-level package的原因解读)-程序员宅基地

文章浏览阅读2.4w次,点赞22次,收藏70次。先在讨论python导入问题时,先弄清楚几个重要概念和区别:一、什么是模块,什么是脚本(script vs module)二、命名(naming)三、不通过包导入访问一个模块四、相对导入…五、…只能用在相对导入当使用六、脚本不能包含相对导入七、解决办法感谢博主 小舔哥 :https://www.cnblogs.com/jiaxin359/p/7580375.html ..._attempted relative import beyond

mysql 消息队列_一个简单的 MySQL 批量事务消息队列-程序员宅基地

文章浏览阅读1k次。基于 MySQL 的批量事务消息队列消息队列本质上是一个存储介质,通常是链表结构,不同的进程或线程可以向消息队列中写入或读取消息。消息队列的使用场景有很多,比如异步处理任务、应用解耦、流量削锋等等。通常我们使用消息队列,都是直接使用 MNS、RocketMQ、Kafka 等产品。但某些场景下这些产品也难以满足,或者使用起来成本比较高,比如:批量创建大量(比如 1 万条)消息,并且要么都写入,要么不..._mysql 大量 update 走队列机制

随便推点

Oracle ORA-12541:TNS:无监听程序_net 无监听程序-程序员宅基地

文章浏览阅读4.4k次。1.打开Net Configuration Assistant 2.选择监听程序配置,下一步3.选择重新配置,下一步4.选择监听程序,默认,下一步注:如果你的监听已启动,则出现提示框,选择是5.选择协议,使用默认的TCP协议,下一步6.选择端口号,使用标准端口号1521,下一步7.不配置另一个监听程序,选择否,下一步8.监听程序配置完成,下一步重配服务名,测试连接1.选择Net..._net 无监听程序

BZOJ 1001 网络流最小割 解题报告_网格图最小割 bzoj1001-程序员宅基地

文章浏览阅读269次。001: [BeiJing2006]狼抓兔子Description现在小朋友们最喜欢的”喜羊羊与灰太狼”,话说灰太狼抓羊不到,但抓兔子还是比较在行的, 而且现在的兔子还比较笨,它们只有两个窝,现在你做为狼王,面对下面这样一个网格的地形: 左上角点为(1,1),右下角点为(N,M)(上图中N=4,M=5).有以下三种类型的道路 1:(x,y)<==>(x+1,y) 2:(x,y)<=_网格图最小割 bzoj1001

Part 4: CRUD Operations on BackboneJs Models using HTTP REST Service-程序员宅基地

文章浏览阅读129次。In this article we will discuss how we can perform CRUD operations on a backbone model using a REST based HTTP service.[size=large][b]Background[/b][/size]Earlier we have discussed about the b..._backbone.js实现crud

android自定义RadioButton的样式_android radiobutton 自定义样式-程序员宅基地

文章浏览阅读2k次。一、样式的实现 <TextView android:layout_width="wrap_content" android:layout_height="50dp" android:layout_gravity="center" andro..._android radiobutton 自定义样式

stl文件转stp (二次开发)_stl转stp-程序员宅基地

文章浏览阅读3.6w次,点赞29次,收藏82次。前几天有个美女问我stl文件怎么处理,很尴尬我也处理不了,为了避免再次发生这种情况,所以我做了这个小软件。其下载链接将在文末给出。因为是电脑软件,所以使用的是.net c# 编写,ide是秒天秒地秒空气的visual studio。下面分几步说一下思路和代码过程:1、stl文件和stp文件的数据存储形式一、stl文件格式stl的文件格式是很容易就能找到的,比如说直接问度娘:..._stl转stp

UVa1625——颜色长度(DP)_dp颜色函数-程序员宅基地

文章浏览阅读239次。题目链接:https://vjudge.net/contest/232313#problem/H思路:紫书上写的很详细了:不是等到一个颜色全部移完之后再相加,而是每次都计算已经开始但还没结束的颜色的个数并将长度累加。所以,用res[i][j]表示第一个串还剩i个,第二个串还剩j个,已经开始但还没结束的字符个数。dp[i][j]表示第一个还剩i个,第二个串还剩j个,还需要的最小指标函数。..._dp颜色函数

推荐文章

热门文章

相关标签