Redis
主页 > 数据库 > Redis >

redis淘汰策略的几种实现介绍

2024-05-22 | 佚名 | 点击:

redis内存数据数据集大小升到一定大的时候,就会实行数据淘汰策略(回收策略)。

1,volatile-lru:从已设置过期时间的哈希表(server.db[i].expires)中随机挑选多个key,然后在选到的key中用lru算法淘汰最近最少使用的数据

2,allkey-lru:从所有key的哈希表(server.db[i].dict)中随机挑选多个key,然后再选到的key中利用lru算法淘汰最近最少使用的数据

3,volatile-ttl:从已设置过期时间的哈希表(server.db[i].expires)中随机挑选多个key,然后在选到的key中选择过期时间最小的数据淘汰掉。

4,volatile-random:从已设置过期时间的哈希表(server.db[i].expires)中随机挑选key淘汰掉。

5,allkey-random:从所有的key的哈希表(server.db[i].dict)中随机挑数据淘汰

6,no-eviction(驱逐):内存达到上限,不淘汰数据。

redis确认驱逐某个键值对后,会删除这个数据,并将这个数据变更消息发布到本地(AOF持久化)和从机(主从连接)。

 LRU数据淘汰机制是这样的:在数据集中随机挑选几个键值对,去除其中最近最少使用的键值对淘汰。所以Redis并不是保证取得所有数据集中最少最少使用的键值对,而只是在随机挑选的几个键值对中。

TTL数据淘汰机制:从国企时间redisDB.expires表中随机挑选几个键值对,取出其中最快过期的键值对淘汰。所以Redis并不保证取得所有过期时间表中最快过期的键值对,而是随机挑选的几个键值对中。

无论是什么机制,都是从所有的键值对中挑选合适的淘汰。

在哪里开始淘汰数据:

Redis服务器每执行一次命令的时候,会检测使用的内存是否超额。如果超额,即进行数据淘汰。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

int freeMemoryIfNeeded(void) {

    /**

     * noeviction 不淘汰数据,什么都不做

     */

    if (server.maxmemory_policy == MAXMEMORY_NO_EVICTION)

        return C_ERR;

    while (mem_freed < mem_tofree) {

        int j, k, keys_freed = 0;

        for (j = 0; j < server.dbnum; j++) {

            /**

             * 选择操作的哈希表,Redis另外维护着一个保存过期时间的key=>expire关联的哈希表

             */

            if (server.maxmemory_policy == MAXMEMORY_ALLKEYS_LRU ||

                server.maxmemory_policy == MAXMEMORY_ALLKEYS_RANDOM)

            {

                dict = server.db[j].dict;

            } else {

                dict = server.db[j].expires;

            }

            /**

             * 分支一:全局哈希表随机或者过期时间哈希表中,随机淘汰一个key

             */

            if (server.maxmemory_policy == MAXMEMORY_ALLKEYS_RANDOM ||

                server.maxmemory_policy == MAXMEMORY_VOLATILE_RANDOM)

            {

                de = dictGetRandomKey(dict);

                bestkey = dictGetKey(de);

            }

            /**

             * 分支二:全局哈希表随机或者过期时间哈希表中,随机采样多个数据,再运用lru算法挑选一个淘汰

             */

            else if (server.maxmemory_policy == MAXMEMORY_ALLKEYS_LRU ||

                server.maxmemory_policy == MAXMEMORY_VOLATILE_LRU)

            {

                /* 样本集 */

                struct evictionPoolEntry *pool = db->eviction_pool;

                while(bestkey == NULL) {

                    /*

                     * 采样,更新和维护样本集;

                     * 样本集开始是空的,每次操作完并不会清空样本集;

                     * 而且每次采样,都会采集多个数据,同时和样本集中已有的数据进行比较,新增或者更新样本集;

                     */

                    evictionPoolPopulate(dict, db->dict, db->eviction_pool);

                    /**

                     * 开始对样本集使用lru算法,淘汰样本集中访问时间最晚的key

                     */

                    for (k = MAXMEMORY_EVICTION_POOL_SIZE-1; k >= 0; k--) {

                        if (pool[k].key == NULL) continue;

                        de = dictFind(dict,pool[k].key);

                        /* 把选取到的key从样本集中移除 */

                        sdsfree(pool[k].key);

                        memmove(pool+k,pool+k+1,

                            sizeof(pool[0])*(MAXMEMORY_EVICTION_POOL_SIZE-k-1));

                        pool[MAXMEMORY_EVICTION_POOL_SIZE-1].key = NULL;

                        pool[MAXMEMORY_EVICTION_POOL_SIZE-1].idle = 0;

                        /* pool样本集内的key,只是样本,不一定和db内保持一致,也不必,可能在db中已经被删除的,所以要作判断 */

                        if (de) {

                            bestkey = dictGetKey(de);

                            break;

                        } else {

                            /* Ghost... */

                            continue;

                        }

                    }

                }

            }

            /**

             * 分支三:在设置了过期时间的哈希表里面随机选择多个key,在挑选到的key中选择过期时间最小的一个淘汰掉

             */

            else if (server.maxmemory_policy == MAXMEMORY_VOLATILE_TTL) {

                for (k = 0; k < server.maxmemory_samples; k++) {

                    sds thiskey;

                    long thisval;

                    de = dictGetRandomKey(dict);

                    thiskey = dictGetKey(de);

                    thisval = (long) dictGetVal(de);

                    if (bestkey == NULL || thisval < bestval) {

                        bestkey = thiskey;

                        bestval = thisval;

                    }

                }

            }

            if (bestkey) {

                long long delta;

                robj *keyobj = createStringObject(bestkey,sdslen(bestkey));

                // 命令扩散,把删除key的命令同步到所有从库slave

                propagateExpire(db,keyobj);

                // 删除key

                dbDelete(db,keyobj);

            }

        }

    }

    return C_OK;

}

原文链接:
相关文章
最新更新