小红书软件设计架构、教程及详细说明

IT 技术 96 阅读 更新于 2026-09-04 08:01

📐 一、整体系统架构

1.1 小红书整体架构概览

系统定位

小红书是一款以"生活方式分享社区"为核心的社交电商平台,日均活跃用户超过1亿,内容涵盖美妆、时尚、美食、旅行、健身等生活领域。其技术架构需要同时满足以下核心需求:

  • 高并发:支持亿级用户同时在线,峰值QPS达到百万级别
  • 实时性:信息流秒级推送、评论即时可见
  • 海量存储:数亿条笔记内容、百亿级用户互动数据
  • 智能推荐:千人千面的个性化内容分发
  • 电商闭环:从种草到购买的完整商业链路

整体架构分层

┌─────────────────────────────────────────────────────────────────┐ │ 用户接入层 (Client Layer) │ │ iOS App | Android App | Web端 | 小程序 | 开放API │ └─────────────────────────────────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────────┐ │ 网关层 (Gateway Layer) │ │ CDN加速 | WAF防火墙 | API网关(鉴权/限流/路由) | 负载均衡 │ └─────────────────────────────────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────────┐ │ 业务服务层 (Business Service Layer) │ │ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ │ │用户服务 │ │笔记服务 │ │社交服务 │ │电商服务 │ │ │ └──────────┘ └──────────┘ └──────────┘ └──────────┘ │ │ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ │ │推荐服务 │ │搜索服务 │ │消息服务 │ │直播服务 │ │ │ └──────────┘ └──────────┘ └──────────┘ └──────────┘ │ └─────────────────────────────────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────────┐ │ 基础服务层 (Infrastructure Layer) │ │ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ │ │配置中心 │ │注册中心 │ │链路追踪 │ │监控系统 │ │ │ └──────────┘ └──────────┘ └──────────┘ └──────────┘ │ │ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ │ │消息队列 │ │分布式缓存 │ │任务调度 │ │日志平台 │ │ │ └──────────┘ └──────────┘ └──────────┘ └──────────┘ │ └─────────────────────────────────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────────┐ │ 数据存储层 (Data Layer) │ │ MySQL集群 | Redis集群 | Elasticsearch | HBase | MongoDB │ │ HDFS | Kafka | TiDB | ClickHouse │ └─────────────────────────────────────────────────────────────────┘

核心技术栈

层次技术选型说明
客户端React Native / Flutter / Swift / Kotlin跨平台+原生混合开发
网关Nginx + Kong + Envoy高性能API网关
服务框架Spring Cloud / Go-Micro / gRPC微服务通信框架
消息队列Kafka / RocketMQ / RabbitMQ异步解耦、削峰填谷
缓存Redis Cluster + 本地缓存(Caffeine)多级缓存架构
数据库MySQL + TiDB + MongoDB + HBase混合存储方案
搜索Elasticsearch + 自研NLP引擎全文检索与语义搜索
大数据Spark + Flink + Hadoop实时与离线计算
容器化Kubernetes + Docker + Helm云原生部署

1.2 微服务架构设计

微服务拆分原则

小红书采用领域驱动设计(DDD)进行服务拆分,遵循以下原则:

  • 单一职责:每个微服务只负责一个明确的业务领域
  • 高内聚低耦合:服务内部功能紧密相关,服务间依赖最小化
  • 业务边界清晰:按照限界上下文(Bounded Context)划分
  • 独立部署:每个服务可独立开发、测试、部署和扩展
  • 数据自治:每个服务拥有独立的数据库

核心微服务清单

服务名职责核心技术QPS预估
user-service用户注册、登录、资料管理、等级体系Go + MySQL + Redis50,000+
note-service笔记发布、编辑、管理、审核Java + MongoDB + Kafka30,000+
feed-service信息流拉取、聚合排序、分页Go + Redis + ES200,000+
social-service关注、粉丝、好友、互动Go + Redis + HBase80,000+
interaction-service点赞、收藏、评论、分享Java + Redis + Kafka150,000+
search-service搜索索引、查询、排序、推荐Java + ES + 自研NLP100,000+
recommend-service个性化推荐、召回、排序Python/Go + TensorFlow + Redis150,000+
media-service图片/视频上传、处理、CDN分发Go + FFmpeg + OSS50,000+
commerce-service商品管理、订单、支付、物流Java + MySQL + MQ20,000+
push-service消息推送、通知、IM聊天Go + WebSocket + Redis100,000+

服务间通信

采用同步+异步混合的通信模式:

  • 同步调用:gRPC (内部服务间) + RESTful API (对外)
  • 异步通信:Kafka消息队列 (事件驱动架构)
  • 服务发现:Consul + Nacos
  • 负载均衡:客户端LB (gRPC) + 服务端LB (Nginx)
  • 熔断降级:Sentinel / Hystrix / Go Circuit Breaker

服务调用链路示例: ┌──────┐ gRPC ┌──────────┐ Kafka ┌──────────┐ │用户端│ ──────────▶ │API Gateway│ ────────▶ │note-svc │ └──────┘ └──────────┘ └──────────┘ │ │ gRPC │ Kafka│Event ▼ ▼ ┌──────────┐ ┌──────────┐ │feed-svc │◀─────────│recommend │ └──────────┘ └──────────┘ │ gRPC │ ▼ ┌──────────┐ │Redis缓存 │ │ES索引 │ └──────────┘

1.3 网关层设计详解

API网关核心功能

小红书采用自研网关(基于OpenResty/Kong二次开发),承担以下核心职责:

1. 统一鉴权

// 请求鉴权流程
1. 客户端携带 JWT Token 请求到达网关
2. 网关解析 Token,验证签名和有效期
3. 查询用户权限(角色/接口白名单)
4. 通过则转发请求,否则返回401
5. 将用户ID注入请求Header传递给下游

Token结构:
{
  "sub": "user_12345",
  "role": "normal_user",
  "exp": 1699999999,
  "device_id": "iPhone14,2",
  "permissions": ["note.create", "note.view"]
}

2. 流量控制与限流

// 限流策略(基于令牌桶算法)
限流维度:
- 用户级: 每个用户每分钟最多请求100次
- IP级: 每个IP每秒最多50次请求
- 接口级: 每个接口设置独立的QPS上限
- 全局限流: 保护后端系统整体不超过承载能力

// 限流降级策略
正常流量 → 全功能
80%容量  → 关闭部分非核心功能
90%容量  → 仅保留核心浏览功能
100%容量 → 静态页面降级

3. 灰度发布与A/B测试

  • 基于用户ID哈希进行流量分割
  • 支持按地域、设备、用户标签分流
  • 实时切换流量比例,无需重启

4. 请求聚合

