2018.6.21
前面有提到过memcached使用的LRU是多段的LRU方法,对于每一个slab class都会匹配一个LRU方法,下面来具体分析下这种方法
Memcached的LRU算法分析
Memcached的LRU几种策略
1.惰性删除。
memcached一般不会主动去清除已经过期或者失效的缓存,当get请求一个item的时候,才会去检查item是否失效。
2.flush命令。
flush命令会将所有的item设置为失效。
3.创建的时候检查。
Memcached会在创建ITEM的时候去LRU的链表尾部开始检查,是否有失效的ITEM,如果没有的话就重新创建。
4.LRU爬虫。
memcached默认是关闭LRU爬虫的。LRU爬虫是一个单独的线程,会去清理失效的ITEM。
5.LRU淘汰。
当缓存没有内存可以分配给新的元素的时候,memcached会从LRU链表的尾部开始淘汰一个ITEM,不管这个ITEM是否还在有效期都将会面临淘汰。LRU链表插入缓存ITEM的时候有先后顺序,所以淘汰一个ITEM也是从尾部进行 也就是先淘汰最早的ITEM。
下面分别对这几种策略进行一个简单的说明:
首先是LRU链表的连接和删除,就是常见的链表的操作
然后对上面的LRU缓存的4中策略进行说明:
策略1 - 惰性删除
Memcached的缓存清除策略是惰性的。这个如何来理解?当用户设置了一个缓存数据,缓存有效期为5分钟。当5分钟时间过后,缓存失效,这个时候Memcached并不会自动去检查当前的Item是否过期。当客户端再次来请求这个数据的时候,才会去检查缓存是否失效了,如果失效则会去清除这个数据。
策略2 - flush命令
当用户发送一个flush命令的时候,Memcached会将命令之前的所有的缓存都设置为失效。
Memcached不会主动去清除这些item。主要通过两种方式:
1.do_item_flush_expired方法。
Memcached会在接受到flush命令的时候,
将设置全局参数settings.oldest_live =current_time - 1。然后去调用item_flush_expired方法。
因为设置全局参数item_flush_expired到调用缓存锁方法之间会有一定的时间差,有可能这个过程中,会有新的item在操作。
然后Memcached调用do_item_flush_expired方法,去遍历所有的LRU链表。do_item_flush_expired不会将每一个在flush命令前的Item删除,因为这样会非常耗时,而是删除在设置全局变量到加上缓存锁这之间操作的item。这样就能加快flush的速度。
2.惰性删除方法。
Memcached会在get操作的时候去判断it->time是否小于settings.oldest_live,如果小于,说明这个item就是过期的。通过这种方法,惰性删除大批量的item数据。
策略3 - 分配Item的时候去检查
Memcached在分配一个新的Item。(这个流程有点绕,需要看N遍,才能明白)步骤如下:
1.先检查缓存存储空间大小。前几章我们讲到,memcached的命令中会将key的长度和value的长度带上,这样就可以计算出item总的占用空间的大小。
2.通过缓存item的存储空间大小,就可以找到slabs class和slabs class的LRU双向链表。
3.开始尝试分配内存,尝试次数为5次。
4.尝试分配内存的过程中,会从LRU链表的尾部开始搜索,检查ITEM状态,如果item内容为空或者item被其它worker引用锁定等情况,则继续往LRU列表尾部搜索。
5.如果尝试了5次,从LRU尾部搜索都没有找到符合预期的ITEM,则会slabs_alloc方法,申请创建一个新的内存块。
6.如果从LRU尾部搜索找到符合预期的ITEM(没有锁定和有数据),首先会检查ITEM是否已经过了有效期,如果已经过了有效期,则将这个ITEM淘汰,占用该ITEM。
7.如果ITEM还是有效的,则使用slabs_alloc分配一个新的ITEM,分配成功,则就用最新分配的ITEM
8.如果使用slabs_alloc分配一个新的ITEM,分配失败,则开启了不使用LRU强制淘汰,返回ERROR;如果开启了强制淘汰,会将当前LRU链表尾部搜索到的ITEM强制进行淘汰(如果ITEM有效期还在或者设置了永久的也会被淘汰)
这里的LRU替换策略与传统的不同,需要好好比较下!!!!!!!!
替换策略一共有4步:
1、首先判断是不是有被其他worker占用,占用不能使用其他方法。如果链表倒数5个搜索都被占用的话,去进行强制的slab_alloc分配一个新的内存块,如果分配失败的话,报错内存不够。
注意,被worker占用是不能触发替换策略的,因为不能将其他线程占用的item替换出去
2、如果找到了一个没有被占用的,判断这个缓存块item是否过期失效,如果过期失效,则直接使用当前的item作为新的item即可。
3、如果没有过期,则调用slab_alloc分配一个新的内存块,如果分配失败的话,表示内存不够,但是当前并不是都被占用,此时触发LRU的替换策略。
4、如果使用slabs_alloc分配一个新的ITEM,分配失败,则开启了不使用LRU强制淘汰,返回ERROR;如果开启了强制淘汰,会将当前LRU链表尾部搜索到的ITEM强制进行淘汰(如果ITEM有效期还在或者设置了永久的也会被淘汰)
策略4 - LRU爬虫
1.Memcached的LRU爬虫默认是关闭的。
2.Memcached会开一个单独的线程对失效的缓存数据进行处理。