什么是Redis?简述它的优缺点?
Redis的全称是:Remote Dictionary.Server,本质上是一个Key-Value类型的内存数据库,很像memcached,整个数据库统统加载在内存当中进行操作,定期通过异步操作把数据库数据flush到硬盘上进行保存。因为是纯内存操作,Redis的性能非常出色,每秒可以处理超过 10万次读写操作,是已知性能最快的Key-Value DB。Redis的出色之处不仅仅是性能,Redis最大的魅力是支持保存多种数据结构,此外单个value的最大限制是1GB,不像 memcached只能保存1MB的数据,因此Redis可以用来实现很多有用的功能。比方说用他的List来做FIFO双向链表,实现一个轻量级的高性能消息队列服务,用他的Set可以做高性能的tag系统等等。另外Redis也可以对存入的Key-Value设置expire时间,因此也可以被当作一 个功能加强版的memcached来用。Redis的主要缺点是数据库容量受到物理内存的限制,不能用作海量数据的高性能读写,因此Redis适合的场景主要局限在较小数据量的高性能操作和运算上。
Redis与memcached相比有哪些优势?
1.memcached所有的值均是简单的字符串,redis作为其替代者,支持更为丰富的数据类型 2.redis的速度比memcached快很多redis的速度比memcached快很多 3.redis可以持久化其数据redis可以持久化其数据
Redis支持哪几种数据类型?
String、List、Set、Sorted Set、hashes
Redis List应用场景
Redis list的应用场景非常多,也是Redis最重要的数据结构之一,比如twitter的关注列表,粉丝列表等都可以用Redis的list结构来实现。
Lists 就是链表,相信略有数据结构知识的人都应该能理解其结构。使用Lists结构,我们可以轻松地实现最新消息排行等功能。
Lists的另一个应用就是消息队列,
可以利用Lists的PUSH操作,将任务存在Lists中,然后工作线程再用POP操作将任务取出进行执行。Redis还提供了操作Lists中某一段的api,你可以直接查询,删除Lists中某一段的元素。
实现方式
Redis list的实现为一个双向链表,即可以支持反向查找和遍历,更方便操作,不过带来了部分额外的内存开销,Redis内部的很多实现,包括发送缓冲队列等也都是用的这个数据结构。1)入队
2)出队(非阻塞模式) lpop弹出列表首元素(即最后入队的元素)
Rpop弹出列表尾元素 (即入队的最开始的一个元素)
注意:如果要当作队列功能,应该是用这个出队
这里的出队都是非阻塞模式,就是你用pop出队的时候,如果队列是空的话,你得到的是一个NULL的值
3)出队(阻塞模式) 假如现在queue队列为空 我们用brpop命令
BRPOP 是一个阻塞的列表弹出原语。它是 RPOP 的阻塞版本,因为这个命令会在给定list无法弹出任何元素的时候阻塞连接。该命令会按照给出的 key 顺序查看 list,并在找到的第一个非空 list 的尾部弹出一个元素。
用redis的list当作队列可能存在的问题
1)redis崩溃的时候队列功能失效
2)如果入队端一直在塞数据,而出队端没有消费数据,或者是入队的频率大而多,出队端的消费频率慢会导致内存暴涨
3)Redis的队列也可以像rabbitmq那样 即可以做消息的持久化,也可以不做消息的持久化。
当做持久话的时候,需要启动redis的dump数据的功能.暂时不建议开启持久化。
Redis其实只适合作为缓存,而不是数据库或是存储。它的持久化方式适用于救救急啥的,不太适合当作一个普通功能来用。应为dump时候,会影响性能,数据量小的时候还看不出来,当数据量达到百万级别,内存10g左右的时候,非常影响性能。
4)假如有多个消费者同时监听一个队列,其中一个出队了一个元素,另一个则获取不到该元素
5)Redis的队列应用场景是一对多或者一对一的关系,即有多个入队端,但是只有一个消费端(出队)
消息队列任务调度
代码模拟
生产者模拟程序
package scheduleTest;
import java.util.Random;
import java.util.UUID;
import redis.clients.jedis.Jedis;
/**
* 模拟一个生产者
* <p>Title: TaskProducer</p>
* <p>Description: </p>
* <p>Company: </p>
* @date
* @vesion 1.0
*/
public class TaskProducer implements Runnable{
Jedis jedis = new Jedis("120.55.195.177",6379);
public void run() {
Random random = new Random();
while(true){
try{
Thread.sleep(random.nextInt(600) + 600);
// 模拟生成一个任务
UUID taskid = UUID.randomUUID();
//将任务插入任务队列:task-queue
jedis.lpush("task-queue", taskid.toString());
System.out.println("插入了一个新的任务:" + taskid);
}catch(Exception e){
e.printStackTrace();
}
}
}
}
消费者模拟程序
package scheduleTest;
import java.util.Random;
import redis.clients.jedis.Jedis;
/**
* 模拟消费者
* <p>Title: TaskConsumer</p>
* <p>Description: </p>
* <p>Company: </p>
* @date
* @vesion 1.0
*/
public class TaskConsumer implements Runnable {
Jedis jedis = new Jedis("120.55.195.177",6379);
public void run() {
Random random = new Random();
while(true){
//从任务队列"task-queue"中获取一个任务,并将该任务放入暂存队列"tmp-queue"
String taskid = jedis.rpoplpush("task-queue", "tmp-queue");
// 处理任务----纯属业务逻辑,模拟一下:睡觉
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
//模拟成功和失败的偶然现象
if(random.nextInt(13) % 7 == 0){// 模拟失败的情况,概率为2/13
//将本次处理失败的任务从暂存队列"tmp-queue"中,弹回任务队列"task-queue"
jedis.rpoplpush("tmp-queue", "task-queue");
System.out.println(taskid + "处理失败,被弹回任务队列");
} else {// 模拟成功的情况
// 将本次任务从暂存队列"tmp-queue"中清除
jedis.rpop("tmp-queue");
System.out.println(taskid+"处理成功,被清除");
}
}
}
}
调度主程序
/**
*
*/
package scheduleTest;
/**
* <p>Title: TaskShedulerSystem</p>
* <p>Description: </p>
* <p>Company: </p>
* @date
* @vesion 1.0
*/
public class TaskShedulerSystem {
public static void main(String[] args) throws Exception {
// 启动一个生产者线程,模拟任务的产生
new Thread(new TaskProducer()).start();
Thread.sleep(15000);
//启动一个线程者线程,模拟任务的处理
new Thread(new TaskConsumer()).start();
//主线程休眠
Thread.sleep(Long.MAX_VALUE);
}
}
运行结果
资料整理
整理了一份java面试资料,包括:
- ActiveMQ消息中间件面试专题
- BAT80道面试题
- BAT面试的Mysql面试55题
- Dubbo面试专题
- JVM面试专题
- Kafka面试专题
- Linux面试专题
- memcached面试专题
- MongoDB面试专题
- MyBatis面试专题
- mysql面试专题
- Mysql性能优化面试专题
- Netty面试专题
- ……
网盘地址:
【地址获取:回复58】