6.Netty UDP客户端搭建(UdpClient),UdpClient生命周期回调,连接配置,Metrics(指标监控)

目录


Netty专栏目录(点击进入…)


Netty UDP客户端(UdpClient)

Reactor Netty提供了易于使用和易于配置的UdpClient。它隐藏了创建UDP客户端所需的大部分Netty功能,并添加了Reactive Streams背压(Reactive Streams是具有无阻塞背压的异步流处理的标准)


连接和断开

要将UDP客户端连接到给定端点,必须创建和配置UdpClient实例
默认情况下,主机配置localhost、端口12012

返回的Connection提供了一个简单的连接 API,连接到主机为example.com,端口为80;包括disposeNow(),它以阻塞方式关闭客户端。

import reactor.netty.Connection;
import reactor.netty.udp.UdpClient;
import java.time.Duration;

public class Application {

	public static void main(String[] args) {
		Connection connection =
				UdpClient.create()   // 创建一个UdpClient准备好配置的实例                     
						 .host("example.com")  // 配置host此客户端应连接到的
				         .port(80)    // 配置port此客户端应连接到的
                          // 以阻塞方式连接客户端并等待它完成初始化
				         .connectNow(Duration.ofSeconds(30)); 

		connection.onDispose()
		          .block();
	}
	
}

当需要预加载这些资源时,可以进行UdpClient如下配置:

import reactor.core.publisher.Mono;
import reactor.netty.Connection;
import reactor.netty.udp.UdpClient;

import java.time.Duration;

public class Application {

	public static void main(String[] args) {
		UdpClient udpClient = UdpClient.create()
		                               .host("example.com")
		                               .port(80)
		                               .handle((udpInbound, udpOutbound) -> udpOutbound.sendString(Mono.just("hello")));

		udpClient.warmup()  // 初始化并加载事件循环组、主机名解析器和本机传输库
		         .block();
        // 连接到远程对等方时发生主机名解析
		Connection connection = udpClient.connectNow(Duration.ofSeconds(30)); 

		connection.onDispose()
		          .block();
	}
	
}

写入数据

要将数据发送到给定的对等方,必须附加一个I/O处理程序。I/O处理程序有权访问UdpOutbound,以便能够写入数据

import reactor.core.publisher.Mono;
import reactor.netty.Connection;
import reactor.netty.udp.UdpClient;

import java.time.Duration;

public class Application {

	public static void main(String[] args) {
		Connection connection =
				UdpClient.create()
				         .host("example.com")
				         .port(80)
				         // 将hello字符串发送到远程对等方
				         .handle((udpInbound, udpOutbound) ->
				         	udpOutbound.sendString(Mono.just("hello")
			         	 ) 
				         .connectNow(Duration.ofSeconds(30));

		connection.onDispose()
		          .block();
	}
	
}

消费数据

要从给定的对等方接收数据,必须附加一个I/O处理程序。I/O处理程序有权访问UdpInbound,以便能够读取数据

消费数据:

import reactor.netty.Connection;
import reactor.netty.udp.UdpClient;
import java.time.Duration;

public class Application {

	public static void main(String[] args) {
		Connection connection =
				UdpClient.create()
				         .host("example.com")
				         .port(80)
                          // 从给定的对等方接收数据
				         .handle((udpInbound, udpOutbound) -> udpInbound.receive().then()) 
				         .connectNow(Duration.ofSeconds(30));

		connection.onDispose()
		          .block();
	}
	
}

生命周期回调

提供了以下生命周期回调以扩展UdpClient:

回调函数 描述
doAfterResolve 在成功解析远程地址后调用
doOnChannelInit 初始化通道时调用
doOnConnect 当通道即将连接时调用
doOnConnected 在通道连接后调用
doOnDisconnected 在通道断开连接后调用
doOnResolve 在即将解析远程地址时调用
doOnResolveError 在远程地址未成功解析的情况下调用

使用doOnConnected和doOnChannelInit回调:

import io.netty.handler.codec.LineBasedFrameDecoder;
import io.netty.handler.logging.LoggingHandler;
import reactor.netty.Connection;
import reactor.netty.udp.UdpClient;
import java.time.Duration;

public class Application {

