2024-09-02

Redis的底层实现中,双向链表是一种常用的数据结构,它被广泛应用于组织数据集合,提供高性能的节点插入、删除和遍历操作。

在Redis中,双向链表被广泛用于实现复杂的数据结构,如列表键、发布/订阅机制、慢查询日志等。

以下是一个简单的双向链表实现的例子:




#include <stdio.h>
#include <stdlib.h>
 
// 定义链表节点结构体
typedef struct listNode {
    struct listNode *prev;
    struct listNode *next;
    void *value;
} listNode;
 
// 创建一个新的链表节点
listNode *listNodeCreate(void *value) {
    listNode *node = (listNode *)malloc(sizeof(listNode));
    node->prev = NULL;
    node->next = NULL;
    node->value = value;
    return node;
}
 
// 将节点插入到链表头部
void listAddNodeHead(listNode **list, listNode *node) {
    if (*list == NULL) {
        *list = node;
    } else {
        node->next = *list;
        (*list)->prev = node;
        *list = node;
    }
}
 
// 移除链表的头节点
void listDelNode(listNode **list, listNode *node) {
    if (node->prev == NULL) {
        *list = node->next;
    } else {
        node->prev->next = node->next;
    }
    
    if (node->next) {
        node->next->prev = node->prev;
    }
}
 
// 打印链表
void listPrint(listNode *list) {
    while (list != NULL) {
        printf("%d\n", *(int *)(list->value));
        list = list->next;
    }
}
 
int main() {
    listNode *list = NULL;
    listNode *node1 = listNodeCreate((void *)1);
    listNode *node2 = listNodeCreate((void *)2);
    listNode *node3 = listNodeCreate((void *)3);
 
    listAddNodeHead(&list, node1);
    listAddNodeHead(&list, node2);
    listAddNodeHead(&list, node3);
 
    printf("List content:\n");
    listPrint(list);
 
    listDelNode(&list, node2);
    printf("\nList after delete node2:\n");
    listPrint(list);
 
    return 0;
}

在这个例子中,我们定义了一个简单的双向链表节点结构体listNode,并实现了创建新节点、将节点插入到链表头部以及移除节点的函数。最后,在main函数中演示了如何使用这些函数来创建、修改和打印链表。

2024-09-02

FastAdmin 框架中使用 Redis 的方法通常是通过内置的 Redis 驱动进行。以下是一个使用 Redis 的基本示例:

首先,确保你的环境中已经安装并配置了 Redis。

  1. 在应用的配置文件中启用 Redis 配置(通常在 application/config.php 或者 config/cache.php)。



// 开启缓存
'cache' => [
    // 默认缓存驱动
    'type'   => 'Redis',
    'host'   => '127.0.0.1',
    'port'   => 6379,
    'password' => '',
    // 更多的 Redis 配置...
],
  1. 在控制器中使用 Redis 客户端:



public function index()
{
    // 获取缓存驱动
    $redis = \org\Redis::getInstance();
 
    // 设置一个 key
    $redis->set('test', 'Hello, FastAdmin!');
 
    // 获取这个 key 的值
    $value = $redis->get('test');
 
    echo $value; // 输出 Hello, FastAdmin!
}

确保你已经使用命名空间正确地引用了 Redis 类。FastAdmin 的 Redis 驱动一般遵循 org\Redis 这样的路径。

以上代码展示了如何在 FastAdmin 中使用 Redis 客户端进行简单的 set 和 get 操作。在实际应用中,你可能需要根据业务逻辑来使用更复杂的 Redis 命令和数据结构。

2024-09-02

Redis的高级特性包括持久化、主从模式和哨兵模式,以及分片集群。

  1. Redis 持久化:

    Redis提供了两种持久化方式,RDB(默认)和AOF。




# 配置RDB快照
save 900 1      # 900秒内至少1个键被修改则触发保存
save 300 10     # 300秒内至少10个键被修改则触发保存
save 60 10000   # 60秒内至少10000个键被修改则触发保存