// 减少客户端请求次数,网关聚合多个服务响应
GET /api/homepage 一次请求返回:
{
  "user_info": "user-service",      // 用户信息
  "feed_list": "feed-service",      // 信息流
  "recommend": "recommend-service", // 推荐内容
  "notifications": "push-service"   // 通知数量
}
// 网关内部并发调用4个服务,合并后返回

🎨 二、前端架构设计

2.1 移动端架构设计

混合架构方案

小红书采用"原生+跨平台+H5"的混合架构:

  • 核心模块(原生):首页Feed流、相机拍摄、视频播放等性能敏感模块
  • 业务模块(React Native/Flutter):个人中心、设置页、活动页面等
  • 运营模块(H5/Webview):活动专题页、营销落地页等需要热更新的页面

图片加载优化策略

// 瀑布流图片加载流程
1. 图片懒加载:只加载可视区域±1屏的图片
2. 渐进式加载:先加载缩略图,再替换高清图
3. WebP自适应:支持WebP的终端优先使用WebP格式
4. 占位计算:根据宽高比预计算布局,避免重排
5. 预加载策略:用户浏览时预加载下一页图片
6. CDN多域名:图片分布在不同CDN节点,并行下载

// 图片URL格式示例
https://ci.xiaohongshu.com/note_id?imageView2/2/w/540/format/webp
https://sns-webpic.xhscdn.com/20240101/hash.jpg@540w_720h.webp

视频播放架构

视频播放流程: ┌──────┐ ┌──────────┐ ┌─────────┐ │用户 │ 点击 │视频详情页 │ HLS │CDN边缘 │ │上滑 │──────▶│播放组件 │◀─────│节点 │ └──────┘ └──────────┘ └────┬────┘ │ │ 预加载│ 回源│ ▼ ▼ ┌──────────┐ ┌─────────┐ │本地缓存 │ │源站存储 │ │(LRU策略) │ │(OSS) │ └──────────┘ └─────────┘ 关键优化: - 滑动预加载:上滑时预加载下一个视频 - 自适应码率:根据网络状况切换清晰度 - 首帧优化:使用视频首帧作为封面图 - 弱网降级:网络差时自动降低分辨率

2.2 瀑布流布局实现

瀑布流核心算法

小红书采用多列不等高的瀑布流布局,核心思路:

// 瀑布流布局算法(最短列优先)
class WaterfallLayout {
    constructor(columns = 2) {
        this.columns = columns;
        this.columnHeights = new Array(columns).fill(0);
    }

    addItem(item) {
        // 1. 找到当前最短的列
        const shortestColumn = this.columnHeights.indexOf(
            Math.min(...this.columnHeights)
        );

        // 2. 计算该卡片的高度(基于宽高比)
        const cardHeight = this.calculateHeight(item);

        // 3. 放置卡片到最短列
        item.position = {
            column: shortestColumn,
            top: this.columnHeights[shortestColumn]
        };

        // 4. 更新列高度
        this.columnHeights[shortestColumn] += cardHeight + GAP;

        return item;
    }

    calculateHeight(item) {
        // 根据图片宽高比和固定列宽计算实际高度
        const columnWidth = (screenWidth - padding) / this.columns;
        const aspectRatio = item.width / item.height;
        return columnWidth / aspectRatio;
    }
}

// 列数适配策略
- 手机竖屏: 2列
- 手机横屏: 3列
- 平板: 3-4列
- 电脑: 4-5列(可拖拽调整)

虚拟滚动优化

// 虚拟列表只渲染可视区域的卡片
class VirtualWaterfall {
    render() {
        const scrollTop = container.scrollTop;
        const viewHeight = container.clientHeight;

        // 计算可视区域范围
        const startIndex = this.findFirstVisibleIndex(scrollTop);
        const endIndex = this.findLastVisibleIndex(scrollTop + viewHeight);

        // 只渲染 startIndex 到 endIndex 之间的卡片
        // 配合 buffer 区域(上下各多渲染2-3个)避免白屏

        this.renderItems(startIndex - BUFFER, endIndex + BUFFER);
    }

    // 通过二分查找快速定位可见区域
    findFirstVisibleIndex(scrollTop) {
        let low = 0, high = this.totalItems - 1;
        while (low < high) {
            const mid = Math.floor((low + high) / 2);
            if (this.items[mid].bottom < scrollTop) {
                low = mid + 1;
            } else {
                high = mid;
            }
        }
        return low;
    }
}

2.3 性能优化策略

启动优化

优化项措施效果
冷启动预编译、懒加载、异步初始化启动时间从3s降至1.2s
首页渲染SSR预渲染 + 骨架屏 + 本地缓存首屏渲染时间<500ms
页面切换预加载下一页 + 共享元素转场切换感知延迟<100ms
内存管理图片内存池 + LRU缓存 + 及时回收内存占用降低40%

网络优化

  • HTTP/2多路复用:减少连接建立开销
  • 请求合并:短时间内多个请求合并为一个批次
  • 弱网优化:自动切换协议(QUIC/HTTP3)
  • 智能DNS:基于地理位置和网络状况选择最优节点
  • 请求优先级:Feed流数据>用户信息>非关键资源

⚙️ 三、后端架构设计

3.1 信息流Feed系统设计

Feed流核心挑战

信息流系统是社交平台的核心,小红书面临以下技术挑战:

  • 亿级用户 × 千万级内容 = 海量数据存储与查询
  • 实时性要求高:新内容需要秒级进入用户Feed流
  • 个性化需求:每个用户的Feed流内容都不同
  • 热点处理:爆款内容可能瞬间产生千万级互动

推拉结合的Feed架构

┌─────────────────────────────────────────────────────┐ │ Feed架构选择 │ ├───────────────┬─────────────────┬───────────────────┤ │ 拉模式(Pull) │ 推模式(Push) │ 推拉结合(推荐) │ ├───────────────┼─────────────────┼───────────────────┤ │用户主动拉取 │写入时推送给粉丝 │混合策略 │ │适合大V(粉丝多) │适合普通用户 │根据粉丝数选择 │ │存储成本低 │存储成本高 │平衡存储与实时性 │ │实时性差 │实时性好 │实时性好 │ └───────────────┴─────────────────┴───────────────────┘ // 推拉结合策略 IF 发布者粉丝数 < 1000: 使用Push模式,直接写入每个粉丝的Timeline ELIF 发布者粉丝数 < 100万: Push到活跃粉丝 + Pull补充非活跃粉丝 ELSE (大V/官方号): 使用Pull模式,用户拉取时实时聚合

Feed数据存储结构

// Timeline存储 - 使用Redis ZSet (有序集合)
// Key: timeline:{user_id}
// Score: 发布时间戳(毫秒)
// Member: 笔记ID

ZADD timeline:user_123 1699900000000 note_abc
ZADD timeline:user_123 1699900001000 note_def

// 获取用户最新20条Feed
ZREVRANGE timeline:user_123 0 19

// 分页加载(游标分页)
ZREVRANGEBYSCORE timeline:user_123 last_score -INF LIMIT 0 20

