您现在的位置是:首页 >其他 >Redis学习总结(三)网站首页其他

Redis学习总结(三)

路上阡陌 2024-10-03 00:01:02
简介Redis学习总结(三)

Redis 内存淘汰机制

当 Redis 内存空间超限时,为了避免数据丢失,Redis 会通过内存淘汰机制从内存中删除一些数据。Redis 内存淘汰机制包括以下几种:

  1. noeviction:当 Redis 内存空间已满,如果没有设置淘汰策略或者设置了 noeviction 策略,则 Redis 将停止执行写操作,并向客户端返回错误信息。

  2. allkeys-lru:LRU(最近最少使用)淘汰策略会删除最近最少使用的 Key。当内存空间已满时,Redis 将从所有的 Key 中,选取最近最少使用的 Key 进行淘汰。

  3. allkeys-random:随机淘汰策略会随机删除一个 Key。当内存空间已满时,Redis 将随机选取一个 Key 进行淘汰。

  4. volatile-lru:与 allkeys-lru 策略类似,它会删除已设置过期时间的 Key 中,最近最少使用的 Key。

  5. volatile-random:与 allkeys-random 策略类似,它会删除已设置过期时间的 Key 中,随机一个 Key 进行淘汰。

  6. volatile-ttl:它会删除已设置过期时间的 Key 中,最近即将过期的 Key。

4.0 版本后增加以下两种:

  1. volatile-lfu(least frequently used):从已设置过期时间的数据集(server.db[i].expires)中挑选最不经常使用的数据淘汰。

  2. allkeys-lfu(least frequently used):当内存不足以容纳新写入数据时,在键空间中,移除最不经常使用的 key。

可以通过 CONFIG GET maxmemory-policy 命令获取当前设置的淘汰策略。

需要注意的是,对于 Master-Slave 模式的 Redis 集群,只有 Master 执行内存淘汰操作。Slave 只是接收来自 Master 的数据。

我们可以通过以下命令设置 Redis 的最大内存限制:

$ redis-cli config set maxmemory 1G  // 设置最大内存限制为 1GB

当 Redis 的内存使用量超过这个限制时,Redis 将会执行内存淘汰,以保证 Redis 不会因内存不足而宕机。

总结来说,Redis 内存淘汰机制是用于保护 Redis 内存不会超限,避免数据丢失,并保证 Redis 的可用性。Redis 内存淘汰机制包括 noeviction、allkeys-lru、allkeys-random、volatile-lru、volatile-random 和 volatile-ttl 六种策略,可以根据具体应用场景进行配置。

Reactor 模式

Reactor 模式是一种高效的网络编程模式,常用于构建高性能的服务器应用程序。它是基于事件驱动机制来实现的,可以有效地处理大量的并发请求,同时避免了多线程编程中的一些问题。下面详细介绍 Reactor 模式的概念、作用、结构以及代码实现。

概念

Reactor 模式是指,在一个单独的线程中,通过异步 I/O 的方式来监视多个连接的状态,如果有连接有数据可读或可写,就触发相应的事件处理器进行处理。它的核心是将 I/O 操作异步化,避免了阻塞式 I/O 的等待时间,提高了服务器的并发能力和响应速度。

作用

Reactor 模式的主要作用是提高服务器的并发能力和响应速度。通过将 I/O 操作异步化,避免了阻塞式 I/O 的等待时间,使得服务器能够同时处理多个连接,大大提高了并发能力。同时,由于 Reactor 模式采用了事件驱动的方式,可以有效地减少线程的使用,避免了多线程编程中的一些问题,如线程间竞争、上下文切换等,提高了应用程序的性能和可靠性。

结构

Reactor 模式包含以下几个组件:

  1. Handle:表示一个 I/O 事件,如可读、可写等。

  2. Synchronous Event Demultiplexer:同步事件多路复用器,用于等待事件的发生,如 select、poll、epoll 等。

  3. Event Handler:事件处理器,用于处理特定类型的 I/O 事件。

  4. Concrete Event Handler:具体的事件处理器,实现了 Event Handler 接口,用于处理具体的业务逻辑。

Reactor 模式的基本流程

  1. 应用程序向 Reactor 注册一个或多个事件处理器,每个事件处理器都与一个 Handle 相关联。

  2. Reactor 启动一个单独的线程,通过 Synchronous Event Demultiplexer 等待事件的发生。

  3. 当某个事件发生时,Synchronous Event Demultiplexer 将对应的 Handle 交给 Reactor 处理。

  4. Reactor 根据 Handle 上注册的事件类型,选择相应的事件处理器来处理该事件。

  5. 事件处理器根据具体的业务逻辑,完成对该事件的处理。

  6. 处理完成后,事件处理器将控制权交还给 Reactor。

