Netty-流量整形实践

当系统负载压力比较大时,系统进入过负荷状态,可能是CPU、内存资源已经过载,也可能是应用进程内部的资源几乎耗尽,如果继续全量处理业务,可能会导致长时间的Full GC、消息严重积压或者应用进程宕机,最终将压力转移到集群中的其他节点,引起级联故障。通过动态流控,拒绝一定比例新接入的请求消息,可以保障系统不被压垮
除了动态流控,有时候还需要对消息的读取和发送速度做控制,以便消息能以比较恒定的速度发送到下游网元,保护下游各系统不受突发的流量冲击,通过Netty提供的流量整形功能,就可以达到控制消息读取和发送速度的目标。


   流量整形功能
   流量整形应用


流量整形功能

     流量整形是一种主动调整流量输出速度的措施。一个典型的应用是基于下游网络节点的TPS指标控制本地流量的输出。流量整形与流量控制的主要区别在于,流量整形是对流量控制中需要丢弃的报文进行缓存–通常是将它们放入缓冲区或者队列。当令牌桶有足够多的令牌时,再均匀地向外发送这些被缓存的报文。流量整形与流量控制的另一区别是,整形可能会增加延迟,而流控几乎不引入额外的延迟。
     流量整形工作原理:
在这里插入图片描述
     Netty内置三种流量整形功能:

  1. 单个链路流量整形:ChannelTrafficShapingHandler,可以对某个链路的消息发送和读取速度进行控制。
  2. 全局流量整形:GlobalTrafficShapingHandler,针对某个进程所有链路的消息发送和读取速度的总和进行控制。
  3. 全局和单个链路综合型流量整形:GlobalChannelTrafficShapingHandler,同时对全局和单个链路的消息发送和读取速度进行控制。

     流量整形主要作用:

  1. 防止由于上、下游网元性能不均衡导致下游网元被压垮,业务流程中断。
  2. 防止由于通信模块接受消息过快,后端业务线程处理不及时,导致出现"撑死"问题。

流量整形应用

     只需要将流量整形ChannelHandler添加到业务解码器之前,即可对消息的读取额发送速度进行均匀控制,而且不会丢弃消息。服务端单个Channel读取速度进行整形Demo,创建客户端TCP连接,启动定时任务,以10MB/s的速度向服务端发送请求信息:


public class TrafficShappingClientHandler extends ChannelInboundHandlerAdapter {

    private static AtomicInteger SEQ = new AtomicInteger(0);

    static final byte[] ECHO_REQ = new byte[1024 * 1024];

    static final String DELIMITER = "$_";

    static ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(1);

    @Override
    public void channelActive(ChannelHandlerContext ctx) {
        scheduledExecutorService.scheduleAtFixedRate(()
                -> {
            ByteBuf buf = null;
            for (int i = 0; i < 10; i++) {
                buf = Unpooled.copiedBuffer(ECHO_REQ, DELIMITER.getBytes());
                SEQ.getAndAdd(buf.readableBytes());
                if (ctx.channel().isWritable())
                    ctx.write(buf);
            }
            ctx.flush();
            int counter = SEQ.getAndSet(0);
            System.out.println("The client send rate is : " + counter + " bytes/s");
        }, 0, 1000, TimeUnit.MILLISECONDS);
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
        cause.printStackTrace();
        ctx.close();
    }
}

     在服务端添加ChannelTrafficShapingHandler对消息读取速度进行整形,代码如下(TrafficShappingServer):


	    ServerBootstrap bootstrap = new ServerBootstrap();
		bootstrap.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) {
				ch.pipeline().addLast("Channel Traffic Shaping",new ChannelTrafficShapingHandler(1024 * 1024,1024 * 1024, 1000));
			    ByteBuf delimiter = Unpooled.copiedBuffer("$_".getBytes());
			    ch.pipeline().addLast(new DelimiterBasedFrameDecoder(2048 * 1024, delimiter));
			    ch.pipeline().addLast(new StringDecoder());
			    ch.pipeline().addLast(new TrafficShapingServerHandler());
			}
		});

     在服务端的ChannelHandler中,启动定时任务对消息的读取速度进行打印,代码如下(TrafficShapingServerHandler):


public class TrafficShapingServerHandler extends ChannelInboundHandlerAdapter {

    AtomicInteger counter = new AtomicInteger(0);

    static ScheduledExecutorService es = Executors.newScheduledThreadPool(1);

    public TrafficShapingServerHandler() {
        es.scheduleAtFixedRate(() ->
        {
            System.out.println("The server receive client rate is : " + counter.getAndSet(0) + " bytes/s");
        }, 0, 1000, TimeUnit.MILLISECONDS);

    }

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg)
            throws Exception {
        String body = (String) msg;
        counter.addAndGet(body.getBytes().length);
        body += "$_";
        ByteBuf echo = Unpooled.copiedBuffer(body.getBytes());
        ctx.writeAndFlush(echo);
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
        cause.printStackTrace();
        ctx.close();// 发生异常,关闭链路
    }
}

     功能测试,客户端以约10MB/s的速度发送请求信息:
在这里插入图片描述
     服务端通过添加ChannelTrafficShapingHandler实现了精准流量整形,以1MB/s的速度读取请求消息:
在这里插入图片描述
     下一篇:Netty-流量整形工作机制

  • 3
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值