nestjs-fullstack-notes.zip

  • 初中级 】之前有使用 Node.js 开发过服务端吗?说说你最常用的 Node.js 服务端框架,并简单说明其设计思想与原理
  • 中高级 】架构设计一个复杂业务的后端服务,数据持久化设计这块有没有什么最佳实战经验
  • 专家级 】作为技术 Leader,服务端高可用高并发这块有哪些实战经验,请以 Node.js 服务架构详细介绍

初中级 】之前有使用 Node.js 开发过服务端吗?说说你最常用的 Node.js 服务端框架,并简单说明其设计思想与原理

NestJS 基本使用

什么是 NestJS

  • NestJS 定位

    • NestJS 是一个渐进式框架,用于构建高效、可靠和可维护的服务端应用。
    • 适合 微服务架构模块化开发
  • 核心理念

    • 强调开发者体验,通过 TypeScript 提供类型安全。
    • 使用模块化架构使代码更易维护和扩展。
    • 提供可插拔的生态系统,支持多种技术(如 GraphQL、WebSocket 等)。

NestJS 核心概念

NestJS 中有多个核心概念,以下是它们的设计初衷及用法:

模块(Modules)

  • 设计意图

    • 将应用划分为逻辑单元,每个模块负责特定功能。
    • 提高代码的可复用性和可维护性。
  • 用法

@Module({
  imports: [UserModule],
  controllers: [AppController],
  providers: [AppService],
})
export class AppModule {}

控制器(Controllers)

  • 设计意图

    • 控制器处理请求,负责接收客户端请求并返回响应。
    • 遵循单一职责原则,将业务逻辑分离到服务中。
  • 用法

@Controller('users')
export class UserController {
  @Get()
  findAll(): string {
    return 'This action returns all users';
  }
}

服务(Providers)

  • 设计意图

    • 负责核心业务逻辑。
    • 服务是可注入的,使用依赖注入的方式将其提供给控制器或其他服务。
  • 用法

@Injectable()
export class UserService {
  getAllUsers(): string[] {
    return ['user1', 'user2'];
  }
}

中间件(Middleware)

  • 设计意图

    • 在请求到达控制器之前,对请求进行拦截和处理。
    • 适用于日志记录、身份验证等场景。
  • 用法

export class LoggerMiddleware implements NestMiddleware {
  use(req: Request, res: Response, next: Function) {
    console.log(
${req.method} ${req.url}
);
    next();
  }
}

拦截器(Interceptors)

  • 设计意图

    • 用于拦截请求或响应。
    • 可以对数据进行转换、增强,或记录处理时间。
  • 用法

@Injectable()
export class LoggingInterceptor implements NestInterceptor {
  intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
    const now = Date.now();
    return next
      .handle()
      .pipe(tap(() => console.log(
Execution time: ${Date.now() - now}ms
)));
  }
}

过滤器(Filters)

  • 设计意图

    • 捕获和处理异常。
    • 统一异常处理,提高代码简洁性。
  • 用法

@Catch(HttpException)
export class HttpExceptionFilter implements ExceptionFilter<HttpException> {
  catch(exception: HttpException, host: ArgumentsHost) {
    const ctx = host.switchToHttp();
    const response = ctx.getResponse();
    const status = exception.getStatus();
    response.status(status).json({
      statusCode: status,
      timestamp: new Date().toISOString(),
    });
  }
}

守卫(Guards)

  • 设计意图

    • 控制访问权限。
    • 在请求处理之前进行身份验证和授权。
  • 用法

@Injectable()
export class RolesGuard implements CanActivate {
  canActivate(context: ExecutionContext): boolean {
    const request = context.switchToHttp().getRequest();
    const user = request.user;
    return user && user.roles.includes('admin');
  }
}

NestJS 模块组织形式

单模块应用

适用于小型应用,所有功能集中在一个模块中实现。

多模块应用

适用于中大型应用,将不同功能划分到不同模块中。

@Module({
  imports: [AuthModule, UserModule, ProductModule],
})
export class AppModule {}

动态模块【自定义集中模块常用】

  • 设计意图 :动态模块允许模块根据运行时配置动态导入服务。
  • 实现示例
@Module({})
export class DatabaseModule {
  static forRoot(config: DatabaseConfig): DynamicModule {
    return {
      module: DatabaseModule,
      providers: [
        {
          provide: 'DATABASE_CONNECTION',
          useValue: createConnection(config),
        },
      ],
    };
  }
}

NestJS 自定义模块(PostgreSQL 驱动)

以下实现了一个 PostgreSQL 驱动模块:

自定义服务

@Injectable()
export class PostgresService {
  private pool: Pool;
  constructor() {
    this.pool = new Pool({
      host: 'localhost',
      port: 5432,
      user: 'postgres',
      password: 'password',
      database: 'test',
    });
  }
  async query(sql: string, params?: any[]): Promise<any> {
    return this.pool.query(sql, params);
  }
}

自定义模块

@Module({
  providers: [PostgresService],
  exports: [PostgresService],
})
export class PostgresModule {}

NestJS 依赖注入的实现原理(源码分析)

核心源码

NestJS 的依赖注入基于其 IoC 容器 实现,核心模块包括:

  • ModuleRef :模块引用,用于管理模块实例。
  • Injector :负责创建和注入依赖。

https://github.com/nestjs/nest/blob/b40649fd69c3e2132d83f40190f030fbdb320e8c/packages/core/injector/module.ts#L593

依赖注入的关键步骤

  1. 解析模块元数据

    • 通过 @Module 装饰器定义模块及其依赖。
  2. 实例化模块

    • NestJS 使用 ModuleFactory 实例化模块及其组件。
