Redis在NestJS中的应用与实践

452 阅读4分钟

前言

Redis是一种开源的内存数据结构存储系统,它可以用作数据库、缓存和消息中间件。在现代Web应用程序中,Redis已经成为处理高并发、提升性能不可或缺的组件。本文将详细介绍Redis在NestJS应用中的集成和最佳实践,并结合实际项目代码展示其应用场景。

Redis基础概述

Redis(Remote Dictionary Server)是一个基于内存的高性能键值数据库,具有以下特点:

  • 高性能:所有数据存储在内存中,提供极快的读写速度
  • 丰富的数据结构:支持字符串、哈希、列表、集合、有序集合等
  • 原子操作:Redis的所有操作都是原子性的,避免并发问题
  • 持久化:支持RDB和AOF两种持久化方式,保证数据不丢失
  • 主从复制:支持主从复制,提高系统可用性

启动Redis 服务

在 docker desktop 搜索框搜索 redis,点击 run,把 redis 官方镜像下载并跑起来。 image.png 点击Run,然后填写相关信息: image.png 端口映射就是把主机的 6379 端口映射到容器内的 6379 端口,这样就能直接通过本机端口访问容器内的服务了。 指定数据卷,用本机的任意一个目录挂载到容器内的 /data 目录,这样数据就会保存在本机。

在NestJS中集成Redis

安装所需依赖

npm install redis @nestjs/config

创建Redis模块

在NestJS中,我们通常会创建一个独立的Redis模块来封装Redis客户端的创建和管理。以下是项目中的实现:

// src/redis/redis.module.ts
import { Global, Module } from '@nestjs/common';
import { RedisService } from './redis.service';
import { createClient } from 'redis';
import { ConfigService } from '@nestjs/config';

@Global()
@Module({
    providers: [
        RedisService,
        {
            provide: 'REDIS_CLIENT',
            inject: [ConfigService],
            useFactory: async (configService: ConfigService) => {
                const redisConfig = configService.get('redis');
                const client = createClient({
                    socket: {
                        host: redisConfig.host,
                        port: redisConfig.port,
                    },
                    database: redisConfig.db,
                });
                await client.connect();
                return client;
            },
        },
    ],
    exports: [RedisService],
})
export class RedisModule {}

注意我们使用了@Global()装饰器,使Redis模块成为全局模块,这样其他模块无需导入即可使用RedisService。

创建Redis服务

接下来,我们创建一个RedisService来封装常用的Redis操作:

// src/redis/redis.service.ts
import { Inject, Injectable } from '@nestjs/common';
import { RedisClientType } from 'redis';

@Injectable()
export class RedisService {
    @Inject('REDIS_CLIENT')
    private redisClient: RedisClientType;

    async get(key: string) {
        return await this.redisClient.get(key);
    }

    async set(key: string, value: string | number, ttl?: number) {
        await this.redisClient.set(key, value);

        if (ttl) {
            await this.redisClient.expire(key, ttl);
        }
    }
    
    // 可以根据需要添加更多方法
    async del(key: string) {
        return await this.redisClient.del(key);
    }
    
    async exists(key: string) {
        return await this.redisClient.exists(key);
    }
}

配置Redis连接

在配置文件中定义Redis连接参数:

// src/config/configuration.ts
export default () => ({
  // 其他配置...
  redis: {
    host: process.env.REDIS_HOST || 'localhost',
    port: parseInt(process.env.REDIS_PORT, 10) || 6379,
    db: parseInt(process.env.REDIS_DB, 10) || 0,
  },
});

Redis常见使用场景

Redis在Web应用中有许多常见的使用场景:

  1. 缓存:最常见的用途是作为缓存层,减轻数据库负担,提高响应速度。
  2. 会话存储:存储用户会话信息,替代传统的服务器内存存储。
  3. 限流控制:实现API限流,防止恶意请求和DDoS攻击。
  4. 计数器:高性能计数器,如文章浏览量、点赞数等。
  5. 消息队列:轻量级消息队列,用于系统解耦和异步处理。

Redis存储优化策略

  1. 键命名规范:良好的键命名规范可以提高代码可读性和维护性
  2. 设置合理的TTL:为数据设置合适的过期时间,避免内存无限增长
  3. 使用Pipeline和事务:对于批量操作,使用Pipeline可以显著提高性能

总结

  1. 使用模块化设计:将Redis功能封装为独立模块
  2. 定义清晰的键命名规则:保持一致的命名约定
  3. 设置合理的TTL:避免内存无限增长
  4. 选择合适的数据结构:根据业务需求选择最适合的Redis数据类型
  5. 监控和优化:监控Redis内存使用情况,及时优化

通过在NestJS中正确集成和使用Redis,我们可以显著提高应用程序的性能和可扩展性。Redis不仅可以作为简单的缓存系统,还可以支持各种复杂的功能,如会话管理、限流控制和实时统计等。