Redis主要通过控制内存上限和回收策略实现内存管理。



设置内存上限


config set maxmemory xx,maxmemory限制的是Redis真正使用的内存,也就是used_memory对应的内存,由于内存碎片的存在,实际消耗的内存可能会比maxmemory大,实际使用时要小心这部分内存溢出。



内存回收策略


Redis的内存回收机制主要体现在以下两个方面:

 - 删除到达过期时间的键对象。

 - 内存使用达到maxmemory上限时触发内存溢出控制策略。



删除过期键对象


Redis所有键都可以设置过期属性,内部保存在过期字典中。由于有大量的键,维护每个键精准的过期删除机制会导致消耗大量的CPU,对于单线程的Redis来说成本过高,因此Redis采用惰性删除和定时任务删除机制实现过期键的内存回收。


惰性删除:当客户端读取带有超时属性的键时,如果已经超过键设置的过期时间,会执行删除操作并返回空。但当过期键一直没有访问无法得到及时删除,从而导致内存不能及时释放。Redis还提供另一种定时任务删除机制作为补充。


定时任务删除:Redis内存维护一个定时任务,默认每秒运行10次(通过hz控制)。定时任务中删除过期键逻辑采用了自适应算法,根据键的过期比例,使用快慢速率模式回收键。


# Redis calls an internal function to perform many background tasks, like

# closing connections of clients in timeout, purging expired keys that are

# never requested, and so forth.

#

# Not all tasks are performed with the same frequency, but Redis checks for

# tasks to perform according to the specified "hz" value.

#

# By default "hz" is set to 10. Raising the value will use more CPU when

# Redis is idle, but at the same time will make Redis more responsive when

# there are many keys expiring at the same time, and timeouts may be

# handled with more precision.

#

# The range is between 1 and 500, however a value over 100 is usually not

# a good idea. Most users should use the default of 10 and raise this up to

# 100 only in environments where very low latency is required.

hz 10



内存溢出控制策略


当Redis所用内存达到maxmemory上限时会触发相应的溢出控制策略,具体控制策略由maxmemory-policy参数控制。


# MAXMEMORY POLICY: how Redis will select what to remove when maxmemory

# is reached. You can select among five behaviors:

#

# volatile-lru -> remove the key with an expire set using an LRU algorithm

# allkeys-lru -> remove any key according to the LRU algorithm

# volatile-random -> remove a random key with an expire set

# allkeys-random -> remove a random key, any key

# volatile-ttl -> remove the key with the nearest expire time (minor TTL)

# noeviction -> don't expire at all, just return an error on write operations


# Note: with any of the above policies, Redis will return an error on write

#  operations, when there are no suitable keys for eviction.


#  At the date of writing these commands are: set setnx setex append      

#  incr decr rpush lpush rpushx lpushx linsert lset rpoplpush sadd     

#  sinter sinterstore sunion sunionstore sdiff sdiffstore zadd zincrby     

#  zunionstore zinterstore hset hsetnx hmset hincrby incrby decrby     

#  getset mset msetnx exec sort      


# The default is:

# maxmemory-policy noeviction


Redis在使用LRU算法回收过期键时,并不是采用维护TTL链表,而是使用采样的方式。采样的多少由maxmemory-samples控制。


# LRU and minimal TTL algorithms are not precise algorithms but approximated

# algorithms (in order to save memory), so you can tune it for speed or

# accuracy. For default Redis will check five keys and pick the one that was

# used less recently, you can change the sample size using the following

# configuration directive.


# The default of 5 produces good enough results. 10 Approximates very closely

# true LRU but costs a bit more CPU. 3 is very fast but not very accurate.


# maxmemory-samples 5


每次Redis执行命令时若设置了maxmemory参数,都会尝试执行内存回收操作。当Redis一直工作在内存溢出(used_memory>maxmemory)状态下,且设置非noeviction策略时,会频繁触发内存回收操作,主要包括查找可回收的键和删除键的开销,影响Redis的性能。如果当前Redis有从节点时,回收内存操作对应的删除命令会同步到从节点,导致写放大的问题。