// 核心部分
async createModule(
  module: Type<any>,
  scope: Type<any>[]
): Promise<Module> {
  const moduleInstance = new Module(module, scope);
  await this.init(moduleInstance);
  return moduleInstance;
}
  1. 解析依赖关系

    • 通过 Reflect 获取类构造函数的参数元数据。
const dependencies = Reflect.getMetadata('design:paramtypes', target);

依赖注入的高级实现

  • 自定义工厂
@Module({
  providers: [
    {
      provide: 'CONFIG',
      useFactory: () => {
        return { host: 'localhost', port: 5432 };
      },
    },
  ],
})
export class ConfigModule {}
  • 动态模块注入
@Module({})
export class CustomModule {
  static register(options: Options): DynamicModule {
    return {
      module: CustomModule,
      providers: [
        {
          provide: 'OPTIONS',
          useValue: options,
        },
      ],
    };
  }
}

中高级 】架构设计一个复杂业务的后端服务,数据持久化设计这块有没有什么最佳实战经验

复杂项目服务端架构设计的重点

设计目标

在复杂业务场景下,服务端的架构设计需要满足以下核心需求:

  • 高可用性 :系统能够持续提供服务。
  • 高性能 :快速响应用户请求,支持高并发。
  • 扩展性 :系统模块易于扩展和升级。
  • 可维护性 :代码结构清晰、逻辑分离,方便开发和调试。
  • 数据安全性 :支持数据备份、容灾和加密。

关键设计问题

  1. 缓存设计 :快速访问频繁使用的数据,减轻数据库压力。
  2. 数据库设计 :选择合适的数据库,根据场景调整表结构和查询优化。
  3. 日志数据库设计 :集中式日志存储与分析,用于调试和性能监控。
  4. 海量数据设计 :优化数据存储和查询,降低延迟和存储成本。
  5. 实时数据流设计 :处理实时事件流和数据流计算。

技术选型

  1. Redis :缓存服务,支持持久化和高性能存储,适合会话管理、热点数据存储。
  2. PostgreSQL :关系型数据库,支持强大的事务处理能力和扩展性。
  3. ClickHouse :列式数据库,适合海量数据的实时分析。
  4. Kafka :分布式消息队列,支持实时数据流的处理。

Docker 环境搭建(基于 bitnami 镜像)

Docker Compose 配置

以下是包含 Redis、PostgreSQL、ClickHouse 和 Kafka 的 docker-compose.yml 配置示例:

version: '3.8'
services:
  redis:
    image: bitnami/redis:latest
    container_name: redis
    ports:
      - "6379:6379"
    environment:
      - ALLOW_EMPTY_PASSWORD=yes
  postgres:
    image: bitnami/postgresql:latest
    container_name: postgres
    ports:
      - "5432:5432"
    environment:
      - POSTGRESQL_USERNAME=admin
      - POSTGRESQL_PASSWORD=admin123
      - POSTGRESQL_DATABASE=mydb
  clickhouse:
    image: bitnami/clickhouse:latest
    container_name: clickhouse
    ports:
      - "8123:8123"
  kafka:
    image: bitnami/kafka:latest
    container_name: kafka
    ports:
      - "9092:9092"
    environment:
      - KAFKA_CFG_ZOOKEEPER_CONNECT=zookeeper:2181
      - ALLOW_PLAINTEXT_LISTENER=yes
    depends_on:
      - zookeeper
  zookeeper:
    image: bitnami/zookeeper:latest
    container_name: zookeeper
    ports:
      - "2181:2181"
    environment:
      - ALLOW_ANONYMOUS_LOGIN=yes

启动容器:

docker-compose up -d

核心技术点与基础概述

Redis

技术概述:

  • Redis 是一个开源的高性能键值数据库,支持多种数据结构(字符串、列表、哈希、集合等)。
  • 提供强大的缓存功能和持久化支持,适用于 会话管理热点数据缓存分布式锁

基本操作:

  • 安装与启动 : 使用 Docker 启动:
docker run -d --name redis -p 6379:6379 bitnami/redis:latest
  • 常用命令
# 设置值
SET key value
# 获取值
GET key
# 设置带过期时间的值(单位:秒)
SETEX key 60 value
# 删除值
DEL key

PostgreSQL

技术概述:

  • PostgreSQL 是一个功能强大的开源关系型数据库,支持事务、索引、触发器和扩展。
  • 适用于 强一致性数据存储复杂查询场景

基本操作:

  • 安装与启动 : 使用 Docker 启动:
docker run -d --name postgres -p 5432:5432 \
  -e POSTGRESQL_USERNAME=admin \
  -e POSTGRESQL_PASSWORD=admin123 \
  -e POSTGRESQL_DATABASE=mydb \
  bitnami/postgresql:latest
  • 常用 SQL
-- 创建表
CREATE TABLE users (
    id SERIAL PRIMARY KEY,
    name VARCHAR(100),
    email VARCHAR(100) UNIQUE
);
-- 插入数据
INSERT INTO users (name, email) VALUES ('Alice', 'alice@example.com');
-- 查询数据
SELECT * FROM users;

ClickHouse

技术概述:

  • ClickHouse 是一个高性能的列式数据库,适用于处理海量数据和实时分析场景。
  • 提供极高的读写性能,适合 日志存储数据分析

基本操作:

  • 安装与启动 : 使用 Docker 启动:
docker run -d --name clickhouse -p 8123:8123 bitnami/clickhouse:latest
  • 基本查询
