Стратегия устранения памяти Redis

Redis

Redis занимает объем памяти

Мы знаем, что Redis — это база данных типа «ключ-значение» на основе памяти.Поскольку объем памяти системы ограничен, мы можем настроить максимальный объем памяти, который Redis может использовать при использовании Redis.

1. Настроить через конфигурационный файл

Установите размер памяти, добавив следующую конфигурацию в файл конфигурации redis.conf в каталоге установки Redis.

//设置Redis最大占用内存大小为100M
maxmemory 100mb

Файл конфигурации Redis не обязательно использует файл redis.conf в каталоге установки.При запуске службы Redis вы можете передать параметр, чтобы указать файл конфигурации Redis.

2. Изменить по команде

Redis поддерживает динамическое изменение размера памяти с помощью команд во время выполнения.

//设置Redis最大占用内存大小为100M
127.0.0.1:6379> config set maxmemory 100mb
//获取设置的Redis能使用的最大内存大小
127.0.0.1:6379> config get maxmemory

Если вы не установите максимальный размер памяти или установите для максимального размера памяти значение 0, размер памяти не будет ограничен в 64-разрядной операционной системе, а в 32-разрядной операционной системе будет использоваться максимум 3 ГБ памяти.

Устранение памяти Redis

Поскольку можно установить максимальный размер памяти Redis, сконфигурированная память будет израсходована. Затем, когда память закончится, если вы продолжите добавлять данные в Redis, не будет ли доступной памяти?

На самом деле Redis определяет несколько стратегий для решения этой ситуации:

Невыселение (политика по умолчанию): для запросов на запись услуга не предоставляется, и ошибка возвращается напрямую (за исключением запросов DEL и некоторых специальных запросов).

allkeys-lru: исключить использование алгоритма LRU из всех ключей

volatile-lru: Устранить с помощью алгоритма LRU из ключа с установленным сроком годности

allkeys-random: Произвольное удаление данных со всех ключей

volatile-random: Случайным образом исключается из ключа с установленным сроком действия

volatile-ttl: Среди ключей с установленным временем истечения они удаляются в соответствии со временем истечения срока действия ключа.Чем раньше время истечения, тем больший приоритет будет устранен

когда используешьvolatile-lru,volatile-random,volatile-ttlВ этих трех стратегиях, если ни один ключ не может быть устранен, иnoevictionвозвращает ту же ошибку

Как получить и установить политику исключения памяти

Получите текущую политику вытеснения памяти:

127.0.0.1:6379> config get maxmemory-policy

Задайте стратегию исключения через конфигурационный файл (модифицируйте файл redis.conf):

maxmemory-policy allkeys-lru

Измените стратегию устранения командой:

127.0.0.1:6379> config set maxmemory-policy allkeys-lru

Алгоритм LRU

Что такое ЛРУ?

Как упоминалось выше, максимальная память, которую может использовать Redis, исчерпана, и алгоритм LRU можно использовать для устранения памяти.Так что же такое алгоритм LRU?

LRU(Least Recently Used), наименее используемый в последнее время, представляет собой алгоритм замены кеша. При использовании памяти в качестве кеша размер кеша обычно фиксирован. Когда кеш заполнен, если вы продолжаете добавлять данные в кеш в это время, вам необходимо удалить некоторые старые данные и освободить место в памяти для хранения новых данных. В это время можно использовать алгоритм LRU. Основная идея заключается в следующем: если часть данных не использовалась в последний период, вероятность того, что она будет использована в будущем, также очень мала, поэтому ее можно исключить.

Реализуйте простой алгоритм LRU, используя java
public class LRUCache<k, v> {
    //容量
    private int capacity;
    //当前有多少节点的统计
    private int count;
    //缓存节点
    private Map<k, Node<k, v>> nodeMap;
    private Node<k, v> head;
    private Node<k, v> tail;

    public LRUCache(int capacity) {
        if (capacity < 1) {
            throw new IllegalArgumentException(String.valueOf(capacity));
        }
        this.capacity = capacity;
        this.nodeMap = new HashMap<>();
        //初始化头节点和尾节点,利用哨兵模式减少判断头结点和尾节点为空的代码
        Node headNode = new Node(null, null);
        Node tailNode = new Node(null, null);
        headNode.next = tailNode;
        tailNode.pre = headNode;
        this.head = headNode;
        this.tail = tailNode;
    }

    public void put(k key, v value) {
        Node<k, v> node = nodeMap.get(key);
        if (node == null) {
            if (count >= capacity) {
                //先移除一个节点
                removeNode();
            }
            node = new Node<>(key, value);
            //添加节点
            addNode(node);
        } else {
            //移动节点到头节点
            moveNodeToHead(node);
        }
    }

    public Node<k, v> get(k key) {
        Node<k, v> node = nodeMap.get(key);
        if (node != null) {
            moveNodeToHead(node);
        }
        return node;
    }

    private void removeNode() {
        Node node = tail.pre;
        //从链表里面移除
        removeFromList(node);
        nodeMap.remove(node.key);
        count--;
    }

