3

I need to push a big file to client, but I want to limit the speed(such as 100Kb/s), how to use ChannelTrafficShapingHandler?

ServerBootstrap b = new ServerBootstrap();
              b.group(bossGroup, workerGroup)
               .channel(NioServerSocketChannel.class)
               .option(ChannelOption.SO_BACKLOG, 100)
               .handler(new LoggingHandler(LogLevel.INFO))
               .childHandler(new ChannelInitializer<SocketChannel>() {
                   @Override
                   public void initChannel(SocketChannel ch) throws Exception {
                       ChannelPipeline p = ch.pipeline();

                       p.addLast(
                               new StringEncoder(CharsetUtil.UTF_8),
                               new LineBasedFrameDecoder(8192),
                               new StringDecoder(CharsetUtil.UTF_8),
                               new ChannelTrafficShapingHandler(1,1,10L),
                               new ChunkedWriteHandler(),
                               new FileServerHandler()
                               );
                   }
               });

This demo doesn't work, why?

高鸿武
  • 33
  • 1
  • 3

1 Answers1

6

Did you manage the channel write capability in your FileServerHandler ?

As stated in Netty API for ChannelTrafficShapingHandler

In your handler, you should consider to use the channel.isWritable() and channelWritabilityChanged(ctx) to handle writability, or through future.addListener(new GenericFutureListener()) on the future returned by ctx.write().

You shall also consider to have object size in read or write operations relatively adapted to the bandwidth you required: for instance having 10 MB objects for 10KB/s will lead to burst effect, while having 100 KB objects for 1 MB/s should be smoothly handle by this TrafficShaping handler.

And the initialization:

  • First item is Write limit in B/s (Here 1 is strongly not recommended, something close to 1024 is minimal, for 1KB/s)
  • second item is Read limit in B/S (Here 1 is strongly not recommended, something close to 1024 is minimal, for 1KB/s, or 0 for no limit)
  • First item is interval check in ms (Here 1L means every ms, which is strongly not recommended, something close to 1000 is minimal, for every 1s)

You can see an example (using Discard example) here, in particular:

Frederic Brégier
  • 2,108
  • 1
  • 18
  • 25
  • Could you explain what the `checkInterval` does? I don't understand it. – Alexander Feb 12 '19 at 00:53
  • @Alexander as the doc says: `checkInterval` - The delay between two computations of performances for channels or 0 if no stats are to be computed. This means the bandwidth has to be computed in some ways time to time. The bandwidth is not known immediately but from the recent past, where **recent** is as you like. 1 ms is too short to get correct computation (average), 1s is usually a good choice. – Frederic Brégier Feb 13 '19 at 07:19
  • Does that mean that the throttling is applied by having a "square" wave alternating between max speed and 0 speed, with a duty cycle which averages out to the throttle limit you set? – Alexander Feb 13 '19 at 18:20
  • It is not from 0 to full speed. Yes, the bandwidth computation checks the correctness of what is send (bytes according to time). But the precision depends on this interval. The smallet, the better, but too small implies too many callbacks. Indeed, once writing to a wire, there is no real way to prevent the packet to go fast. But one can prevent to sent packet from time to time. So the bandwidth is more related to packet limitation, where an extra control is made, statistics, using this interval. Hoping it is clear... ;-) – Frederic Brégier Feb 14 '19 at 21:16
  • Got it! Thanks for the explanation! – Alexander Feb 14 '19 at 22:03
  • Could you explain the `maxTime` parameter? Does it mean "packets that were throttled will be held up at most `maxTime`, then they'll be released"? – Alexander Mar 06 '19 at 18:03
  • Yes exactly. The `maxTime` specifies the time limit where the packet will be released whatever the bandwidth is. This is intend to ensure there is no "dead lock" (I know the comparison is incorrect, but still it is a matter to explain this issue that it tries to prevent). – Frederic Brégier Mar 07 '19 at 20:21
  • So that means that this can only limit spikes in bandwidth, but it can't be used to implement a sustained throttle? – Alexander Mar 07 '19 at 22:54
  • The throttle is maintained during time, using receiving or sending packet sizes. Of course, sending is more precise, since Netty can implement within it's own buffering the way the packets are sent. On the contrary, receiving is more linked to the "accept" status of the connexion and the incoming buffer of Netty of course. Those limits are there to make as much as possible the throttling precise. Sending is almost perfect, except the limit maxTime, that prevents side-effects such as KeepAlive lost. – Frederic Brégier Mar 08 '19 at 16:06
  • I got all that, except the last sentence: "Sending is almost perfect, except the limit maxTime, that prevents side-effects such as KeepAlive lost" Could you elaborate on that? – Alexander Mar 08 '19 at 16:34
  • OK, I try to elaborate. Let say you specify a throtle very low (let say 1 B/s), and you want to send 1 MB. Then it should take 1 million of seconds according to the bandwith limit. But most of the time, what occurs in that extreme case, is the KeepAlive system will try to prevent (from receiver point of view) the "no data receiving". But as you limit the sending (throttle), the KeepAlive answer will come also very late, so the client will shutdown the connection. So to prevent this, one generaly put the `maxTime` to the KeepAlive limit (30 seconds for instance) in order to force sending some. – Frederic Brégier Mar 09 '19 at 19:30
  • If not, then the KeepAlive answer is lost, and therefore the transmission too (as a stale connection). So using this parameter close to the limit of KeepAlive will help the connection to stay open and functional, at the price to accept extra sending at the `maxTime` period, but only if necessary. If necessary means if some data where sent during the period, the reference time is reset, therefore the 30 seconds (or so) are counting down newly again. So this is only in very constraint situation that this parameter is useful. – Frederic Brégier Mar 09 '19 at 19:34