-- 创建表
CREATE TABLE logs (
    timestamp DateTime,
    level String,
    message String
) ENGINE = MergeTree()
ORDER BY timestamp;
-- 插入数据
INSERT INTO logs VALUES (now(), 'INFO', 'Service started');
-- 查询数据
SELECT * FROM logs WHERE level = 'INFO';

Kafka

技术概述:

  • Kafka 是一个分布式消息队列,支持高吞吐量的实时数据流处理。
  • 适用于 事件驱动架构日志流式处理

基本操作:

  • 安装与启动 : 使用 Docker 启动:
docker-compose up -d
  • 基本概念

    • Producer :向 Kafka 发布消息。
    • Consumer :从 Kafka 读取消息。
    • Topic :消息的分类容器。
  • 使用示例

# 启动生产者
kafka-console-producer.sh --topic test --bootstrap-server localhost:9092
# 启动消费者
kafka-console-consumer.sh --topic test --bootstrap-server localhost:9092 --from-beginning

NestJS 封装动态公共模块

Redis 缓存模块

创建 Redis 模块

import { Module, Global } from '@nestjs/common';
import { createClient } from 'redis';
@Global()
@Module({
  providers: [
    {
      provide: 'REDIS_CLIENT',
      useFactory: async () => {
        const client = createClient({ url: 'redis://localhost:6379' });
        await client.connect();
        return client;
      },
    },
  ],
  exports: ['REDIS_CLIENT'],
})
export class RedisModule {}

使用 Redis 缓存

import { Inject, Injectable } from '@nestjs/common';
import { RedisClientType } from 'redis';
@Injectable()
export class CacheService {
  constructor(@Inject('REDIS_CLIENT') private readonly redisClient: RedisClientType) {}
  async set(key: string, value: any): Promise<void> {
    await this.redisClient.set(key, JSON.stringify(value));
  }
  async get(key: string): Promise<any> {
    const value = await this.redisClient.get(key);
    return value ? JSON.parse(value) : null;
  }
}

PostgreSQL 数据库模块

创建 PostgreSQL 模块

import { Module, Global } from '@nestjs/common';
import { Pool } from 'pg';
@Global()
@Module({
  providers: [
    {
      provide: 'POSTGRES_POOL',
      useFactory: () => {
        return new Pool({
          host: 'localhost',
          port: 5432,
          user: 'admin',
          password: 'admin123',
          database: 'mydb',
        });
      },
    },
  ],
  exports: ['POSTGRES_POOL'],
})
export class PostgresModule {}

使用 PostgreSQL

import { Inject, Injectable } from '@nestjs/common';
import { Pool } from 'pg';
@Injectable()
export class PostgresService {
  constructor(@Inject('POSTGRES_POOL') private readonly pool: Pool) {}
  async query(sql: string, params: any[]): Promise<any> {
    const result = await this.pool.query(sql, params);
    return result.rows;
  }
}

ClickHouse 模块

创建 ClickHouse 模块

import { Module, Global } from '@nestjs/common';
import { ClickHouse } from 'clickhouse';
@Global()
@Module({
  providers: [
    {
      provide: 'CLICKHOUSE_CLIENT',
      useFactory: () => {
        return new ClickHouse({
          url: 'http://localhost',
          port: 8123,
        });
      },
    },
  ],
  exports: ['CLICKHOUSE_CLIENT'],
})
export class ClickHouseModule {}

使用 ClickHouse

import { Inject, Injectable } from '@nestjs/common';
import { ClickHouse } from 'clickhouse';
@Injectable()
export class AnalyticsService {
  constructor(@Inject('CLICKHOUSE_CLIENT') private readonly clickhouse: ClickHouse) {}
  async query(sql: string): Promise<any> {
    return this.clickhouse.query(sql).toPromise();
  }
}

Kafka 模块

创建 Kafka 模块

import { Module, Global } from '@nestjs/common';
import { Kafka, Producer } from 'kafkajs';
@Global()
@Module({
  providers: [
    {
      provide: 'KAFKA_PRODUCER',
      useFactory: async () => {
        const kafka = new Kafka({ brokers: ['localhost:9092'] });
        const producer = kafka.producer();
        await producer.connect();
        return producer;
      },
    },
  ],
  exports: ['KAFKA_PRODUCER'],
})
export class KafkaModule {}

使用 Kafka

import { Inject, Injectable } from '@nestjs/common';
import { Producer } from 'kafkajs';
@Injectable()
export class MessagingService {
  constructor(@Inject('KAFKA_PRODUCER') private readonly producer: Producer) {}
  async sendMessage(topic: string, message: string): Promise<void> {
    await this.producer.send({
      topic,
      messages: [{ value: message }],
    });
  }
}

复杂场景的最佳实践

缓存设计

  • 缓存失效策略 :使用 Redis 的 TTL 自动删除过期数据。
  • 分布式缓存 :对于多实例部署,可以使用 Redis Cluster。

数据库设计

  • 主从分离 :PostgreSQL 支持逻辑复制,用于读写分离。
  • 索引优化 :根据查询频率优化索引。

日志数据库设计

  • ClickHouse 高效存储 :压缩日志数据,支持实时分析。

实时数据流设计

  • Kafka 消息分区 :提高并发消费能力。
  • 事件驱动架构 :每个业务模块处理独立的事件流,保证高可用性。

专家级 】作为技术 Leader,服务端高可用高并发这块有哪些实战经验,请以 Node.js 服务架构详细介绍

服务端高可用与高并发的核心目标

