Echo Server:压测、索引、Redis 与限流

第六阶段:从普通 CRUD 项目升级成有高并发意识的社区后端项目

wrk索引优化Redis限流

0. 阶段定位

这一阶段不是盲目加 Redis,而是先压测、再分析 SQL、再消除 N+1、最后对热点接口做缓存和限流。

项目说明
建议位置精选作品详情页 / 项目文档页
统一风格左侧导航、右侧正文、表格说明、折叠代码块、阶段总结。
阅读顺序建议从总览页进入,再按卡片顺序阅读。

1. wrk 压测脚本

用相同并发参数压测最新帖子、用户主页、帖子详情,记录吞吐和延迟。

#!/bin/bash
BASE_URL="http://127.0.0.1:8080"

echo "压测最新帖子列表"
wrk -t4 -c100 -d30s -L "$BASE_URL/api/posts/latest?page=1&page_size=20"

echo "压测用户主页"
wrk -t4 -c100 -d30s -L "$BASE_URL/api/users/home?user_id=1&page=1&page_size=10"

echo "压测帖子详情"
wrk -t4 -c100 -d30s -L "$BASE_URL/api/posts/detail?post_id=1"

2. 索引优化

围绕 where、join、order by、group by 建索引,让列表和统计查询减少扫描。

ALTER TABLE posts ADD INDEX idx_posts_id_desc (id);
ALTER TABLE posts ADD INDEX idx_posts_user_id_id (user_id, id);
ALTER TABLE comments ADD INDEX idx_comments_post_id_id (post_id, id);
ALTER TABLE post_likes ADD UNIQUE KEY uk_post_user (post_id, user_id);
ALTER TABLE post_likes ADD INDEX idx_likes_user_id_post_id (user_id, post_id);

EXPLAIN SELECT * FROM posts ORDER BY id DESC LIMIT 20;

3. N+1 查询改造

把循环查作者、点赞数、评论数的逻辑改为 JOIN + 聚合。

SELECT
  p.id,
  p.user_id,
  u.username,
  COALESCE(u.nickname, '') AS nickname,
  COALESCE(p.image_url, '') AS image_url,
  p.content,
  COALESCE(lc.like_count, 0) AS like_count,
  COALESCE(cc.comment_count, 0) AS comment_count,
  CASE WHEN pl_me.user_id IS NULL THEN 0 ELSE 1 END AS liked
FROM posts p
JOIN users u ON u.id = p.user_id
LEFT JOIN post_likes pl_me
  ON pl_me.post_id = p.id AND pl_me.user_id = ?
LEFT JOIN (
  SELECT post_id, COUNT(*) AS like_count FROM post_likes GROUP BY post_id
) lc ON lc.post_id = p.id
LEFT JOIN (
  SELECT post_id, COUNT(*) AS comment_count FROM comments GROUP BY post_id
) cc ON cc.post_id = p.id
ORDER BY p.id DESC
LIMIT ? OFFSET ?;

4. Redis 缓存与限流

先缓存用户资料和帖子详情,再做热点 key 与限流,为后续点赞 Redis 化和异步落库做准备。

缓存 key 建议:
user:profile:{user_id}      -> 用户资料
post:detail:{post_id}       -> 帖子详情
rate:ip:{ip}:{minute}       -> IP 限流计数
rate:user:{user_id}:{minute}-> 登录用户限流计数

读帖子详情流程:
1. 先 GET post:detail:{post_id}
2. 命中则直接返回
3. 未命中查 MySQL
4. SETEX post:detail:{post_id} 60 JSON

写帖子或删帖子后:
删除相关缓存,避免旧数据继续返回。