Redis第五天
1,什么是 Redis 慢查询?
与 mysql 一样:当执行时间超过极大值时,会将发生时间 耗时 命令记录. 通信流程如下:
Redis 的所有指令全部会存放到队列, 由单线程按顺序获取并执行指令, 如果某个指令执行很慢, 会出现阻塞, 以上图可以得出: Redis 的慢查询指的是在执行第 3 个操作的时候发生的。
2,Redis 如何设值?
a),动态设置 6379:> config set slowlog-log-slower-than 10000 //10 毫秒使用 config set 完后,若想将配置持久化保存到 redis.conf,要执行 config rewrite;
b),redis.conf 修改:找到 slowlog-log-slower-than 10000 ,修改保存即可。
注意:slowlog-log-slower-than =0 记录所有命令 -1 命令都不记录 。
3,Redis 慢查询原理
慢查询记录也是存在队列里的,slow-max-len 存放的记录最大条数,比如设置的 slow-max-len=10,当有第 11 条慢查询命令插入时,队列的第一条命令就会出列,第 11 条入列到慢查询队列中, 可以 config set 动态设置,也可以修改 redis.conf 完成配置。
4,Redis 慢查询的命令
获取队列里慢查询的命令: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)
5,Redis 性能测试工具如何使用?
A、redis-benchmark -h 192.168.42.111 -p 6379 -c 100 -n 10000
//100 个并发连接,10000 个请求,检测服务器性能
B、redis-benchmark -h 192.168.42.111 -p 6379 -q -d 100
//测试存取大小为 100 字节的数据包的性能
C、redis-benchmark -h 192.168.42.111 -p 6379 -t set,get -n 100000 -q
//只测试 set,lpush 操作的性能
D 、 redis-benchmark -h 192.168.42.111 -p 6379 -n 100000 -q script load "redis.call('set','foo','bar')"
//只测试某些数值存取的性能
6,什么是 Resp 协议?
Redis 服务器与客户端通过 RESP(REdis Serialization Protocol)协议通信。
主要以下特点:容易实现,解析快,人类可读. RESP 底层采用的是 TCP 的连接方式,通过 tcp 进行数据传输,然后根据解析规则解析相应信息,完成交互。我们可以测试下,首先运行一个 serverSocket 监听 6379,来接收 redis 客户端的请求信息,实现如下:
服务端程序如下:
客户端程序如下:
测试发现, 服务端打印的信息如下:
这就是 Resp 协议的结构。
7,将你现有表数据快速存放到 Redis
流程如下:
A), 使用用户名和密码登陆连接数据库
B) , 登陆成功后执行 order.sql 的 select 语句得到查询结果集 result
C) , 使用密码登陆 Redis
D), Redis 登陆成功后, 使用 PIPE 管道将 result 导入 Redis. 操作指令如下:
mysql -utest -ptest stress --default-character-set=utf8 --skip-column-names --raw < order.sql | redis-cli -h 192.168.42.111 -p 6379 -a 12345678 --pipe
8,PIPELINE 操作流程
大多数情况下,我们都会通过请求-相应机制去操作 redis。只用这种模式的一般的步骤是,先获得 jedis 实例,然后通过 jedis 的 get/put 方法与 redis 交互。
由于 redis 是单线程的,下一次请求必须等待上一次请求执行完成后才能继续执行。然而使用 Pipeline 模式,客户端可以一次性的发送多个命令,无需等待服务端返回。这样就大大的减少了网络往返时间,提高了系统性能。
A>批量操作时使用如下代码网络开销非常大:
每一次请求都会建立网络连接, 非常耗时, 特别是跨机房的场景下:
B>使用 PIPELINE 可以解决网络开销的问题,代码如下:
原理也非常简单,流程如下, 将多个指令打包后,一次性提交到 Redis, 网络通信只有一次:
9,Redis 弱事务
刚大家知道,pipeline 是多条命令的组合,为了保证它的原子性,redis 提供了简单的事务,什么是事务?事务是指一组动作的执行,这一组动作要么成功,要么失败。
A > redis 的简单事务,将一组需要一起执行的命令放到 multi 和 exec 两个命令之间,其中 multi 代表事务开始,exec 代表事务结束:
注:在 multi 前 set user:age 4 //请提前初始化该值
B > 停止事务 discard:
C > 命令错误,语法不正确,导致事务不能正常结束:
D > 运行错误,语法正确,但类型错误,事务可以正常结束:
可以看到 redis 不支持回滚功能。
E > Watch 让事务失效,操作命令:
10,redis 主要提供发布消息、订阅频道、取消订阅以及按照模式订阅和取消订阅
A〉发布消息:publish channel:test "hello world"
B〉订阅消息:subscrible channel:test
此时另一个客户端发布一个消息:publish channel:test "james test" 当前订阅者客户端会收到如下消息:
和很多专业的消息队列(kafka rabbitmq),redis 的发布订阅显得很 lower, 比如无法实现消息规程和回溯, 但就是简单,如果能满足应用场景,用这个也可以 。
C〉查看订阅数:pubsub numsub channel:test // 频道 channel:test 的订阅数
D〉取消订阅:unsubscribe channel:test
客户端可以通过 unsubscribe 命令取消对指定频道的订阅,取消后,不会再收到该频道的消息
E〉按模式订阅和取消订阅:psubscribe ch* //订阅以 ch 开头的所有频道
punsubscribe ch* //取消以 ch 开头的所有频道
F〉应用场景:
1、今日头条订阅号、微信订阅公众号、新浪微博关注、邮件订阅系统
2、即使通信系统
3、群聊部落系统(微信群)
测试实践:微信班级群 class:20170101
1、学生 C 订阅一个主题叫 :class:20170101
> subscribe class:20170101
2、学生 A 针对 class:20170101 主体发送消息,那么所有订阅该主题的用户都能够接收到该数据。
> publish class:20170101 "hello world! I am A"
3、学生 B 针对 class:20170101 主体发送消息,那么所有订阅该主题的用户都能够接收到该数据。
> publish class:20170101 "hello world! I am B"
展示学生 C 接受到的 A\B 同学发送过来的消息信息
1) "subscribe"
2) "class:20170101"
3) (integer) 1
1) "message"
2) "class:20170101"
3) "hello world! I am A"
1) "message"
2) "class:20170101"
3) "hello word! I am B"
11, 键的迁移:把部分数据迁移到另一台 redis 服务器
1, move key db //reids 有 16 个库, 编号为 0-15
set name james1; move name 5 //迁移到第 6 个库
select 5 ; //数据库切换到第 6 个库, get name 可以取到 james1
这种模式不建议在生产环境使用,在同一个 reids 里可以玩;
2, dump key;
restore key ttl value//实现不同 redis 实例的键迁移,ttl=0 代表没有过期时间
例子:在 A 服务器上 192.168.42.111
set name james;
dump name; // 得到"\x00\x05james\b\x001\x82;f\"DhJ" ;
在 B 服务器上:192.168.1.118
restore name 0 "\x00\x05james\b\x001\x82;f\"DhJ" get name //返回 james
3,migrate 用于在 Redis 实例间进行数据迁移,实际上 migrate 命令是将 dump、restore、del 三个命令进行组合,从而简化了操作流程。
migrate 命令具有原子性,从 Redis 3.0.6 版本后已经支持迁移多个键的功能。
migrate 命令的数据传输直接在源 Redis 和目标 Redis 上完成,目标 Redis 完成restore 后会发送 OK 给源 Redis。
migrate 实例操作:
migrate 指令迁移到其它实例 redis,在 4222.111 服务器上将 name 移到 112:
指令如下:把 111 上的 name 键值迁移到 112 上的 redis ;
192.168.42.111:6379> migrate 192.168.42.112 6379 name 0 1000 copy 。
12,键的遍历
redis 提供了两个命令来遍历所有的键
1,键全量遍历:
mset country china city bj name james //设置 3 个字符串键值对
keys * //返回所有的键, *匹配任意字符多个字符
keys *y //以结尾的键,
keys n*e //以 n 开头以 e 结尾,返回 name
keys n?me // ?问号代表只匹配一个字符 返回 name,全局匹配
keys n?m* //返回 name
keys [j,l]* //返回以 j l 开头的所有键 keys [j]ames 全量匹配 james
考虑到是单线程, 在生产环境不建议使用,如果键多可能会阻塞,如果键少,可以考虑。
2,渐进式遍历
初始化 13 组 KEY-VALUE
渐进式遍历
2.1,初始化数据
mset n1 1 n2 2 n3 3 n4 4 n5 5 n6 6 n7 7 n8 8 n9 9 n10 10 n11 11 n12 12 n13 13
2.2,遍历匹配:匹配以 n 开头的键,最大是取 5 条,第一次 scan 0 开始:scan 0 match n* count 5
第二次从游标 4096 开始取 20 个以 n 开头的键,相当于一页一页的取当最后;
返回 0 时,键被取完,但 count 不准,一般用来代替 keys *操作,可避免阻塞:
第二次从游标 18 开始取 20 个以 n 开头的键,相当于一页一页的取,当最后返回 0 时,键被取完。
3,两种遍历对比
scan 相比 keys 具备有以下特点:
1,通过游标分布进行的,不会阻塞线程(可能这个特点我们靠谱点,下面了解即可);
2,提供 limit 参数,可以控制每次返回结果的最大条数,limit 不准,返回的结果可多可少;
3,同 keys 一样,Scan 也提供模式匹配功能;
4,服务器不需要为游标保存状态,游标的唯一状态就是 scan 返回给客户端的游标整数;
5,scan 返回的结果可能会有重复,需要客户端去重复;
6,scan 遍历的过程中如果有数据修改,改动后的数据能不能遍历到是不确定的;
7,单次返回的结果是空的并不意味着遍历结束,而要看返回的游标值是否为零;
注:可有效地解决 keys 命令可能产生的阻塞问题。
除 scan 字符串外,还有以下:
SCAN 命令用于迭代当前数据库中的数据库键。
SSCAN 命令用于迭代集合键中的元素。
HSCAN 命令用于迭代哈希键中的键值对。
ZSCAN 命令用于迭代有序集合中的元素(包括元素成员和分值)。
用法和 scan 一样。