	public static void main(String[] args) {
		Connection connection =
				UdpClient.create()
				         .host("example.com")
				         .port(80)
                      // NettyLineBasedFrameDecoder当通道被连接时,管道被扩展
				         .doOnConnected(conn -> conn.addHandler(new LineBasedFrameDecoder(8192))) 
                      // Netty管道LoggingHandle在初始化通道时扩展
				         .doOnChannelInit((observer, channel, remoteAddress) ->
				             channel.pipeline()
				                    .addFirst(new LoggingHandler("reactor.netty.examples")))      
				         .connectNow(Duration.ofSeconds(30));

		connection.onDispose()
		          .block();
	}
	
}

Option和childOption参数设置

Option和childOption参数设置(点击进入…)


连接配置

(1)Channel Options:通道参数配置

默认情况下,UDP客户端配置有以下选项:

UdpClientConnect() {
	this.config = new UdpClientConfig(
			ConnectionProvider.newConnection(),
			Collections.singletonMap(ChannelOption.AUTO_READ, false),
			() -> new InetSocketAddress(NetUtil.LOCALHOST, DEFAULT_PORT));
}

如果需要附加选项或需要更改当前选项,可以应用以下配置:

import io.netty.channel.ChannelOption;
import reactor.netty.Connection;
import reactor.netty.udp.UdpClient;
import java.time.Duration;

public class Application {

	public static void main(String[] args) {
		Connection connection =
				UdpClient.create()
				         .host("example.com")
				         .port(80)
				         .option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 10000)
				         .connectNow(Duration.ofSeconds(30));

		connection.onDispose()
		          .block();
	}
	
}

(2)Wire Logger:连线日志记录

Reactor Netty 提供线路日志记录,用于何时需要检查对等点之间的流量。默认情况下,线路日志记录处于禁用状态。要启用它,必须将记录器reactor.netty.udp.UdpClient级别设置为DEBUG并应用以下配置:

import reactor.netty.Connection;
import reactor.netty.udp.UdpClient;
import java.time.Duration;

public class Application {

	public static void main(String[] args) {
		Connection connection =
				UdpClient.create()
				         .host("example.com")
				         .port(80)
				         .wiretap(true)  // 启用连线记录
				         .connectNow(Duration.ofSeconds(30));

		connection.onDispose()
   }
   
}

当需要更改默认格式化程序时,可以按如下方式进行配置:

import io.netty.handler.logging.LogLevel;
import reactor.netty.Connection;
import reactor.netty.transport.logging.AdvancedByteBufFormat;
import reactor.netty.udp.UdpClient;

import java.time.Duration;

public class Application {

	public static void main(String[] args) {
		Connection connection =
				UdpClient.create()
				         .host("example.com")
				         .port(80)
				         // 启用连线记录, AdvancedByteBufFormat#TEXTUAL用于打印内容
				         .wiretap("logger-name", LogLevel.DEBUG, AdvancedByteBufFormat.TEXTUAL) 
				         .connectNow(Duration.ofSeconds(30));
  }
  
}

Wire Logger格式化程序

Reactor Netty支持3种不同的格式化程序:

连线日志格式化 描述
AdvancedByteBufFormat#HEX_DUM 同时记录事件和内容。内容将采用十六进制格式(默认)
AdvancedByteBufFormat#SIMPLE 使用此格式启用连线记录时,仅记录事件
AdvancedByteBufFormat#TEXTUAL 同时记录事件和内容。内容将采用纯文本格式

(3)Event Loop Group:事件循环组

默认情况下,UDP客户端使用“事件循环组”,其中工作线程的数量等于初始化时运行时可用的处理器数量(但最小值为4)。当需要不同的配置时,可以使用其中一种LoopResources#create()

默认配置:

/**
 * 默认工作线程数,回退到可用处理器(但最小值为4)
 */
public static final String IO_WORKER_COUNT = "reactor.netty.ioWorkerCount";
/**
 * 默认选择器线程计数,回退到-1(无选择器线程)
 */
public static final String IO_SELECT_COUNT = "reactor.netty.ioSelectCount";
/**
 * UDP的默认工作线程数,回退到可用处理器(但最小值为4)
 */