在设计高可用高并发的服务端时,主要解决以下问题:

  1. 高可用性 :系统持续运行,即使某些组件或节点出现故障。
  2. 高并发性 :支持大量用户同时访问,快速响应请求。
  3. 横向扩展性 :系统能够轻松扩展以支持更大的负载。
  4. 数据一致性 :分布式环境中确保事务一致性。
  5. 容灾能力 :快速恢复服务,减少故障对用户的影响。

关键设计理念与技术选型

微服务架构设计

  • 核心思想

    • 将单体应用拆分为多个独立运行的小服务,每个服务专注于单一功能。
    • 服务之间通过异步消息或 HTTP 通信,松耦合、易扩展。
  • 优势

    • 服务独立部署,增强可靠性。
    • 横向扩展灵活,资源利用率高。

分布式系统设计

  • 分布式消息队列 :使用 Kafka 处理异步任务,解耦服务之间的依赖。
  • 分布式数据库 :通过 PostgreSQL 实现分片存储与主从复制。

技术选型

  1. NestJS :提供模块化架构,支持微服务开发。
  2. Kafka :分布式消息队列,支持高吞吐和低延迟。
  3. PostgreSQL :强一致性数据库,支持事务与分布式扩展。
  4. Redis :提供分布式缓存与分布式锁。
  5. Docker + Kubernetes :实现服务容器化和编排管理。

高可用与高并发架构设计思路

以下是典型高可用与高并发架构的设计思路:

网关层

  • 使用 API Gateway (如 Nginx 或 NestJS Gateway)处理所有外部请求。

  • 实现功能:

    • 负载均衡 :将请求分发到多个服务实例。
    • 限流 :防止突发流量导致系统崩溃。
    • 鉴权与认证 :统一处理用户身份验证。

微服务拆分

  1. 用户服务(User Service)

    • 负责用户的注册、登录与身份管理。
  2. 订单服务(Order Service)

    • 管理用户订单与支付逻辑。
  3. 通知服务(Notification Service)

    • 使用 Kafka 发送实时通知(如短信或邮件)。
  4. 分析服务(Analytics Service)

    • 使用 ClickHouse 存储与分析业务数据。

异步通信与事件驱动

  • 使用 Kafka 实现事件驱动架构。

    • 每个微服务向 Kafka 发布事件。
    • 消费者服务订阅相关事件,完成任务。
  • 优势:

    • 消息持久化,防止丢失。
    • 高并发处理能力,解耦服务依赖。

数据存储

  1. PostgreSQL

    • 主从复制:实现读写分离,提升性能。
    • 分片存储:支持海量数据存储与查询。
  2. Redis

    • 提供缓存支持,降低数据库压力。
    • 实现分布式锁,解决并发冲突。

容器化与服务编排

  • 使用 Docker 容器化微服务,统一部署。
  • 使用 Kubernetes(K8s)管理服务,支持自动扩容与故障恢复。

基于 NestJS 的微服务架构实现

使用 Kafka 实现异步通信

创建 Kafka 模块

import { Module, Global } from '@nestjs/common';
import { ClientsModule, Transport } from '@nestjs/microservices';
@Global()
@Module({
  imports: [
    ClientsModule.register([
      {
        name: 'KAFKA_CLIENT',
        transport: Transport.KAFKA,
        options: {
          client: {
            brokers: ['localhost:9092'],
          },
        },
      },
    ]),
  ],
  exports: [ClientsModule],
})
export class KafkaModule {}

生产者服务

import { Injectable, Inject } from '@nestjs/common';
import { ClientKafka } from '@nestjs/microservices';
@Injectable()
export class KafkaProducerService {
  constructor(@Inject('KAFKA_CLIENT') private kafkaClient: ClientKafka) {}
  async sendMessage(topic: string, message: any): Promise<void> {
    await this.kafkaClient.emit(topic, message).toPromise();
  }
}

消费者服务

import { Controller } from '@nestjs/common';
import { EventPattern, Payload } from '@nestjs/microservices';
@Controller()
export class KafkaConsumerController {
  @EventPattern('order_created')
  async handleOrderCreated(@Payload() message: any) {
    console.log('Order created:', message.value);
  }
}

使用 PostgreSQL 实现主从复制

数据库配置

# docker-compose.yml
services:
  postgres-master:
    image: bitnami/postgresql:latest
    environment:
      POSTGRESQL_USERNAME: admin
      POSTGRESQL_PASSWORD: admin123
      POSTGRESQL_DATABASE: mydb
    ports:
      - "5432:5432"

  postgres-replica:
    image: bitnami/postgresql:latest
    environment:
      POSTGRESQL_REPLICATION_MODE: replica
      POSTGRESQL_REPLICATION_USER: repl_user
      POSTGRESQL_REPLICATION_PASSWORD: repl_pass
      POSTGRESQL_PRIMARY_HOST: postgres-master
      POSTGRESQL_PRIMARY_PORT_NUMBER: 5432
    ports:
      - "5433:5432"

数据库访问模块

import { Injectable, Inject } from '@nestjs/common';
import { Pool } from 'pg';
@Injectable()
export class PostgresService {
  constructor(@Inject('DATABASE_POOL') private readonly pool: Pool) {}
  async query(sql: string, params?: any[]): Promise<any> {
    const result = await this.pool.query(sql, params);
    return result.rows;
  }
}

实现全局缓存

Redis 模块

import { Module, Global } from '@nestjs/common';
import { createClient } from 'redis';
@Global()
@Module({
  providers: [
    {
      provide: 'REDIS_CLIENT',
      useFactory: async () => {
        const client = createClient({ url: 'redis://localhost:6379' });
        await client.connect();
        return client;
      },
    },
  ],
  exports: ['REDIS_CLIENT'],
})
export class RedisModule {}

