一、 慢查询原因分析

与mysql一样:当执行时间超过阀值,会将发生时间耗时的命令记录

redis命令生命周期:发送 排队 执行 返回
慢查询只统计第3个执行步骤的时间

预设阀值:两种方式,默认为10毫秒
1,动态设置6379:> config set slowlog-log-slower-than 10000 //10毫秒10000微秒
使用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=10,当有第11条慢查询命令插入时,队列的第一条命令就会出列,第11条入列到慢查询队列中, 可以config set动态设置,也可以修改redis.conf完成配置。

2 命令:
获取队列里慢查询的命令:slowlog get 查询返回的结构如下

获取慢查询列表当前的长度:slowlog len //返回7

对慢查询列表清理(重置):slowlog reset //再查slowlog len 此时返回0 清空

对于线上slow-max-len配置的建议:线上可加大slow-max-len的值,记录慢查询存长命令时redis会做截断,不会占用大量内存,线上可设置1000以上
对于线上slowlog-log-slower-than配置的建议:默认为10毫秒,根据redis并发量来调整,对于高并发比建议为1毫秒
注意:

1,慢查询只记录命令在redis的执行时间,不包括排队、网络传输时间
2,慢查询是先进先出的队列,访问日志记录出列丢失,需定期执行slow get,将结果存储到其它设备中(如mysql)

二、redis-cli详解

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

三、 redis-server详解

./redis-server ./redis.conf & //指定配置文件启动
./redis-server --test-memory 1024 //检测操作系统能否提供1G内存给redis, 常用于测试,想快速占满机器内存做极端条件的测试,可使用这个指令
redis上线前,做一次测试

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

100个客户端同时请求redis,共执行10000次,会对各类数据结构的命令进行测试:

./redis-benchmark -h 127.0.0.1 -c 100 -n 10000  //100个并发连接,100000个请求,检测host为localhost 端口为6379的redis服务器性能

测试存取大小为100字节的数据包的性能:

./redis-benchmark -h 127.0.0.1 -p 6379 -q -d 100

只测试 set,lpush操作的性能,-q只显示每秒钟能处理多少请求数结果:

./redis-benchmark -h 127.0.0.1 -t set,lpush -n 100000 -q

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

./redis-benchmark -h 192.168.1.111 -n 100000 -q script load "redis.call('set','foo','bar')"

五、Pipeline(管道)

1.背景:

没有pipeline之前,一般的redis命令的执行过程都是:发送命令-〉命令排队-〉命令执行-〉返回结果。

多条命令的时候就会产生更多的网络开销

这个时候需要pipeline来解决这个问题:使用pipeline来打包执行N条命令,这样的话就只需简历一次网络连接,网络开销就少了

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

使用Pipeline执行速度与逐条执行要快,特别是客户端与服务端的网络延迟越大,性能体能越明显

3.原生批命令(mset, mget)与Pipeline对比

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

4. pipeline正确使用方式:

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

如:有300个命令需要执行,可以拆分成每30个一个pipeline执行

六、redis事务

pipeline是多条命令的组合,为了保证它的原子性,redis提供了简单的事务;redis的事物与mysql事物的最大区别是redis事物不支持事物回滚

事务:事务是指一组动作的执行,这一组动作要么都成功,要么都失败。

1. redis的简单事务,将一组需要一起执行的命令放到multi和exec两个命令之间,其中multi代表事务开始,exec代表事务结束

2.停止事务discard

3. 命令错误,语法不正确,导致事务不能正常执行,即事物的原子性

4. watch命令:使用watch后, multi失效,事务失效,其他的线程任然可以对值进行修改

在客户端1设置值使用watch监听key并使用multi开启事物,在客户端2追加完c之后再来客户端1追加redis,然后执行事物,可以看到在客户端1追加的redis没有起效果:

客户端1:

客户端2:

七、LUA语言与Redis配合使用

1. LUA脚本语言是C开发的,类似存储过程

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

语法:

eval+脚本+KEYS[1]+键个数+键——》eval script numkeys key [key ...]

eval "return redis.call('get',KEYS[1])" 1 name 

