项目优化
我已经完全理解目前各个企业的hr或者项目组成员看着下面这份千篇一律的hmdp优化版简历已经头都麻了 完全挑不出来到底该面谁然后只能挑学历高的面。
在经过思考之后我感觉我的简历可以继续有几个优化点 然后能告诉他们 我更有一点点点点自己的思考 然后约面我 ;w; 我没招了 只感觉上不去下不来
本文优化项目后续会放到GitHub上,其实我也是依靠他人的基础继续优化。不过大家继续学习都是一样的,重点是有没有继续深挖的想法和思考业务的过程。

诚然 这一版hmdp确实是比一开始的好了很多:引入消息队列,拥抱llm和ai等的确是提升,但是大半年前够看的东西,再加上很多人直接照搬,直接让他成为了新版本的“基础”,也就是千篇一律。
实际上该项目可以往美团应用的方向去想,在实际的生产环境的业务中我们还需要什么?还可以加什么?如果这是现在项目的base,我能通过什么去优化来脱颖而出?
那我们要对这个项目动刀子了
关于一键部署
首先第一步,连一键部署都没有,在这边一个一个启动是在劝退人吗
站在用户角度看:
一个 web 应用如果连一键部署都没有,尤其还面向个人开发者、开源社区、小团队,那确实会显得有点难绷。不是技术不行,而是产品化意识不够。
因为很多人看项目,不只看它能不能跑,还看:
- 能不能快速跑起来
- 出错后好不好排查
- 新手会不会被环境折磨死
- 部署流程是不是可复制
写了个很牛的系统,结果部署要手配 Nginx、手改 env、手建数据库、手跑迁移、手配 HTTPS、手处理跨域……那别人第一反应往往不是“这个项目真强”,而是
我为什么要给自己找罪受?;w;
那总之我们先整一个docker-compose.yml 这样才知道我做的是个产品 部署的中间也发现原项目的一点磕磕绊绊的问题 之后我会在理解好系统架构后继续学习k8s 在这里想到的面试题及一些简单操作命令放到最后。
services:
mysql:
image: mysql:8.0
container_name: hmdp-mysql
environment:
MYSQL_ROOT_PASSWORD: root
TZ: Asia/Shanghai
ports:
- "3306:3306"
volumes:
- mysql-data:/var/lib/mysql
- ./sql:/docker-entrypoint-initdb.d:ro
command:
- --default-authentication-plugin=mysql_native_password
- --character-set-server=utf8mb4
- --collation-server=utf8mb4_unicode_ci
healthcheck:
test: ["CMD", "mysqladmin", "ping", "-h", "127.0.0.1", "-proot"]
interval: 10s
timeout: 5s
retries: 20
redis:
image: redis:7-alpine
container_name: hmdp-redis
ports:
- "6379:6379"
volumes:
- redis-data:/data
command: ["redis-server", "--appendonly", "yes"]
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 10s
timeout: 3s
retries: 20
kafka:
image: apache/kafka:3.7.0
container_name: hmdp-kafka
ports:
- "9092:9092"
environment:
KAFKA_NODE_ID: 1
KAFKA_PROCESS_ROLES: broker,controller
KAFKA_LISTENERS: PLAINTEXT://:9092,CONTROLLER://:9093
KAFKA_ADVERTISED_LISTENERS: PLAINTEXT://kafka:9092
KAFKA_CONTROLLER_LISTENER_NAMES: CONTROLLER
KAFKA_LISTENER_SECURITY_PROTOCOL_MAP: CONTROLLER:PLAINTEXT,PLAINTEXT:PLAINTEXT
KAFKA_CONTROLLER_QUORUM_VOTERS: 1@kafka:9093
KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR: 1
KAFKA_TRANSACTION_STATE_LOG_REPLICATION_FACTOR: 1
KAFKA_TRANSACTION_STATE_LOG_MIN_ISR: 1
KAFKA_GROUP_INITIAL_REBALANCE_DELAY_MS: 0
KAFKA_AUTO_CREATE_TOPICS_ENABLE: "true"
volumes:
- kafka-data:/var/lib/kafka/data
backend:
build:
context: .
dockerfile: docker/backend.Dockerfile
container_name: hmdp-backend
depends_on:
mysql:
condition: service_healthy
redis:
condition: service_healthy
kafka:
condition: service_started
environment:
SPRING_PROFILES_ACTIVE: docker
HMDP_IMAGE_UPLOAD_DIR: /app/data/imgs
TZ: Asia/Shanghai
ports:
- "8085:8085"
frontend:
build:
context: .
dockerfile: docker/frontend.Dockerfile
container_name: hmdp-frontend
depends_on:
backend:
condition: service_started
ports:
- "5173:80"
volumes:
mysql-data:
redis-data:
kafka-data:
关于分库分表
我感觉在这种业务之下,真实的数据量绝对是巨额的。那我们可以选择分库分表来避免一张表、一个库膨胀到一个不可观的大小。进一步说,分库分表的核心目的不只是“把数据拆开”,而是从容量和性能两个层面一起做治理。
首先是容量问题。像订单、用户、优惠券、秒杀记录这类核心业务表,随着时间增长会持续累积,单表一旦达到千万级、上亿级,索引体积会非常大,查询和写入都会越来越重,单机磁盘、内存、IO 压力也会被持续放大。把数据拆到多个库、多个表后,单库单表的数据规模就能被控制在更合理的范围内。
其次是性能问题。单表过大时,即使 SQL 本身写得没问题,也可能因为索引层级变深、热点页竞争严重、锁冲突增多,导致查询延迟和写入吞吐明显下降。通过水平分片,可以把压力打散到不同库表甚至不同机器上,让系统整体吞吐能力提升。
再往业务层看,分库分表通常不是随便拆,而是围绕访问模式设计分片键。比如按 user_id 分库,适合“按用户查订单”这种高频场景;按 voucher_id 分表,可以进一步分散券维度的并发热点。也就是说,分片规则本质上是在“数据分布均衡”和“核心查询路径命中效率”之间找平衡。
不过分库分表也不是没有代价。它会带来跨分片查询复杂、分页和聚合成本上升、扩容迁移困难、分片键一旦选错很难调整等问题。所以实际落地时,一般是当单库单表已经逼近容量或性能瓶颈,或者业务增长非常明确时,才会引入像 ShardingSphere 这样的中间件来统一管理逻辑表和真实库表映射。
而我目前为了学习已经引入了 ShardingSphere 这个中间件。它的好处在于,我不需要在业务代码里手动判断“这条数据该落哪个库、哪张表”,而是把分片规则统一配置在中间件层,由它在 JDBC 层完成路由、改写和执行。
具体来说,业务代码看到的仍然是逻辑表,比如 tb_user、tb_seckill_voucher、tb_voucher_order,开发方式和单库单表时基本一致;但在底层,ShardingSphere 会根据我配置的分库键、分表键和分片算法,把 SQL 自动路由到真实的库表,比如 hmdp_0.tb_voucher_order_0 或 hmdp_1.tb_voucher_order_1。这样做的优势是业务侵入性比较低,后续如果要调整分片规则,也主要是在配置层和数据层处理,而不是把大量分片逻辑散落在代码里。
在我这个项目里,它承担的核心职责主要有三块。第一是数据源统一管理,我把多个真实数据源交给它托管;第二是逻辑表到真实表的映射,比如配置实际节点 ds_${0..1}.tb_xxx_${0..1};第三是分片算法执行,比如对 ID 做取模、对手机号做哈希取模等。这样在应用层写 MyBatis 或 MyBatis-Plus 的时候,还是正常查逻辑表,中间件会把 SQL 自动展开成真实 SQL。
我引入它也是想更系统地理解分库分表在真实项目里的落地方式,而不是只停留在概念层。因为只会说“可以按用户 ID 取模分库”其实还不够,真正落地时还要考虑逻辑表和真实表的映射、分片键怎么选、广播表怎么处理、跨分片查询会发生什么、以及启动和运维阶段如何验证真实 SQL 是否路由正确。ShardingSphere 正好能把这些问题都串起来。
我感觉最有说法的就是在秒杀券这边,存订单逻辑的时候 用user_id来分库,用order_id来分表。前者保证根据用户查订单的时候不会打偏,减少跨库开销;后者保证查order的时候把数据打散,请求不会打在一张表,很有意思。这个设计体现的是:分片规则应该围绕业务访问路径和数据分布特征来定,而不是只看某个字段好不好取模。
关于简历描述
我去了你总不能改都不改直接照搬吧 那我第一个pass的就是你(没错就是我)
经历了STAR法则的修改之后 把简历搓出来了一点感觉 并且尽量缩减到一页 接下来要把我的blog塞进简历里了 不知道面试官看到这么多答辩是什么心情。。。
后续改进
直接尝试学习并且上es和优化llm这边的东西,会的多一点也没问题 坚持慢慢学习就好。
感觉本文内可以问的面试题 回答是GPT-5.4
Docker 的核心概念有哪些?
核心概念主要有四个:
- Image:镜像,应用运行模板
- Container:容器,镜像的运行实例
- Volume:数据卷,用来持久化数据
- Network:网络,用来让容器之间通信
镜像和容器有什么区别?
镜像是静态模板,容器是镜像启动后的运行实例。
- 镜像不变,类似只读模板
- 容器是运行态,有自己的进程、网络、可写层
- 一个镜像可以启动多个容器
Docker 怎么实现隔离?
答:
底层主要依赖 Linux 的 Namespace 和 Cgroups。
- Namespace 做资源隔离,比如进程、网络、挂载点
- Cgroups 做资源限制,比如 CPU、内存
- UnionFS 提供分层文件系统
Docker 容器之间怎么通信?
同一个 Docker network 下的容器可以通过服务名直接访问。
比如 Compose 里:
- 后端访问 MySQL 可以直接用 mysql (3306)
- 访问 Redis 可以用 redis (6379)
因为 Compose 会自动创建网络并提供服务名解析。
Docker 容器退出了,怎么排查?
一般按这个顺序:
- 看容器状态:docker ps -a
- 看日志:docker logs
- 看 Compose 日志:docker compose logs
- 看环境变量、端口、挂载、依赖服务是否正常
- 判断是应用异常、配置异常,还是中间件没起来
你在项目里是怎么用 Docker 的?
该项目用 Docker Compose 把 MySQL、Redis、消息队列、后端、前端一起编排起来。数据库数据目录挂 volume 保证持久化,后端通过服务名访问中间件,配合 healthcheck 保证依赖就绪后再启动应用。这样本地开发、测试环境和部署环境的一致性更好。
Docker常用命令
镜像相关
docker images
查看本地镜像
docker build -t myapp:latest .
根据当前目录 Dockerfile 构建镜像
docker rmi myapp:latest
删除镜像
docker pull nginx
拉取镜像
docker push myrepo/myapp:latest
推送镜像到仓库
容器相关
docker ps
查看运行中的容器
docker ps -a
查看所有容器,包括已退出的
docker run -d --name my-nginx -p 8080:80 nginx
后台启动一个容器并映射端口
docker stop my-nginx
停止容器
docker start my-nginx
启动已存在的容器
docker restart my-nginx
重启容器
docker rm my-nginx
删除容器
docker logs my-nginx
查看容器日志
docker logs -f my-nginx
持续跟踪容器日志
docker exec -it my-nginx sh
进入容器终端
数据卷相关
docker volume ls
查看 volume 列表
docker volume inspect mysql-data
查看某个 volume 详情
docker volume rm mysql-data
删除 volume
网络相关
docker network ls
查看网络
docker network inspect bridge
查看某个网络详情
系统清理相关
docker system df
查看 Docker 占用空间
docker system prune
清理未使用的资源
docker system prune -a
清理更多无用镜像和资源
Compose 相关
docker compose up
启动服务
docker compose up -d
后台启动服务
docker compose up --build
启动前先重新构建镜像
docker compose down
停止并删除容器、网络
docker compose down -v
停止并删除容器、网络、volume
docker compose stop
停止服务但不删除容器
docker compose start
启动已存在的服务容器
docker compose restart
重启服务
docker compose ps
查看 Compose 服务状态
docker compose logs
查看所有服务日志
docker compose logs -f backend
持续查看某个服务日志
docker compose exec mysql mysql -uroot -p
进入某个服务容器并执行命令
这几个最值得背
开发里最常用的一般是:
docker psdocker logs -f <container>docker exec -it <container> shdocker build -t xxx .docker compose up -ddocker compose up --builddocker compose downdocker compose down -vdocker compose psdocker compose logs -f <service>
(以下为自己感悟)
个人感觉哈,在我使用的过程中最常用的肯定是build完start和stop、compose up/down
然后排问题就log 然后进终端exec
之前刚用这玩意的时候不用 docker-compose 还用 network 组 ;w;
哈哈。面试都没有。有面的话,估计没有很多面试经验一软脚,也讲不全讲不出来。想死。;w;