# 配置AOF
appendonly yes  # 开启AOF持久化存储
appendfsync everysec  # 每秒同步到磁盘
  1. Redis 主从模式:

    通过复制功能,Redis可以建立主从关系,实现数据的同步。




# 配置Slave
slaveof <master-ip> <master-port>
  1. Redis 哨兵模式:

    哨兵是Redis的高可用解决方案,它由一个或多个哨兵实例组成,可以监控主节点和从节点,并在主节点故障时自动进行故障转移。




# 配置哨兵
sentinel monitor mymaster <master-ip> <master-port> 2
sentinel down-after-milliseconds mymaster 30000
sentinel parallel-syncs mymaster 1
sentinel failover-timeout mymaster 180000
  1. Redis 分片集群:

    Redis Cluster是Redis官方提供的分布式解决方案,它通过分片(sharding)来提供数据分布式存储。




# 配置Redis Cluster
cluster-enabled yes
cluster-config-file nodes-6379.conf
cluster-node-timeout 5000
appendonly yes

以上是Redis高级特性的简要说明和配置示例,具体实现时需要根据实际需求进行调整。

2024-09-02

在监控Redis时,我们通常关注的是Redis的运行状态、内存使用、命令执行情况、持久化延迟等指标。以下是一个使用Prometheus和Redis自带的INFO命令来获取监控数据的示例。

首先,需要编写一个脚本或者使用现有的Exporter(比如redis_exporter)来获取Redis的监控数据,并将其暴露给Prometheus。




#!/bin/bash
 
redis_host="localhost"
redis_port=6379
 
redis-cli -h ${redis_host} -p ${redis_port} info | grep -E "^#|db0" | awk '/(connected_clients|blocked_clients|used_memory|changes_since_last_save|bgsave_in_progress|last_save_time_sec|total_commands_processed|rejected_connections|expired_keys|evicted_keys|keyspace_hits|keyspace_misses|used_cpu_sys|used_cpu_user|used_cpu_sys_children|used_cpu_user_children):/'

保存为redis_exporter.sh并给予执行权限:




chmod +x redis_exporter.sh

然后,在Prometheus配置文件prometheus.yml中添加一个新的job来抓取这个脚本的输出:




scrape_configs:
  - job_name: 'redis'
    static_configs:
      - targets: ['localhost:9100']

在上面的配置中,我们假设脚本运行在本地的9100端口。

最后,启动一个服务来持续运行这个脚本并暴露端口:




python -m http.server 9100

或者使用一个系统服务来做这件事,例如使用systemd




[Unit]
Description=Redis Exporter
After=network.target
 
[Service]
Type=simple
User=nobody
ExecStart=/path/to/redis_exporter.sh
Restart=on-failure
 
[Install]
WantedBy=multi-user.target

保存为redis_exporter.service,然后使用systemctl来启动服务:




systemctl start redis_exporter.service
systemctl enable redis_exporter.service

现在,Prometheus会定期抓取Redis监控数据,并在Grafana中展示。

2024-09-02

Redis是一个开源的使用C语言编写、支持网络、可基于内存亦可持久化的日志型、Key-Value数据库,并提供多种语言的API。