    private void removeFromList(Node<k, v> node) {
        Node pre = node.pre;
        Node next = node.next;

        pre.next = next;
        next.pre = pre;

        node.next = null;
        node.pre = null;
    }

    private void addNode(Node<k, v> node) {
        //添加节点到头部
        addToHead(node);
        nodeMap.put(node.key, node);
        count++;
    }

    private void addToHead(Node<k, v> node) {
        Node next = head.next;
        next.pre = node;
        node.next = next;
        node.pre = head;
        head.next = node;
    }

    public void moveNodeToHead(Node<k, v> node) {
        //从链表里面移除
        removeFromList(node);
        //添加节点到头部
        addToHead(node);
    }

    class Node<k, v> {
        k key;
        v value;
        Node pre;
        Node next;

        public Node(k key, v value) {
            this.key = key;
            this.value = value;
        }
    }
}

Приведенный выше код реализует простой LUR-алгоритм, код очень простой, к тому же он аннотирован, его легко понять, если внимательно посмотреть.

Реализация LRU в Redis

Приблизительный алгоритм LRU

Redis использует приблизительный алгоритм LRU, который отличается от обычного алгоритма LRU. Приближенный алгоритм LRU исключает данные путем случайной выборки, каждый раз случайным образом генерируя 5 ключей (по умолчанию) и удаляя из них последний использованный ключ.

Количество выборок может быть изменено параметром maxmemory-samples: Пример: maxmemory-samples 10 Чем больше конфигурация maxmenory-samples, тем ближе результат исключения к строгому алгоритму LRU.

Чтобы реализовать приблизительный алгоритм LRU, Redis добавляет к каждому ключу дополнительное 24-битное поле для хранения времени последнего доступа к ключу.

Redis3.0 оптимизация приблизительного LRU

Redis3.0 внесла некоторые оптимизации в приблизительный алгоритм LRU. Новый алгоритм будет поддерживать пул кандидатов (размер 16), данные в пуле сортируются по времени доступа, ключи, выбранные случайным образом в первый раз, будут помещены в пул, а ключи, выбранные случайным образом каждый раз, будут выбирается только тогда, когда время доступа меньше пула. Минимальное время будет помещено в пул, пока пул кандидатов не будет заполнен. Когда он заполнен, если необходимо ввести новый ключ, ключ с самым длительным временем доступа (самый последний доступ) в пуле будет удален.

Когда его необходимо устранить, просто выберите из пула ключ с наименьшим временем доступа (самый длинный недоступный) и удалите его.

Сравнение алгоритмов LRU

Мы можем сравнить точность каждого алгоритма LRU с помощью эксперимента.Сначала добавьте определенное количество данных n в Redis, чтобы израсходовать доступную память Redis, а затем добавьте n/2 новых данных в Redis. , нам нужно исключить его часть.Согласно строгому алгоритму LRU, должны быть исключены первые n/2 данных. Создайте сравнительную диаграмму следующих алгоритмов LRU (Источник изображения):

Вы можете видеть, что на графике есть три точки разного цвета:

  • Светло-серый - устранены данные
  • Серый - старые данные, которые не были устранены
  • Зеленый — недавно добавленные данные

Мы видим, что количество выборок Redis 3.0, равное 10, создает граф, наиболее близкий к строгому LRU. А также с использованием 5 образцов Redis3.0 также лучше, чем Redis2.8.

LFU-алгоритм

Алгоритм LFU — это новая стратегия исключения, добавленная в Redis 4.0. его полное названиеLeast Frequently Used, его основная идея состоит в том, чтобы исключить ключи в соответствии с частотой недавних обращений к ключам, те, к которым редко обращаются, удаляются в первую очередь, а те, к которым обращаются чаще, сохраняются.

Алгоритм LFU может лучше представить, насколько активен доступ к ключу. Если вы используете алгоритм LRU, к ключу долгое время не обращались, а обращались только изредка, то он считается горячими данными и не будет устранен, а некоторые ключи, вероятно, будут доступны в будущем. был ликвидирован. Это не тот случай, если используется алгоритм LFU, потому что его однократное использование не делает ключ горячими данными.

Есть две стратегии для LFU:

  • volatile-lfu: Используйте алгоритм LFU для устранения ключа в ключе с установленным временем истечения срока действия.
  • allkeys-lfu: использовать алгоритм LFU для удаления данных во всех ключах.

Установка и использование этих двух стратегий исключения такие же, как и предыдущая, но следует отметить, что двухнедельная стратегия может быть установлена ​​только в Redis4.0 и выше, и будет сообщено об ошибке, если она будет установлена ​​ниже Redis4. 0

проблема

Наконец, я оставлю небольшой вопрос. Некоторые люди могли заметить. Я не объяснял, почему Redis использует приблизительный алгоритм LRU вместо точного алгоритма LRU. Вы можете дать свой ответ в области комментариев, и мы можем обсудить и изучить вместе .

использованная литература:

Redis.IO/topics/например - ...

сегмент fault.com/ah/119000001…

сегмент fault.com/ah/119000001…