代码实现

Reactor模式是一种设计模式,用于处理高并发的I/O操作。它的核心思想是将I/O操作分为两个部分:读取请求和处理请求。Reactor模式通过使用一个单独的线程来处理所有的I/O请求,并将这些请求分派到不同的处理器中去。

在Java中,可以使用NIO(New I/O)来实现Reactor模式。下面是一个简单的示例代码:

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.Set;
public class Reactor implements Runnable {
    private final Selector selector;
    private final ServerSocketChannel serverSocket;
    public Reactor(int port) throws IOException {
        selector = Selector.open();
        serverSocket = ServerSocketChannel.open();
        serverSocket.socket().bind(new InetSocketAddress(port));
        serverSocket.configureBlocking(false);
        SelectionKey sk = serverSocket.register(selector, SelectionKey.OP_ACCEPT);
        sk.attach(new Acceptor());
    }
    @Override
    public void run() {
        try {
            while (!Thread.interrupted()) {
                selector.select();
                Set<SelectionKey> selectedKeys = selector.selectedKeys();
                Iterator<SelectionKey> it = selectedKeys.iterator();
                while (it.hasNext()) {
                    SelectionKey sk = it.next();
                    dispatch(sk);
                }
                selectedKeys.clear();
            }
        } catch (IOException ex) {
            ex.printStackTrace();
        }
    }
    private void dispatch(SelectionKey sk) {
        Runnable runnable = (Runnable) sk.attachment();
        if (runnable != null) {
            runnable.run();
        }
    }
    class Acceptor implements Runnable {
        @Override
        public void run() {
            try {
                SocketChannel socketChannel = serverSocket.accept();
                if (socketChannel != null) {
                    new Handler(selector, socketChannel);
                }
            } catch (IOException ex) {
                ex.printStackTrace();
            }
        }
    }
    class Handler implements Runnable {
        private final SocketChannel socketChannel;
        private final SelectionKey selectionKey;
        private ByteBuffer input = ByteBuffer.allocate(1024);
        private ByteBuffer output = ByteBuffer.allocate(1024);
        public Handler(Selector selector, SocketChannel socketChannel) throws IOException {
            this.socketChannel = socketChannel;
            socketChannel.configureBlocking(false);
            selectionKey = socketChannel.register(selector, 0);
            selectionKey.attach(this);
            selectionKey.interestOps(SelectionKey.OP_READ);
            selector.wakeup();
        }
        @Override
        public void run() {
            try {
                if (selectionKey.isReadable()) {
                    read();
                } else if (selectionKey.isWritable()) {
                    write();
                }
            } catch (IOException ex) {
                ex.printStackTrace();
            }
        }
        private void read() throws IOException {
            socketChannel.read(input);
            input.flip();
            // do something with input
            selectionKey.interestOps(SelectionKey.OP_WRITE);
        }
        private void write() throws IOException {
            output.clear();
            socketChannel.write(output);
            selectionKey.interestOps(SelectionKey.OP_READ);
        }
    }
    public static void main(String[] args) throws IOException {
        new Thread(new Reactor(8080)).start();
    }
}

在这个示例代码中,Reactor类实现了Runnable接口,表示它是一个线程。在构造函数中,它创建了一个Selector对象,并将ServerSocketChannel对象注册到Selector中,用于监听客户端的连接请求。

Acceptor类是一个内部类,它实现了Runnable接口。当有新的客户端连接时,Acceptor将会被调用,用于创建一个新的Handler对象来处理客户端请求。

Handler类也是一个内部类,它实现了Runnable接口。它包含了两个ByteBuffer对象,一个用于读取数据,一个用于写入数据。当客户端发送数据时,Handler将读取数据并进行处理,然后切换到写模式,将结果写回给客户端。

在Reactor类的run方法中,它使用Selector对象的select方法来阻塞等待事件的发生。当有事件发生时,它将调用dispatch方法来处理这些事件。dispatch方法将会找到对应的Runnable对象并执行它的run方法。

这个示例代码只是一个简单的实现,实际上Reactor模式还有很多细节需要考虑,例如如何处理异步操作、如何处理异常等等。但是通过这个示例代码,你可以了解到Reactor模式的基本思想和实现方式。

风语者!平时喜欢研究各种技术,目前在从事后端开发工作,热爱生活、热爱工作。