// 内容详情存储 - Redis Hash
HSET note:note_abc title "今日穿搭分享"
HSET note:note_abc author_id "user_456"
HSET note:note_abc image_list "[url1,url2,url3]"
HSET note:note_abc like_count 1520

// 过期清理策略
- 超过30天的非热门内容移至HBase冷存储
- Timeline中只保留最近7天的活跃内容
- 使用TTL自动过期清理

3.2 高并发点赞系统设计

设计挑战

点赞系统看似简单,在高并发场景下存在诸多挑战:

  • 单条爆款笔记可能产生千万级点赞
  • 计数准确性与实时性的平衡
  • 用户点赞状态的快速判断
  • 防止重复点赞和刷赞

技术方案

// 点赞系统架构设计
class LikeService {

    // 用户点赞操作
    async likeNote(userId, noteId) {
        // 1. 幂等性检查 - Redis Set判断是否已点赞
        const likeKey = `note_likes:${noteId}`;
        const isLiked = await redis.sismember(likeKey, userId);
        if (isLiked) return { success: true, msg: 'already liked' };

        // 2. Redis原子操作 - 点赞+计数+1
        const pipeline = redis.pipeline();
        pipeline.sadd(likeKey, userId);           // 记录点赞用户
        pipeline.hincrby('note:stats', `${noteId}:likes`, 1); // 计数+1
        pipeline.sadd(`user_likes:${userId}`, noteId); // 用户的点赞列表
        await pipeline.exec();

        // 3. 异步写入MySQL(批量合并写入)
        await kafka.send('like_events', {
            userId, noteId, action: 'like',
            timestamp: Date.now()
        });

        // 4. 推送通知(异步)
        await notifyAuthor(userId, noteId, 'like');
    }

    // 计数显示策略
    async getLikeCount(noteId) {
        // 优先从Redis读取实时计数
        let count = await redis.hget('note:stats', `${noteId}:likes`);

        // 如果Redis没有数据,从MySQL兜底
        if (!count) {
            count = await mysql.getLikeCount(noteId);
            await redis.hset('note:stats', `${noteId}:likes`, count);
        }

        // 大数字友好显示
        return formatCount(count); // 1520 → "1.5k"
    }
}

// 批量写入MySQL策略
// 消费Kafka消息,每10秒或累积1000条时批量写入
// 使用INSERT ON DUPLICATE KEY UPDATE实现增量更新

数据存储分层

存储层存储内容读写比例
Redis实时点赞状态、计数、最近点赞用户读90% / 写10%
MySQL完整点赞关系记录写多读少(批量写入)
HBase历史点赞数据归档写多读少

3.3 评论系统设计

多级评论数据模型

小红书采用两级评论结构:一级评论(直接评论笔记)+ 二级评论(回复一级评论)

// 评论表结构设计
CREATE TABLE comments (
    id BIGINT PRIMARY KEY AUTO_INCREMENT,
    note_id BIGINT NOT NULL,           -- 笔记ID
    user_id BIGINT NOT NULL,           -- 评论者ID
    parent_id BIGINT DEFAULT 0,        -- 父评论ID(0表示一级评论)
    reply_to_user_id BIGINT,           -- 回复目标用户ID
    content TEXT NOT NULL,             -- 评论内容
    like_count INT DEFAULT 0,          -- 点赞数
    child_count INT DEFAULT 0,         -- 子评论数
    status TINYINT DEFAULT 1,          -- 状态: 0-删除 1-正常 2-审核中
    ip_location VARCHAR(50),           -- IP属地
    created_at TIMESTAMP DEFAULT NOW(),
    INDEX idx_note_parent (note_id, parent_id, created_at),
    INDEX idx_user (user_id)
);

// 热门评论排序算法
hot_score = like_count * log(time_decay + 1)
其中:
- like_count: 点赞数(权重最大)
- time_decay: 时间衰减因子(越新越靠前)
- 作者回复加分 +5
- 优质用户加分 +2

评论加载策略

  • 首页加载:默认展示3条热门评论 + 2条最新评论
  • 展开子评论:点击"展开更多"时加载该评论下的回复
  • 评论排序:支持"最热"和"最新"两种排序方式切换
  • 增量加载:新评论通过WebSocket实时推送到页面

3.4 消息推送系统设计

推送通道

通道使用场景技术实现
App内通知点赞、评论、新粉丝、系统通知WebSocket长连接 + Redis Pub/Sub
App Push重要通知唤醒用户APNs(iOS) / FCM+厂商通道(Android)
短信验证码、重要安全通知短信服务商API
站内信活动通知、运营消息消息中心 + 未读数Badge

推送架构

推送流程: ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │业务事件 │───▶│消息服务 │───▶│路由分发 │───▶│推送通道 │ │点赞/评论 │ │聚合去重 │ │用户偏好 │ │WS/Push │ └──────────┘ └──────────┘ └──────────┘ └──────────┘ // 消息去重与聚合策略 - 同一用户短时间内多次点赞同一笔记 → 合并为一条通知 - 10秒窗口内的多个新粉丝 → 聚合为"新增N个粉丝" - 用户设置的免打扰时间段 → 延迟推送 - 消息疲劳度控制 → 单日推送上限30条

3.5 分布式缓存架构

多级缓存设计

// 三级缓存架构
请求 → 本地缓存(L1) → Redis(L2) → 数据库(L3)

L1 本地缓存 (Caffeine/Guava):
- 容量: 每节点10000个Key
- 过期时间: 30秒
- 适用: 热点数据(热门笔记、大V用户信息)
- 优势: 微秒级响应,无网络开销

L2 分布式缓存 (Redis Cluster):
- 容量: TB级别
- 过期时间: 根据数据类型不同(1min~24h)
- 适用: 用户会话、Feed流、计数器、分布式锁
- 集群: 主从+哨兵 或 Redis Cluster模式

L3 数据库 (MySQL/HBase):
- 容量: 无限
- 适用: 持久化数据、冷数据
- 回源策略: 缓存未命中时查询并回填缓存

缓存一致性策略

// 采用 Cache Aside Pattern + 延迟双删
async function updateUserProfile(userId, newData) {
    // 1. 先更新数据库
    await db.update('users', userId, newData);

    // 2. 删除缓存(第一次删除)
    await redis.del(`user:${userId}`);

    // 3. 延迟双删(防止并发读导致脏数据)
    setTimeout(async () => {
        await redis.del(`user:${userId}`);
    }, 500); // 500ms后再次删除
}

// 读取时自动回填
async function getUserProfile(userId) {
    // 1. 尝试从缓存获取
    let data = await redis.get(`user:${userId}`);
    if (data) return JSON.parse(data);

    // 2. 缓存未命中,查数据库
    data = await db.query('users', { id: userId });

    // 3. 回填缓存
    await redis.setex(`user:${userId}`, 3600, JSON.stringify(data));
    return data;
}