缓存服务

import { Inject, Injectable } from '@nestjs/common';
import { RedisClientType } from 'redis';
@Injectable()
export class CacheService {
  constructor(@Inject('REDIS_CLIENT') private readonly redisClient: RedisClientType) {}
  async set(key: string, value: any, ttl: number): Promise<void> {
    await this.redisClient.set(key, JSON.stringify(value), { EX: ttl });
  }
  async get(key: string): Promise<any> {
    const data = await this.redisClient.get(key);
    return data ? JSON.parse(data) : null;
  }
}

分布式锁

分布式锁设计与实现

在分布式系统中,为了防止多个服务实例同时访问共享资源(如数据库或文件)导致数据冲突或资源竞争,我们通常需要使用 分布式锁

分布式锁的常见场景

  1. 库存扣减 :高并发秒杀场景,确保商品库存不被超卖。
  2. 定时任务 :多个实例运行时,确保只有一个实例执行任务。
  3. 资源更新 :多个服务实例对同一资源进行更新时,避免冲突。

分布式锁的技术实现

  1. 使用 Redis 作为分布式锁的实现工具。
  2. 基于 Redis 的 SET 命令,结合 NXEX 参数实现加锁。

Redis 分布式锁核心命令

# 设置锁
SET lock_key unique_value NX EX 10
# 释放锁
DEL lock_key
  • NX :表示只有当 lock_key 不存在时才设置成功。
  • EX :设置过期时间,防止死锁。

NestJS 实现分布式锁

Redis 模块

创建全局的 Redis 模块,用于连接 Redis:

import { Module, Global } from '@nestjs/common';
import { createClient } from 'redis';
@Global()
@Module({
  providers: [
    {
      provide: 'REDIS_CLIENT',
      useFactory: async () => {
        const client = createClient({ url: 'redis://localhost:6379' });
        await client.connect();
        return client;
      },
    },
  ],
  exports: ['REDIS_CLIENT'],
})
export class RedisModule {}

分布式锁服务

封装分布式锁的核心逻辑:

import { Inject, Injectable } from '@nestjs/common';
import { RedisClientType } from 'redis';

@Injectable()
export class DistributedLockService {
  private readonly lockTimeout = 10; // 锁的过期时间(秒)

  constructor(@Inject('REDIS_CLIENT') private readonly redisClient: RedisClientType) {}

  /**
   * 获取分布式锁
   */
  async acquireLock(key: string, value: string): Promise<boolean> {
    const result = await this.redisClient.set(key, value, {
      NX: true,
      EX: this.lockTimeout,
    });
    return result === 'OK'; // 如果返回 'OK' 表示加锁成功
  }

  /**
   * 释放分布式锁
   */
  async releaseLock(key: string, value: string): Promise<boolean> {
    const script = `
      if redis.call("GET", KEYS[1]) == ARGV[1] then
        return redis.call("DEL", KEYS[1])
      else
        return 0
      end
    `;
    const result = await this.redisClient.eval(script, {
      keys: [key],
      arguments: [value],
    });
    return result === 1; // 如果返回 1 表示释放成功
  }
}

使用分布式锁

示例:实现一个高并发库存扣减的场景。

import { Injectable, OnModuleInit } from '@nestjs/common';
import { DistributedLockService } from './distributed-lock.service';
@Injectable()
export class InventoryService {
  constructor(private readonly lockService: DistributedLockService) {}
  async reduceStock(productId: string, quantity: number): Promise<string> {
    const lockKey = 
lock:product:${productId}
;
    const uniqueValue = 
${Date.now()}-${Math.random()}
; // 唯一标识
    // 尝试获取锁
    const lockAcquired = await this.lockService.acquireLock(lockKey, uniqueValue);
    if (!lockAcquired) {
      return 'Another operation is in progress, please try again later.';
    }
    try {
      // 加锁后,执行库存扣减逻辑
      console.log(
Lock acquired, reducing stock for product ${productId} by ${quantity}
);
      // 执行具体的业务逻辑,例如扣减数据库中的库存
      // ...
      return 'Stock reduced successfully.';
    } finally {
      // 释放锁
      const lockReleased = await this.lockService.releaseLock(lockKey, uniqueValue);
      if (!lockReleased) {
        console.warn('Failed to release lock, it may have expired.');
      }
    }
  }
}

测试与运行

  1. 启动 Redis

使用 Docker 启动 Redis:

docker run -d --name redis -p 6379:6379 bitnami/redis:latest
  1. 调用扣减库存接口

模拟多个并发请求调用服务:

const productId = '12345';
const quantity = 1;
for (let i = 0; i < 5; i++) {
  inventoryService.reduceStock(productId, quantity).then(console.log);
}
  1. 运行结果
  • 第一个请求获取到锁并成功扣减库存。
  • 其他请求返回 "Another operation is in progress, please try again later."

注意事项与优化

  1. 锁的唯一性

    • 锁的值( unique_value )需要全局唯一,防止其他服务误删锁。
  2. 锁的过期时间

    • 锁的过期时间应该根据业务逻辑设定,避免死锁问题。
  3. 重试机制

    • 如果获取锁失败,可以设置重试机制,以提高成功率。
  4. 高性能优化

    • Redis 是单线程模型,过多的锁竞争可能导致性能瓶颈。可使用 分布式锁库 (如 Redlock)优化锁实现。

