Java面试07|Redis数据库

1、Redis持久化的几种方式

(1)RDB(Redis DataBase)持久化 

(2)AOF(Append Only File)持久化

 

2、Redis的缓存失效策略 

主要涉及到expire对主键过期时间的设置。

Redis对缓存失效的处理机制大概分为两种,一种是客户端访问key的时候消极的处理,一种是主线程定期的积极地去执行缓存失效清理逻辑

参考:Redis缓存失效机制 https://my.oschina.net/andylucc/blog/679222

 

3、Redis和Memcached的区别 

Redis的特性:

(1) 速度快,因为数据存在内存中,类似于HashMap,HashMap的优势就是查找和操作的时间复杂度都是O(1) 
(2) 支持丰富数据类型,支持字符串、链表、哈希、集合和有序集合 
(3) 支持事务,操作都是原子性,所谓的原子性就是对数据的更改要么全部执行,要么全部不执行 
(4) 丰富的特性:可用于缓存,消息,按key设置过期时间,过期后将会自动删除

与Memcached的区别在于:

(1)、存储方式 
Memecache把数据全部存在内存之中,断电后会挂掉,数据不能超过内存大小。Redis有部分存在硬盘上,这样能保证数据的持久性。 
(2)、数据支持类型 
Memcache对数据类型支持相对简单。Redis有复杂的数据类型。 
(3)、使用底层模型不同 
它们之间底层实现方式 以及与客户端之间通信的应用协议不一样。 
Redis直接自己构建了VM(Virtual Memory)机制 ,因为一般的系统调用系统函数的话(例如java调用自己的API),会浪费一定的时间去移动和请求。

 

 

4、Redis分布式锁的实现

 

Redis的分布式缓存特性使其成为了分布式锁的一种基础实现。通过Redis中是否存在某个锁ID,则可以判断是否上锁。为了保证判断锁是否存在的原子性,保证只有一个线程获取同一把锁,Redis有SETNX(即SET if Not
eXists)和GETSET(先写新值,返回旧值,原子性操作,可以用于分辨是不是首次操作)操作。

关于SETNX:

将 key 的值设为value ,当且仅当 key 不存在,返回值为1。

若给定的 key 已经存在,则 SETNX 不做任何动作,返回值为0。 

 

为了防止主机宕机或网络断开之后的死锁,Redis没有ZK那种天然的实现方式,只能依赖设置超时时间来规避。

以下是一种比较普遍但不太完善的Redis分布式锁的实现步骤(与下图一一对应):

(1)线程A发送SETNX lock.orderid 尝试获得锁,如果锁不存在,则set并获得锁。

(2)如果锁存在,则再判断锁的值(时间戳)是否大于当前时间,如果没有超时,则等待一下再重试。

(3)如果已经超时了,在用GETSET lock.{orderid} 来尝试获取锁,如果这时候拿到的时间戳仍旧超时,则说明已经获得锁了。

(4)如果在此之前,另一个线程C快一步执行了上面的操作,那么A拿到的时间戳是个未超时的值,这时A没有如期获得锁,需要再次等待或重试。

Java实现如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
while  ( this .lock !=  1 ) {   // 可以加一个超时机制,如果一定时间内还获取不到就直接返回false
                 long  nanoTime = System.nanoTime();
                 timeout = nanoTime + timeout * MILLI_NANO_TIME +  1 // 转换为纳秒
 
                 // 线程发送SETNX lock.orderid 尝试获得锁,如果锁不存在,则set并获得锁
                 // 如果锁存在,则再判断锁的值(时间戳)是否大于当前时间,如果没有超时,则等待一下再重试
                 // 如果已经超时了,在用GETSET lock.{orderid}
                 // 来尝试获取锁,如果这时候拿到的时间戳仍旧超时,则说明已经获得锁了
                 // 如果在此之前,另一个线程C快一步执行了上面的操作,那么A拿到的时间戳是个未超时的值,这时A没有如期获得锁,需要再次等待或重试
                 this .lock =  this .redisClient.setnx( this .key, LOCKED);
                 if  ( this .lock ==  1  || nanoTime > ( long ) redisClient.getByKey(key)
                         && nanoTime > ( long ) redisClient.getSetT(key, timeout)) {
                     return  true ;
                 else  {
                     Thread.sleep( 3 , RANDOM.nextInt( 30 ));
                 }
             }

这种锁的机制是否也可以使用数据库的乐观锁来实现?

新建数据库有id与num(表示商品数量),则

1
2
3
4
5
6
7
select num as y from table
 
// 判断y是否大于0
 
update table set num = num- 1  where id=x and num=y
 
失败了就重新试

 

参考:

(1)基于redis分布式锁实现“秒杀”  http://blog.csdn.net/u010359884/article/details/50310387

(2)http://blog.csdn.net/ugg/article/details/41894947

5、Redis解决缓存被击穿问题

缓存在某个时间点过期的时候,恰好在这个时间点对这个Key有大量的并发请求过来,这些请求发现缓存过期一般都会从后端DB加载数据并回设到缓存,这个时候大并发的请求可能会瞬间把后端DB压垮。

如何解决:业界比较常用的做法,是使用mutex。简单地来说,就是在缓存失效的时候(判断拿出来的值为空),不是立即去load db,而是先使用缓存工具的某些带成功操作返回值的操作(比如Redis的SETNX或者Memcache的ADD)去set一个mutex key,当操作返回成功时,再进行load db的操作并回设缓存;否则,就重试整个get缓存的方法。类似下面的代码:

 

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public  String get(String key) {
         String value = redis.get(key);
         if  (value ==  null ) {  // 代表缓存值过期
             // 设置3min的超时,防止del操作失败的时候,下次缓存过期一直不能load db
             if  (redis.setnx(key_mutex,  1 3  60 ) ==  1 ) {  // 代表设置成功
                 value = db.get(key);
                 redis.set(key, value, expire_secs);
                 redis.del(key_mutex);
             else  // 这个时候代表同时候的其他线程已经load db并回设到缓存了,这时候重试获取缓存值即可
                 sleep( 50 );
                 get(key);  // 重试
             }
         else  {
             return  value;
         }
}

  

 

6、Redis的Reactor模式

 

参考 :

(1)Redis与Reactor模式

(2)《Redis设计与实现》中的第151页

 

7、MySQL里有2000w数据,redis中只存20w的数据,如何保证redis中的数据都是热点数据

 

redis 内存数据集大小上升到一定大小的时候,就会施行数据淘汰策略。redis 提供6种数据淘汰策略: 

(1)volatile-lru:   从已设置过期时间的数据集(server.db[i].expires)中挑选最近最少使用的数据淘汰 
(2)volatile-ttl:   从已设置过期时间的数据集(server.db[i].expires)中挑选将要过期的数据淘汰 
(3)volatile-random: 从已设置过期时间的数据集(server.db[i].expires)中任意选择数据淘汰 
(4)allkeys-lru:    从数据集(server.db[i].dict)中挑选最近最少使用的数据淘汰 
(5)allkeys-random:  从数据集(server.db[i].dict)中任意选择数据淘汰 
(6)no-eviction(驱逐):禁止驱逐数据

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值