// 防缓存击穿: 使用互斥锁
async function getUserWithLock(userId) {
    const lockKey = `lock:user:${userId}`;
    const acquired = await redis.set(lockKey, 1, 'EX', 10, 'NX');

    if (acquired) {
        try {
            // 获取到锁,查数据库并回填缓存
            const data = await db.query('users', { id: userId });
            await redis.setex(`user:${userId}`, 3600, JSON.stringify(data));
            return data;
        } finally {
            await redis.del(lockKey);
        }
    } else {
        // 未获取到锁,等待后重试
        await sleep(100);
        return redis.get(`user:${userId}`);
    }
}

🗄️ 四、数据库设计

4.1 用户表设计

核心用户表

-- 用户主表
CREATE TABLE users (
    id BIGINT PRIMARY KEY,                -- 雪花算法生成
    phone VARCHAR(20) UNIQUE,             -- 手机号(加密存储)
    email VARCHAR(100),                   -- 邮箱
    password_hash VARCHAR(255),           -- 密码哈希(bcrypt)
    nickname VARCHAR(50) NOT NULL,        -- 昵称
    avatar_url VARCHAR(500),              -- 头像URL
    bio VARCHAR(500),                     -- 个人简介
    gender TINYINT DEFAULT 0,             -- 性别: 0未知 1男 2女
    birthday DATE,                        -- 生日
    location VARCHAR(100),                -- 地区
    level TINYINT DEFAULT 1,              -- 用户等级 1-10
    verification_type TINYINT DEFAULT 0,  -- 认证类型
    status TINYINT DEFAULT 1,             -- 账号状态
    created_at TIMESTAMP DEFAULT NOW(),
    updated_at TIMESTAMP DEFAULT NOW() ON UPDATE NOW(),
    INDEX idx_phone (phone),
    INDEX idx_created (created_at)
);

-- 用户统计表(异步更新)
CREATE TABLE user_stats (
    user_id BIGINT PRIMARY KEY,
    note_count INT DEFAULT 0,             -- 发布笔记数
    follower_count INT DEFAULT 0,         -- 粉丝数
    following_count INT DEFAULT 0,        -- 关注数
    like_count INT DEFAULT 0,             -- 获赞总数
    collect_count INT DEFAULT 0,          -- 被收藏次数
    updated_at TIMESTAMP DEFAULT NOW() ON UPDATE NOW()
);

-- 用户成长值表
CREATE TABLE user_growth (
    user_id BIGINT PRIMARY KEY,
    exp_points INT DEFAULT 0,             -- 经验值
    creator_score INT DEFAULT 0,          -- 创作者分数
    badges JSON,                          -- 获得的徽章
    last_active_at TIMESTAMP              -- 最后活跃时间
);

分库分表策略

  • 分片键:user_id (雪花ID)
  • 分库数量:64个库
  • 分表数量:每库256张表
  • 路由算法:user_id % 64 → 库号,user_id / 64 % 256 → 表号
  • 中间件:ShardingSphere / MyCat

4.2 笔记内容表设计

笔记主表

-- 笔记表
CREATE TABLE notes (
    id BIGINT PRIMARY KEY,
    user_id BIGINT NOT NULL,
    title VARCHAR(200),                   -- 标题
    content TEXT,                         -- 正文内容
    type TINYINT DEFAULT 1,               -- 类型: 1图文 2视频 3直播
    cover_url VARCHAR(500),               -- 封面图
    images JSON,                          -- 图片列表[{url, width, height}]
    video_url VARCHAR(500),               -- 视频URL
    video_duration INT,                   -- 视频时长(秒)
    topics JSON,                          -- 话题标签["#美食","#探店"]
    location VARCHAR(200),                -- 发布地点
    poi_id BIGINT,                        -- POI地点ID
    status TINYINT DEFAULT 0,             -- 状态: 0审核中 1已发布 2已删除 3违规
    audit_status TINYINT DEFAULT 0,       -- 审核状态
    visibility TINYINT DEFAULT 1,         -- 可见性: 1公开 2仅粉丝 3私密
    is_top TINYINT DEFAULT 0,             -- 是否置顶
    publish_at TIMESTAMP,                 -- 发布时间
    created_at TIMESTAMP DEFAULT NOW(),
    updated_at TIMESTAMP DEFAULT NOW() ON UPDATE NOW(),
    INDEX idx_user_status (user_id, status, created_at),
    INDEX idx_publish (publish_at, status),
    FULLTEXT INDEX ft_content (title, content) -- 全文索引
);

-- 笔记统计表
CREATE TABLE note_stats (
    note_id BIGINT PRIMARY KEY,
    view_count INT DEFAULT 0,             -- 浏览量
    like_count INT DEFAULT 0,             -- 点赞数
    collect_count INT DEFAULT 0,          -- 收藏数
    comment_count INT DEFAULT 0,          -- 评论数
    share_count INT DEFAULT 0,            -- 分享数
    score DECIMAL(10,2) DEFAULT 0,        -- 综合评分
    updated_at TIMESTAMP DEFAULT NOW() ON UPDATE NOW()
);

-- 笔记标签关系表
CREATE TABLE note_tags (
    id BIGINT PRIMARY KEY,
    note_id BIGINT NOT NULL,
    tag_id BIGINT NOT NULL,
    tag_name VARCHAR(50) NOT NULL,
    INDEX idx_note (note_id),
    INDEX idx_tag (tag_id)
);

4.3 社交关系表设计

关注关系存储

-- 关注关系表
CREATE TABLE follows (
    id BIGINT PRIMARY KEY,
    follower_id BIGINT NOT NULL,          -- 关注者ID
    following_id BIGINT NOT NULL,         -- 被关注者ID
    status TINYINT DEFAULT 1,             -- 状态: 0已取消 1关注中
    group_name VARCHAR(50) DEFAULT 'default', -- 关注分组
    is_mute TINYINT DEFAULT 0,            -- 是否静音
    created_at TIMESTAMP DEFAULT NOW(),
    UNIQUE KEY uk_relation (follower_id, following_id),
    INDEX idx_following (following_id, status, created_at)
);

-- 由于社交关系数据量巨大,实际使用以下方案:
-- 1. 热数据: Redis Set存储活跃用户的关注/粉丝列表
--    followers:{user_id} -> Set[follower_ids]
--    following:{user_id} -> Set[following_ids]
-- 2. 温数据: MySQL分表存储
-- 3. 冷数据: HBase归档存储

-- 共同关注查询
-- 查询用户A和用户B的共同关注
SELECT following_id FROM follows
WHERE follower_id = A AND status = 1
INTERSECT
SELECT following_id FROM follows
WHERE follower_id = B AND status = 1;

-- 使用Redis实现:
SINTER following:A following:B

🤖 五、推荐系统设计

5.1 推荐系统整体架构