以下是一些基本的Redis命令:

  1. 连接操作相关命令
  • AUTH password:认证密码。
  • ECHO message:打印信息。
  • PING:测试与服务器的连接是否仍然有效。
  • QUIT:关闭当前连接。
  • SELECT index:更改当前选择的数据库。
  1. 服务器管理操作相关命令
  • BGREWRITEAOF:在后台异步重写AOF文件。
  • BGSAVE:在后台异步保存当前数据库到磁盘。
  • CLIENT LIST:获取连接到服务器的客户端连接列表。
  • CLIENT KILL ip:port:关闭客户端连接。
  • CLIENT GETNAME:获取连接的客户端名称。
  • CLIENT PAUSE timeout:在指定时间内暂停接收来自客户端的命令。
  • CLIENT SETNAME connection-name:设置当前连接的名称。
  • CLUSTER SLOTS:获取集群的slot数据。
  • COMMAND:获取Redis命令的详细信息。
  • CONFIG GET parameter:获取配置参数的值。
  • CONFIG REWRITE:重写配置文件。
  • CONFIG SET parameter value:设置配置参数的值。
  • CONFIG RESETSTAT:重置所有统计数据。
  • DBSIZE:返回当前数据库的键的数量。
  • DEBUG OBJECT key:获取有关key的调试信息。
  • DEBUG SEGFAULT:造成程序崩溃。
  • FLUSHALL:删除所有数据库的所有键。
  • FLUSHDB:删除当前数据库的所有键。
  • INFO:获取有关Redis服务器的信息和统计。
  • LASTSAVE:返回上次成功将数据保存到磁盘的时间。
  • MONITOR:实时监控所有经过Redis服务器的请求。
  • ROLE:返回当前Redis服务器的角色信息。
  • SAVE:同步保存数据到磁盘。
  • SHUTDOWN [NOSAVE] [SAVE]:关闭服务器。
  • SLAVEOF host port:将当前服务器转变为指定服务器的从属服务器。
  • SLOWLOG GET [N]:获取慢查询日志。
  • SLOWLOG LEN:获取慢查询日志的长度。
  • SLOWLOG RESET:重置慢查询日志。
  • SYNC:用于复制功能,同步连接的从服务器。
  • TIME:返回服务器的当前时间。
  1. 键操作相关命令
  • DEL key [key ...]:删除一个或多个键。
  • DUMP key:返回给定key的序列化版本。
  • EXISTS key:检查给定key是否存在。
  • EXPIRE key seconds:为key设置过期时间。
  • EXPIREAT key timestamp:为key设置UNIX时间戳作为过期时间。
  • KEYS pattern:查找所有符合给定模式的key。
  • MOVE key db:将key从当前数据库移动到指定数据库。
  • PERSIST key:移除key的过期时间。
  • PEXPIRE key milliseconds:为key设置
2024-09-02



import { Module, Global } from '@nestjs/common';
import { createClient } from 'redis';
import { RedisService } from './redis.service';
 
@Global() // 使服务全局可用
@Module({
  providers: [RedisService],
  exports: [RedisService],
})
export class RedisModule {}
 
// redis.service.ts
import { Inject, Injectable, OnModuleInit } from '@nestjs/common';
import { createClient, RedisClientType } from 'redis';
 
@Injectable()
export class RedisService implements OnModuleInit {
  private client: RedisClientType;
 
  async onModuleInit() {
    this.client = createClient();
    await this.client.connect();
  }
 
  // 定义你的存取方法
  async set(key: string, value: any) {
    return this.client.set(key, value);
  }
 
  async get(key: string) {
    return this.client.get(key);
  }
}

在这个例子中,我们创建了一个全局的RedisModule,它提供了一个RedisService,该服务在模块初始化时建立了与Redis的连接,并定义了set和get方法来存取数据。这样,我们就可以在任何需要的地方注入RedisService来使用Redis功能了。

2024-09-02



import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.index.GeoIndexDefinition;
import org.springframework.data.redis.connection.RedisGeoCommands;
import org.springframework.data.redis.connection.RedisConnection;
 
import java.util.List;
import java.util.concurrent.TimeUnit;
 
public class RedisGeoExample {
 
    private final RedisTemplate<String, String> redisTemplate;
 
    public RedisGeoExample(RedisTemplate<String, String> redisTemplate) {
        this.redisTemplate = redisTemplate;
    }
 
    public void addGeoLocation(String key, double longitude, double latitude, String member) {
        redisTemplate.opsForGeo().add(key, new Point(longitude, latitude), member);
    }
 
    public List<Point> searchGeoLocationsWithinRadius(String key, double longitude, double latitude, double radius) {
        return redisTemplate.opsForGeo().findGeoWithin(key, new Point(longitude, latitude), radius);
    }
 
    public void expireGeoKey(String key, long timeout, TimeUnit unit) {
        RedisConnection connection = redisTemplate.getConnectionFactory().getConnection();
        connection.pExpire(key.getBytes(), unit.toMillis(timeout));
        connection.close();
    }
}

