Redis命令执行生命周期:

  发送命令--->排队(单线程)--->执行命令--->返回结果

慢查询:

  只是针对命令执行阶段

  慢查询日志通过一个固定长度的FIFO queue,这个queue保存在内存中,通过设置命令执行时间慢查询范围,超过这个范围进入慢查询范围,就

会保存到queue中

慢查询有两个相关参数:

  slowlog-log-slower-than 1000

  slowlog-max-len 1000

可以通过修改redis.conf或者命令config set slowlog-log-slower-than 1000设置,通过config get获取参数

慢查询命令:

slowlog get:

127.0.0.1:6379> slowlog get
1) 1) (integer) 2
2) (integer) 1558081229
3) (integer) 293
4) 1) "COMMAND"
5) "127.0.0.1:58194"
6) ""
2) 1) (integer) 1
2) (integer) 1552552609
3) (integer) 15589
4) 1) "save"
5) "127.0.0.1:54516"
6) ""

参数说明:

1、慢查询记录id

2、发起命令的时间戳

3、 命令耗时,单位为微秒

4、 该条记录的命令及参数

5、客户端网络套接字(ip: port)

slowlog len:慢查询队列长度

127.0.0.1:6379> slowlog len
(integer) 2

slowlog reset:清空慢查询队列

127.0.0.1:6379> slowlog reset
OK

慢查询日志优化:

  1、slowlog-log-slower-than默认10000微秒,就是10ms,通常设置1ms

  2、slowlog-max-lan默认128,通常设置1000,当超过最大queue长度,最先进入的记录被剔除,最新的一条记录加入slow log

  3、参数可以动态设置,前面说了

  4、可以定期将慢查询日志进行持久化,因为它保存在内存中

pipeline:

  1次网络+n次命令时间

  pipeline也就是流水线,将多个命令进行打包,在Redis server端计算出来,然后依次将结果返回

简单应用:

@Test
public void countTimes() {
SimpleDateFormat format = new SimpleDateFormat("hh:mm:ss");
String startTime = format.format(new Date());
log.info("开始时间:{}", startTime);
String realKey = "test";
Pipeline pipeline = redisService.pipeline();
for (int i=0; i<10000; i++) {
pipeline.set(realKey + i, "a" );
}
for (int i=0; i<10000; i++) {
pipeline.del(realKey +i);
}
pipeline.sync();
log.info("结束时间:{}", format.format(new Date()));
}
2019-05-17 16:57:14.357  INFO 11132 --- [           main] com.it.RedisServiceTest                  : 开始时间:04:57:14
2019-05-17 16:57:16.184 INFO 11132 --- [ main] com.it.RedisServiceTest : 结束时间:04:57:16

  如果使用set和del各自操作10000次,由于本人在上海,买的阿里云归属地是北京,加上配置太渣,网络问题等,1分钟过后才插入5000条。是

在等不下去了可以看出pipeline的速度是有多快

注意点:

  m相关命令是原子操作,而pipeline不是,会拆分为很多子命令

计数器:

  通过incr、incrby实现

应用场景:

  用户登录次数记录

  社交点赞等

消息队列:

一般可以用来单对单消息队列,这不是Redis本身的功能,而是通过list实现,不保证可靠性投递。如果真的需要消息队列,还是通过MQ实现

实现:

127.0.0.1:6379> lpush list 1
(integer) 1
127.0.0.1:6379> blpop list 10 //blpop,从左边弹出一个元素,在timeout时间内如果没有元素就阻塞
1) "list"
2) "1"
(4.98s)
127.0.0.1:6379> brpop list 10 //brpop,从右边谈,和blpop相同
1) "list"
2) "1"
(4.98s)

java代码实现:

Redis基本方法:lpush、rpush、lpop、rpop、brpop、blpop