推荐系统流水线

推荐系统处理流程 (漏斗模型): 全量内容池 (数亿条笔记) │ ▼ ① 内容过滤 候选集 (~1000万条) ← 去除违规/低质/过期内容 │ ▼ ② 召回层 (Recall) 粗排集 (~10000条) ← 多路召回合并 │ ▼ ③ 粗排层 (Pre-ranking) 精排集 (~1000条) ← 轻量级模型快速打分 │ ▼ ④ 精排层 (Ranking) 最终排序 (~500条) ← 深度模型精确打分 │ ▼ ⑤ 重排层 (Re-ranking) 展示列表 (~20条) ← 多样性/新鲜度/商业化调整 │ ▼ 用户Feed流展示

核心指标

指标说明目标值
CTR (点击率)用户点击内容的概率>15%
互动率点赞/收藏/评论/分享的比例>5%
观看时长用户在内容上的停留时间>30秒(图文) / >60秒(视频)
推荐延迟从请求到返回推荐结果的耗时<200ms
多样性推荐内容的话题/类目覆盖度>8个类目

5.2 多路召回策略

召回层详细设计

召回层负责从海量内容中快速筛选出用户可能感兴趣的候选集,采用多路召回合并的策略:

召回路原理召回数量
协同过滤召回 (CF)基于相似用户的喜好推荐(User-CF / Item-CF)~2000条
内容标签召回根据用户兴趣标签匹配相关内容~1000条
热门召回全站/分类下的热门内容兜底~500条
向量召回 (DeepWalk)基于图神经网络的内容向量化匹配~2000条
实时兴趣召回根据用户最近行为实时调整~500条
关注人召回用户关注的人发布的新内容~1000条
地理位置召回附近的热门内容(同城推荐)~500条

向量召回实现

// 基于双塔模型的向量召回
// User塔: 用户特征 → 用户向量 (128维)
// Item塔: 内容特征 → 内容向量 (128维)

class TwoTowerRecall:
    def __init__(self):
        self.user_tower = DNN([256, 128])  # 用户特征编码
        self.item_tower = DNN([256, 128])  # 内容特征编码
        self.index = FaissIndex(dimension=128)  # 向量检索引擎

    def get_user_embedding(self, user_features):
        """生成用户向量"""
        return self.user_tower.forward(user_features)

    def recall(self, user_vector, top_k=2000):
        """在Faiss索引中检索最相似的内容"""
        return self.index.search(user_vector, top_k)

// Faiss索引构建 (离线)
// 将所有内容向量写入Faiss,支持毫秒级检索
// 使用 IVF(倒排文件) + PQ(乘积量化) 加速

5.3 精排模型设计

特征工程

特征类别具体特征维度
用户特征年龄、性别、城市、兴趣标签、活跃度、消费能力~100维
用户行为序列最近50条点击/搜索/浏览序列序列特征
内容特征类目、标签、文本embedding、图片质量分、时长~200维
上下文特征时间、设备、网络类型、地理位置~20维
统计特征内容CTR、互动率、完播率、曝光数~50维
交叉特征用户-类目偏好、用户-标签亲和度~100维

模型架构

// 精排模型: Deep & Cross Network + Attention
// 多目标学习: 同时预测点击/互动/停留时长

class MultiTaskRankingModel:
    def __init__(self):
        # 特征编码层
        self.dense_features = DenseEncoder()      # 连续特征
        self.sparse_features = EmbeddingLayer()    # 离散特征

        # 交叉网络 (Cross Network) - 学习特征交叉
        self.cross_net = CrossNetwork(num_layers=3)

        # 深度网络 (Deep Network) - 学习高阶特征
        self.deep_net = DNN([512, 256, 128])

        # 注意力层 - 用户行为序列建模
        self.attention = TargetAttention()

        # 多目标输出头
        self.ctr_head = DNN([64, 1])       # 点击率预测
        self.interact_head = DNN([64, 1])  # 互动率预测
        self.duration_head = DNN([64, 1])  # 停留时长预测

    def forward(self, features):
        # 特征编码
        x_dense = self.dense_features(features['dense'])
        x_sparse = self.sparse_features(features['sparse'])
        x = concat([x_dense, x_sparse])

        # 交叉+深度并行
        cross_out = self.cross_net(x)
        deep_out = self.deep_net(x)

        # 注意力机制处理行为序列
        seq_features = features['behavior_seq']
        attention_out = self.attention(seq_features, target_item)

        # 合并
        merged = concat([cross_out, deep_out, attention_out])

        # 多任务输出
        ctr_prob = sigmoid(self.ctr_head(merged))
        interact_prob = sigmoid(self.interact_head(merged))
        duration_pred = self.duration_head(merged)

        return ctr_prob, interact_prob, duration_pred

// 融合打分公式
final_score = α * ctr_prob + β * interact_prob + γ * normalize(duration_pred)
其中 α, β, γ 为可调节权重,用于平衡不同目标

5.4 用户画像构建

用户画像层次

  • 基础属性:年龄、性别、城市、设备类型
  • 行为偏好:浏览/点赞/收藏/搜索的类目分布
  • 兴趣标签:通过行为挖掘的长期兴趣+短期兴趣
  • 消费能力:基于浏览和购买行为推断
  • 社交属性:社交活跃度、圈子特征

兴趣标签体系

// 三级兴趣标签体系
{
  "长期兴趣": {
    "美妆护肤": {"权重": 0.85, "更新时间": "2024-01-15"},
    "穿搭时尚": {"权重": 0.72, "更新时间": "2024-01-14"},
    "健身运动": {"权重": 0.45, "更新时间": "2024-01-10"}
  },
  "短期兴趣": {
    "三亚旅行": {"权重": 0.90, "衰减时间": "3天"},
    "日式料理": {"权重": 0.65, "衰减时间": "7天"}
  },
  "实时兴趣": {
    "今日浏览类目": ["家居", "母婴"],
    "最近搜索词": ["宝宝辅食", "婴儿床"]
  }
}

// 兴趣权重更新公式 (时间衰减)
weight(t) = weight(0) * e^(-λ * t)
其中:
- weight(0): 初始权重
- λ: 衰减系数(短期兴趣衰减快,长期兴趣衰减慢)
- t: 距离上次行为的时间

📝 六、开发教程

6.1 项目初始化教程

环境准备

# 1. 安装基础环境
# Node.js >= 18.x
curl -fsSL https://deb.nodesource.com/setup_18.x | sudo -E bash -
sudo apt-get install -y nodejs

# Go >= 1.21
wget https://go.dev/dl/go1.21.0.linux-amd64.tar.gz
sudo tar -C /usr/local -xzf go1.21.0.linux-amd64.tar.gz
export PATH=$PATH:/usr/local/go/bin

# Java 17 (OpenJDK)
sudo apt install openjdk-17-jdk

