04 API设计的一些原则
4 API设计的一些原则
4.1 一个原则 两个结构
一个原则
原子性、细粒度、高内聚低耦合,类似于迪米特法则
也就是说接口的设计需要单一性,一个接口专注于具体的事件,不要既要又要还要;内部的业务处理逻辑聚合在该API中,减少再次API直接调用,实在需要可以用MQ等解耦;
两个结构
资源结构:
好的URL路径:http://www.wusuitaitou.com/auth/login.json
规则:
简单:http://{domain}/{product}/{method}?
带版本:http://{domain}/{product}/{version}/{method}?
大小类:http://{domain}/{product}/{category}/{subCategory}/{method}?
数据结构:
好的请求:
好的返回值:
{"appId": "",
"deviceId": "",
"data":{业务返回
}
}
4.2 一个原则 三各高度
高安全
业务认证:token认证用户的身份令牌
敏感字段:身份信息,手机等前后端加密
SQL注入:主要是后端注意SQL写法
文件上传:主意病毒上传,需要对文件检测,使用供应商方案一般
越权操控:A不能看B的数据,或代替A操作交易
篡改操作:截取报文修改里面的信息
高性能
响应要快:最优方式处理,避免耗时长
功能要稳:对于异常的考虑,要尽可能周详
必要缓存:对于变化频率不高的数据表内容,可以考虑上缓存
高并发
竞争少,怎么考虑
稍微有点竞争,又怎么考虑
更大的竞争,又怎么考虑
4.3 一个原则 建议 避免
四个建议
建议将入参结合业务进行一定规则的校验
建议设计层面忽略字符串null和""的概念
建议设计层面忽略集合的null和""的概念
建议把代码最基本最必要的文档注释写好
五个避免
避免参数列表个数无限膨胀
避免不受控约束的可变参数
避免过度追求一个接口万能的方案
避免词不达意业务接口逻辑
避免过度把Optional当成宝
4.4 登录换取令牌
要做什么
用什么登录?
账号+密码,手机号+密码
核心逻辑在那个系统?
sy-admin-service
网关逻辑?
sy-gateway-service
一个原则
auth/login 这个接口就是用来干用户名+密码登录,不做其他
两个结构
资源结构
类名: LoginFacade
方法名:loginByAccountPwd
方法参数名:LoginByAccountPwdReq
数据结构
- 基本入参
- 额外的
- 用户IP
- 设备号mac地址
- 设备类型等
- 抽象的:
- 来源系统
- 调用系统IP
- 反参
- 基本返参: 长/短Token,过期时间,用户信息,哈希标识
- 额外的:考虑对方获取反参后做什么逻辑
- 抽象的:响应码,响应描述
4.5 业务接口认证
考虑认证的逻辑写在哪里
HTTP请求的流程
Nginx → Tomcat → Filter → Servlet → DispatcherServlet → HandlerInterceptor → Spring AOP
→ Controller
## 流程说明
1. **Nginx**
- 反向代理服务器,处理静态资源和负载均衡
2. **Tomcat**
- Servlet 容器,接收并处理 HTTP 请求
3. **Filter**
- Java EE 过滤器,可进行请求/响应的预处理和后处理
- 示例:编码设置、安全过滤、日志记录
4. **Servlet**
- 基础请求处理组件,Tomcat 会将请求路由到对应的 Servlet
5. **DispatcherServlet** (Spring MVC 核心)
- 前端控制器,统一接收请求并分发给对应的 Controller
- 负责视图解析、异常处理等
6. **HandlerInterceptor**
- Spring MVC 拦截器,在 Controller 前后执行逻辑
- 典型应用:权限验证、日志记录
7. **Spring AOP**
- 面向切面编程,处理业务逻辑中的横切关注点
- 示例:事务管理、性能监控
## 流程特点
- 箭头方向表示请求流向
- 每个组件可对请求进行拦截或修改
- 响应按相反顺序返回
可以看出在HandlerInterceptor 比较好;
4.6 Nginx的参数和Tomcat的参数设定
1 Tomcat 线程池参数配置建议
2CPU/8GB内存 Docker容器
server.tomcat.max-threads=200 # 最大工作线程数
server.tomcat.min-spare-threads=10 # 最小空闲线程数
server.tomcat.max-connections=1000 # 最大并发连接数
server.tomcat.accept-count=100 # 等待队列大小
4CPU/8GB内存
server.tomcat.max-threads=400 # 最大工作线程数
server.tomcat.min-spare-threads=20 # 最小空闲线程数
server.tomcat.max-connections=2000 # 最大并发连接数
server.tomcat.accept-count=200 # 等待队列大小
2 从Deepseek回答4CPU8G的配置:
以下是针对 4核8G内存Docker容器运行Tomcat 的详细线程池配置建议,包括参数解释、推荐值和调优逻辑:
Tomcat 线程池核心配置(4CPU/8GB内存)
在 application.properties
或 application.yml
中配置:
1. 基础线程池参数
# 最大工作线程数(关键参数)
server.tomcat.threads.max=400
# 最小空闲线程数
server.tomcat.threads.min-spare=20
# 最大连接数(含活跃和Keep-Alive连接)
server.tomcat.max-connections=2000
# 等待队列大小(超出max-threads的请求排队数)
server.tomcat.accept-count=200
2. 高级调优参数(可选)
# 连接超时(毫秒,默认60s)
server.tomcat.connection-timeout=30000
# Keep-Alive超时(毫秒)
server.tomcat.keep-alive-timeout=15000
配置详解与调优逻辑
参数 | 推荐值 | 计算依据 | 监控与调整信号 |
---|---|---|---|
max-threads | 400 | 4核 × 100 (IO密集型)上限不超过800(避免上下文切换开销) | 线程使用率持续>80% → 调高 |
min-spare-threads | 20 | max-threads 的5% | 突发流量响应慢 → 适当增加 |
max-connections | 2000 | 内存限制:8GB - JVM预留 ≈ 6GB可用 (按每连接3MB计算) | 内存使用>90% → 调低 |
accept-count | 200 | 经验值,对应5秒队列等待时间 (假设平均处理25ms/请求) | 队列频繁满 → 检查系统瓶颈 |
配套JVM参数(关键!)
# Docker容器中建议的JVM配置
JAVA_OPTS="
-Xms5g -Xmx7g # 堆内存(预留1GB给系统)
-XX:MaxMetaspaceSize=512m # 元空间
-XX:+UseG1GC # 垃圾回收器
-XX:MaxGCPauseMillis=200 # 目标GC停顿时间
"
容器部署注意事项
资源限制必须明确:
docker run -d \ --cpus=4 \ # 明确CPU限制 -m 8g \ # 内存限制 -e JAVA_OPTS="..." \ # 传递JVM参数 your-tomcat-image
监控指标:
- 线程池:
active_threads / max_threads
- 队列堆积:
accepted_count - processed_count
- 内存:
used_memory / max_memory
- 线程池:
压力测试命令:
# 模拟高并发测试 wrk -t4 -c500 -d60s http://localhost:8080/api
不同场景调整建议
- CPU密集型应用(如大量计算):
server.tomcat.threads.max=200 # 减少线程数
- 高并发短连接:
server.tomcat.max-connections=3000 # 增加连接数 server.tomcat.connection-timeout=5000 # 缩短超时
- 长连接服务(如WebSocket):
server.tomcat.max-connections=1000 # 降低连接数 server.tomcat.keep-alive-timeout=30000 # 延长超时
常见问题排查
线程池耗尽:
- 现象:日志中出现
RejectedExecutionException
- 解决:增加
max-threads
或优化业务逻辑耗时
- 现象:日志中出现
队列堆积:
- 现象:请求延迟高但CPU未打满
- 解决:检查是否有阻塞操作(如慢SQL),或增加
accept-count
内存溢出:
- 现象:容器被OOMKill
- 解决:降低
max-connections
或增加JVM堆内存
通过以上配置,Tomcat可以在4核8G容器中平衡吞吐量和资源使用率。实际值建议通过 压测+监控 逐步调整到最优。
3 从Deepseek回答4CPU8G,分配4个docker容器的配置:
在 4核8G内存 的宿主机上运行 4个Tomcat容器 时,需要合理分配资源以避免竞争,并确保每个容器都能高效运行。以下是配置建议和优化策略:
1. 单容器资源配置(均分原则)
每个容器分配:
- CPU:
1核
(4核 ÷ 4容器) - 内存:
2GB
(8GB ÷ 4容器,预留部分给系统和其他进程)
关键配置示例(单容器)
# Tomcat 线程池(按1核2GB优化)
server.tomcat.threads.max=100 # 最大线程数(1核×100)
server.tomcat.threads.min-spare=10 # 最小空闲线程
server.tomcat.max-connections=500 # 最大连接数(按2GB内存限制)
server.tomcat.accept-count=50 # 等待队列
# JVM参数(占容器内存的70%~80%)
JAVA_OPTS="-Xms1g -Xmx1.5g -XX:MaxMetaspaceSize=256m"
2. Docker启动参数(单容器示例)
docker run -d \
--name tomcat1 \
--cpus=1 \ # 限制1核CPU
-m 2g \ # 限制2GB内存
-e JAVA_OPTS="-Xms1g -Xmx1.5g" \
-p 8080:8080 \
tomcat:9.0
重复4次(调整端口和名称如 tomcat2
、tomcat3
、tomcat4
)。
3. 宿主机全局优化
(1) CPU隔离
- 使用
--cpuset-cpus
绑定容器到特定CPU核心,避免上下文切换开销:# 容器1绑定CPU0,容器2绑定CPU1,依此类推 docker run --cpuset-cpus=0 ... docker run --cpuset-cpus=1 ...
(2) 内存超卖风险控制
- 确保所有容器内存总和不超过宿主机可用内存(如4容器×2GB=8GB,无缓冲空间)。
- 建议:总内存限制设为
6GB
(4容器×1.5GB),预留2GB给系统和Docker守护进程。
(3) 网络优化
- 使用
--network=host
模式减少NAT开销(需端口不冲突):docker run --network=host ...
- 或为每个容器分配独立端口:
-p 8081:8080 # 容器1 -p 8082:8080 # 容器2
4. 负载均衡配置(Nginx示例)
在宿主机上部署Nginx,将流量均匀分发到4个Tomcat容器:
upstream tomcat_cluster {
server 127.0.0.1:8081;
server 127.0.0.1:8082;
server 127.0.0.1:8083;
server 127.0.0.1:8084;
}
server {
listen 80;
location / {
proxy_pass http://tomcat_cluster;
}
}
5. 监控与动态调整
(1) 监控指标
- 单容器:
docker stats tomcat1 # 查看CPU/内存使用率
- 全局:
top
或htop
观察宿主机资源。- Prometheus + Grafana 监控各容器线程池状态。
(2) 调优信号
现象 | 可能原因 | 解决方案 |
---|---|---|
某容器CPU持续100% | 线程不足或业务阻塞 | 增加 max-threads 或优化代码 |
内存频繁OOM | 容器内存不足 | 调高 -m 或降低 max-connections |
请求延迟高但CPU低 | 队列堆积 | 增大 accept-count 或检查网络 |
6. 压测建议
# 模拟生产流量(并发数≈总max-threads×容器数)
wrk -t4 -c400 -d60s http://nginx-host/api
- 预期吞吐量:4容器×100线程 ≈ 400 RPS(取决于业务逻辑耗时)。
总结配置表
参数 | 单容器值 | 全局值(4容器) |
---|---|---|
CPU | 1核 | 4核 |
内存 | 2GB | 8GB(实际限制6GB) |
max-threads | 100 | 400(100×4) |
max-connections | 500 | 2000(500×4) |
JVM堆 | 1.5GB | 6GB(1.5GB×4) |
通过以上配置,可实现资源隔离和水平扩展。实际值需根据业务负载微调!