语法示例1:

 local int sum =
local int i =
while i <=
do sum = sum+i
i = i+
end
print(sum)

语法示例2:

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

2. 案例:

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

a)使用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条指令, 传输过多.

b)使用lua脚本来处理,包括了原子性

lua脚本:

ipAccessCount.lua

 local key =  KEYS[]
local limit = tonumber(ARGV[])
local expire_time = ARGV[] local is_exists = redis.call("EXISTS", key)
if is_exists == then
if redis.call("INCR", key) > limit then
return
else
return
end
else
redis.call("SET", key, )
redis.call("EXPIRE", key, expire_time)
return
end

使用redis命令获取lua脚本来执行:

./redis-cli -p 6379 -a 12345678 --eval ipAccessCount.lua rate.limit:127.0.0.1, 10 20

和lua脚本的对应关系为: keys[1] = rate.limit:127.0.0.1   argv[1]=10次,  argv[2]=20S失效

执行逻辑:使用redis-cli --eavl时,客户端把lua脚本字符串发给redis服务端,将结果返回客户端,如下图

3. redis对Lua脚本的管理

1.将Lua脚本加载到redis中,得到 返回的sha1值(类似于我们说的数字签名):afe90689cdeec602e374ebad421e3911022f47c0

  redis-cli -h 192.168.1.111 -a 12345678 script load "$(cat random.lua)"
2.检查脚本加载是否成功,返回1 已加载成功

  script exists afe90689cdeec602e374ebad421e3911022f47c0
3.清空Lua脚本内容

  script flush 
4.杀掉正在执行的Lua脚本

  script kill

八、发布与订阅

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

redis主要提供发布消息、订阅频道、取消订阅以及按照模式订阅和取消订阅

1.发布消息
publish channel:test "hello world"

2.订阅消息
subscrible channel:test
此时另一个客户端发布一个消息:publish channel:test "james test"
当前订阅者客户端会收到如下消息:

和很多专业的消息队列(kafka rabbitmq),redis的发布订阅显得很lower, 比如无法实现消息规程和回溯, 但就是简单,如果能满足应用场景,用这个也可以

3.查看订阅数:
pubsub numsub channel:test // 频道channel:test的订阅数

4.取消订阅
unsubscribe channel:test
客户端可以通过unsubscribe命令取消对指定频道的订阅,取消后,不会再收到该频道的消息

5.按模式订阅和取消订阅
psubscribe ch* //订阅以ch开头的所有频道

punsubscribe ch*  //取消以ch开头的所有频道

6.应用场景:
1、今日头条订阅号、微信订阅公众号、新浪微博关注、邮件订阅系统
2、即时通信系统
3、群聊部落系统(微信群)

