Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
wushizhenking
advanced-java
提交
b85a4c83
A
advanced-java
项目概览
wushizhenking
/
advanced-java
与 Fork 源项目一致
从无法访问的项目Fork
通知
2
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
A
advanced-java
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
前往新版Gitcode,体验更适合开发者的 AI 搜索 >>
提交
b85a4c83
编写于
11月 16, 2018
作者:
Y
yanglbme
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
docs(redis): add redis-expiration-policies-and-lru.md
上级
f5ab66fd
变更
2
隐藏空白更改
内联
并排
Showing
2 changed file
with
72 addition
and
1 deletion
+72
-1
README.md
README.md
+1
-1
docs/high-concurrency/redis-expiration-policies-and-lru.md
docs/high-concurrency/redis-expiration-policies-and-lru.md
+71
-0
未找到文件。
README.md
浏览文件 @
b85a4c83
...
...
@@ -61,7 +61,7 @@
-
[
在项目中缓存是如何使用的?缓存如果使用不当会造成什么后果?
](
/docs/high-concurrency/why-cache.md
)
-
[
Redis 和 Memcached 有什么区别?Redis 的线程模型是什么?为什么单线程的 Redis 比多线程的 Memcached 效率要高得多?
](
/docs/high-concurrency/redis-single-thread-model.md
)
-
[
Redis 都有哪些数据类型?分别在哪些场景下使用比较合适?
](
/docs/high-concurrency/redis-data-types.md
)
-
Redis 的过期策略都有哪些?手写一下 LRU 代码实现?
-
[
Redis 的过期策略都有哪些?手写一下 LRU 代码实现?
](
/docs/high-concurrency/redis-expiration-policies-and-lru.md
)
-
如何保证 Redis 高并发、高可用、持久化?Redis的主从复制原理能介绍一下么?Redis 的哨兵原理能介绍一下么?
-
Redis 的持久化有哪几种方式?不同的持久化机制都有什么优缺点?持久化机制具体底层是如何实现的?
-
Redis 集群模式的工作原理能说一下么?在集群模式下,Redis 的 key 是如何寻址的?分布式寻址都有哪些算法?了解一致性 hash 算法吗?如何动态增加和删除一个节点?
...
...
docs/high-concurrency/redis-expiration-policies-and-lru.md
0 → 100644
浏览文件 @
b85a4c83
## 面试题
redis 的过期策略都有哪些?内存淘汰机制都有哪些?手写一下 LRU 代码实现?
## 面试官心理分析
如果你连这个问题都不知道,上来就懵了,回答不出来,那线上你写代码的时候,想当然的认为写进 redis 的数据就一定会存在,后面导致系统各种 bug,谁来负责?
常见的有两个问题:
-
往 redis 写入的数据怎么没了?
可能有同学会遇到,在生产环境的 redis 经常会丢掉一些数据,写进去了,过一会儿可能就没了。我的天,同学,你问这个问题就说明 redis 你就没用对啊。redis是缓存,你给当存储了是吧?
啥叫缓存?用内存当缓存。内存是无限的吗,内存是很宝贵而且是有限的,磁盘是廉价而且是大量的。可能一台机器就几十个 G 的内存,但是可以有几个 T 的硬盘空间。redis 主要是基于内存来进行高性能、高并发的读写操作的。
那既然内存是有限的,比如 redis 就只能用 10G,你要是往里面写了 20G 的数据,会咋办?当然会干掉 10G 的数据,然后就保留 10G 的数据了。那干掉哪些数据?保留哪些数据?当然是干掉不常用的数据,保留常用的数据了。
-
数据明明过期了,怎么还占用着内存?
这是由 redis 的过期策略来决定。
## 面试题剖析
### redis 过期策略
redis 过期策略是:
**定期删除+惰性删除**
。
所谓
**定期删除**
,指的是 redis 默认是每隔 100ms 就随机抽取一些设置了过期时间的 key,检查其是否过期,如果过期就删除。
假设 redis 里放了 10w 个 key,都设置了过期时间,你每隔几百毫秒,就检查 10w 个 key,那 redis 基本上就死了,cpu 负载会很高的,消耗在你的检查过期 key 上了。注意,这里可不是每隔 100ms 就遍历所有的设置过期时间的 key,那样就是一场性能上的
**灾难**
。实际上 redis 是每隔 100ms
**随机抽取**
一些 key 来检查和删除的。
但是问题是,定期删除可能会导致很多过期 key 到了时间并没有被删除掉,那咋整呢?所以就是惰性删除了。这就是说,在你获取某个 key 的时候,redis 会检查一下 ,这个 key 如果设置了过期时间那么是否过期了?如果过期了此时就会删除,不会给你返回任何东西。
> 获取key 的时候,如果此时 key 已经过期,就删除,不会返回任何东西。
但是实际上这还是有问题的,如果定期删除漏掉了很多过期 key,然后你也没及时去查,也就没走惰性删除,此时会怎么样?如果大量过期 key 堆积在内存里,导致 redis 内存块耗尽了,咋整?
答案是:
**走内存淘汰机制**
。
### 内存淘汰机制
redis 内存淘汰机制有以下几个:
-
noeviction: 当内存不足以容纳新写入数据时,新写入操作会报错,这个一般没人用吧,实在是太恶心了。
-
**allkeys-lru**
:当内存不足以容纳新写入数据时,在
**键空间**
中,移除最近最少使用的key(这个是
**最常用**
的)
-
allkeys-random:当内存不足以容纳新写入数据时,在
**键空间**
中,随机移除某个 key,这个一般没人用吧,为啥要随机,肯定是把最近最少使用的key给干掉啊。
-
volatile-lru:当内存不足以容纳新写入数据时,在
**设置了过期时间的键空间**
中,移除最近最少使用的 key(这个一般不太合适)
-
volatile-random:当内存不足以容纳新写入数据时,在
**设置了过期时间的键空间**
中,
**随机移除**
某个 key。
-
volatile-ttl:当内存不足以容纳新写入数据时,在
**设置了过期时间的键空间**
中,有
**更早过期时间**
的 key 优先移除。
### 手写一个 LRU 算法
你可以现场手写最原始的 LRU 算法,那个代码量太大了,似乎不太现实。
不求自己纯手工从底层开始打造出自己的 LRU,但是起码要知道如何利用已有的 JDK 数据结构实现一个 Java 版的 LRU。
```
java
class
LRUCache
<
K
,
V
>
extends
LinkedHashMap
<
K
,
V
>
{
private
final
int
CACHE_SIZE
;
/**
* 传递进来最多能缓存多少数据
*
* @param cacheSize 缓存大小
*/
public
LRUCache
(
int
cacheSize
)
{
// true 表示让 linkedHashMap 按照访问顺序来进行排序,最近访问的放在头部,最老访问的放在尾部。
super
((
int
)
Math
.
ceil
(
cacheSize
/
0.75
)
+
1
,
0.75f
,
true
);
CACHE_SIZE
=
cacheSize
;
}
@Override
protected
boolean
removeEldestEntry
(
Map
.
Entry
<
K
,
V
>
eldest
)
{
// 当 map中的数据量大于指定的缓存个数的时候,就自动删除最老的数据。
return
size
()
>
CACHE_SIZE
;
}
}
```
\ No newline at end of file
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录