1886 lines
45 KiB
Markdown
1886 lines
45 KiB
Markdown
|
|
# 解班客后端架构文档
|
|||
|
|
|
|||
|
|
## 1. 后端架构概述
|
|||
|
|
|
|||
|
|
### 1.1 架构目标
|
|||
|
|
- **高性能**:支持高并发访问和快速响应
|
|||
|
|
- **高可用**:99.9%以上的服务可用性
|
|||
|
|
- **可扩展**:支持业务快速发展和功能扩展
|
|||
|
|
- **安全性**:全方位的安全防护机制
|
|||
|
|
- **可维护**:清晰的代码结构和完善的文档
|
|||
|
|
|
|||
|
|
### 1.2 技术选型
|
|||
|
|
| 技术栈 | 版本 | 选型理由 |
|
|||
|
|
|--------|------|----------|
|
|||
|
|
| Node.js | 18+ LTS | 高性能、生态丰富、开发效率高 |
|
|||
|
|
| Express.js | 4.x | 成熟的Web框架,中间件丰富 |
|
|||
|
|
| TypeScript | 5.x | 类型安全,提高代码质量 |
|
|||
|
|
| MySQL | 8.0+ | 成熟稳定的关系型数据库 |
|
|||
|
|
| Redis | 7.x | 高性能缓存和会话存储 |
|
|||
|
|
| MongoDB | 6.x | 灵活的文档型数据库 |
|
|||
|
|
| RabbitMQ | 3.11+ | 可靠的消息队列 |
|
|||
|
|
| Elasticsearch | 8.x | 强大的搜索和分析引擎 |
|
|||
|
|
|
|||
|
|
### 1.3 架构原则
|
|||
|
|
- **单一职责**:每个服务专注于特定的业务领域
|
|||
|
|
- **松耦合**:服务间通过标准接口通信
|
|||
|
|
- **高内聚**:相关功能聚合在同一服务内
|
|||
|
|
- **无状态**:服务设计为无状态,支持水平扩展
|
|||
|
|
- **容错性**:具备故障隔离和自动恢复能力
|
|||
|
|
|
|||
|
|
## 2. 系统架构设计
|
|||
|
|
|
|||
|
|
### 2.1 整体架构图
|
|||
|
|
```mermaid
|
|||
|
|
graph TB
|
|||
|
|
subgraph "客户端"
|
|||
|
|
A1[微信小程序]
|
|||
|
|
A2[管理后台]
|
|||
|
|
A3[官方网站]
|
|||
|
|
end
|
|||
|
|
|
|||
|
|
subgraph "网关层"
|
|||
|
|
B1[API Gateway]
|
|||
|
|
B2[Load Balancer]
|
|||
|
|
end
|
|||
|
|
|
|||
|
|
subgraph "业务服务层"
|
|||
|
|
C1[用户服务<br/>User Service]
|
|||
|
|
C2[活动服务<br/>Activity Service]
|
|||
|
|
C3[认领服务<br/>Adoption Service]
|
|||
|
|
C4[支付服务<br/>Payment Service]
|
|||
|
|
C5[消息服务<br/>Message Service]
|
|||
|
|
C6[文件服务<br/>File Service]
|
|||
|
|
C7[管理服务<br/>Admin Service]
|
|||
|
|
C8[通知服务<br/>Notification Service]
|
|||
|
|
end
|
|||
|
|
|
|||
|
|
subgraph "数据层"
|
|||
|
|
D1[MySQL<br/>主数据库]
|
|||
|
|
D2[MySQL<br/>从数据库]
|
|||
|
|
D3[Redis<br/>缓存集群]
|
|||
|
|
D4[MongoDB<br/>文档数据库]
|
|||
|
|
D5[Elasticsearch<br/>搜索引擎]
|
|||
|
|
end
|
|||
|
|
|
|||
|
|
subgraph "消息队列"
|
|||
|
|
E1[RabbitMQ<br/>消息队列]
|
|||
|
|
end
|
|||
|
|
|
|||
|
|
subgraph "第三方服务"
|
|||
|
|
F1[微信API]
|
|||
|
|
F2[支付接口]
|
|||
|
|
F3[短信服务]
|
|||
|
|
F4[对象存储]
|
|||
|
|
end
|
|||
|
|
|
|||
|
|
A1 --> B1
|
|||
|
|
A2 --> B1
|
|||
|
|
A3 --> B1
|
|||
|
|
|
|||
|
|
B1 --> B2
|
|||
|
|
B2 --> C1
|
|||
|
|
B2 --> C2
|
|||
|
|
B2 --> C3
|
|||
|
|
B2 --> C4
|
|||
|
|
B2 --> C5
|
|||
|
|
B2 --> C6
|
|||
|
|
B2 --> C7
|
|||
|
|
B2 --> C8
|
|||
|
|
|
|||
|
|
C1 --> D1
|
|||
|
|
C2 --> D1
|
|||
|
|
C3 --> D1
|
|||
|
|
C4 --> D1
|
|||
|
|
C7 --> D1
|
|||
|
|
|
|||
|
|
C1 --> D2
|
|||
|
|
C2 --> D2
|
|||
|
|
C3 --> D2
|
|||
|
|
C4 --> D2
|
|||
|
|
C7 --> D2
|
|||
|
|
|
|||
|
|
C1 --> D3
|
|||
|
|
C2 --> D3
|
|||
|
|
C3 --> D3
|
|||
|
|
C4 --> D3
|
|||
|
|
C5 --> D3
|
|||
|
|
C8 --> D3
|
|||
|
|
|
|||
|
|
C6 --> D4
|
|||
|
|
C2 --> D5
|
|||
|
|
C3 --> D5
|
|||
|
|
|
|||
|
|
C2 --> E1
|
|||
|
|
C3 --> E1
|
|||
|
|
C4 --> E1
|
|||
|
|
C5 --> E1
|
|||
|
|
C8 --> E1
|
|||
|
|
|
|||
|
|
C1 --> F1
|
|||
|
|
C4 --> F2
|
|||
|
|
C8 --> F3
|
|||
|
|
C6 --> F4
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 2.2 服务分层架构
|
|||
|
|
```mermaid
|
|||
|
|
graph TB
|
|||
|
|
subgraph "表现层 Presentation Layer"
|
|||
|
|
A1[REST API]
|
|||
|
|
A2[GraphQL API]
|
|||
|
|
A3[WebSocket API]
|
|||
|
|
end
|
|||
|
|
|
|||
|
|
subgraph "业务逻辑层 Business Logic Layer"
|
|||
|
|
B1[用户业务逻辑]
|
|||
|
|
B2[活动业务逻辑]
|
|||
|
|
B3[认领业务逻辑]
|
|||
|
|
B4[支付业务逻辑]
|
|||
|
|
B5[消息业务逻辑]
|
|||
|
|
end
|
|||
|
|
|
|||
|
|
subgraph "服务层 Service Layer"
|
|||
|
|
C1[用户服务]
|
|||
|
|
C2[活动服务]
|
|||
|
|
C3[认领服务]
|
|||
|
|
C4[支付服务]
|
|||
|
|
C5[消息服务]
|
|||
|
|
C6[通知服务]
|
|||
|
|
end
|
|||
|
|
|
|||
|
|
subgraph "数据访问层 Data Access Layer"
|
|||
|
|
D1[MySQL DAO]
|
|||
|
|
D2[Redis DAO]
|
|||
|
|
D3[MongoDB DAO]
|
|||
|
|
D4[ES DAO]
|
|||
|
|
end
|
|||
|
|
|
|||
|
|
subgraph "数据存储层 Data Storage Layer"
|
|||
|
|
E1[MySQL数据库]
|
|||
|
|
E2[Redis缓存]
|
|||
|
|
E3[MongoDB文档库]
|
|||
|
|
E4[Elasticsearch]
|
|||
|
|
end
|
|||
|
|
|
|||
|
|
A1 --> B1
|
|||
|
|
A1 --> B2
|
|||
|
|
A1 --> B3
|
|||
|
|
A1 --> B4
|
|||
|
|
A1 --> B5
|
|||
|
|
|
|||
|
|
B1 --> C1
|
|||
|
|
B2 --> C2
|
|||
|
|
B3 --> C3
|
|||
|
|
B4 --> C4
|
|||
|
|
B5 --> C5
|
|||
|
|
|
|||
|
|
C1 --> D1
|
|||
|
|
C2 --> D1
|
|||
|
|
C3 --> D1
|
|||
|
|
C4 --> D1
|
|||
|
|
C5 --> D2
|
|||
|
|
C6 --> D3
|
|||
|
|
|
|||
|
|
D1 --> E1
|
|||
|
|
D2 --> E2
|
|||
|
|
D3 --> E3
|
|||
|
|
D4 --> E4
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 3. 核心服务设计
|
|||
|
|
|
|||
|
|
### 3.1 用户服务 (User Service)
|
|||
|
|
|
|||
|
|
#### 3.1.1 服务职责
|
|||
|
|
- 用户注册、登录、认证
|
|||
|
|
- 用户资料管理
|
|||
|
|
- 权限验证和授权
|
|||
|
|
- 用户关系管理(关注、粉丝)
|
|||
|
|
- 用户行为记录
|
|||
|
|
|
|||
|
|
#### 3.1.2 核心模块
|
|||
|
|
```mermaid
|
|||
|
|
graph TB
|
|||
|
|
A[用户服务] --> B[认证模块]
|
|||
|
|
A --> C[用户管理模块]
|
|||
|
|
A --> D[权限模块]
|
|||
|
|
A --> E[关系模块]
|
|||
|
|
A --> F[行为记录模块]
|
|||
|
|
|
|||
|
|
B --> B1[微信登录]
|
|||
|
|
B --> B2[JWT Token]
|
|||
|
|
B --> B3[刷新Token]
|
|||
|
|
|
|||
|
|
C --> C1[用户注册]
|
|||
|
|
C --> C2[资料管理]
|
|||
|
|
C --> C3[实名认证]
|
|||
|
|
|
|||
|
|
D --> D1[角色管理]
|
|||
|
|
D --> D2[权限验证]
|
|||
|
|
D --> D3[资源控制]
|
|||
|
|
|
|||
|
|
E --> E1[关注关系]
|
|||
|
|
E --> E2[好友推荐]
|
|||
|
|
E --> E3[社交图谱]
|
|||
|
|
|
|||
|
|
F --> F1[登录记录]
|
|||
|
|
F --> F2[操作日志]
|
|||
|
|
F --> F3[行为分析]
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
#### 3.1.3 数据模型
|
|||
|
|
```sql
|
|||
|
|
-- 用户基本信息表
|
|||
|
|
CREATE TABLE users (
|
|||
|
|
id BIGINT PRIMARY KEY AUTO_INCREMENT,
|
|||
|
|
openid VARCHAR(64) UNIQUE NOT NULL,
|
|||
|
|
unionid VARCHAR(64),
|
|||
|
|
phone VARCHAR(20),
|
|||
|
|
nickname VARCHAR(50),
|
|||
|
|
avatar VARCHAR(255),
|
|||
|
|
gender TINYINT DEFAULT 0,
|
|||
|
|
birthday DATE,
|
|||
|
|
city VARCHAR(50),
|
|||
|
|
bio TEXT,
|
|||
|
|
status TINYINT DEFAULT 1,
|
|||
|
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|||
|
|
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
|||
|
|
INDEX idx_openid (openid),
|
|||
|
|
INDEX idx_phone (phone),
|
|||
|
|
INDEX idx_status (status)
|
|||
|
|
);
|
|||
|
|
|
|||
|
|
-- 用户认证信息表
|
|||
|
|
CREATE TABLE user_auths (
|
|||
|
|
id BIGINT PRIMARY KEY AUTO_INCREMENT,
|
|||
|
|
user_id BIGINT NOT NULL,
|
|||
|
|
real_name VARCHAR(50),
|
|||
|
|
id_card VARCHAR(18),
|
|||
|
|
auth_status TINYINT DEFAULT 0,
|
|||
|
|
auth_time TIMESTAMP NULL,
|
|||
|
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|||
|
|
FOREIGN KEY (user_id) REFERENCES users(id),
|
|||
|
|
INDEX idx_user_id (user_id),
|
|||
|
|
INDEX idx_auth_status (auth_status)
|
|||
|
|
);
|
|||
|
|
|
|||
|
|
-- 用户关系表
|
|||
|
|
CREATE TABLE user_relations (
|
|||
|
|
id BIGINT PRIMARY KEY AUTO_INCREMENT,
|
|||
|
|
follower_id BIGINT NOT NULL,
|
|||
|
|
following_id BIGINT NOT NULL,
|
|||
|
|
status TINYINT DEFAULT 1,
|
|||
|
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|||
|
|
FOREIGN KEY (follower_id) REFERENCES users(id),
|
|||
|
|
FOREIGN KEY (following_id) REFERENCES users(id),
|
|||
|
|
UNIQUE KEY uk_relation (follower_id, following_id),
|
|||
|
|
INDEX idx_follower (follower_id),
|
|||
|
|
INDEX idx_following (following_id)
|
|||
|
|
);
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 3.2 活动服务 (Activity Service)
|
|||
|
|
|
|||
|
|
#### 3.2.1 服务职责
|
|||
|
|
- 活动发布和管理
|
|||
|
|
- 活动报名和参与
|
|||
|
|
- 活动搜索和推荐
|
|||
|
|
- 活动评价和反馈
|
|||
|
|
- 活动统计分析
|
|||
|
|
|
|||
|
|
#### 3.2.2 核心模块
|
|||
|
|
```mermaid
|
|||
|
|
graph TB
|
|||
|
|
A[活动服务] --> B[活动管理模块]
|
|||
|
|
A --> C[报名管理模块]
|
|||
|
|
A --> D[搜索推荐模块]
|
|||
|
|
A --> E[评价模块]
|
|||
|
|
A --> F[统计模块]
|
|||
|
|
|
|||
|
|
B --> B1[活动发布]
|
|||
|
|
B --> B2[活动编辑]
|
|||
|
|
B --> B3[活动状态管理]
|
|||
|
|
|
|||
|
|
C --> C1[报名申请]
|
|||
|
|
C --> C2[报名审核]
|
|||
|
|
C --> C3[参与者管理]
|
|||
|
|
|
|||
|
|
D --> D1[活动搜索]
|
|||
|
|
D --> D2[个性化推荐]
|
|||
|
|
D --> D3[热门活动]
|
|||
|
|
|
|||
|
|
E --> E1[活动评价]
|
|||
|
|
E --> E2[用户反馈]
|
|||
|
|
E --> E3[评分统计]
|
|||
|
|
|
|||
|
|
F --> F1[活动数据统计]
|
|||
|
|
F --> F2[用户行为分析]
|
|||
|
|
F --> F3[运营报表]
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
#### 3.2.3 数据模型
|
|||
|
|
```sql
|
|||
|
|
-- 活动信息表
|
|||
|
|
CREATE TABLE activities (
|
|||
|
|
id BIGINT PRIMARY KEY AUTO_INCREMENT,
|
|||
|
|
creator_id BIGINT NOT NULL,
|
|||
|
|
title VARCHAR(100) NOT NULL,
|
|||
|
|
description TEXT,
|
|||
|
|
category_id INT,
|
|||
|
|
start_time TIMESTAMP NOT NULL,
|
|||
|
|
end_time TIMESTAMP NOT NULL,
|
|||
|
|
location VARCHAR(255),
|
|||
|
|
latitude DECIMAL(10,8),
|
|||
|
|
longitude DECIMAL(11,8),
|
|||
|
|
max_participants INT DEFAULT 0,
|
|||
|
|
current_participants INT DEFAULT 0,
|
|||
|
|
fee_type TINYINT DEFAULT 0, -- 0:免费 1:AA制 2:付费
|
|||
|
|
fee_amount DECIMAL(10,2) DEFAULT 0,
|
|||
|
|
status TINYINT DEFAULT 1,
|
|||
|
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|||
|
|
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
|||
|
|
FOREIGN KEY (creator_id) REFERENCES users(id),
|
|||
|
|
INDEX idx_creator (creator_id),
|
|||
|
|
INDEX idx_category (category_id),
|
|||
|
|
INDEX idx_start_time (start_time),
|
|||
|
|
INDEX idx_location (latitude, longitude),
|
|||
|
|
INDEX idx_status (status)
|
|||
|
|
);
|
|||
|
|
|
|||
|
|
-- 活动报名表
|
|||
|
|
CREATE TABLE activity_participants (
|
|||
|
|
id BIGINT PRIMARY KEY AUTO_INCREMENT,
|
|||
|
|
activity_id BIGINT NOT NULL,
|
|||
|
|
user_id BIGINT NOT NULL,
|
|||
|
|
status TINYINT DEFAULT 0, -- 0:待审核 1:已通过 2:已拒绝 3:已取消
|
|||
|
|
apply_message TEXT,
|
|||
|
|
apply_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|||
|
|
review_time TIMESTAMP NULL,
|
|||
|
|
FOREIGN KEY (activity_id) REFERENCES activities(id),
|
|||
|
|
FOREIGN KEY (user_id) REFERENCES users(id),
|
|||
|
|
UNIQUE KEY uk_participant (activity_id, user_id),
|
|||
|
|
INDEX idx_activity (activity_id),
|
|||
|
|
INDEX idx_user (user_id),
|
|||
|
|
INDEX idx_status (status)
|
|||
|
|
);
|
|||
|
|
|
|||
|
|
-- 活动评价表
|
|||
|
|
CREATE TABLE activity_reviews (
|
|||
|
|
id BIGINT PRIMARY KEY AUTO_INCREMENT,
|
|||
|
|
activity_id BIGINT NOT NULL,
|
|||
|
|
user_id BIGINT NOT NULL,
|
|||
|
|
rating TINYINT NOT NULL,
|
|||
|
|
comment TEXT,
|
|||
|
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|||
|
|
FOREIGN KEY (activity_id) REFERENCES activities(id),
|
|||
|
|
FOREIGN KEY (user_id) REFERENCES users(id),
|
|||
|
|
UNIQUE KEY uk_review (activity_id, user_id),
|
|||
|
|
INDEX idx_activity (activity_id),
|
|||
|
|
INDEX idx_rating (rating)
|
|||
|
|
);
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 3.3 认领服务 (Adoption Service)
|
|||
|
|
|
|||
|
|
#### 3.3.1 服务职责
|
|||
|
|
- 动物信息管理
|
|||
|
|
- 认领申请处理
|
|||
|
|
- 认领关系维护
|
|||
|
|
- 探访预约管理
|
|||
|
|
- 成长记录管理
|
|||
|
|
|
|||
|
|
#### 3.3.2 核心模块
|
|||
|
|
```mermaid
|
|||
|
|
graph TB
|
|||
|
|
A[认领服务] --> B[动物管理模块]
|
|||
|
|
A --> C[认领管理模块]
|
|||
|
|
A --> D[探访管理模块]
|
|||
|
|
A --> E[成长记录模块]
|
|||
|
|
A --> F[农场管理模块]
|
|||
|
|
|
|||
|
|
B --> B1[动物信息]
|
|||
|
|
B --> B2[动物分类]
|
|||
|
|
B --> B3[动物状态]
|
|||
|
|
|
|||
|
|
C --> C1[认领申请]
|
|||
|
|
C --> C2[认领审核]
|
|||
|
|
C --> C3[认领关系]
|
|||
|
|
|
|||
|
|
D --> D1[探访预约]
|
|||
|
|
D --> D2[探访记录]
|
|||
|
|
D --> D3[探访路线]
|
|||
|
|
|
|||
|
|
E --> E1[成长日记]
|
|||
|
|
E --> E2[照片记录]
|
|||
|
|
E --> E3[健康档案]
|
|||
|
|
|
|||
|
|
F --> F1[农场信息]
|
|||
|
|
F --> F2[农场服务]
|
|||
|
|
F --> F3[农产品]
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
#### 3.3.3 数据模型
|
|||
|
|
```sql
|
|||
|
|
-- 农场信息表
|
|||
|
|
CREATE TABLE farms (
|
|||
|
|
id BIGINT PRIMARY KEY AUTO_INCREMENT,
|
|||
|
|
name VARCHAR(100) NOT NULL,
|
|||
|
|
description TEXT,
|
|||
|
|
address VARCHAR(255),
|
|||
|
|
latitude DECIMAL(10,8),
|
|||
|
|
longitude DECIMAL(11,8),
|
|||
|
|
contact_phone VARCHAR(20),
|
|||
|
|
contact_person VARCHAR(50),
|
|||
|
|
images JSON,
|
|||
|
|
status TINYINT DEFAULT 1,
|
|||
|
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|||
|
|
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
|||
|
|
INDEX idx_status (status),
|
|||
|
|
INDEX idx_location (latitude, longitude)
|
|||
|
|
);
|
|||
|
|
|
|||
|
|
-- 动物信息表
|
|||
|
|
CREATE TABLE animals (
|
|||
|
|
id BIGINT PRIMARY KEY AUTO_INCREMENT,
|
|||
|
|
farm_id BIGINT NOT NULL,
|
|||
|
|
name VARCHAR(50),
|
|||
|
|
species VARCHAR(50) NOT NULL,
|
|||
|
|
breed VARCHAR(50),
|
|||
|
|
gender TINYINT,
|
|||
|
|
birth_date DATE,
|
|||
|
|
description TEXT,
|
|||
|
|
images JSON,
|
|||
|
|
adoption_fee DECIMAL(10,2),
|
|||
|
|
adoption_period INT, -- 认领周期(月)
|
|||
|
|
status TINYINT DEFAULT 1, -- 1:可认领 2:已认领 3:不可认领
|
|||
|
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|||
|
|
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
|||
|
|
FOREIGN KEY (farm_id) REFERENCES farms(id),
|
|||
|
|
INDEX idx_farm (farm_id),
|
|||
|
|
INDEX idx_species (species),
|
|||
|
|
INDEX idx_status (status)
|
|||
|
|
);
|
|||
|
|
|
|||
|
|
-- 认领关系表
|
|||
|
|
CREATE TABLE adoptions (
|
|||
|
|
id BIGINT PRIMARY KEY AUTO_INCREMENT,
|
|||
|
|
animal_id BIGINT NOT NULL,
|
|||
|
|
user_id BIGINT NOT NULL,
|
|||
|
|
adoption_name VARCHAR(50), -- 用户给动物起的名字
|
|||
|
|
start_date DATE NOT NULL,
|
|||
|
|
end_date DATE NOT NULL,
|
|||
|
|
total_fee DECIMAL(10,2),
|
|||
|
|
status TINYINT DEFAULT 1, -- 1:认领中 2:已到期 3:已取消
|
|||
|
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|||
|
|
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
|||
|
|
FOREIGN KEY (animal_id) REFERENCES animals(id),
|
|||
|
|
FOREIGN KEY (user_id) REFERENCES users(id),
|
|||
|
|
INDEX idx_animal (animal_id),
|
|||
|
|
INDEX idx_user (user_id),
|
|||
|
|
INDEX idx_status (status),
|
|||
|
|
INDEX idx_date_range (start_date, end_date)
|
|||
|
|
);
|
|||
|
|
|
|||
|
|
-- 探访记录表
|
|||
|
|
CREATE TABLE visits (
|
|||
|
|
id BIGINT PRIMARY KEY AUTO_INCREMENT,
|
|||
|
|
adoption_id BIGINT NOT NULL,
|
|||
|
|
visit_date DATE NOT NULL,
|
|||
|
|
visit_time TIME,
|
|||
|
|
visitor_count INT DEFAULT 1,
|
|||
|
|
notes TEXT,
|
|||
|
|
photos JSON,
|
|||
|
|
status TINYINT DEFAULT 1, -- 1:已预约 2:已完成 3:已取消
|
|||
|
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|||
|
|
FOREIGN KEY (adoption_id) REFERENCES adoptions(id),
|
|||
|
|
INDEX idx_adoption (adoption_id),
|
|||
|
|
INDEX idx_visit_date (visit_date),
|
|||
|
|
INDEX idx_status (status)
|
|||
|
|
);
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 3.4 支付服务 (Payment Service)
|
|||
|
|
|
|||
|
|
#### 3.4.1 服务职责
|
|||
|
|
- 支付订单管理
|
|||
|
|
- 支付流程处理
|
|||
|
|
- 退款处理
|
|||
|
|
- 账户余额管理
|
|||
|
|
- 交易记录查询
|
|||
|
|
|
|||
|
|
#### 3.4.2 核心模块
|
|||
|
|
```mermaid
|
|||
|
|
graph TB
|
|||
|
|
A[支付服务] --> B[订单管理模块]
|
|||
|
|
A --> C[支付处理模块]
|
|||
|
|
A --> D[退款模块]
|
|||
|
|
A --> E[账户模块]
|
|||
|
|
A --> F[对账模块]
|
|||
|
|
|
|||
|
|
B --> B1[订单创建]
|
|||
|
|
B --> B2[订单查询]
|
|||
|
|
B --> B3[订单状态管理]
|
|||
|
|
|
|||
|
|
C --> C1[微信支付]
|
|||
|
|
C --> C2[支付宝支付]
|
|||
|
|
C --> C3[余额支付]
|
|||
|
|
|
|||
|
|
D --> D1[退款申请]
|
|||
|
|
D --> D2[退款处理]
|
|||
|
|
D --> D3[退款查询]
|
|||
|
|
|
|||
|
|
E --> E1[余额管理]
|
|||
|
|
E --> E2[充值提现]
|
|||
|
|
E --> E3[交易记录]
|
|||
|
|
|
|||
|
|
F --> F1[支付对账]
|
|||
|
|
F --> F2[财务报表]
|
|||
|
|
F --> F3[异常处理]
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
#### 3.4.3 数据模型
|
|||
|
|
```sql
|
|||
|
|
-- 支付订单表
|
|||
|
|
CREATE TABLE payment_orders (
|
|||
|
|
id BIGINT PRIMARY KEY AUTO_INCREMENT,
|
|||
|
|
order_no VARCHAR(32) UNIQUE NOT NULL,
|
|||
|
|
user_id BIGINT NOT NULL,
|
|||
|
|
business_type TINYINT NOT NULL, -- 1:活动支付 2:认领支付 3:商品支付
|
|||
|
|
business_id BIGINT NOT NULL,
|
|||
|
|
amount DECIMAL(10,2) NOT NULL,
|
|||
|
|
currency VARCHAR(3) DEFAULT 'CNY',
|
|||
|
|
payment_method TINYINT, -- 1:微信 2:支付宝 3:余额
|
|||
|
|
payment_channel VARCHAR(20),
|
|||
|
|
status TINYINT DEFAULT 0, -- 0:待支付 1:支付中 2:支付成功 3:支付失败 4:已取消
|
|||
|
|
paid_at TIMESTAMP NULL,
|
|||
|
|
expired_at TIMESTAMP NOT NULL,
|
|||
|
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|||
|
|
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
|||
|
|
FOREIGN KEY (user_id) REFERENCES users(id),
|
|||
|
|
INDEX idx_order_no (order_no),
|
|||
|
|
INDEX idx_user (user_id),
|
|||
|
|
INDEX idx_business (business_type, business_id),
|
|||
|
|
INDEX idx_status (status),
|
|||
|
|
INDEX idx_created_at (created_at)
|
|||
|
|
);
|
|||
|
|
|
|||
|
|
-- 支付记录表
|
|||
|
|
CREATE TABLE payment_records (
|
|||
|
|
id BIGINT PRIMARY KEY AUTO_INCREMENT,
|
|||
|
|
order_id BIGINT NOT NULL,
|
|||
|
|
transaction_id VARCHAR(64),
|
|||
|
|
payment_method TINYINT NOT NULL,
|
|||
|
|
amount DECIMAL(10,2) NOT NULL,
|
|||
|
|
status TINYINT DEFAULT 0, -- 0:处理中 1:成功 2:失败
|
|||
|
|
response_data JSON,
|
|||
|
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|||
|
|
FOREIGN KEY (order_id) REFERENCES payment_orders(id),
|
|||
|
|
INDEX idx_order (order_id),
|
|||
|
|
INDEX idx_transaction (transaction_id),
|
|||
|
|
INDEX idx_status (status)
|
|||
|
|
);
|
|||
|
|
|
|||
|
|
-- 用户账户表
|
|||
|
|
CREATE TABLE user_accounts (
|
|||
|
|
id BIGINT PRIMARY KEY AUTO_INCREMENT,
|
|||
|
|
user_id BIGINT UNIQUE NOT NULL,
|
|||
|
|
balance DECIMAL(10,2) DEFAULT 0.00,
|
|||
|
|
frozen_balance DECIMAL(10,2) DEFAULT 0.00,
|
|||
|
|
total_income DECIMAL(10,2) DEFAULT 0.00,
|
|||
|
|
total_expense DECIMAL(10,2) DEFAULT 0.00,
|
|||
|
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|||
|
|
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
|||
|
|
FOREIGN KEY (user_id) REFERENCES users(id),
|
|||
|
|
INDEX idx_user (user_id)
|
|||
|
|
);
|
|||
|
|
|
|||
|
|
-- 账户流水表
|
|||
|
|
CREATE TABLE account_transactions (
|
|||
|
|
id BIGINT PRIMARY KEY AUTO_INCREMENT,
|
|||
|
|
user_id BIGINT NOT NULL,
|
|||
|
|
type TINYINT NOT NULL, -- 1:收入 2:支出 3:冻结 4:解冻
|
|||
|
|
amount DECIMAL(10,2) NOT NULL,
|
|||
|
|
balance_after DECIMAL(10,2) NOT NULL,
|
|||
|
|
business_type TINYINT,
|
|||
|
|
business_id BIGINT,
|
|||
|
|
description VARCHAR(255),
|
|||
|
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|||
|
|
FOREIGN KEY (user_id) REFERENCES users(id),
|
|||
|
|
INDEX idx_user (user_id),
|
|||
|
|
INDEX idx_type (type),
|
|||
|
|
INDEX idx_business (business_type, business_id),
|
|||
|
|
INDEX idx_created_at (created_at)
|
|||
|
|
);
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 3.5 消息服务 (Message Service)
|
|||
|
|
|
|||
|
|
#### 3.5.1 服务职责
|
|||
|
|
- 即时消息处理
|
|||
|
|
- 群聊管理
|
|||
|
|
- 消息存储和查询
|
|||
|
|
- 消息推送
|
|||
|
|
- 敏感词过滤
|
|||
|
|
|
|||
|
|
#### 3.5.2 核心模块
|
|||
|
|
```mermaid
|
|||
|
|
graph TB
|
|||
|
|
A[消息服务] --> B[即时消息模块]
|
|||
|
|
A --> C[群聊管理模块]
|
|||
|
|
A --> D[消息存储模块]
|
|||
|
|
A --> E[推送模块]
|
|||
|
|
A --> F[内容审核模块]
|
|||
|
|
|
|||
|
|
B --> B1[私聊消息]
|
|||
|
|
B --> B2[消息发送]
|
|||
|
|
B --> B3[消息接收]
|
|||
|
|
|
|||
|
|
C --> C1[群组创建]
|
|||
|
|
C --> C2[成员管理]
|
|||
|
|
C --> C3[群消息]
|
|||
|
|
|
|||
|
|
D --> D1[消息持久化]
|
|||
|
|
D --> D2[消息查询]
|
|||
|
|
D --> D3[消息同步]
|
|||
|
|
|
|||
|
|
E --> E1[实时推送]
|
|||
|
|
E --> E2[离线推送]
|
|||
|
|
E --> E3[推送统计]
|
|||
|
|
|
|||
|
|
F --> F1[敏感词检测]
|
|||
|
|
F --> F2[图片审核]
|
|||
|
|
F --> F3[内容过滤]
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 3.6 文件服务 (File Service)
|
|||
|
|
|
|||
|
|
#### 3.6.1 服务职责
|
|||
|
|
- 文件上传处理
|
|||
|
|
- 图片压缩和处理
|
|||
|
|
- 文件存储管理
|
|||
|
|
- CDN加速
|
|||
|
|
- 文件安全检查
|
|||
|
|
|
|||
|
|
#### 3.6.2 核心模块
|
|||
|
|
```mermaid
|
|||
|
|
graph TB
|
|||
|
|
A[文件服务] --> B[上传处理模块]
|
|||
|
|
A --> C[图片处理模块]
|
|||
|
|
A --> D[存储管理模块]
|
|||
|
|
A --> E[CDN模块]
|
|||
|
|
A --> F[安全检查模块]
|
|||
|
|
|
|||
|
|
B --> B1[文件上传]
|
|||
|
|
B --> B2[分片上传]
|
|||
|
|
B --> B3[断点续传]
|
|||
|
|
|
|||
|
|
C --> C1[图片压缩]
|
|||
|
|
C --> C2[格式转换]
|
|||
|
|
C --> C3[水印添加]
|
|||
|
|
|
|||
|
|
D --> D1[本地存储]
|
|||
|
|
D --> D2[云存储]
|
|||
|
|
D --> D3[存储策略]
|
|||
|
|
|
|||
|
|
E --> E1[CDN分发]
|
|||
|
|
E --> E2[缓存管理]
|
|||
|
|
E --> E3[访问优化]
|
|||
|
|
|
|||
|
|
F --> F1[病毒扫描]
|
|||
|
|
F --> F2[内容检测]
|
|||
|
|
F --> F3[访问控制]
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 4. 数据架构设计
|
|||
|
|
|
|||
|
|
### 4.1 数据库架构
|
|||
|
|
|
|||
|
|
#### 4.1.1 MySQL主从架构
|
|||
|
|
```mermaid
|
|||
|
|
graph TB
|
|||
|
|
A[应用服务] --> B[数据库代理]
|
|||
|
|
B --> C[MySQL主库]
|
|||
|
|
B --> D[MySQL从库1]
|
|||
|
|
B --> E[MySQL从库2]
|
|||
|
|
|
|||
|
|
C --> F[写操作]
|
|||
|
|
D --> G[读操作]
|
|||
|
|
E --> G
|
|||
|
|
|
|||
|
|
C --> H[主从同步]
|
|||
|
|
H --> D
|
|||
|
|
H --> E
|
|||
|
|
|
|||
|
|
I[备份服务] --> C
|
|||
|
|
I --> J[备份存储]
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
#### 4.1.2 数据分库分表策略
|
|||
|
|
```mermaid
|
|||
|
|
graph TB
|
|||
|
|
A[业务数据] --> B[用户相关数据]
|
|||
|
|
A --> C[活动相关数据]
|
|||
|
|
A --> D[认领相关数据]
|
|||
|
|
A --> E[支付相关数据]
|
|||
|
|
|
|||
|
|
B --> B1[用户库1<br/>user_id % 4 = 0]
|
|||
|
|
B --> B2[用户库2<br/>user_id % 4 = 1]
|
|||
|
|
B --> B3[用户库3<br/>user_id % 4 = 2]
|
|||
|
|
B --> B4[用户库4<br/>user_id % 4 = 3]
|
|||
|
|
|
|||
|
|
C --> C1[活动库1<br/>按时间分表]
|
|||
|
|
C --> C2[活动库2<br/>按时间分表]
|
|||
|
|
|
|||
|
|
D --> D1[认领库1<br/>按农场分表]
|
|||
|
|
D --> D2[认领库2<br/>按农场分表]
|
|||
|
|
|
|||
|
|
E --> E1[支付库1<br/>按时间分表]
|
|||
|
|
E --> E2[支付库2<br/>按时间分表]
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 4.2 缓存架构
|
|||
|
|
|
|||
|
|
#### 4.2.1 Redis集群架构
|
|||
|
|
```mermaid
|
|||
|
|
graph TB
|
|||
|
|
A[应用服务] --> B[Redis代理]
|
|||
|
|
B --> C[Redis主节点1]
|
|||
|
|
B --> D[Redis主节点2]
|
|||
|
|
B --> E[Redis主节点3]
|
|||
|
|
|
|||
|
|
C --> F[Redis从节点1]
|
|||
|
|
D --> G[Redis从节点2]
|
|||
|
|
E --> H[Redis从节点3]
|
|||
|
|
|
|||
|
|
I[哨兵节点1] --> C
|
|||
|
|
I --> D
|
|||
|
|
I --> E
|
|||
|
|
|
|||
|
|
J[哨兵节点2] --> C
|
|||
|
|
J --> D
|
|||
|
|
J --> E
|
|||
|
|
|
|||
|
|
K[哨兵节点3] --> C
|
|||
|
|
K --> D
|
|||
|
|
K --> E
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
#### 4.2.2 缓存策略
|
|||
|
|
- **用户信息缓存**:用户基本信息,过期时间30分钟
|
|||
|
|
- **活动列表缓存**:热门活动列表,过期时间10分钟
|
|||
|
|
- **搜索结果缓存**:搜索结果,过期时间5分钟
|
|||
|
|
- **计数器缓存**:点赞数、评论数等,实时更新
|
|||
|
|
- **会话缓存**:用户登录状态,过期时间7天
|
|||
|
|
|
|||
|
|
### 4.3 搜索架构
|
|||
|
|
|
|||
|
|
#### 4.3.1 Elasticsearch集群
|
|||
|
|
```mermaid
|
|||
|
|
graph TB
|
|||
|
|
A[应用服务] --> B[ES负载均衡]
|
|||
|
|
B --> C[ES主节点1]
|
|||
|
|
B --> D[ES主节点2]
|
|||
|
|
B --> E[ES主节点3]
|
|||
|
|
|
|||
|
|
C --> F[ES数据节点1]
|
|||
|
|
C --> G[ES数据节点2]
|
|||
|
|
D --> H[ES数据节点3]
|
|||
|
|
D --> I[ES数据节点4]
|
|||
|
|
E --> J[ES数据节点5]
|
|||
|
|
E --> K[ES数据节点6]
|
|||
|
|
|
|||
|
|
L[数据同步服务] --> M[MySQL]
|
|||
|
|
L --> B
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
#### 4.3.2 索引设计
|
|||
|
|
```json
|
|||
|
|
{
|
|||
|
|
"activities": {
|
|||
|
|
"mappings": {
|
|||
|
|
"properties": {
|
|||
|
|
"id": {"type": "long"},
|
|||
|
|
"title": {
|
|||
|
|
"type": "text",
|
|||
|
|
"analyzer": "ik_max_word",
|
|||
|
|
"search_analyzer": "ik_smart"
|
|||
|
|
},
|
|||
|
|
"description": {
|
|||
|
|
"type": "text",
|
|||
|
|
"analyzer": "ik_max_word"
|
|||
|
|
},
|
|||
|
|
"category": {"type": "keyword"},
|
|||
|
|
"location": {"type": "geo_point"},
|
|||
|
|
"start_time": {"type": "date"},
|
|||
|
|
"creator_id": {"type": "long"},
|
|||
|
|
"status": {"type": "integer"},
|
|||
|
|
"tags": {"type": "keyword"}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 5. API设计规范
|
|||
|
|
|
|||
|
|
### 5.1 RESTful API设计
|
|||
|
|
|
|||
|
|
#### 5.1.1 URL设计规范
|
|||
|
|
```
|
|||
|
|
GET /api/v1/users # 获取用户列表
|
|||
|
|
GET /api/v1/users/{id} # 获取指定用户
|
|||
|
|
POST /api/v1/users # 创建用户
|
|||
|
|
PUT /api/v1/users/{id} # 更新用户
|
|||
|
|
DELETE /api/v1/users/{id} # 删除用户
|
|||
|
|
|
|||
|
|
GET /api/v1/activities # 获取活动列表
|
|||
|
|
POST /api/v1/activities # 创建活动
|
|||
|
|
GET /api/v1/activities/{id} # 获取活动详情
|
|||
|
|
PUT /api/v1/activities/{id} # 更新活动
|
|||
|
|
DELETE /api/v1/activities/{id} # 删除活动
|
|||
|
|
|
|||
|
|
POST /api/v1/activities/{id}/join # 参加活动
|
|||
|
|
DELETE /api/v1/activities/{id}/leave # 退出活动
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
#### 5.1.2 请求响应格式
|
|||
|
|
```json
|
|||
|
|
// 请求格式
|
|||
|
|
{
|
|||
|
|
"data": {
|
|||
|
|
"title": "周末爬山活动",
|
|||
|
|
"description": "一起去爬山,享受自然风光",
|
|||
|
|
"start_time": "2024-01-20T09:00:00Z",
|
|||
|
|
"location": "香山公园"
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 成功响应格式
|
|||
|
|
{
|
|||
|
|
"code": 200,
|
|||
|
|
"message": "success",
|
|||
|
|
"data": {
|
|||
|
|
"id": 12345,
|
|||
|
|
"title": "周末爬山活动",
|
|||
|
|
"description": "一起去爬山,享受自然风光",
|
|||
|
|
"start_time": "2024-01-20T09:00:00Z",
|
|||
|
|
"location": "香山公园",
|
|||
|
|
"created_at": "2024-01-15T10:30:00Z"
|
|||
|
|
},
|
|||
|
|
"timestamp": 1705312200
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 错误响应格式
|
|||
|
|
{
|
|||
|
|
"code": 400,
|
|||
|
|
"message": "参数错误",
|
|||
|
|
"error": {
|
|||
|
|
"field": "start_time",
|
|||
|
|
"reason": "开始时间不能早于当前时间"
|
|||
|
|
},
|
|||
|
|
"timestamp": 1705312200
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
#### 5.1.3 状态码规范
|
|||
|
|
| 状态码 | 说明 |
|
|||
|
|
|--------|------|
|
|||
|
|
| 200 | 请求成功 |
|
|||
|
|
| 201 | 创建成功 |
|
|||
|
|
| 400 | 请求参数错误 |
|
|||
|
|
| 401 | 未授权 |
|
|||
|
|
| 403 | 禁止访问 |
|
|||
|
|
| 404 | 资源不存在 |
|
|||
|
|
| 409 | 资源冲突 |
|
|||
|
|
| 422 | 参数验证失败 |
|
|||
|
|
| 500 | 服务器内部错误 |
|
|||
|
|
| 502 | 网关错误 |
|
|||
|
|
| 503 | 服务不可用 |
|
|||
|
|
|
|||
|
|
### 5.2 认证授权机制
|
|||
|
|
|
|||
|
|
#### 5.2.1 JWT Token设计
|
|||
|
|
```json
|
|||
|
|
// JWT Header
|
|||
|
|
{
|
|||
|
|
"alg": "HS256",
|
|||
|
|
"typ": "JWT"
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// JWT Payload
|
|||
|
|
{
|
|||
|
|
"user_id": 12345,
|
|||
|
|
"openid": "wx_openid_123",
|
|||
|
|
"role": "user",
|
|||
|
|
"permissions": ["activity:read", "activity:create"],
|
|||
|
|
"iat": 1705312200,
|
|||
|
|
"exp": 1705398600
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
#### 5.2.2 权限控制
|
|||
|
|
```typescript
|
|||
|
|
// 权限定义
|
|||
|
|
enum Permission {
|
|||
|
|
// 用户权限
|
|||
|
|
USER_READ = 'user:read',
|
|||
|
|
USER_WRITE = 'user:write',
|
|||
|
|
|
|||
|
|
// 活动权限
|
|||
|
|
ACTIVITY_READ = 'activity:read',
|
|||
|
|
ACTIVITY_WRITE = 'activity:write',
|
|||
|
|
ACTIVITY_DELETE = 'activity:delete',
|
|||
|
|
|
|||
|
|
// 认领权限
|
|||
|
|
ADOPTION_READ = 'adoption:read',
|
|||
|
|
ADOPTION_WRITE = 'adoption:write',
|
|||
|
|
|
|||
|
|
// 管理权限
|
|||
|
|
ADMIN_USER = 'admin:user',
|
|||
|
|
ADMIN_ACTIVITY = 'admin:activity',
|
|||
|
|
ADMIN_SYSTEM = 'admin:system'
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 角色权限映射
|
|||
|
|
const rolePermissions = {
|
|||
|
|
user: [
|
|||
|
|
Permission.USER_READ,
|
|||
|
|
Permission.ACTIVITY_READ,
|
|||
|
|
Permission.ACTIVITY_WRITE,
|
|||
|
|
Permission.ADOPTION_READ,
|
|||
|
|
Permission.ADOPTION_WRITE
|
|||
|
|
],
|
|||
|
|
admin: [
|
|||
|
|
...rolePermissions.user,
|
|||
|
|
Permission.ADMIN_USER,
|
|||
|
|
Permission.ADMIN_ACTIVITY,
|
|||
|
|
Permission.ADMIN_SYSTEM
|
|||
|
|
]
|
|||
|
|
};
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 6. 消息队列架构
|
|||
|
|
|
|||
|
|
### 6.1 RabbitMQ架构设计
|
|||
|
|
|
|||
|
|
#### 6.1.1 集群架构
|
|||
|
|
```mermaid
|
|||
|
|
graph TB
|
|||
|
|
A[生产者服务] --> B[RabbitMQ集群]
|
|||
|
|
|
|||
|
|
subgraph "RabbitMQ集群"
|
|||
|
|
C[节点1<br/>主节点]
|
|||
|
|
D[节点2<br/>从节点]
|
|||
|
|
E[节点3<br/>从节点]
|
|||
|
|
|
|||
|
|
C --> F[队列镜像]
|
|||
|
|
D --> F
|
|||
|
|
E --> F
|
|||
|
|
end
|
|||
|
|
|
|||
|
|
B --> G[消费者服务1]
|
|||
|
|
B --> H[消费者服务2]
|
|||
|
|
B --> I[消费者服务3]
|
|||
|
|
|
|||
|
|
J[HAProxy] --> C
|
|||
|
|
J --> D
|
|||
|
|
J --> E
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
#### 6.1.2 队列设计
|
|||
|
|
```typescript
|
|||
|
|
// 队列配置
|
|||
|
|
const queueConfig = {
|
|||
|
|
// 用户相关队列
|
|||
|
|
'user.register': {
|
|||
|
|
durable: true,
|
|||
|
|
exclusive: false,
|
|||
|
|
autoDelete: false,
|
|||
|
|
arguments: {
|
|||
|
|
'x-message-ttl': 300000, // 5分钟TTL
|
|||
|
|
'x-dead-letter-exchange': 'dlx.user'
|
|||
|
|
}
|
|||
|
|
},
|
|||
|
|
|
|||
|
|
// 活动相关队列
|
|||
|
|
'activity.created': {
|
|||
|
|
durable: true,
|
|||
|
|
exclusive: false,
|
|||
|
|
autoDelete: false,
|
|||
|
|
arguments: {
|
|||
|
|
'x-message-ttl': 600000, // 10分钟TTL
|
|||
|
|
'x-dead-letter-exchange': 'dlx.activity'
|
|||
|
|
}
|
|||
|
|
},
|
|||
|
|
|
|||
|
|
// 支付相关队列
|
|||
|
|
'payment.success': {
|
|||
|
|
durable: true,
|
|||
|
|
exclusive: false,
|
|||
|
|
autoDelete: false,
|
|||
|
|
arguments: {
|
|||
|
|
'x-message-ttl': 1800000, // 30分钟TTL
|
|||
|
|
'x-dead-letter-exchange': 'dlx.payment'
|
|||
|
|
}
|
|||
|
|
},
|
|||
|
|
|
|||
|
|
// 通知相关队列
|
|||
|
|
'notification.push': {
|
|||
|
|
durable: true,
|
|||
|
|
exclusive: false,
|
|||
|
|
autoDelete: false,
|
|||
|
|
arguments: {
|
|||
|
|
'x-message-ttl': 60000, // 1分钟TTL
|
|||
|
|
'x-dead-letter-exchange': 'dlx.notification'
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
};
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 6.2 消息处理模式
|
|||
|
|
|
|||
|
|
#### 6.2.1 发布订阅模式
|
|||
|
|
```typescript
|
|||
|
|
// 事件发布
|
|||
|
|
class EventPublisher {
|
|||
|
|
async publishUserRegistered(userId: number, userData: any) {
|
|||
|
|
const message = {
|
|||
|
|
eventType: 'user.registered',
|
|||
|
|
userId,
|
|||
|
|
userData,
|
|||
|
|
timestamp: Date.now()
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
await this.publish('user.events', message);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
async publishActivityCreated(activityId: number, activityData: any) {
|
|||
|
|
const message = {
|
|||
|
|
eventType: 'activity.created',
|
|||
|
|
activityId,
|
|||
|
|
activityData,
|
|||
|
|
timestamp: Date.now()
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
await this.publish('activity.events', message);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 事件消费
|
|||
|
|
class EventConsumer {
|
|||
|
|
async handleUserRegistered(message: any) {
|
|||
|
|
// 发送欢迎邮件
|
|||
|
|
await this.sendWelcomeEmail(message.userId);
|
|||
|
|
|
|||
|
|
// 初始化用户数据
|
|||
|
|
await this.initUserData(message.userId);
|
|||
|
|
|
|||
|
|
// 推送注册成功通知
|
|||
|
|
await this.pushRegistrationNotification(message.userId);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
async handleActivityCreated(message: any) {
|
|||
|
|
// 更新搜索索引
|
|||
|
|
await this.updateSearchIndex(message.activityId);
|
|||
|
|
|
|||
|
|
// 推荐给相关用户
|
|||
|
|
await this.recommendToUsers(message.activityId);
|
|||
|
|
|
|||
|
|
// 发送创建成功通知
|
|||
|
|
await this.pushCreationNotification(message.activityId);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 7. 监控和日志
|
|||
|
|
|
|||
|
|
### 7.1 监控架构
|
|||
|
|
|
|||
|
|
#### 7.1.1 监控体系
|
|||
|
|
```mermaid
|
|||
|
|
graph TB
|
|||
|
|
A[应用服务] --> B[Metrics收集]
|
|||
|
|
A --> C[日志收集]
|
|||
|
|
A --> D[链路追踪]
|
|||
|
|
|
|||
|
|
B --> E[Prometheus]
|
|||
|
|
C --> F[ELK Stack]
|
|||
|
|
D --> G[Jaeger]
|
|||
|
|
|
|||
|
|
E --> H[Grafana]
|
|||
|
|
F --> H
|
|||
|
|
G --> H
|
|||
|
|
|
|||
|
|
H --> I[告警系统]
|
|||
|
|
I --> J[短信告警]
|
|||
|
|
I --> K[邮件告警]
|
|||
|
|
I --> L[微信告警]
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
#### 7.1.2 关键指标监控
|
|||
|
|
```typescript
|
|||
|
|
// 业务指标
|
|||
|
|
const businessMetrics = {
|
|||
|
|
// 用户指标
|
|||
|
|
userRegistrations: 'counter', // 用户注册数
|
|||
|
|
activeUsers: 'gauge', // 活跃用户数
|
|||
|
|
userRetention: 'gauge', // 用户留存率
|
|||
|
|
|
|||
|
|
// 活动指标
|
|||
|
|
activitiesCreated: 'counter', // 活动创建数
|
|||
|
|
activitiesJoined: 'counter', // 活动参与数
|
|||
|
|
activityCompletionRate: 'gauge', // 活动完成率
|
|||
|
|
|
|||
|
|
// 认领指标
|
|||
|
|
adoptionsCreated: 'counter', // 认领创建数
|
|||
|
|
adoptionRevenue: 'counter', // 认领收入
|
|||
|
|
visitCount: 'counter', // 探访次数
|
|||
|
|
|
|||
|
|
// 支付指标
|
|||
|
|
paymentSuccess: 'counter', // 支付成功数
|
|||
|
|
paymentFailure: 'counter', // 支付失败数
|
|||
|
|
paymentAmount: 'counter' // 支付金额
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
// 技术指标
|
|||
|
|
const technicalMetrics = {
|
|||
|
|
// 性能指标
|
|||
|
|
responseTime: 'histogram', // 响应时间
|
|||
|
|
throughput: 'counter', // 吞吐量
|
|||
|
|
errorRate: 'gauge', // 错误率
|
|||
|
|
|
|||
|
|
// 系统指标
|
|||
|
|
cpuUsage: 'gauge', // CPU使用率
|
|||
|
|
memoryUsage: 'gauge', // 内存使用率
|
|||
|
|
diskUsage: 'gauge', // 磁盘使用率
|
|||
|
|
networkIO: 'gauge', // 网络IO
|
|||
|
|
|
|||
|
|
// 数据库指标
|
|||
|
|
dbConnections: 'gauge', // 数据库连接数
|
|||
|
|
dbQueryTime: 'histogram', // 查询时间
|
|||
|
|
dbSlowQueries: 'counter', // 慢查询数
|
|||
|
|
|
|||
|
|
// 缓存指标
|
|||
|
|
cacheHitRate: 'gauge', // 缓存命中率
|
|||
|
|
cacheMemoryUsage: 'gauge', // 缓存内存使用
|
|||
|
|
cacheConnections: 'gauge' // 缓存连接数
|
|||
|
|
};
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 7.2 日志架构
|
|||
|
|
|
|||
|
|
#### 7.2.1 日志分类
|
|||
|
|
```typescript
|
|||
|
|
// 日志级别
|
|||
|
|
enum LogLevel {
|
|||
|
|
ERROR = 'error',
|
|||
|
|
WARN = 'warn',
|
|||
|
|
INFO = 'info',
|
|||
|
|
DEBUG = 'debug'
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 日志类型
|
|||
|
|
enum LogType {
|
|||
|
|
ACCESS = 'access', // 访问日志
|
|||
|
|
ERROR = 'error', // 错误日志
|
|||
|
|
BUSINESS = 'business', // 业务日志
|
|||
|
|
SECURITY = 'security', // 安全日志
|
|||
|
|
PERFORMANCE = 'performance' // 性能日志
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 日志格式
|
|||
|
|
interface LogEntry {
|
|||
|
|
timestamp: string;
|
|||
|
|
level: LogLevel;
|
|||
|
|
type: LogType;
|
|||
|
|
service: string;
|
|||
|
|
traceId: string;
|
|||
|
|
userId?: number;
|
|||
|
|
message: string;
|
|||
|
|
data?: any;
|
|||
|
|
error?: {
|
|||
|
|
name: string;
|
|||
|
|
message: string;
|
|||
|
|
stack: string;
|
|||
|
|
};
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
#### 7.2.2 日志收集流程
|
|||
|
|
```mermaid
|
|||
|
|
graph LR
|
|||
|
|
A[应用服务] --> B[日志文件]
|
|||
|
|
B --> C[Filebeat]
|
|||
|
|
C --> D[Logstash]
|
|||
|
|
D --> E[Elasticsearch]
|
|||
|
|
E --> F[Kibana]
|
|||
|
|
|
|||
|
|
G[实时日志] --> H[Fluentd]
|
|||
|
|
H --> D
|
|||
|
|
|
|||
|
|
I[错误日志] --> J[告警系统]
|
|||
|
|
J --> K[通知服务]
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 8. 安全架构
|
|||
|
|
|
|||
|
|
### 8.1 安全防护体系
|
|||
|
|
|
|||
|
|
#### 8.1.1 多层安全防护
|
|||
|
|
```mermaid
|
|||
|
|
graph TB
|
|||
|
|
A[用户请求] --> B[CDN/WAF]
|
|||
|
|
B --> C[负载均衡器]
|
|||
|
|
C --> D[API网关]
|
|||
|
|
D --> E[应用服务]
|
|||
|
|
E --> F[数据库]
|
|||
|
|
|
|||
|
|
G[DDoS防护] --> B
|
|||
|
|
H[SQL注入防护] --> D
|
|||
|
|
I[XSS防护] --> D
|
|||
|
|
J[CSRF防护] --> D
|
|||
|
|
K[数据加密] --> F
|
|||
|
|
L[访问控制] --> F
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
#### 8.1.2 安全措施
|
|||
|
|
```typescript
|
|||
|
|
// 安全配置
|
|||
|
|
const securityConfig = {
|
|||
|
|
// JWT配置
|
|||
|
|
jwt: {
|
|||
|
|
secret: process.env.JWT_SECRET,
|
|||
|
|
expiresIn: '7d',
|
|||
|
|
refreshExpiresIn: '30d',
|
|||
|
|
algorithm: 'HS256'
|
|||
|
|
},
|
|||
|
|
|
|||
|
|
// 密码策略
|
|||
|
|
password: {
|
|||
|
|
minLength: 8,
|
|||
|
|
requireUppercase: true,
|
|||
|
|
requireLowercase: true,
|
|||
|
|
requireNumbers: true,
|
|||
|
|
requireSymbols: true,
|
|||
|
|
maxAttempts: 5,
|
|||
|
|
lockoutDuration: 300000 // 5分钟
|
|||
|
|
},
|
|||
|
|
|
|||
|
|
// 接口限流
|
|||
|
|
rateLimit: {
|
|||
|
|
windowMs: 60000, // 1分钟
|
|||
|
|
max: 100, // 最大请求数
|
|||
|
|
skipSuccessfulRequests: false,
|
|||
|
|
skipFailedRequests: false
|
|||
|
|
},
|
|||
|
|
|
|||
|
|
// CORS配置
|
|||
|
|
cors: {
|
|||
|
|
origin: ['https://jiebanke.com', 'https://admin.jiebanke.com'],
|
|||
|
|
credentials: true,
|
|||
|
|
optionsSuccessStatus: 200
|
|||
|
|
},
|
|||
|
|
|
|||
|
|
// 数据加密
|
|||
|
|
encryption: {
|
|||
|
|
algorithm: 'aes-256-gcm',
|
|||
|
|
keyLength: 32,
|
|||
|
|
ivLength: 16,
|
|||
|
|
tagLength: 16
|
|||
|
|
}
|
|||
|
|
};
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 8.2 数据安全
|
|||
|
|
|
|||
|
|
#### 8.2.1 敏感数据加密
|
|||
|
|
```typescript
|
|||
|
|
// 数据加密服务
|
|||
|
|
class EncryptionService {
|
|||
|
|
// 加密敏感数据
|
|||
|
|
async encryptSensitiveData(data: string): Promise<string> {
|
|||
|
|
const key = crypto.randomBytes(32);
|
|||
|
|
const iv = crypto.randomBytes(16);
|
|||
|
|
const cipher = crypto.createCipher('aes-256-gcm', key, iv);
|
|||
|
|
|
|||
|
|
let encrypted = cipher.update(data, 'utf8', 'hex');
|
|||
|
|
encrypted += cipher.final('hex');
|
|||
|
|
|
|||
|
|
const tag = cipher.getAuthTag();
|
|||
|
|
|
|||
|
|
return JSON.stringify({
|
|||
|
|
encrypted,
|
|||
|
|
key: key.toString('hex'),
|
|||
|
|
iv: iv.toString('hex'),
|
|||
|
|
tag: tag.toString('hex')
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 解密敏感数据
|
|||
|
|
async decryptSensitiveData(encryptedData: string): Promise<string> {
|
|||
|
|
const { encrypted, key, iv, tag } = JSON.parse(encryptedData);
|
|||
|
|
|
|||
|
|
const decipher = crypto.createDecipher('aes-256-gcm',
|
|||
|
|
Buffer.from(key, 'hex'),
|
|||
|
|
Buffer.from(iv, 'hex')
|
|||
|
|
);
|
|||
|
|
|
|||
|
|
decipher.setAuthTag(Buffer.from(tag, 'hex'));
|
|||
|
|
|
|||
|
|
let decrypted = decipher.update(encrypted, 'hex', 'utf8');
|
|||
|
|
decrypted += decipher.final('utf8');
|
|||
|
|
|
|||
|
|
return decrypted;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 9. 性能优化
|
|||
|
|
|
|||
|
|
### 9.1 数据库优化
|
|||
|
|
|
|||
|
|
#### 9.1.1 索引优化策略
|
|||
|
|
```sql
|
|||
|
|
-- 用户表索引优化
|
|||
|
|
CREATE INDEX idx_users_openid ON users(openid);
|
|||
|
|
CREATE INDEX idx_users_phone ON users(phone);
|
|||
|
|
CREATE INDEX idx_users_status_created ON users(status, created_at);
|
|||
|
|
|
|||
|
|
-- 活动表索引优化
|
|||
|
|
CREATE INDEX idx_activities_creator_status ON activities(creator_id, status);
|
|||
|
|
CREATE INDEX idx_activities_category_time ON activities(category_id, start_time);
|
|||
|
|
CREATE INDEX idx_activities_location ON activities(latitude, longitude);
|
|||
|
|
CREATE INDEX idx_activities_status_time ON activities(status, start_time);
|
|||
|
|
|
|||
|
|
-- 复合索引优化
|
|||
|
|
CREATE INDEX idx_activity_participants_complex
|
|||
|
|
ON activity_participants(activity_id, status, apply_time);
|
|||
|
|
|
|||
|
|
-- 覆盖索引优化
|
|||
|
|
CREATE INDEX idx_activities_list_cover
|
|||
|
|
ON activities(status, start_time, id, title, creator_id, current_participants);
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
#### 9.1.2 查询优化
|
|||
|
|
```typescript
|
|||
|
|
// 分页查询优化
|
|||
|
|
class ActivityService {
|
|||
|
|
// 使用游标分页替代OFFSET
|
|||
|
|
async getActivitiesByCursor(cursor?: number, limit: number = 20) {
|
|||
|
|
const whereClause = cursor ? 'WHERE id < ?' : '';
|
|||
|
|
const params = cursor ? [cursor, limit] : [limit];
|
|||
|
|
|
|||
|
|
const sql = `
|
|||
|
|
SELECT id, title, creator_id, start_time, current_participants
|
|||
|
|
FROM activities
|
|||
|
|
${whereClause}
|
|||
|
|
ORDER BY id DESC
|
|||
|
|
LIMIT ?
|
|||
|
|
`;
|
|||
|
|
|
|||
|
|
return await this.db.query(sql, params);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 批量查询优化
|
|||
|
|
async getActivitiesWithCreators(activityIds: number[]) {
|
|||
|
|
const sql = `
|
|||
|
|
SELECT
|
|||
|
|
a.id, a.title, a.start_time,
|
|||
|
|
u.id as creator_id, u.nickname, u.avatar
|
|||
|
|
FROM activities a
|
|||
|
|
JOIN users u ON a.creator_id = u.id
|
|||
|
|
WHERE a.id IN (${activityIds.map(() => '?').join(',')})
|
|||
|
|
`;
|
|||
|
|
|
|||
|
|
return await this.db.query(sql, activityIds);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 9.2 缓存优化
|
|||
|
|
|
|||
|
|
#### 9.2.1 多级缓存策略
|
|||
|
|
```typescript
|
|||
|
|
// 缓存服务
|
|||
|
|
class CacheService {
|
|||
|
|
private l1Cache: Map<string, any> = new Map(); // 内存缓存
|
|||
|
|
private redis: Redis; // Redis缓存
|
|||
|
|
|
|||
|
|
async get(key: string): Promise<any> {
|
|||
|
|
// L1缓存查询
|
|||
|
|
if (this.l1Cache.has(key)) {
|
|||
|
|
return this.l1Cache.get(key);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// L2缓存查询
|
|||
|
|
const value = await this.redis.get(key);
|
|||
|
|
if (value) {
|
|||
|
|
const parsed = JSON.parse(value);
|
|||
|
|
// 回写L1缓存
|
|||
|
|
this.l1Cache.set(key, parsed);
|
|||
|
|
return parsed;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return null;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
async set(key: string, value: any, ttl: number = 300): Promise<void> {
|
|||
|
|
// 设置L1缓存
|
|||
|
|
this.l1Cache.set(key, value);
|
|||
|
|
|
|||
|
|
// 设置L2缓存
|
|||
|
|
await this.redis.setex(key, ttl, JSON.stringify(value));
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 缓存预热
|
|||
|
|
async warmupCache(): Promise<void> {
|
|||
|
|
// 预热热门活动
|
|||
|
|
const hotActivities = await this.getHotActivities();
|
|||
|
|
for (const activity of hotActivities) {
|
|||
|
|
await this.set(`activity:${activity.id}`, activity, 600);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 预热用户信息
|
|||
|
|
const activeUsers = await this.getActiveUsers();
|
|||
|
|
for (const user of activeUsers) {
|
|||
|
|
await this.set(`user:${user.id}`, user, 1800);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 9.3 异步处理优化
|
|||
|
|
|
|||
|
|
#### 9.3.1 任务队列优化
|
|||
|
|
```typescript
|
|||
|
|
// 任务队列服务
|
|||
|
|
class TaskQueueService {
|
|||
|
|
private queues: Map<string, Queue> = new Map();
|
|||
|
|
|
|||
|
|
constructor() {
|
|||
|
|
this.initQueues();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private initQueues(): void {
|
|||
|
|
// 高优先级队列
|
|||
|
|
this.queues.set('high', new Queue('high-priority', {
|
|||
|
|
redis: redisConfig,
|
|||
|
|
defaultJobOptions: {
|
|||
|
|
removeOnComplete: 100,
|
|||
|
|
removeOnFail: 50,
|
|||
|
|
attempts: 3,
|
|||
|
|
backoff: 'exponential'
|
|||
|
|
}
|
|||
|
|
}));
|
|||
|
|
|
|||
|
|
// 普通优先级队列
|
|||
|
|
this.queues.set('normal', new Queue('normal-priority', {
|
|||
|
|
redis: redisConfig,
|
|||
|
|
defaultJobOptions: {
|
|||
|
|
removeOnComplete: 50,
|
|||
|
|
removeOnFail: 25,
|
|||
|
|
attempts: 2,
|
|||
|
|
backoff: 'fixed'
|
|||
|
|
}
|
|||
|
|
}));
|
|||
|
|
|
|||
|
|
// 低优先级队列
|
|||
|
|
this.queues.set('low', new Queue('low-priority', {
|
|||
|
|
redis: redisConfig,
|
|||
|
|
defaultJobOptions: {
|
|||
|
|
removeOnComplete: 20,
|
|||
|
|
removeOnFail: 10,
|
|||
|
|
attempts: 1
|
|||
|
|
}
|
|||
|
|
}));
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
async addTask(priority: string, taskType: string, data: any): Promise<void> {
|
|||
|
|
const queue = this.queues.get(priority);
|
|||
|
|
if (!queue) {
|
|||
|
|
throw new Error(`Queue ${priority} not found`);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
await queue.add(taskType, data, {
|
|||
|
|
priority: this.getPriorityValue(priority),
|
|||
|
|
delay: this.getDelayTime(taskType)
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private getPriorityValue(priority: string): number {
|
|||
|
|
const priorities = { high: 10, normal: 5, low: 1 };
|
|||
|
|
return priorities[priority] || 1;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private getDelayTime(taskType: string): number {
|
|||
|
|
const delays = {
|
|||
|
|
'send-email': 0,
|
|||
|
|
'update-search-index': 5000,
|
|||
|
|
'generate-report': 10000
|
|||
|
|
};
|
|||
|
|
return delays[taskType] || 0;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 10. 部署和运维
|
|||
|
|
|
|||
|
|
### 10.1 Docker容器化
|
|||
|
|
|
|||
|
|
#### 10.1.1 Dockerfile优化
|
|||
|
|
```dockerfile
|
|||
|
|
# 多阶段构建
|
|||
|
|
FROM node:18-alpine AS builder
|
|||
|
|
|
|||
|
|
WORKDIR /app
|
|||
|
|
COPY package*.json ./
|
|||
|
|
RUN npm ci --only=production && npm cache clean --force
|
|||
|
|
|
|||
|
|
COPY . .
|
|||
|
|
RUN npm run build
|
|||
|
|
|
|||
|
|
# 生产镜像
|
|||
|
|
FROM node:18-alpine AS production
|
|||
|
|
|
|||
|
|
# 创建非root用户
|
|||
|
|
RUN addgroup -g 1001 -S nodejs
|
|||
|
|
RUN adduser -S nodejs -u 1001
|
|||
|
|
|
|||
|
|
WORKDIR /app
|
|||
|
|
|
|||
|
|
# 复制构建产物
|
|||
|
|
COPY --from=builder --chown=nodejs:nodejs /app/dist ./dist
|
|||
|
|
COPY --from=builder --chown=nodejs:nodejs /app/node_modules ./node_modules
|
|||
|
|
COPY --from=builder --chown=nodejs:nodejs /app/package*.json ./
|
|||
|
|
|
|||
|
|
# 健康检查
|
|||
|
|
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
|
|||
|
|
CMD curl -f http://localhost:3000/health || exit 1
|
|||
|
|
|
|||
|
|
USER nodejs
|
|||
|
|
|
|||
|
|
EXPOSE 3000
|
|||
|
|
|
|||
|
|
CMD ["node", "dist/index.js"]
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
#### 10.1.2 Docker Compose配置
|
|||
|
|
```yaml
|
|||
|
|
version: '3.8'
|
|||
|
|
|
|||
|
|
services:
|
|||
|
|
app:
|
|||
|
|
build: .
|
|||
|
|
ports:
|
|||
|
|
- "3000:3000"
|
|||
|
|
environment:
|
|||
|
|
- NODE_ENV=production
|
|||
|
|
- DB_HOST=mysql
|
|||
|
|
- REDIS_HOST=redis
|
|||
|
|
depends_on:
|
|||
|
|
- mysql
|
|||
|
|
- redis
|
|||
|
|
restart: unless-stopped
|
|||
|
|
|
|||
|
|
mysql:
|
|||
|
|
image: mysql:8.0
|
|||
|
|
environment:
|
|||
|
|
MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
|
|||
|
|
MYSQL_DATABASE: jiebanke
|
|||
|
|
volumes:
|
|||
|
|
- mysql_data:/var/lib/mysql
|
|||
|
|
- ./scripts/init.sql:/docker-entrypoint-initdb.d/init.sql
|
|||
|
|
restart: unless-stopped
|
|||
|
|
|
|||
|
|
redis:
|
|||
|
|
image: redis:7-alpine
|
|||
|
|
command: redis-server --appendonly yes
|
|||
|
|
volumes:
|
|||
|
|
- redis_data:/data
|
|||
|
|
restart: unless-stopped
|
|||
|
|
|
|||
|
|
nginx:
|
|||
|
|
image: nginx:alpine
|
|||
|
|
ports:
|
|||
|
|
- "80:80"
|
|||
|
|
- "443:443"
|
|||
|
|
volumes:
|
|||
|
|
- ./nginx.conf:/etc/nginx/nginx.conf
|
|||
|
|
- ./ssl:/etc/nginx/ssl
|
|||
|
|
depends_on:
|
|||
|
|
- app
|
|||
|
|
restart: unless-stopped
|
|||
|
|
|
|||
|
|
volumes:
|
|||
|
|
mysql_data:
|
|||
|
|
redis_data:
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 10.2 Kubernetes部署
|
|||
|
|
|
|||
|
|
#### 10.2.1 应用部署配置
|
|||
|
|
```yaml
|
|||
|
|
apiVersion: apps/v1
|
|||
|
|
kind: Deployment
|
|||
|
|
metadata:
|
|||
|
|
name: jiebanke-backend
|
|||
|
|
labels:
|
|||
|
|
app: jiebanke-backend
|
|||
|
|
spec:
|
|||
|
|
replicas: 3
|
|||
|
|
selector:
|
|||
|
|
matchLabels:
|
|||
|
|
app: jiebanke-backend
|
|||
|
|
template:
|
|||
|
|
metadata:
|
|||
|
|
labels:
|
|||
|
|
app: jiebanke-backend
|
|||
|
|
spec:
|
|||
|
|
containers:
|
|||
|
|
- name: backend
|
|||
|
|
image: jiebanke/backend:latest
|
|||
|
|
ports:
|
|||
|
|
- containerPort: 3000
|
|||
|
|
env:
|
|||
|
|
- name: NODE_ENV
|
|||
|
|
value: "production"
|
|||
|
|
- name: DB_HOST
|
|||
|
|
valueFrom:
|
|||
|
|
secretKeyRef:
|
|||
|
|
name: db-secret
|
|||
|
|
key: host
|
|||
|
|
- name: DB_PASSWORD
|
|||
|
|
valueFrom:
|
|||
|
|
secretKeyRef:
|
|||
|
|
name: db-secret
|
|||
|
|
key: password
|
|||
|
|
resources:
|
|||
|
|
requests:
|
|||
|
|
memory: "256Mi"
|
|||
|
|
cpu: "250m"
|
|||
|
|
limits:
|
|||
|
|
memory: "512Mi"
|
|||
|
|
cpu: "500m"
|
|||
|
|
livenessProbe:
|
|||
|
|
httpGet:
|
|||
|
|
path: /health
|
|||
|
|
port: 3000
|
|||
|
|
initialDelaySeconds: 30
|
|||
|
|
periodSeconds: 10
|
|||
|
|
readinessProbe:
|
|||
|
|
httpGet:
|
|||
|
|
path: /ready
|
|||
|
|
port: 3000
|
|||
|
|
initialDelaySeconds: 5
|
|||
|
|
periodSeconds: 5
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
apiVersion: v1
|
|||
|
|
kind: Service
|
|||
|
|
metadata:
|
|||
|
|
name: jiebanke-backend-service
|
|||
|
|
spec:
|
|||
|
|
selector:
|
|||
|
|
app: jiebanke-backend
|
|||
|
|
ports:
|
|||
|
|
- protocol: TCP
|
|||
|
|
port: 80
|
|||
|
|
targetPort: 3000
|
|||
|
|
type: ClusterIP
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
apiVersion: networking.k8s.io/v1
|
|||
|
|
kind: Ingress
|
|||
|
|
metadata:
|
|||
|
|
name: jiebanke-backend-ingress
|
|||
|
|
annotations:
|
|||
|
|
kubernetes.io/ingress.class: nginx
|
|||
|
|
cert-manager.io/cluster-issuer: letsencrypt-prod
|
|||
|
|
spec:
|
|||
|
|
tls:
|
|||
|
|
- hosts:
|
|||
|
|
- api.jiebanke.com
|
|||
|
|
secretName: jiebanke-tls
|
|||
|
|
rules:
|
|||
|
|
- host: api.jiebanke.com
|
|||
|
|
http:
|
|||
|
|
paths:
|
|||
|
|
- path: /
|
|||
|
|
pathType: Prefix
|
|||
|
|
backend:
|
|||
|
|
service:
|
|||
|
|
name: jiebanke-backend-service
|
|||
|
|
port:
|
|||
|
|
number: 80
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 10.3 CI/CD流水线
|
|||
|
|
|
|||
|
|
#### 10.3.1 GitHub Actions配置
|
|||
|
|
```yaml
|
|||
|
|
name: Backend CI/CD
|
|||
|
|
|
|||
|
|
on:
|
|||
|
|
push:
|
|||
|
|
branches: [ main, develop ]
|
|||
|
|
pull_request:
|
|||
|
|
branches: [ main ]
|
|||
|
|
|
|||
|
|
jobs:
|
|||
|
|
test:
|
|||
|
|
runs-on: ubuntu-latest
|
|||
|
|
|
|||
|
|
services:
|
|||
|
|
mysql:
|
|||
|
|
image: mysql:8.0
|
|||
|
|
env:
|
|||
|
|
MYSQL_ROOT_PASSWORD: test
|
|||
|
|
MYSQL_DATABASE: test
|
|||
|
|
options: >-
|
|||
|
|
--health-cmd="mysqladmin ping"
|
|||
|
|
--health-interval=10s
|
|||
|
|
--health-timeout=5s
|
|||
|
|
--health-retries=3
|
|||
|
|
|
|||
|
|
redis:
|
|||
|
|
image: redis:7-alpine
|
|||
|
|
options: >-
|
|||
|
|
--health-cmd="redis-cli ping"
|
|||
|
|
--health-interval=10s
|
|||
|
|
--health-timeout=5s
|
|||
|
|
--health-retries=3
|
|||
|
|
|
|||
|
|
steps:
|
|||
|
|
- uses: actions/checkout@v3
|
|||
|
|
|
|||
|
|
- name: Setup Node.js
|
|||
|
|
uses: actions/setup-node@v3
|
|||
|
|
with:
|
|||
|
|
node-version: '18'
|
|||
|
|
cache: 'npm'
|
|||
|
|
|
|||
|
|
- name: Install dependencies
|
|||
|
|
run: npm ci
|
|||
|
|
|
|||
|
|
- name: Run linting
|
|||
|
|
run: npm run lint
|
|||
|
|
|
|||
|
|
- name: Run tests
|
|||
|
|
run: npm run test:coverage
|
|||
|
|
env:
|
|||
|
|
DB_HOST: localhost
|
|||
|
|
DB_PORT: 3306
|
|||
|
|
DB_USER: root
|
|||
|
|
DB_PASSWORD: test
|
|||
|
|
DB_NAME: test
|
|||
|
|
REDIS_HOST: localhost
|
|||
|
|
REDIS_PORT: 6379
|
|||
|
|
|
|||
|
|
- name: Upload coverage to Codecov
|
|||
|
|
uses: codecov/codecov-action@v3
|
|||
|
|
|
|||
|
|
build-and-deploy:
|
|||
|
|
needs: test
|
|||
|
|
runs-on: ubuntu-latest
|
|||
|
|
if: github.ref == 'refs/heads/main'
|
|||
|
|
|
|||
|
|
steps:
|
|||
|
|
- uses: actions/checkout@v3
|
|||
|
|
|
|||
|
|
- name: Build Docker image
|
|||
|
|
run: |
|
|||
|
|
docker build -t jiebanke/backend:${{ github.sha }} .
|
|||
|
|
docker tag jiebanke/backend:${{ github.sha }} jiebanke/backend:latest
|
|||
|
|
|
|||
|
|
- name: Login to Docker Hub
|
|||
|
|
uses: docker/login-action@v2
|
|||
|
|
with:
|
|||
|
|
username: ${{ secrets.DOCKER_USERNAME }}
|
|||
|
|
password: ${{ secrets.DOCKER_PASSWORD }}
|
|||
|
|
|
|||
|
|
- name: Push Docker image
|
|||
|
|
run: |
|
|||
|
|
docker push jiebanke/backend:${{ github.sha }}
|
|||
|
|
docker push jiebanke/backend:latest
|
|||
|
|
|
|||
|
|
- name: Deploy to Kubernetes
|
|||
|
|
uses: azure/k8s-deploy@v1
|
|||
|
|
with:
|
|||
|
|
manifests: |
|
|||
|
|
k8s/deployment.yaml
|
|||
|
|
k8s/service.yaml
|
|||
|
|
k8s/ingress.yaml
|
|||
|
|
images: |
|
|||
|
|
jiebanke/backend:${{ github.sha }}
|
|||
|
|
kubectl-version: 'latest'
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 11. 总结
|
|||
|
|
|
|||
|
|
### 11.1 架构优势
|
|||
|
|
|
|||
|
|
#### 11.1.1 技术优势
|
|||
|
|
- **现代化技术栈**:采用Node.js + TypeScript,开发效率高
|
|||
|
|
- **微服务架构**:服务解耦,独立部署和扩展
|
|||
|
|
- **容器化部署**:Docker + Kubernetes,运维便捷
|
|||
|
|
- **多数据库支持**:MySQL + Redis + MongoDB + ES,满足不同场景需求
|
|||
|
|
- **消息队列**:RabbitMQ异步处理,提高系统性能
|
|||
|
|
|
|||
|
|
#### 11.1.2 性能优势
|
|||
|
|
- **多级缓存**:内存缓存 + Redis缓存,提高响应速度
|
|||
|
|
- **读写分离**:MySQL主从架构,提高数据库性能
|
|||
|
|
- **分库分表**:支持大数据量和高并发
|
|||
|
|
- **CDN加速**:静态资源CDN分发,提高访问速度
|
|||
|
|
- **异步处理**:消息队列异步处理,提高系统吞吐量
|
|||
|
|
|
|||
|
|
#### 11.1.3 安全优势
|
|||
|
|
- **多层防护**:WAF + API网关 + 应用层多重安全防护
|
|||
|
|
- **数据加密**:敏感数据加密存储和传输
|
|||
|
|
- **权限控制**:RBAC权限模型,细粒度权限控制
|
|||
|
|
- **安全监控**:实时安全监控和告警
|
|||
|
|
- **合规性**:符合数据保护和隐私法规要求
|
|||
|
|
|
|||
|
|
### 11.2 扩展性设计
|
|||
|
|
|
|||
|
|
#### 11.2.1 水平扩展
|
|||
|
|
- **无状态服务**:支持服务实例水平扩展
|
|||
|
|
- **数据库扩展**:支持读库扩展和分库分表
|
|||
|
|
- **缓存扩展**:Redis集群支持水平扩展
|
|||
|
|
- **消息队列扩展**:RabbitMQ集群支持扩展
|
|||
|
|
|
|||
|
|
#### 11.2.2 垂直扩展
|
|||
|
|
- **功能模块化**:新功能可独立开发和部署
|
|||
|
|
- **插件化架构**:支持功能插件化扩展
|
|||
|
|
- **API版本管理**:支持API平滑升级
|
|||
|
|
- **配置化管理**:业务规则配置化,灵活调整
|
|||
|
|
|
|||
|
|
### 11.3 运维保障
|
|||
|
|
|
|||
|
|
#### 11.3.1 监控告警
|
|||
|
|
- **全方位监控**:业务指标 + 技术指标 + 系统指标
|
|||
|
|
- **实时告警**:多渠道告警通知
|
|||
|
|
- **可视化面板**:Grafana可视化监控面板
|
|||
|
|
- **日志分析**:ELK日志分析和查询
|
|||
|
|
|
|||
|
|
#### 11.3.2 高可用保障
|
|||
|
|
- **服务冗余**:多实例部署,故障自动切换
|
|||
|
|
- **数据备份**:定期数据备份和恢复测试
|
|||
|
|
- **灾备方案**:异地灾备和快速恢复
|
|||
|
|
- **故障演练**:定期故障演练和应急响应
|
|||
|
|
|
|||
|
|
### 11.4 持续改进
|
|||
|
|
|
|||
|
|
#### 11.4.1 技术演进
|
|||
|
|
- **云原生**:向云原生架构演进
|
|||
|
|
- **服务网格**:引入Istio服务网格
|
|||
|
|
- **AI集成**:集成机器学习和AI能力
|
|||
|
|
- **边缘计算**:支持边缘计算场景
|
|||
|
|
|
|||
|
|
#### 11.4.2 性能优化
|
|||
|
|
- **持续优化**:基于监控数据持续优化性能
|
|||
|
|
- **新技术引入**:关注新技术,适时引入
|
|||
|
|
- **架构重构**:根据业务发展适时重构
|
|||
|
|
- **最佳实践**:总结和推广最佳实践
|
|||
|
|
|
|||
|
|
本后端架构文档为解班客项目提供了完整的技术架构指导,涵盖了从服务设计到部署运维的各个方面。通过合理的架构设计和技术选型,确保系统的高性能、高可用、高安全和高扩展性,为业务发展提供坚实的技术保障。
|