这个代码示例展示了如何在Spring应用程序中使用RedisTemplate操作Geo类型的数据。它包括添加地理位置数据、搜索指定范围内的地理位置数据,以及设置Geo key的过期时间。这些操作是在Redis中实现向量数据库功能的基础。

2024-09-02

停止Redis服务的命令取决于你的操作系统和安装方式。以下是一些常用的方法:

  1. 使用redis-cli工具:



redis-cli shutdown
  1. 如果你是通过系统服务管理器(如systemd或init.d)安装的Redis,可以使用对应的命令:



# 使用systemctl(systemd)
sudo systemctl stop redis
 
# 使用init.d(旧系统)
sudo /etc/init.d/redis-server stop
  1. 如果你是在Docker容器中运行Redis,可以使用以下命令停止容器:



docker stop <container_id_or_name>

确保你有足够的权限执行这些命令,否则你可能需要使用sudo

2024-09-02

Redisson 是一个在 Java 中实现的 Redis 客户端,提供了一系列分布式的服务。在 Spring Boot 中,可以很容易地配置和使用 Redisson。

以下是一个使用 Redisson 的基本示例:

  1. 添加 Maven 依赖:



<dependency>
    <groupId>org.redisson</groupId>
    <artifactId>redisson-spring-boot-starter</artifactId>
    <version>3.16.2</version>
</dependency>
  1. application.ymlapplication.properties 中配置 Redisson:



# application.yml
 
spring:
  redisson:
    address: redis://127.0.0.1:6379

或者使用 properties 格式:




# application.properties
 
spring.redisson.address=redis://127.0.0.1:6379
  1. 使用 Redisson 提供的分布式服务,例如使用 RLock 实现分布式锁:



import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
 
@RestController
public class RedissonController {
 
    @Autowired
    private RedissonClient redissonClient;
 
    @GetMapping("/lock")
    public String lock() {
        RLock lock = redissonClient.getLock("myLock");
        try {
            lock.lock();
            // 业务逻辑
            return "Lock acquired";
        } finally {
            lock.unlock();
        }
    }
}

在这个例子中,我们创建了一个简单的 REST 接口 /lock,它使用 Redisson 提供的分布式锁来确保在同一时间只有一个请求可以执行业务逻辑。这是一个基本的使用 Redisson 的例子,Redisson 还提供了其他分布式服务,如 RTopic, RQueue, RMap, RSet 等,可以用于不同的场景。

2024-09-02

Redis Stream 是 Redis 5.0 版本新引入的数据类型,用于提供一个消息流的功能,类似于 Kafka 或者 RabbitMQ 的功能。

Redis Stream 是一个key-item的集合,其中每个item都是一个消息,每个消息都有一个唯一的ID和对应的内容。

Redis Stream 的主要特点:

  1. 消息ID唯一,由10字节的Long类型组成,可以唯一标识一条消息。
  2. 消息内容可以是任何格式,可以是字符串、列表、集合、有序集合等。
  3. 可以通过XADD命令添加消息到Stream,使用XREAD命令读取消息。
  4. 消息是持久化的,即使服务器重启,消息也不会丢失。
  5. 可以通过消息ID设置消费者的读取位置,实现消息的顺序读取。
  6. 支持消费者组,允许多个消费者同时消费Stream中的消息。

以下是一些基本操作的示例代码:

  1. 添加消息到Stream:



XADD mystream * field1 value1 field2 value2
  1. 读取Stream中的消息:



XREAD COUNT 2 STREAMS mystream mystream2
  1. 创建消费者组并添加消费者:



XGROUP CREATE mystream mygroup $
XGROUP CREATE mystream mygroup 0
  1. 从消费者组读取消息:



XREADGROUP GROUP mygroup myconsumer COUNT 2 STREAMS mystream >
  1. 确认消息已消费:



XACK mystream mygroup 15269333347-0

以上操作都是基于Redis Stream的基本操作,实际应用中可能还会涉及到消息的持久化、高可用性等更复杂的场景。