public void lpush(byte[] key, byte[] value) {
Jedis jedis = null;
try {
jedis = jedisPool.getResource();
jedis.lpush(key, value);
} finally {
returnToPool(jedis);
}
} public void rpush(byte[] key, byte[] value) {
Jedis jedis = null;
try {
jedis = jedisPool.getResource();
jedis.rpush(key, value);
} finally {
returnToPool(jedis);
}
} public Object lpop(String key) {
Jedis jedis = null;
try {
jedis = jedisPool.getResource();
String message = jedis.lpop(key);
return message;
} finally {
returnToPool(jedis);
}
} public byte[] rpop(byte[] key) {
Jedis jedis = null;
try {
jedis = jedisPool.getResource();
return jedis.rpop(key);
} finally {
returnToPool(jedis);
}
} public List<byte[]> brpop(int timeout, String key) {
Jedis jedis = null;
try {
jedis = jedisPool.getResource();
return jedis.brpop(timeout, key.getBytes());
} finally {
returnToPool(jedis);
}
}
@Data
@AllArgsConstructor
public class RedisMessage implements Serializable { private int id;
private String message; }
@Slf4j
@Service
public class RedisQueue {
@Autowired
private RedisService redisService; public void sendRedisMessage(int id, String message) {
RedisMessage redisMessage = new RedisMessage(id, message);
String key = RedisConstant.LIST_KEY + id;
try {
redisService.lpush(key.getBytes(), ObjectUtils.object2Bytes(redisMessage));
} catch (IOException e) {
log.error("Redis消息发送失败:{}",e);
}
} public RedisMessage receiveMessage(int id){
String key = RedisConstant.LIST_KEY + id;
List<byte[]> list = redisService.brpop(0, key);
RedisMessage message = null;
try {
message = (RedisMessage)ObjectUtils.bytes2Object(list.get(1));
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
return message; }
}
@Slf4j
public class RedisServiceTest extends ApplicationTests{ @Autowired
private RedisQueue redisQueue; @Test
public void sendMessage() {
for (int i=0; i<5; i++)
redisQueue.sendRedisMessage(1, "send redis message!!!");
} @Test
public void receiveMessage() {
RedisMessage message = redisQueue.receiveMessage(1);
log.info("接收redis message:{}",message.getMessage());
}
}

发送消息:

127.0.0.1:6379> lrange redisQueue1 0 -1
1) "\xac\xed\x00\x05sr\x00\x19com.it.redis.RedisMessage$\xd4D'>[g\xf8\x02\x00\x02I\x00\x02idL\x00\amessaget\x00\x12Ljava/lang/String;xp\x00\x00\x00\x01t\x00\x15send redis message!!!"
2) "\xac\xed\x00\x05sr\x00\x19com.it.redis.RedisMessage$\xd4D'>[g\xf8\x02\x00\x02I\x00\x02idL\x00\amessaget\x00\x12Ljava/lang/String;xp\x00\x00\x00\x01t\x00\x15send redis message!!!"
3) "\xac\xed\x00\x05sr\x00\x19com.it.redis.RedisMessage$\xd4D'>[g\xf8\x02\x00\x02I\x00\x02idL\x00\amessaget\x00\x12Ljava/lang/String;xp\x00\x00\x00\x01t\x00\x15send redis message!!!"
4) "\xac\xed\x00\x05sr\x00\x19com.it.redis.RedisMessage$\xd4D'>[g\xf8\x02\x00\x02I\x00\x02idL\x00\amessaget\x00\x12Ljava/lang/String;xp\x00\x00\x00\x01t\x00\x15send redis message!!!"
5) "\xac\xed\x00\x05sr\x00\x19com.it.redis.RedisMessage$\xd4D'>[g\xf8\x02\x00\x02I\x00\x02idL\x00\amessaget\x00\x12Ljava/lang/String;xp\x00\x00\x00\x01t\x00\x15send redis message!!!"

接收消息:

2019-05-20 10:35:04.576  INFO 3780 --- [           main] com.it.RedisServiceTest                  : 接收redis message:send redis message!!!

解释:

RedisMessage:实体,实现Serializable,作为收发消息载体

RedisQueue:消息队列,包含收发消息方法

RedisServiceTest:测试类

brpop(timeout, key),timeout取0,表示如果无法取到消息,就会一直阻塞

发布订阅:

  一个新的订阅者订阅一个频道是无法收到以前的消息的,没有消息堆积的能力

角色:

  发布者publisher、订阅者subscriber、频道channel