最佳实践总结

  1. 分布式锁 :使用 Redis 分布式锁解决高并发下的资源竞争问题。
  2. 读写分离 :利用 PostgreSQL 主从复制实现读写分离,提升性能。
  3. 服务解耦 :通过 Kafka 实现异步通信,降低服务之间的耦合度。
  4. 缓存层优化 :优先缓存热点数据,避免频繁访问数据库。
  5. 容器化部署 :使用 Docker 和 Kubernetes 进行服务管理,实现自动扩容和故障恢复。

专家简历优化指南(目标 35K+ )

核心技能

  • 熟练掌握 HTML、CSS、JavaScript、Typescript 以及 OOP、FP、 AOP 等设计思想

  • 掌握样式体系构建与落地,对 css 预编译、css in js、module css 以及 utility-first CSS 有深入研究,并从零改良过样式体系以支持 SSR、SSG

  • 熟悉 React、Vue 相关技术栈,熟悉 React、Vue 及相关技术框架的实现原理

  • 掌握构建工具 Webpack、Vite 等,掌握编译工具 Babel,并深入理解其原理,并参与 Rspack 构建

  • 丰富的数据可视化经验,熟悉 Canvas、svg 开发范式,理解 Echarts、Antv 原理,能根据业务需求基于 d3、zrender 开发自定义渲染引擎

  • 丰富的跨端开发经验,熟练使用 Taro、Flutter、React-Native 开发跨端应用,对构建 hybird App 有丰富经验,深入理解跨端开发编译原理

  • 基于 Node.js 开发脚手架、打包构建优化工具及中间件服务

  • 掌握常用设计模式、算法与安全知识,追求开发高质量、高可维护性代码,追求极致产品体验

  • 团队管理经验,并在项目架构设计与性能优化方面具有丰富经验

  • 算法与编程技术

    • 精通各种算法题的分类及解决方法,包括排序与查找、数据结构、动态规划、贪心算法、回溯算法、分治算法、图论算法、数学算法等。
    • 重点掌握动态规划的基本概念、解题步骤和经典题目。
  • 3D 数字孪生平台开发经验

    • 熟练使用 WebGL 和 WebAssembly 技术,开发高效的 3D 渲染引擎。
    • 精通正射影像和倾斜摄影技术,具备 Tile 和模型(包括白膜和精模)的处理经验,能够使用 Blender 进行模型制作。
    • 熟悉材质、光效和粒子系统的实现与优化。
  • 全面性能优化能力

    • 具备打包构建优化经验,熟练使用 Webpack 进行模块打包,掌握 chunk、treeshaking、happypack、cache-loader 等优化技巧,并使用 Webpack Module Federation 进行模块联邦管理。
    • 精通资源优化,能够有效进行图片、字体压缩,管理请求队列,并通过 OSS 和 CDN 提升资源加载速度。
    • 具有应用性能优化经验,包括数据结构优化和应用模块更新。
    • 深入了解缓存机制,熟悉强缓存(Expiration、Cache-Control)、协商缓存(Etag)和策略缓存(Service-Worker)的配置与管理。

项目重难点

这个环节至关重要,很多同学不重视,简历随便写一写就开始投递了,结果投出去几百份可能一家公司面试都没有,结果就在怀疑前端行情出问题了

STAR 法则:

  • 遇到了什么问题 question,需求
  • 怎么评估解决方案,方案对比,方案落地 react 状态管理(redux、mobx、jotai、recoil)Vue3 -> Pinia
  • 具体方案落地
  • 结果反思,细节优化思考

反面案例:

技术栈:Java、Vue2、echarts、WEui、BaiduMap、JavaScript 、HTTP数据库:MySQL管理工具:SVN

责任描述:

1)产品前端研发负责人,主要负责整体样式沟通,样式调配实现;门户、管理平台、移动端、智端、可视化等前端内容实现;

2)实现组织管理、人员管理、党员关系转接、待办通知、绩效考核(复杂功能算法实现)、发展党员(25个流程)、可视化等主体功能,兼容性优化、适配1920*1080屏幕以及响应式布局实现;

3)相关功能开发,包含前后端、数据库;

4)门户框架搭建、门户整体设计、后端接口、门户前端 UI 实现等;

5)微信小程序框架搭建、小程序页面设计及开发、知识图谱技术预演;

6 )项目经理工作辅助,包含需求沟通、UI设计沟通、交付材料项目经历整理、前端代码质量管理、部分功能设计。

项目经历深度优化

工作内容和成果

  • 架构设计 】参与智慧管理平台整体架构设计、技术选型与方案评审,担任全栈开发,完成相关核心模块
  • 企微开发 】对接企业微信生态,基于企微 SDK 完成平台支付、消息推送、机器人等功能开发
  • 可视化 】主导完成平台可视化渲染引擎(可视化图表的组件,数据协议)设计与开发,基于 echarts (svgRenderer、canvasRenderer 一千万行数据的表格渲染【不能使用 虚拟滚动 】 canvas table,chunk)封装业务图表库,服务于平台可视化场景
  • 地图开发 】使用百度地图 SDK,封装业务地图渲染器(MapRenderer),包含:地图撒点、地区数据下钻等功能
  • 小程序与App 】基于 uniapp 实现智慧党建用户端多端开发落地,产物编译为 H5、微信小程序两端应用
  • 团队基建 】推进团队业务组件库、图表库与基础库沉淀,完成 10+ 个业务组件沉淀,以此提升了团队协同开发效率
  • 优化 】设计产品响应式系统,基于 media query 设计响应式端点规则,适配不同端应用的展示
  • 自研 OA 打通 】...

