⚡ 项目十二:流量整形数据流速率控制
项目概述
项目名称:itstack-demo-netty-2-12
核心功能:使用流量整形技术控制数据流速率(类似某盘限速)
技术要点:TrafficShapingHandler、令牌桶算法、速率监控
为什么需要这个项目?
实际问题:
- 带宽资源有限,需要合理分配
- 防止某个连接占用过多带宽
- 需要限制用户下载/上传速度(VIP和普通用户)
- 保护服务器,防止流量突发
解决方案:
- ✅ TrafficShapingHandler:Netty提供的流量整形处理器
- ✅ 令牌桶算法:精准控制数据发送速率
- ✅ 三种实现:Global、Channel、GlobalChannel
- ✅ 速率监控:实时监控发送速率
适用场景:
- 带宽限制(某盘限速、视频网站限速)
- 服务保护(防止流量突发,保护服务器)
- 公平性保证(多用户带宽公平分配)
- 成本控制(云服务带宽成本控制)
核心问题
什么是流量整形?
流量整形(Traffic Shaping)是一种主动调整流量输出速率的措施。
流量整形 vs 流量监管:
| 特性 | 流量整形 | 流量监管 |
|---|---|---|
| 处理方式 | 缓存超出限制的报文 | 直接丢弃 |
| 实现机制 | 放入缓冲区/队列,等待令牌 | 立即丢弃 |
| 延迟 | 可能增加延迟 | 几乎不引入延迟 |
| 应用场景 | 需要保证数据完整性 | 对实时性要求高 |
核心知识点
1. Netty三种流量整形实现
GlobalTrafficShapingHandler - 全局限制
@Sharable // 可以在多个Channel间共享
public class GlobalTrafficShapingHandler extends AbstractTrafficShapingHandler
特点:
- 限制全局带宽,无论开启多少个Channel
- 所有Channel共享一个计数器
- 使用
@Sharable注解,只需创建一个实例
ChannelTrafficShapingHandler - 单Channel限制
public class ChannelTrafficShapingHandler extends AbstractTrafficShapingHandler
特点:
- 限制单个Channel的带宽
- 每个Channel需要创建独立的Handler实例
GlobalChannelTrafficShapingHandler - 混合限制
@Sharable
public class GlobalChannelTrafficShapingHandler extends AbstractTrafficShapingHandler
特点:
- 同时支持全局限制和单Channel限制
- 增加了误差平衡概念,使各Channel间的读写操作更均衡
2. 客户端流量整形配置
protected void initChannel(SocketChannel channel) {
// 流量整形:写限制10字节/秒,读限制10字节/秒 ⭐
channel.pipeline().addLast(new ChannelTrafficShapingHandler(10, 10));
// 其他处理器...
}
参数说明:
new ChannelTrafficShapingHandler(writeLimit, readLimit)
- writeLimit:写速率限制(字节/秒),0表示不限制
- readLimit:读速率限制(字节/秒),0表示不限制
3. 服务端流量整形配置
protected void initChannel(SocketChannel channel) {
// 全局流量整形:写限制10字节/秒,读限制10字节/秒 ⭐
channel.pipeline().addLast(
new GlobalTrafficShapingHandler(channel.eventLoop().parent(), 10, 10)
);
// 其他处理器...
}
4. 速率监控实现
MyServerCommonHandler.java
public abstract class MyServerCommonHandler extends SimpleChannelInboundHandler<String> {
protected boolean sentFlag;
private AtomicLong consumeMsgLength = new AtomicLong();
private long priorProgress;
@Override
public void channelActive(ChannelHandlerContext ctx) {
sendData(ctx);
// 启动监控线程 - 每500ms统计一次发送速率
new Thread(() -> {
while (true) {
try {
Thread.sleep(500);
long length = consumeMsgLength.getAndSet(0);
if (0 == length) continue;
System.out.println("数据发送速率(KB/S):" + length);
} catch (InterruptedException ignored) {
}
}
}).start();
}
protected ChannelProgressivePromise getChannelProgressivePromise(
ChannelHandlerContext ctx,
Consumer<ChannelProgressiveFuture> completedAction) {
ChannelProgressivePromise promise = ctx.newProgressivePromise();
promise.addListener(new ChannelProgressiveFutureListener() {
@Override
public void operationProgressed(ChannelProgressiveFuture future,
long progress, long total) {
// 累计已发送的字节数
consumeMsgLength.addAndGet(progress - priorProgress);
priorProgress = progress;
}
@Override
public void operationComplete(ChannelProgressiveFuture future) {
sentFlag = false;
if (future.isSuccess()) {
System.out.println("消息发送成功!");
priorProgress -= 10;
Optional.ofNullable(completedAction)
.ifPresent(action -> action.accept(future));
}
}
});
return promise;
}
}
5. 令牌桶算法原理
1. 系统以固定速率向令牌桶中添加令牌
例如:10字节/秒 = 每100ms添加1字节令牌
2. 当需要发送数据时:
- 检查令牌桶中是否有足够的令牌
- 有令牌:消耗令牌,发送数据
- 无令牌:将数据放入队列,等待令牌
3. 流量整形效果:
- 即使应用层快速写入大量数据
- 实际发送速率被限制在设定值
- 超出部分被缓存,不会丢失
测试效果
启动服务端:
itstack-demo-netty server start done.
数据发送速率(KB/S):10
数据发送速率(KB/S):10
数据发送速率(KB/S):10
消息发送成功!
观察:速率被限制在10字节/秒
项目总结
核心技术:
- ✅ TrafficShapingHandler:Netty提供的流量整形处理器
- ✅ 令牌桶算法:控制数据发送速率
- ✅ 速率监控:实时监控发送速率
- ✅ 三种实现:Global、Channel、GlobalChannel
选择建议:
| 场景 | 推荐Handler |
|---|---|
| 限制整个应用总带宽 | GlobalTrafficShapingHandler |
| 限制单个连接带宽 | ChannelTrafficShapingHandler |
| 既要限制总带宽又要保证公平性 | GlobalChannelTrafficShapingHandler |
适用场景:
- 带宽限制(某盘限速)
- 服务保护(防止流量突发)
- 公平性保证(多用户带宽分配)
- 成本控制(云服务带宽成本)
配置建议:
// 开发测试:10字节/秒(便于观察效果)
new GlobalTrafficShapingHandler(executor, 10, 10)
// 生产环境:根据实际需求设置
new GlobalTrafficShapingHandler(executor, 1024 * 100, 1024 * 100) // 100KB/s
&spm=1001.2101.3001.5002&articleId=157907392&d=1&t=3&u=8ac20395bf5e42ae8801b3e64bf77c4a)
5189

被折叠的 条评论
为什么被折叠?