命令:

127.0.0.1:6379> subscribe myChannel
Reading messages... (press Ctrl-C to quit)
1) "subscribe"
2) "myChannel"
3) (integer) 1
1) "message"
2) "myChannel"
3) "aaa"
127.0.0.1:6379> psubscribe channel*
Reading messages... (press Ctrl-C to quit)
1) "psubscribe"
2) "channel*"
3) (integer) 1
1) "pmessage"
2) "channel*"
3) "channel2"
4) "bbb"
1) "pmessage"
2) "channel*"
3) "channel1"
4) "aaa"
127.0.0.1:6379> unsubscribe myChannel
1) "unsubscribe"
2) "myChannel"
3) (integer) 0 127.0.0.1:6379> publish myChannel aaa
(integer) 1

psubscribe pattern:安装某种方式进行订阅,可以使用通配符

抽奖功能:set实现

127.0.0.1:6379> sadd choujiang zhangsan lisi wanger                //添加抽奖名单到set
(integer) 3
127.0.0.1:6379> smembers choujiang //获取抽奖名单
1) "lisi"
2) "zhangsan"
3) "wanger"
127.0.0.1:6379> srandmember choujiang 2 //从名单中随机抽取2名,并且不删除已中奖名单
1) "zhangsan"
2) "wanger"
127.0.0.1:6379> spop choujiang 2 //从名单中随机抽取2名,并且删除已中奖名单
1) "wanger"
2) "lisi"
127.0.0.1:6379> smembers choujiang
1) "zhangsan"

实现点赞、签到具体用户列表:set实现

127.0.0.1:6379> sadd article:1001 zhangsan
(integer) 1
127.0.0.1:6379> sadd article:1001 lisi //lisi给1001文章点赞
(integer) 1
127.0.0.1:6379> srem article:1001 lisi //lisi给1001文章取消点赞
(integer) 1
127.0.0.1:6379> sismember article:1001 zhangsan //检查lisi是否给1001文章点过赞,个人觉得sadd也是一样的,如果返回0,证明set已经包含了
(integer) 1
127.0.0.1:6379> sadd article:1001 lisi1
(integer) 1
127.0.0.1:6379> sadd article:1001 lisi2
(integer) 1
127.0.0.1:6379> smembers article:1001 //获取点赞列表
1) "zhangsan"
2) "lisi2"
3) "lisi1"
127.0.0.1:6379> scard article:1001 //点赞人数
(integer) 3

共同关注列表:set实现

通过sinter实现

127.0.0.1:6379> sadd zhangsanlist jesen kobe
(integer) 2
127.0.0.1:6379> sadd lisilist jesen gakki hebe
(integer) 3
127.0.0.1:6379> sinter zhangsanlist lisilist
1) "jesen"

排行榜:zset实现

127.0.0.1:6379> zadd NouthAmercianMovieRanking 5702 Speed_preparation 2841 The_Avengers 2482 Big_detective_Pikachu
(integer) 3
127.0.0.1:6379> zrevrange NouthAmercianMovieRanking 0 2 withscores
1) "Speed_preparation"
2) "5702"
3) "The_Avengers"
4) "2841"
5) "Big_detective_Pikachu"
6) "2482"

部分内容参考:https://mp.weixin.qq.com/s/FyYhLS3X7LDe0PLxooz_cQ

