netty 案例,netty4.1 中级拓展篇十二《Netty 流量整形数据流速率控制分析与实战》
前言介绍
你是否使用过某盘,在前几年我们使用的时候速度飞快,上传下载嗖嗖嗖。但是近年来只要不办会员,速度慢的像蜗牛,当然人家也得赚钱我们能理解。那么这样的限速是怎么实现的呢,我们这个案例使用Netty的流量整形进行限速传输,测试过程中当你把流量整形功能去掉后你就是年费VIP。
流量整形(Traffic Shaping)是一种主动调整流量输出速率的措施。一个典型应用是基于下游网络结点的TP指标来控制本地流量的输出。流量整形与流量监管的主要区别在于,流量整形对流量监管中需要丢弃的报文进行缓存——通常是将它们放入缓冲区或队列内,也称流量整形(Traffic Shaping,简称TS)。当令牌桶有足够的令牌时,再均匀的向外发送这些被缓存的报文。流量整形与流量监管的另一区别是,整形可能会增加延迟,而监管几乎不引入额外的延迟。
Netty中通过实现抽象类AbstractTrafficShapingHandler,提供了三个流量整形的类;GlobalTrafficShapingHandler、ChannelTrafficShapingHandler、GlobalChannelTrafficShapingHandler;
>AbstractTrafficShapingHandler.java | 功能介绍
AbstractTrafficShapingHandler允许限制全局的带宽(见GlobalTrafficShapingHandler)或者每个session的带宽(见ChannelTrafficShapingHandler)作为流量整形。
它允许你使用TrafficCounter来实现几乎实时的带宽监控,TrafficCounter会在每个检测间期(checkInterval)调用这个处理器的doAccounting方法。
如果你有任何特别的原因想要停止监控(计数)或者改变读写的限制或者改变检测间期(checkInterval),可以使用如下方法:
1、configure:允许你改变读或写的限制,或者检测间期(checkInterval);
2、getTrafficCounter:允许你获得TrafficCounter,并可以停止或启动监控,直接改变检测间期(checkInterval),或去访问它的值。
TrafficCounter:对读和写的字节进行计数以用于限制流量。
它会根据给定的检测间期周期性的计算统计入站和出站的流量,并会回调AbstractTrafficShapingHandler的doAccounting方法。
如果检测间期(checkInterval)是0,将不会进行计数并且统计只会在每次读或写操作时进行计算。
>GlobalTrafficShapingHandler.java | 全局限制
这实现了AbstractTrafficShapingHandler的全局流量整形,也就是说它限制了全局的带宽,无论开启了几个channel。
注意『 OutboundBuffer.setUserDefinedWritability(index, boolean)』中索引使用’2’。
一般用途如下:
创建一个唯一的GlobalTrafficShapingHandler
executor可以是底层的IO工作池
注意,这个处理器是覆盖所有管道的,这意味着只有一个处理器对象会被创建并且作为所有channel间共享的计数器,它必须于所有的channel共享。
所有你可以见到,该类的定义上面有个@Sharable注解。
在你的处理器中,你需要考虑使用『channel.isWritable()』和『channelWritabilityChanged(ctx)』来处理可写性,或通过在ctx.write()返回的future上注册listener来实现。
你还需要考虑读或写操作对象的大小需要和你要求的带宽相对应:比如,你将一个10M大小的对象用于10KB/s的带宽将会导致爆发效果,若你将100KB大小的对象用于在1M/s带宽那么将会被流量整形处理器平滑处理。
一旦不在需要这个处理器时请确保调用『release()』以释放所有内部的资源。这不会关闭EventExecutor,因为它可能是共享的,所以这需要你自己做。
GlobalTrafficShapingHandler中持有一个Channel的哈希表,用于存储当前应用所有的Channel:
key为Channel的hashCode;value是一个PerChannel对象。
PerChannel对象中维护有该Channel的待发送数据的消息队列(ArrayDeque<ToSend> messagesQueue)。
>ChannelTrafficShapingHandler.java | 功能介绍
ChannelTrafficShapingHandler是针对单个Channel的流量整形,和GlobalTrafficShapingHandler的思想是一样的。只是实现中没有对全局概念的检测,仅检测了当前这个Channel的数据。
这里就不再赘述了。
>GlobalChannelTrafficShapingHandler.java | 功能介绍
相比于GlobalTrafficShapingHandler增加了一个误差概念,以平衡各个Channel间的读/写操作。也就是说,使得各个Channel间的读/写操作尽量均衡。比如,尽量避免不同Channel的大数据包都延迟近乎一样的是时间再操作,以及如果小数据包在一个大数据包后才发送,则减少该小数据包的延迟发送时间等。。
开发环境
1、jdk1.8【jdk1.7以下只能部分支持netty】
2、Netty4.1.36.Final【netty3.x 4.x 5每次的变化较大,接口类名也随着变化】
代码示例
部分重点代码块讲解,获取全部代码,关注公众号:bugstack虫洞栈 | 回复netty源码
>client/MyChannelInitializer.java | 增加Channel流量整形配置,速率设置为10bytes/s
>server/common/MyServerCommonHandler.java | 提供抽象类,监控发送速率以及获取发送状态
>server/MyChannelInitializer.java | 增加全局流量整形配置,速率设置为10bytes/s
>server/MyServerHandler.java | 处理消息验证是否可以发送ctx.channel().isWritable()
测试结果
>启动服务端NettyServer | 可以看到速率已经被限制
>启动客户端NettyClient | 可以看到速率已经被限制
------------
版权声明: 本文为 InfoQ 作者【小傅哥】的原创文章。
原文链接:【http://xie.infoq.cn/article/15d644ab21bdbbb013741ad3b】。文章转载请联系作者。
评论