Redis系列(三)--消息队列、排行榜等
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系列(三)--消息队列、排行榜等的更多相关文章
- tp5 (自写) 实现redis消息队列 + 排行榜
1:小皮开启redis, 控制器按Ctrl 点击new Redis 进入 redis.php 进行封装 //向队列添加数据 // LPUSH key value1 [value2] //将一个或多个值 ...
- Redis+php-resque实现消息队列
服务器硬件配置 Dell PowerEdge R310英特尔单路机架式服务器 Intel Xeon Processor X3430 2.4GHz, 8MB Cache 8GB内存(2 x 4GB) ...
- 进程间通信系列 之 消息队列函数(msgget、msgctl、msgsnd、msgrcv)及其范例
进程间通信系列 之 概述与对比 http://blog.csdn.net/younger_china/article/details/15808685 进程间通信系列 之 共享内存及其实例 ...
- Delayer 基于 Redis 的延迟消息队列中间件
Delayer 基于 Redis 的延迟消息队列中间件,采用 Golang 开发,支持 PHP.Golang 等多种语言客户端. 参考 有赞延迟队列设计 中的部分设计,优化后实现. 项目链接:http ...
- 如何使用NODEJS+REDIS开发一个消息队列
作者: RobanLee 原创文章,转载请注明: 萝卜李 http://www.robanlee.com MQ全称为Message Queue, 消息队列(MQ)是一种应用程序对应用程序的通信方法.应 ...
- Spring Cloud(7):事件驱动(Stream)分布式缓存(Redis)及消息队列(Kafka)
分布式缓存(Redis)及消息队列(Kafka) 设想一种情况,服务A频繁的调用服务B的数据,但是服务B的数据更新的并不频繁. 实际上,这种情况并不少见,大多数情况,用户的操作更多的是查询.如果我们缓 ...
- php和redis怎么实现消息队列
把瞬间服务器的请求处理换成异步处理,缓解服务器的压力,实现数据顺序排列获取.本文主要和大家分享php和redis如何实现消息队列,希望能帮助到大家. redis实现消息队列步骤如下: 1).redis ...
- Redis 学习笔记(六)Redis 如何实现消息队列
一.消息队列 消息队列(Messeage Queue,MQ)是在分布式系统架构中常用的一种中间件技术,从字面表述看,是一个存储消息的队列,所以它一般用于给 MQ 中间的两个组件提供通信服务. 1.1 ...
- [转载] 基于Redis实现分布式消息队列
转载自http://www.linuxidc.com/Linux/2015-05/117661.htm 1.为什么需要消息队列?当系统中出现“生产“和“消费“的速度或稳定性等因素不一致的时候,就需要消 ...
随机推荐
- [Java][Android] 多线程同步-主线程等待全部子线程完毕案例
有时候我们会遇到这种问题:做一个大的事情能够被分解为做一系列相似的小的事情,而小的事情无非就是參数上有可能不同样而已! 此时,假设不使用线程,我们势必会浪费许多的时间来完毕整个大的事情.而使用线程的话 ...
- 重构——Martin Fowler 阅读笔记
重构的第一步: 为即将修改的代码建立一组可靠的测试环境. 和任何重构手法一样,当提炼一个函数时,我们必须知道可能出什么错. 安全步骤: 首先在一个函数内找到局部变量和参数.任何不会被修改的变量都可以被 ...
- 开拓新途径找出新方法,上海SEO公司分享3个操作看看是否可行
开拓新途径找出新方法,上海SEO公司分享3个操作看看是否可行 内容收录,外链公布,流量点击.用户体验.这是SEO优化的几个核心和重点.也是SEO站长每天都在绞尽脑汁进行操作的SEO重心,影响着非常多人 ...
- python 【第一篇】初识python
人生苦短,我用python Python是我喜欢的语言,简洁.优美.容易使用.所以我总是很激昂的向朋友宣传Python的好处. python起源 1989年,为了打发圣诞节假期,Guido开始写Pyt ...
- Python开发【第*篇】【Socket网络编程】
1.Socket socket通常也称作"套接字",用于描述IP地址和端口,是一个通信链的句柄,应用程序通常通过"套接字"向网络发出请求或者应答网络请求. so ...
- 2016/1/22 1, 1-100 放集合 特定对象移除 2,List集合和Set集合是否可以重复添加
package shuzu; import java.awt.List; import java.util.*; public class ListIterator { public static v ...
- ZOJ3659 Conquer a New Region 并查集
Conquer a New Region Time Limit: 5 Seconds Memory Limit: 32768 KB The wheel of the history roll ...
- the largest value you actually can transmit between the client and server is determined by the amount of available memory and the size of the communications buffers.
the largest value you actually can transmit between the client and server is determined by the amoun ...
- hdu 4990 Reading comprehension(等比数列法)
题目链接:pid=4990" style="color:rgb(255,153,0); text-decoration:none; font-family:Arial; line- ...
- MAC OS brew安装MNMP
安装HomeBrew Brew是Mac下面的包管理工具,就像centos下面的yum一样.HomeBrew可以通过ruby来安装,mac系统是自带ruby的,所以只要在终端运行下面的代码即可安装Hom ...