Redis系列六:redis相关功能的更多相关文章

  1. Redis系列六 Redis事务

    Redis事务 1.介绍 在Redis事务中可以一次执行多个命令,本质是一组命令的集合.一个事务中的所有命令都会序列化,按顺序地串行化执行而不会被其它命令插入,不许加塞. 2.事务的作用 一个队列中, ...

  2. Redis系列(二):Redis的数据类型及命令操作

    原文链接(转载请注明出处):Redis系列(二):Redis的数据类型及命令操作 Redis 中常用命令 Redis 官方的文档是英文版的,当然网上也有大量的中文翻译版,例如:Redis 命令参考.这 ...

  3. Redis系列(一):Redis的简介与安装

    原文链接(转载请注明出处):Redis系列(一):Redis的简介与安装 什么是 Redis Redis 是一个使用ANSI C 编写的开源.支持网络协议.基于内存.可选持久性的键值对数据库,它是一个 ...

  4. Redis系列一 Redis安装

    Redis系列一    Redis安装 1.安装所使用的操作系统为Ubuntu16.04 Redis版本为3.2.9 软件一般下载存放目录为/opt,以下命令操作目录均为/opt root@ubunt ...

  5. 痞子衡嵌入式:浅谈i.MXRT1xxx系列MCU时钟相关功能引脚的作用

    大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家介绍的是i.MXRT1xxx系列MCU时钟相关功能引脚作用. 如果我们从一颗 MCU 芯片的引脚分类来看芯片功能,大概可以分为三大类:电源.时钟 ...

  6. Redis系列(六):设置/移除键的过期时间

    本篇博客是Redis系列的第6篇,主要讲解以下内容: 数据库数量 切换目标数据库 设置键的过期时间 移除键的过期时间 本系列的前5篇可以点击以下链接查看: Redis系列(一):Redis简介及环境安 ...

  7. 【Redis 系列】redis 学习十六,redis 字典(map) 及其核心编码结构

    redis 是使用 C 语言编写的,但是 C 语言是没有字典这个数据结构的,因此 C 语言自己使用结构体来自定义一个字典结构 typedef struct redisDb src\server.h 中 ...

  8. 深入剖析Redis系列: Redis集群模式搭建与原理详解

    前言 在 Redis 3.0 之前,使用 哨兵(sentinel)机制来监控各个节点之间的状态.Redis Cluster 是 Redis 的 分布式解决方案,在 3.0 版本正式推出,有效地解决了 ...

  9. redis系列之redis是什么

    一.简介 REmote DIctionary Server(Redis),redis是一个基于内存的单机key/value系统,类似memcached,但支持value为多种形式,包括:字符串(str ...

  10. redis系列:redis介绍与安装

    前言 这个redis系列的文章将会记录博主学习redis的过程.基本上现在的互联网公司都会用到redis,所以学习这门技术于你于我都是有帮助的. 博主在写这个系列是用的是目前最新版本4.0.10,虚拟 ...

随机推荐

  1. C# 两个独立exe程序直接通信

    从别的地方转载过来,转载地址不详细,需要知道的话,可以自动去搜索,我不是原作者. 我之前主要是用工序内存做过两个进程的通信. 两个独立的exe程序之间如何完成通信呢?首先想到的办法是利用生成文件的方法 ...

  2. Git 入门详解

    Git git核心概念详解 什么是git git是一个分布式版本控制软件,最初由林纳斯·托瓦兹创作,于2005年以GPL发布.最初目的是为更好地管理Linux内核开发而设计.应注意的是,这与GNU I ...

  3. HDU1069(KB12-C)

    Monkey and Banana Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others ...

  4. org.springframework.transaction.CannotCreateTransactionException Could not open

    org.springframework.transaction.CannotCreateTransactionException: Could not open JDBC Connection for ...

  5. 前端开发笔记(4)css基础(下)

    标签定位 相对定位 相对定位是用来微调元素位置的,让元素相对于原来的位置进行调整. <head> <meta http-equiv="Content-Type" ...

  6. ActiveReports 报表应用教程 (14)---数据可视化

    葡萄城ActiveReports报表中提供了丰富的数据可视化解决方案,用户可以将数据以图像化的方式进行显示,让报表数据更加形象且便于理解.在葡萄城ActiveReports报表中提供了大多数常用的二维 ...

  7. Ubuntu 16.04 Server 设置静态IP

    一.前言 最近需要在虚拟机当中装个Ubuntu Server 16.04的系统,但是在虚拟机安装的时候,并不像Ubuntu Server 18.04那样能一步步的进行配置,因此导致装好后的虚拟机是动态 ...

  8. linux安装activemq

    ActiveMQ是由Apache出品的,一款最流行的,能力强劲的开源消息总线.ActiveMQ是一个完全支持JMS1.1和J2EE 1.4规范的 JMS Provider实现,它非常快速,支持多种语言 ...

  9. C# WinForm中添加用户控件

    转:https://blog.csdn.net/haelang/article/details/40681003 有的时候我们需要频繁使用一些系统默认工具的组合,那么就可以使用自定义用户控件. 起一个 ...

  10. sql server对并发的处理-乐观锁和悲观锁(转)

    假如两个线程同时修改数据库同一条记录,就会导致后一条记录覆盖前一条,从而引发一些问题. 例如: 一个售票系统有一个余票数,客户端每调用一次出票方法,余票数就减一. 情景: 总共300张票,假设两个售票 ...