Redis系列(三)--消息队列、排行榜等的更多相关文章

  1. tp5 (自写) 实现redis消息队列 + 排行榜

    1:小皮开启redis, 控制器按Ctrl 点击new Redis 进入 redis.php 进行封装 //向队列添加数据 // LPUSH key value1 [value2] //将一个或多个值 ...

  2. Redis+php-resque实现消息队列

      服务器硬件配置 Dell PowerEdge R310英特尔单路机架式服务器 Intel Xeon Processor X3430 2.4GHz, 8MB Cache 8GB内存(2 x 4GB) ...

  3. 进程间通信系列 之 消息队列函数(msgget、msgctl、msgsnd、msgrcv)及其范例

    进程间通信系列 之 概述与对比   http://blog.csdn.net/younger_china/article/details/15808685  进程间通信系列 之 共享内存及其实例   ...

  4. Delayer 基于 Redis 的延迟消息队列中间件

    Delayer 基于 Redis 的延迟消息队列中间件,采用 Golang 开发,支持 PHP.Golang 等多种语言客户端. 参考 有赞延迟队列设计 中的部分设计,优化后实现. 项目链接:http ...

  5. 如何使用NODEJS+REDIS开发一个消息队列

    作者: RobanLee 原创文章,转载请注明: 萝卜李 http://www.robanlee.com MQ全称为Message Queue, 消息队列(MQ)是一种应用程序对应用程序的通信方法.应 ...

  6. Spring Cloud(7):事件驱动(Stream)分布式缓存(Redis)及消息队列(Kafka)

    分布式缓存(Redis)及消息队列(Kafka) 设想一种情况,服务A频繁的调用服务B的数据,但是服务B的数据更新的并不频繁. 实际上,这种情况并不少见,大多数情况,用户的操作更多的是查询.如果我们缓 ...

  7. php和redis怎么实现消息队列

    把瞬间服务器的请求处理换成异步处理,缓解服务器的压力,实现数据顺序排列获取.本文主要和大家分享php和redis如何实现消息队列,希望能帮助到大家. redis实现消息队列步骤如下: 1).redis ...

  8. Redis 学习笔记(六)Redis 如何实现消息队列

    一.消息队列 消息队列(Messeage Queue,MQ)是在分布式系统架构中常用的一种中间件技术,从字面表述看,是一个存储消息的队列,所以它一般用于给 MQ 中间的两个组件提供通信服务. 1.1 ...

  9. [转载] 基于Redis实现分布式消息队列

    转载自http://www.linuxidc.com/Linux/2015-05/117661.htm 1.为什么需要消息队列?当系统中出现“生产“和“消费“的速度或稳定性等因素不一致的时候,就需要消 ...

随机推荐

  1. SEO 搜索引擎优化培训01

    百度搜索风云榜:http://top.baidu.com/boards 页面上的因素:对搜索引擎而言

  2. jquery跨域请求json数据

    //服务端生成json数据json.php <?php $json=array("Volvo","BMW","SAAB"); $cb ...

  3. JS 通过选择百度地图地址获取经纬度自动填充到文本框中的方法

    首先要注册百度地图API. 1.登录百度地图开放平台http://lbsyun.baidu.com 注册账号,完善信息,点击网站右上角的“API控制台”,点击,创建应用. 应用类型选择:“浏览器端”, ...

  4. JavaScript基础 -- 常见DOM树操作

    1.创建并增加元素节点 <ul id="ul"> <li>1</li> <li>2</li> <li>3&l ...

  5. Linux/Android——Input系统之InputReader (七)【转】

    本文转载自:http://blog.csdn.net/jscese/article/details/42739197 在前文Linux/Android——Input系统之frameworks层Inpu ...

  6. android压力测试命令monkey详解【转】

    本文转载自:http://www.jb51.net/article/48557.htm 作者: 字体:[增加 减小] 类型:转载 时间:2014-03-29我要评论 这篇文章主要介绍了android ...

  7. Linux微信web开发者工具

    Linux微信web开发者工具 https://github.com/cytle/wechat_web_devtools Linux微信web开发者工具, 可在 linux 桌面环境跑起 微信开发者工 ...

  8. [LeetCode] Construct Binary Tree from Inorder and Pretorder Traversal

    Given preorder and inorder traversal of a tree, construct the binary tree. Note:You may assume that ...

  9. 【转载】limits.h

    limits.h专门用于检测整型数据数据类型的表达值范围. <limits.h>主要提供对整型和字符型范围的限制的宏,同样没有指定类型和函数的定义. 1.整型宏如下表: 2.字符型宏如下表 ...

  10. Opencv+Zbar二维码识别(一维码校正)

    一维码由一组规则排列的黑色线条.白色线条以及对应的字符组成.对倾斜的(没有严重形变)一维码的角度校正,可以根据其黑白相间.排列规则的特点,计算傅里叶频谱,通过傅里叶频谱中直线的倾斜角度计算空间域图像一 ...