# Docker & Docker Compose
curl -fsSL https://get.docker.com | sh
sudo apt install docker-compose

# 2. 克隆项目
git clone https://github.com/xhs-lab/xiaohongshu-clone.git
cd xiaohongshu-clone

# 3. 安装依赖
# Go微服务
cd services/ && go mod download

# 前端项目
cd web/ && npm install

# 4. 启动依赖服务 (Docker Compose)
docker-compose up -d redis mysql kafka elasticsearch

项目目录结构

xiaohongshu-clone/
├── api/                    # API定义 (Protobuf/OpenAPI)
├── services/               # 微服务代码
│   ├── user-service/       # 用户服务 (Go)
│   ├── note-service/       # 笔记服务 (Java)
│   ├── feed-service/       # 信息流服务 (Go)
│   ├── recommend-service/  # 推荐服务 (Python)
│   └── search-service/     # 搜索服务 (Java)
├── web/                    # 前端项目
│   ├── app/               # React Native App
│   └── admin/             # 管理后台 (Vue3)
├── deploy/                 # 部署配置
│   ├── k8s/               # Kubernetes配置
│   └── docker/            # Docker配置
├── docs/                   # 文档
└── scripts/                # 脚本工具

6.2 笔记发布接口开发教程

API设计 (RESTful)

// 发布笔记接口
POST /api/v1/notes
Content-Type: multipart/form-data
Authorization: Bearer {token}

Request Body:
{
  "title": "今日穿搭分享",
  "content": "今天尝试了法式穿搭...",
  "images": [file1, file2, file3],      // 最多9张图
  "topics": ["#穿搭", "#日常"],
  "location": "上海静安",
  "visibility": 1                        // 1公开 2仅粉丝 3私密
}

Response (201 Created):
{
  "code": 0,
  "data": {
    "note_id": "6501234567890",
    "status": "published",
    "cover_url": "https://cdn.xhs.com/...",
    "created_at": "2024-01-15T10:30:00Z"
  }
}

后端实现 (Go)

// note-service/handler/note_handler.go
func (h *NoteHandler) CreateNote(c *gin.Context) {
    // 1. 参数解析
    userID := c.GetInt64("user_id")  // 从JWT中获取
    title := c.PostForm("title")
    content := c.PostForm("content")
    topics := c.PostFormArray("topics")
    location := c.PostForm("location")

    // 2. 参数校验
    if title == "" || len(title) > 200 {
        c.JSON(400, gin.H{"code": 40001, "msg": "标题不合法"})
        return
    }

    // 3. 图片上传到OSS
    images := make([]ImageInfo, 0)
    form, _ := c.MultipartForm()
    files := form.File["images"]
    for _, file := range files {
        url, err := h.ossClient.Upload(file)
        if err != nil {
            c.JSON(500, gin.H{"code": 50001, "msg": "图片上传失败"})
            return
        }
        images = append(images, ImageInfo{
            URL: url,
            Width: getImgWidth(file),
            Height: getImgHeight(file),
        })
    }

    // 4. 内容安全审核
    auditResult := h.contentAudit(title + content, images)
    if !auditResult.Passed {
        c.JSON(400, gin.H{"code": 40002, "msg": "内容包含违规信息"})
        return
    }

    // 5. 生成笔记ID (雪花算法)
    noteID := snowflake.Generate()

    // 6. 写入数据库
    note := &Note{
        ID:      noteID,
        UserID:  userID,
        Title:   title,
        Content: content,
        Images:  images,
        Topics:  topics,
        Location: location,
        Status:  StatusPublished,
        CreatedAt: time.Now(),
    }
    if err := h.noteRepo.Create(note); err != nil {
        c.JSON(500, gin.H{"code": 50002, "msg": "创建笔记失败"})
        return
    }

    // 7. 发送Kafka事件(异步处理后续逻辑)
    h.kafkaProducer.Send("note_created", map[string]interface{}{
        "note_id": noteID,
        "user_id": userID,
        "topics": topics,
        "created_at": time.Now().Unix(),
    })

    // 8. 返回结果
    c.JSON(201, gin.H{
        "code": 0,
        "data": map[string]interface{}{
            "note_id":    noteID,
            "status":     "published",
            "cover_url":  images[0].URL,
            "created_at": note.CreatedAt,
        },
    })
}

// Kafka消费者处理后续逻辑
// - 更新用户笔记数统计
// - 推送给粉丝的Feed流
// - 构建搜索索引
// - 触发推荐模型更新用户画像

6.3 信息流拉取接口教程

Feed流分页拉取

// 获取首页信息流
GET /api/v1/feed?cursor=1699900000000&limit=20&source=discover
Authorization: Bearer {token}

// 响应
{
  "code": 0,
  "data": {
    "notes": [
      {
        "id": "6501234567890",
        "title": "今日穿搭",
        "cover": {"url": "...", "width": 540, "height": 720},
        "author": {"id": "user_456", "name": "时尚达人", "avatar": "..."},
        "stats": {"likes": 1520, "comments": 89},
        "type": "image"
      }
    ],
    "has_more": true,
    "next_cursor": 1699800000000
  }
}

// 后端实现
func (h *FeedHandler) GetFeed(c *gin.Context) {
    userID := c.GetInt64("user_id")
    cursor := c.GetInt64("cursor")
    limit := c.GetInt("limit")
    source := c.GetString("source")

    var notes []*NoteBrief

    if source == "following" {
        // 关注Feed: 按时间倒序拉取关注人的内容
        followingIDs := h.socialService.GetFollowingList(userID)
        notes = h.feedService.GetFollowingFeed(followingIDs, cursor, limit)
    } else {
        // 发现Feed: 个性化推荐
        notes = h.recommendService.GetRecommendFeed(userID, cursor, limit)
    }

    // 构建响应
    hasMore := len(notes) == limit
    var nextCursor int64
    if hasMore && len(notes) > 0 {
        nextCursor = notes[len(notes)-1].SortScore
    }

    c.JSON(200, gin.H{
        "code": 0,
        "data": gin.H{
            "notes":       notes,
            "has_more":    hasMore,
            "next_cursor": nextCursor,
        },
    })
}

6.4 实时搜索实现教程

Elasticsearch索引设计

// 笔记搜索索引Mapping
PUT /notes_index
{
  "settings": {
    "number_of_shards": 5,
    "number_of_replicas": 1,
    "analysis": {
      "analyzer": {
        "xhs_analyzer": {
          "type": "custom",
          "tokenizer": "ik_max_word",
          "filter": ["lowercase", "xhs_synonym", "xhs_stop"]
        }
      }
    }
  },
  "mappings": {
    "properties": {
      "note_id": {"type": "long"},
      "title": {
        "type": "text",
        "analyzer": "xhs_analyzer",
        "boost": 3
      },
      "content": {
        "type": "text",
        "analyzer": "xhs_analyzer"
      },
      "tags": {"type": "keyword"},
      "user_id": {"type": "long"},
      "category": {"type": "keyword"},
      "like_count": {"type": "integer"},
      "score": {"type": "float"},
      "publish_time": {"type": "date"},
      "images": {
        "type": "nested",
        "properties": {
          "url": {"type": "keyword"},
          "width": {"type": "integer"},
          "height": {"type": "integer"}
        }
      }
    }
  }
}