以 STAR 法则梳理

【技术栈】

  • Java、Vue2、ECharts、WEui、BaiduMap、JavaScript、HTTP
  • 数据库 :MySQL
  • 管理工具 :SVN

【产品前端研发负责人】

  • 情境 (Situation) :担任产品前端研发负责人,负责门户、管理平台、移动端、智端、可视化等前端内容的实现。
  • 任务 (Task) :主要任务是与设计团队沟通,调配和实现整体样式,确保产品界面的一致性和用户体验。
  • 行动 (Action) :我协调设计与开发团队,定期召开样式沟通会,亲自进行样式的调配与实现,并负责不同平台和设备的前端内容开发。
  • 结果 (Result) :成功实现了多个平台的前端开发工作,提升了产品的用户体验和一致性,获得了团队和用户的高度评价。

【实现复杂功能及优化】

  • 情境 (Situation) :项目需要实现复杂功能算法和大规模功能模块,包括组织管理、人员管理、党员关系转接、待办通知、绩效考核、发展党员(25个流程)和可视化功能。
  • 任务 (Task) :负责上述复杂功能的实现,并优化其兼容性和响应式布局。
  • 行动 (Action) :通过设计和实现复杂算法,确保各模块的功能性;进行兼容性优化,使系统适配1920*1080屏幕和响应式布局。
  • 结果 (Result) :成功实现并优化了所有复杂功能,系统在不同设备和分辨率下均表现良好,提高了用户操作的流畅度和满意度。

【全面功能开发】

  • 情境 (Situation) :需要进行前后端和数据库的全面开发,确保系统各功能模块的无缝集成。
  • 任务 (Task) :开发和实现相关功能,包括前端UI、后端接口和数据库交互。
  • 行动 (Action) :采用Java、Vue2等技术,开发并调试各功能模块,与后端团队密切合作,确保接口的准确性和数据的一致性。
  • 结果 (Result) :成功完成了所有功能模块的开发和集成,系统运行稳定,性能优异,受到了客户的好评。

【微信小程序开发与知识图谱预演】

  • 情境 (Situation) :项目需要开发微信小程序,并进行知识图谱技术的预演。
  • 任务 (Task) :负责小程序框架的搭建、页面设计及开发,同时进行知识图谱的技术预演。
  • 行动 (Action) :使用WEui、JavaScript等技术,设计并开发小程序页面,进行知识图谱的技术预演和验证。
  • 结果 (Result) :成功搭建了微信小程序框架,完成了页面设计和开发工作,知识图谱技术预演顺利,通过了技术验证。

【项目经理工作辅助】

  • 情境 (Situation) :在项目中辅助项目经理,确保项目需求沟通顺畅,UI设计协调到位,交付材料齐全,前端代码质量高。
  • 任务 (Task) :辅助项目经理进行需求沟通、UI设计沟通、交付材料整理、前端代码质量管理以及部分功能设计。
  • 行动 (Action) :积极参与需求和UI设计的沟通,整理和管理项目交付材料,进行代码审查和质量管理,并参与功能设计。
  • 结果 (Result) :成功辅助项目经理完成了项目的各项工作,提高了项目的开发效率和交付质量,确保了项目的顺利进行。

高级项目实战提升简历看点

你可能不具备这些项目的实战经验,很多同学写了很多年管理系统,简单增删改查项目,如果不跳出这个圈子,很难在薪资上有非常大的突破!

  • 大厂 UI 组件库(Vue3)整体设计与开发实践(monorepo 架构)

  • 大厂业务 Hooks 库(React 18)整体设计与开发实践(从零到一的架构、规范流程)

  • 企业级脚手架工具开发实践

  • 企业级文档编辑器飞书文档开发实践

  • 前端性能、异常与行为监控

  • 3D 可视化数字孪生低代码实战 💥

    • 基于 cesium(arcGis、超图) 方案的 WebGIS 开发实践
    • 基于 openlayer、mapbox 开发
    • 基于 WebGL 3D 可视化开发实践

冲刺年包 50W+ 薪资长线规划

冲刺核心要素

  1. 全面的技术储备

    1. 框架基础

      • Vue 和 React 经验:包括 Vue3 + Typescript 和 React18(Hooks、Concurrent)
      • 掌握框架原理:React 生态库(React-Router、Redux)和 Vue 生态库原理
    2. 工程化能力

      • 构建工具:Webpack、Vite、Rspack、ESBuild、swc
      • CI/CD 自动化:自动化构建和自动化部署
    3. 基建能力

      • Node.js、命令行工具开发(Cli)
      • UI 库、图表库、工具库开发
    4. 业务领域经验

      • 管理系统和图表类应用
      • 可视化、编辑器、云表格、低代码平台、SaaS 产品、数字孪生、三维可视化
  2. 项目经验

    • 参与过至少两个大型项目,并主导过一个复杂项目
    1. 管理系统:包括项目搭建、技术方案选择、技术栈构建、CI/CD 流程
    2. 其他领域项目:如可视化、编辑器、云表格、低代码平台、SaaS 产品、数字孪生、三维可视化
  3. 面试表现

    1. 个人介绍

      • 准备个人介绍草稿,涵盖基本信息、技术栈和项目重难点
    2. STAR 法则

      • 问题描述:阐述遇到的问题或需求
      • 解决方案评估:方案对比与选择(如 React 状态管理:redux、mobx、jotai、recoil,Vue3 使用 Pinia)
      • 方案实施:具体的实施步骤
      • 反思与优化:项目反思及优化建议
    3. 面试准备

      • 重点复习知识点:如 v8 内存管理、Promise A+ 规范、事件循环、this、面向对象编程原型
      • 技术储备:结合项目经验展示技术在项目中的应用
  4. 学历提升

    1. 现有学历:大专
    2. 未来计划:尽快取得本科证书(不需要注明具体年限)
    3. 学历背景:民办学校
    4. 内推建议:应对学历和工作经历问题,通过内推提升机会

