<
从版本< 22.1
xu yang编辑
在2022/04/27 14:05上
到版本
xu yang编辑
在2022/04/27 12:33上
修改评论 该版本没有评论

Summary

Details

Page properties
Content
... ... @@ -44,128 +44,3 @@
44 44  end
45 45  @enduml
46 46  {{/plantuml}}
47 -
48 -
49 -先说明,redis中,过期时间等信息是单独放在一个table中存储的,因为不是所有key都设有过期时间,放在一起存储会额外增加存储成本。
50 -
51 -expireIfNeeded方法用来判断一个key是否过期
52 -返回1,说明已经过期
53 -返回0,说明数据没有过期
54 -
55 -{{plantuml}}
56 -@startuml
57 -start
58 -
59 -
60 -:查询key的过期时间戳;
61 -:获取当前时刻的时间戳;
62 -if(过期时间<0)then(yes)
63 -:说明该key不存在过期设置,返回0;
64 -stop
65 -endif
66 -
67 -if(服务器正在启动中)then(yes)
68 -:过期时间的table可能没完全加载,这时直接返回0;
69 -stop
70 -endif
71 -
72 -if(当前环境是从服务器)then(yes)
73 -:对于从服务器无需删除过期key, 直接计算过期时间和当前时间的关系并返回;
74 -note left
75 -过期时间 <= 当前时间,返回1 : 已经过期
76 -过期时间 > 当前时间,返回0 : 没有过期
77 -endnote
78 -stop
79 -endif
80 -
81 -:写aof删除过期key;
82 -:创建消息通知,用来回调那些监控key过期的钩子;
83 -if(判断服务器是否打开惰性删除)then(yes)
84 -:调用dbAsyncDelete方法异步删除;
85 -else(no)
86 -:调用dbSyncDelete方法同步删除;
87 -endif
88 -:返回删除结果;
89 -note left
90 -删除方法返回值说明
91 -1: 说明数据被删除了
92 -0: 说明数据删除失败了,在过期表中key还存在
93 -endnote
94 -
95 -end
96 -@enduml
97 -{{/plantuml}}
98 -
99 -
100 -再看同步删除dbSyncDelete的策略
101 -
102 -{{plantuml}}
103 -@startuml
104 -start
105 -
106 -if(key过期表是否为空)then(no)
107 -:删除过期表中的key;
108 -endif
109 -
110 -:执行dictDelete方法,删除dict表中具体的数据;
111 -if(删除成功)then(yes)
112 -:在集群模式下的redis,还需要删除cluster中的key,防止路由查询key失败;
113 -:返回1;
114 -else
115 -:返回0;
116 -endif
117 -
118 -
119 -end
120 -@enduml
121 -{{/plantuml}}
122 -
123 -
124 -关于dictDelete这里就先不画图了,讲一下主要的实现逻辑吧。
125 -可以大概认为,java中hashmap结构对应的就是redis中的dict结构,区别是jdk在1.8版本之后使用拉链转红黑树的方式处理哈希冲突,而redis使用的方法还是拉链存储法,对应着jdk1.7。
126 -在redis中也存在内存常量池的概念,主要为是对应字符串/数字这种结构设计的,对于相同的字符串使用同一块内存空间。
127 -这样的结构在删除key和value的时候就存在一个额外的问题,如果我直接free掉这块内存,那么其他key和value指向这块内存的读写就会存在异常。
128 -redis为了避免这样的问题,在dict删除一个key的过程实际是先将dict中的对应的key的指针删除,然后然后在根据情况(内存是否被共享)再决定是否去free内存空间。
129 -
130 -
131 -再看异步删除dbAsyncDelete的策略
132 -{{plantuml}}@startuml
133 -start
134 -
135 -
136 -if(key过期表是否为空)then(no)
137 -:删除过期表中的key;
138 -endif
139 -
140 -:调用dictUnlink方法在dict上删除key指针;
141 -note left
142 -这里dictUnlink方法可以看作是上面dictDelete的一个同名方法,
143 -区别在于,
144 -dictDelete会明确告诉redis尽可能free掉key和value占用的空间(如果key和value没用被共享的情况下),
145 -
146 -而dictUnlink则只移除dict上的key即可,
147 -一定不要free具体的内存,
148 -并把对应的entry(key->value的封装,类似于java中的map.entry对象)返回
149 -endnote
150 -
151 -:获取entry中value占用的大小;
152 -if(如果value的占用空间过多)then(yes)
153 -:由于清理起来会耗用很长时间,
154 -
155 -这里会创建一个删除任务,
156 -本质是将要删除的entry扔到一个清理队列中,
157 -后台线程定期对这个队列中的数据清理;
158 -:将entry指针指向空;
159 -endif
160 -
161 -if(entry不为空,说明没有被异步删除)then(yes)
162 -:直接清理entry;
163 -:返回1;
164 -else(no)
165 -:返回0;
166 -endif
167 -
168 -
169 -
170 -end
171 -@enduml{{/plantuml}}