// 搜索查询构建
func (s *SearchService) Search(query SearchRequest) (*SearchResult, error) {
    // 构建ES查询
    boolQuery := elastic.NewBoolQuery()

    // 关键词匹配
    if query.Keyword != "" {
        multiMatch := elastic.NewMultiMatchQuery(query.Keyword, "title^3", "content", "tags^2")
        boolQuery.Must(multiMatch)
    }

    // 类目过滤
    if query.Category != "" {
        boolQuery.Filter(elastic.NewTermQuery("category", query.Category))
    }

    // 时间范围
    if query.Since > 0 {
        boolQuery.Filter(elastic.NewRangeQuery("publish_time").Gte(query.Since))
    }

    // 排序策略
    var sorters []elastic.Sorter
    switch query.SortBy {
    case "hot":
        sorters = append(sorters, elastic.NewFieldSort("score").Desc())
    case "newest":
        sorters = append(sorters, elastic.NewFieldSort("publish_time").Desc())
    default:
        sorters = append(sorters, elastic.NewScoreSort().Desc())
    }

    // 执行搜索
    result, err := s.esClient.Search().
        Index("notes_index").
        Query(boolQuery).
        SortBy(sorters...).
        From(query.Offset).
        Size(query.Limit).
        Do(context.Background())

    return parseResult(result), err
}

6.5 图片处理服务教程

图片处理流水线

// 图片处理服务 (Go)
type ImageProcessor struct {
    oss     *OSSClient
    cdn     *CDNClient
}

func (p *ImageProcessor) ProcessImage(file multipart.File, filename string) (*ImageResult, error) {
    // 1. 安全检测
    if err := p.checkImageSafety(file); err != nil {
        return nil, fmt.Errorf("图片安全检查不通过: %w", err)
    }

    // 2. 生成多种尺寸
    sizes := []struct {
        name   string
        width  int
        height int
        quality int
    }{
        {"thumbnail", 200, 200, 75},    // 缩略图
        {"small", 480, 0, 80},          // 小图
        {"medium", 720, 0, 85},         // 中图
        {"large", 1080, 0, 90},         // 大图
        {"original", 0, 0, 100},        // 原图
    }

    result := &ImageResult{URLs: make(map[string]string)}
    hash := md5Hash(file) // 内容哈希用于去重

    for _, size := range sizes {
        // 3. 图片压缩和缩放
        processed, err := p.resizeImage(file, size.width, size.height, size.quality)
        if err != nil {
            return nil, err
        }

        // 4. WebP转换 (体积更小)
        webpData, err := p.convertToWebP(processed)
        if err != nil {
            webpData = processed // 降级使用原始格式
        }

        // 5. 上传到OSS
        objectKey := fmt.Sprintf("notes/%s/%s_%s.webp", getDate(), hash, size.name)
        url, err := p.oss.Upload(objectKey, webpData)
        if err != nil {
            return nil, err
        }
        result.URLs[size.name] = url
    }

    // 6. 图片信息提取
    result.Width, result.Height = getImageDimensions(file)
    result.Format = "webp"
    result.Size = fileSize(webpData)

    // 7. CDN预热
    p.cdn.Prefetch(result.URLs["medium"])

    return result, nil
}

// 图片去重 (感知哈希)
func (p *ImageProcessor) CheckDuplicate(imageData []byte) (bool, string) {
    // 计算感知哈希(pHash),相似的图会有相近的哈希
    phash := perceptualhash.Compute(imageData)

    // 查询是否有相似图片
    existing := p.duplicateDB.FindSimilar(phash, threshold=10)
    if existing != nil {
        return true, existing.NoteID
    }
    return false, ""
}

🚀 七、部署与运维

7.1 Kubernetes部署方案

集群规划

集群节点数规格用途
Master集群3 (高可用)8C16G SSDK8s控制面
业务集群200+16C64G NVMe微服务部署
大数据集群50+32C128GSpark/Flink计算
中间件集群30+16C64GRedis/Kafka/ES

Deployment配置示例

# note-service deployment
apiVersion: apps/v1
kind: Deployment
metadata:
  name: note-service
  namespace: xhs-production
  labels:
    app: note-service
spec:
  replicas: 50
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxSurge: 25%
      maxUnavailable: 0
  selector:
    matchLabels:
      app: note-service
  template:
    metadata:
      labels:
        app: note-service
    spec:
      containers:
      - name: note-service
        image: registry.xhs.com/note-service:v2.3.1
        ports:
        - containerPort: 8080
        resources:
          requests:
            cpu: "2"
            memory: "4Gi"
          limits:
            cpu: "4"
            memory: "8Gi"
        livenessProbe:
          httpGet:
            path: /health
            port: 8080
          initialDelaySeconds: 15
          periodSeconds: 10
        readinessProbe:
          httpGet:
            path: /ready
            port: 8080
          initialDelaySeconds: 5
          periodSeconds: 5
        env:
        - name: DB_HOST
          valueFrom:
            secretKeyRef:
              name: db-credentials
              key: host
        - name: REDIS_CLUSTER
          value: "redis-cluster.xhs-infra:6379"
      affinity:
        podAntiAffinity:
          preferredDuringSchedulingIgnoredDuringExecution:
          - weight: 100
            podAffinityTerm:
              labelSelector:
                matchExpressions:
                - key: app
                  operator: In
                  values:
                  - note-service
              topologyKey: kubernetes.io/hostname

HPA自动伸缩

apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: note-service-hpa
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: note-service
  minReplicas: 20
  maxReplicas: 200
  metrics:
  - type: Resource
    resource:
      name: cpu
      target:
        type: Utilization
        averageUtilization: 70
  - type: Resource
    resource:
      name: memory
      target:
        type: Utilization
        averageUtilization: 80
  - type: Pods
    pods:
      metric:
        name: http_requests_per_second
      target:
        type: AverageValue
        averageValue: "1000"

7.2 CI/CD流水线设计

GitOps工作流