自身短板与补益

  • 项目简单,管理后台一做就是大半年,天天 CRUD

    • 看开源项目(react-hook-form ts 类型、hook 处理、状态管理、架构 Provider,keyPath)
    • 找一些不错的项目练手
    • 拿好的项目,学习完放在简历里, 可视化、编辑器、云表格、低代码、SaaS 产品、数字孪生、三维可视化
    • 1.自研:15K, 2.外包:20K ,这个火坑, 灰(供需决定)
  • 技术栈掌握不深不广,只会用 Vue2 (Vue3 + Typescript),React18(React stack reconciler)

  • 架构、方案设计没碰过

    • React,create-react-app、umi,没有真正从零到一去设计初始化过一个项目
    • Vue,Vue CLI,Vite/Webpack。Vue2 CLI 创出来项目 1. webpack、2.vite
  • 没有专精的技能或业务

    • 自驱 (假定自己是 Leader),项目的赢利点、商业价值【 可视化、编辑器、白板、团队基建、AI产品
    • 与生俱来有些东西,好奇心、自驱力、清晰规划
    • 我:管理平台,HPE(官网、后台管理),云表格(维格表、飞书云表格)、云编辑器(CKEditor 老【html string】)(语雀、【石墨文档】)

妙码学院——全程陪跑、督学、真·企业级全栈项目、内推

⚠️ 暂不支持的文档区域,【文档小组件】

  • 跨端开发 Taro(Taro 编译器 compiler、运行时 runtime)、uniapp
  • 协同编辑器(文档类、画板类)
  • 团队基建工程(UI 库、图表库、Cli -> 产生产物 npm 包)
  • 3D 可视化数字孪生 bigdata
  • 低代码平台

课程体系 2.0 升级,除了基础知识夯实,融入了更多项目实战内容,包含:

  • 企业级脚手架工具开发实践

  • 企业级文档编辑器飞书文档开发实践

  • 大厂 UI 组件库(Vue3)整体设计与开发实践

  • 大厂业务 Hooks 库(React 18)整体设计与开发实践

  • 埋点与数据监控平台实战

  • 3D 可视化数字孪生实战 💥

    • 基于 cesium 方案的 WebGIS 开发实践
    • 基于 WebGL 3D 可视化开发实践

妙码学院全网独家项目实战矩阵

所有项目实战,均完全 从零到一手写纯原创 ,项目架构与编码规范真一线大厂级。

  • 微前端在分拆原子应用场景下的落地与实践

  • 类飞书文档协同编辑器从零到一架构实现

  • 推动团队基建落地

    • React UI 库
    • Vue Composition API 库
    • 企业级脚手架
  • 数字孪生平台整体架构设计

  • 企业级无代码可视化平台实践(Vue3)

  • 低代码平台设计与实现

    • 编排引擎
    • 流程引擎
    • 编辑器
    • 代码执行器与 JavaScript 沙箱
  • 用户行为分析 SDK 及监控可视化平台架构设计与实现

  • 可视化渲染引擎设计与实现

  • 基于 RAG / Agent 前端 AI 应用流程编排平台

前端阶段性能力与冲刺目标

以下是对您提供的内容进行权威和专业化改写的建议:

1~3 年

在此阶段,重点在于评估个人的基础知识和热情。对前端基础、计算机原理、网络通信和算法等领域的要求较高。由于在此阶段难以评估业务深度,因此更多关注基础知识的掌握程度。

  • 关键在于通过学术教育或网络资源加强基础知识;
  • 在简历中以多种方式展示对前端的热情,展现个人潜力;
  • 积极探索前沿技术,关注国内外技术动态;
  • 尝试开发小型项目或参与社区开源项目;
  • 建立技术博客,以输出促进知识吸收。

3~5 年

此阶段通常是向成为独立工程师发展的关键时期,避免重复使用有限的经验。

  • 关注社区中关于进阶的资料和路线,强化基础知识;

  • 深入掌握常用框架的高级用法,探索其原理;

  • 在业务开发中不仅完成功能,还需考虑项目结构设计、封装基础工具、设计和开发基础组件;

  • 思考提高团队效率的方法,例如:

    • 集成代码检验和风格统一插件(如 eslint、stylelint、prettier、spellcheck);
    • 从工程化角度提高本地开发效率,优化webpack构建,探索esbuild、vite等工具;
    • 对于多项目开发,整理差异和统一部分,建立内部脚手架以减少重复工作;
    • 尝试搭建CI/CD平台,维护公司内部的通用npm包;
    • 培养软技能,如沟通协作,协调各角色共同推进目标。

5年+

进入此阶段,可能朝技术专家或管理方向发展。期望您能够独立负责高复杂度项目,突破关键技术难题。

  • 负责技术调研,关注行业趋势,选择最优技术方案,具备决策能力;
  • 拥有丰富的技术经验和技术储备,能够解决遇到的困难,并有自己的方法论;
  • 协助或主导业务目标制定,合理推动项目达成预期效果;
  • 是否具有团队领导经验,能够协调跨团队项目,处理团队成员情绪问题,解决技能分布不平衡等问题;
  • 打造技术氛围,促进团队共同成长。

【未知组件reminder】