public static final String UDP_IO_THREAD_COUNT = "reactor.netty.udp.ioThreadCount";
/**
 * 默认的静默期,保证不会发生对底层循环资源的处置,回退到2秒。
 */
public static final String SHUTDOWN_QUIET_PERIOD = "reactor.netty.ioShutdownQuietPeriod";
/**
 * 默认情况下,无论任务是否在静默期内提交,在处理底层资源之前等待的最长时间为15秒。
 */
public static final String SHUTDOWN_TIMEOUT = "reactor.netty.ioShutdownTimeout";
/**
 * 默认值是否首选本机传输(epoll、kqueue),回退在可用时是否首选
 */
public static final String NATIVE = "reactor.netty.native";

如果需要更改这些设置,可以应用以下配置:

import reactor.netty.Connection;
import reactor.netty.resources.LoopResources;
import reactor.netty.udp.UdpClient;
import java.time.Duration;

public class Application {

	public static void main(String[] args) {
		LoopResources loop = LoopResources.create("event-loop", 1, 4, true);

		Connection connection =
				UdpClient.create()
				         .host("example.com")
				         .port(80)
				         .runOn(loop)
				         .connectNow(Duration.ofSeconds(30));

		connection.onDispose()
		          .block();
	}
	
}

Metrics(指标监控)

UDP客户端支持与Micrometer。它公开了前缀为reactor.netty.udp.client的所有指标

启用该集成

import reactor.netty.Connection;
import reactor.netty.udp.UdpClient;

import java.time.Duration;

public class Application {

	public static void main(String[] args) {
		Connection connection =
				UdpClient.create()
				         .host("example.com")
				         .port(80)
				         .metrics(true)  // 启用与Micrometer的内置集成
				         .connectNow(Duration.ofSeconds(30));

		connection.onDispose()
		          .block();
	}
	
}

当需要UDP客户端指标与系统集成时,Micrometer或者想提供自己的集成Micrometer,可以提供自己的指标记录器:

import reactor.netty.Connection;
import reactor.netty.channel.ChannelMetricsRecorder;
import reactor.netty.udp.UdpClient;

import java.net.SocketAddress;
import java.time.Duration;

public class Application {

	public static void main(String[] args) {
		Connection connection =
				UdpClient.create()
				         .host("example.com")
				         .port(80)
            // 启用UDP客户端指标并提供ChannelMetricsRecorder实现
				         .metrics(true, CustomChannelMetricsRecorder::new) 
				         .connectNow(Duration.ofSeconds(30));

		connection.onDispose()
		          .block();
	}
	
}

(1)UDP客户端指标的信息

metric名称 类型 描述
reactor.netty.udp.client.data.received DistributionSummary 接收的数据量,以字节为单位
reactor.netty.udp.client.data.sent DistributionSummary 发送的数据量,以字节为单位
reactor.netty.udp.client.errors Counter 发生的错误数
reactor.netty.udp.client.connect.time Timer 连接到远程地址所花费的时间
reactor.netty.udp.client.address.resolver Timer 解析地址所花费的时间

(2)ByteBufAllocator指标

metric名称 类型 描述
reactor.netty.bytebuf.allocator.used.heap.memory Gauge 堆内存的字节数
reactor.netty.bytebuf.allocator.used.direct.memory Gauge 直接内存的字节数
reactor.netty.bytebuf.allocator.used.heap.arenas Gauge 堆区域的数量(当PooledByteBufAllocator)
reactor.netty.bytebuf.allocator.used.direct.arenas Gauge 直接竞技场的数量(当PooledByteBufAllocator)
reactor.netty.bytebuf.allocator.used.threadlocal.caches Gauge 直接竞技场的数量(当PooledByteBufAllocator)
reactor.netty.bytebuf.allocator.used.small.cache.size Gauge 小缓存的大小(当PooledByteBufAllocator)
reactor.netty.bytebuf.allocator.used.normal.cache.size Gauge 正常缓存的大小(当PooledByteBufAllocator)
reactor.netty.bytebuf.allocator.used.chunk.size Gauge 竞技场的块大小(当PooledByteBufAllocator)

(3)EventLoop指标

metric名称 类型 描述
reactor.netty.eventloop.pending.tasks Gauge 事件循环中待处理的任务数

你可能感兴趣的:(Netty,udp,java,netty)