CI/CD流程: 开发者Push代码 → GitLab/ GitHub │ ▼ ┌─────────────────┐ │ 代码质量检查 │ → Lint + 单元测试 + 安全扫描 │ (Pre-merge CI) │ → 覆盖率>80%才允许合并 └─────────────────┘ │ 合并到main ▼ ┌─────────────────┐ │ 构建镜像 │ → Docker build + Push to Registry │ (Build Stage) │ → 生成版本号 (semver) └─────────────────┘ │ ▼ ┌─────────────────┐ │ 部署到Staging │ → 自动部署到测试环境 │ (Staging) │ → 自动化测试 + 性能测试 └─────────────────┘ │ 测试通过 ▼ ┌─────────────────┐ │ 灰度发布 │ → 先发布10%流量 │ (Canary) │ → 监控指标无异常则扩量 └─────────────────┘ │ ▼ ┌─────────────────┐ │ 全量发布 │ → 滚动更新所有实例 │ (Production) │ → 自动回滚机制保护 └─────────────────┘

GitLab CI配置

# .gitlab-ci.yml
stages:
  - lint
  - test
  - build
  - deploy-staging
  - deploy-production

variables:
  DOCKER_REGISTRY: registry.xhs.com
  IMAGE_NAME: $DOCKER_REGISTRY/note-service

lint:
  stage: lint
  image: golangci/golangci-lint:latest
  script:
    - golangci-lint run ./...

unit-test:
  stage: test
  image: golang:1.21
  script:
    - go test -race -coverprofile=coverage.out ./...
  coverage: '/total:\s+\(statements\)\s+(\d+\.\d+)%/'
  artifacts:
    reports:
      coverage_report:
        coverage_format: cobertura
        path: coverage.xml

build:
  stage: build
  image: docker:latest
  services:
    - docker:dind
  script:
    - docker build -t $IMAGE_NAME:$CI_COMMIT_SHA .
    - docker push $IMAGE_NAME:$CI_COMMIT_SHA
    - docker tag $IMAGE_NAME:$CI_COMMIT_SHA $IMAGE_NAME:latest
    - docker push $IMAGE_NAME:latest

deploy-staging:
  stage: deploy-staging
  image: bitnami/kubectl:latest
  script:
    - kubectl set image deployment/note-service note-service=$IMAGE_NAME:$CI_COMMIT_SHA -n staging
    - kubectl rollout status deployment/note-service -n staging --timeout=300s
  environment:
    name: staging
    url: https://staging.xhs.com
  only:
    - main

deploy-production:
  stage: deploy-production
  image: bitnami/kubectl:latest
  script:
    - kubectl set image deployment/note-service note-service=$IMAGE_NAME:$CI_COMMIT_SHA -n production
    - kubectl rollout status deployment/note-service -n production --timeout=600s
  environment:
    name: production
    url: https://www.xiaohongshu.com
  when: manual  # 生产环境手动触发
  only:
    - tags

7.3 监控告警体系

监控四层模型

层次监控内容工具
基础设施层CPU/内存/磁盘/网络Prometheus + Node Exporter
容器层Pod状态/资源使用/重启次数cAdvisor + kube-state-metrics
应用层QPS/延迟/错误率/饱和度APM (Jaeger/SkyWalking)
业务层DAU/发布量/互动率/GMV自研BI平台 + ClickHouse

核心告警规则

# Prometheus告警规则
groups:
- name: xhs-alerts
  rules:
  # 接口错误率告警
  - alert: HighErrorRate
    expr: |
      sum(rate(http_requests_total{status=~"5.."}[5m])) by (service)
      /
      sum(rate(http_requests_total[5m])) by (service) > 0.05
    for: 3m
    labels:
      severity: critical
    annotations:
      summary: "{{ $labels.service }} 错误率超过5%"

  # 响应延迟告警
  - alert: HighLatency
    expr: |
      histogram_quantile(0.99,
        sum(rate(http_request_duration_seconds_bucket[5m])) by (le, service)
      ) > 2
    for: 5m
    labels:
      severity: warning
    annotations:
      summary: "{{ $labels.service }} P99延迟超过2秒"

  # Pod重启告警
  - alert: PodCrashLoop
    expr: increase(kube_pod_container_status_restarts_total[1h]) > 5
    for: 1m
    labels:
      severity: critical
    annotations:
      summary: "Pod {{ $labels.pod }} 频繁重启"

  # 数据库连接池告警
  - alert: DBConnectionPoolExhausted
    expr: db_pool_active / db_pool_max > 0.85
    for: 2m
    labels:
      severity: warning
    annotations:
      summary: "{{ $labels.service }} 数据库连接池使用率超过85%"

7.4 容灾与高可用方案

多活架构

多活部署方案: ┌─────────────────────────────────────────────┐ │ 全局DNS调度 │ │ (基于地理位置的智能路由) │ └─────────────────────────────────────────────┘ │ │ ┌────▼────┐ ┌───▼─────┐ │ 华东机房 │ │ 华北机房 │ │ (主活) │◀────────▶│ (主活) │ │ 上海 │ 数据同步 │ 北京 │ └────┬────┘ └───┬─────┘ │ │ ┌────▼────┐ ┌───▼─────┐ │ 华南机房 │ │ 西南机房 │ │ (热备) │ │ (冷备) │ │ 广州 │ │ 成都 │ └─────────┘ └─────────┘ 容灾切换: - 正常情况: 用户就近接入 - 机房故障: DNS自动切换到备用机房 (< 30秒) - 数据同步: MySQL主从 + Redis跨机房复制 + Kafka Mirror

故障演练方案

  • 混沌工程:定期注入故障(宕机、网络延迟、磁盘满)
  • 全链路压测:每月进行生产环境全链路压测
  • 红蓝对抗:安全团队定期进行攻防演练
  • 应急预案:每个核心服务都有详细的应急SOP

7.5 安全防护体系

安全防护层次

层次防护措施实现方式
网络层DDoS防护、WAF、IP黑白名单云安全中心 + 自研规则引擎
传输层HTTPS/TLS1.3、证书管理Let's Encrypt + 自研证书管理平台
应用层SQL注入/XSS防护、参数加密ORM参数化 + CSP + 请求签名
数据层敏感数据加密、脱敏展示AES-256加密 + 动态脱敏
用户层风控系统、反作弊、账号安全规则引擎 + 机器学习模型

接口安全设计

// 请求签名防篡改
class RequestSigner {
    static sign(params, secret) {
        // 1. 参数排序
        const sortedParams = Object.keys(params).sort()
            .map(key => `${key}=${params[key]}`)
            .join('&');

        // 2. 拼接密钥
        const signStr = sortedParams + '&key=' + secret;

        // 3. HMAC-SHA256签名
        return crypto
            .createHmac('sha256', secret)
            .update(signStr)
            .digest('hex');
    }
}

// 客户端请求携带签名
{
    "user_id": 12345,
    "timestamp": 1699900000,
    "nonce": "random_string",
    "sign": "a1b2c3d4..."  // 服务端验签
}

// 防重放攻击
// 1. timestamp检查: 请求时间不能超过当前时间5分钟
// 2. nonce检查: Redis存储已使用的nonce,防止重放
// 3. sign验证: 确保请求未被篡改
← 返回IT 技术 yicool 百科 · 小红书软件设计架构、教程及详细说明

评论 0