Java常用开源库梳理(3)

#Netty库

##1. ServerBootstrap, Bootstrap
(1)ServerBootstrap:服务端启动器。
group():指定mainReactor线程池和subReactor线程池,前者是acceptor线程池用于接受客户端连接,后者是worker线程池用于处理IO事件,一类是服务端接收到客户端数据的Read事件,另一类是用户线程主动向客户端发送数据的Write事件。
channel():指定服务端要他寻channel类型,服务端通常是无参构造的NioServerSocketChannel。若要自定义有参构造的channel类型或需要创建大量channel,可用channelFactory()来指定自定义channel工厂。
option()/childOption():指定channel的选项参数ChannelOption,包括TCP相关的参数以及一些Netty自定义的参数。
handler():指定mainReactor的处理器,默认已经添加了ServerBootstrapAcceptor处理器,它将mainReactor接受的Channel传递给subReactor。所以无需用户再指定。
childHandler():指定subReactor中的ChannelHandler处理器,用于为各个客户端对应的子channel添加处理器,处理器的逻辑默认在subReactor线程池中执行。通常使用ChannelInitializer这个初始化处理器。对每个客户端连接产生的SocketChannel上定义了一个ChannelPipeline,通过addLast()可以在pipeline中添加多个处理器,构成请求的一个处理链。而ChannelInitializer这个特殊处理器就可以一次添加多个处理器,例如编解码器。若处理器要执行耗时的业务如数据库操作,还可以为它指定专门的业务线程池,不使用subReactor线程池。完成初始化工作后,ChannelInitializer会从Handler链中删除。
bind():服务端Channel绑定到本地端口,成功后返回ChannelFuture。
childAttr():为各个子channel添加属性值。
validate():验证连接参数的有效性。
(2)Bootstrap:客户端启动器。
group():指定reactor线程池,客户端只需要指定一个。
channel():指定客户端要创建的channel类型。客户端为无参构造的NioSocketChannel。
option():指定channel的选项参数ChannelOption,包括TCP相关的参数以及一些Netty自定义的参数。
handler():指定处理请求的ChannelHandler,客户端一般也用ChannelInitializer处理器,它可以在Channel的pipeline上通过addLast()添加多个处理器到末尾。
connect():将channel连接到远程服务端,指定连接host和port。返回ChannelFuture。

##2. EventExecutorGroup
EventExecutor: SingleThreadEventExecutor/MultithreadEventExecutorGroup, DefaultEventExecutor, ImmediateEventExecutor, GlobalEventExecutor, UnorderedThreadPoolEventExecutor
EventLoop: SingleThreadEventLoop, DefaultEventLoop, ThreadPerChannelEventLoop, NioEventLoop
EventLoopGroup: ThreadPerChannelEventLoopGroup/OioEventLoopGroup/MultithreadEventLoopGroup, DefaultEventLoopGroup, NioEventLoopGroup, EpollEventLoopGroup, KQueueEventLoopGroup
(1)EventExecutor:事件执行器。有一些方法用于确定线程是否在一个事件循环中执行。SingleThreadEventExecutor表示在单个线程中以顺序、串行的方式执行所有提交的任务。DefaultEventExecutor是默认的SingleThreadEventExecutor实现,以串行方式执行所有提交的任务。SingleThreadEventExecutor是单线程事件执行器,MultithreadEventExecutorGroup是多线程事件执行器,可以在线程池中同时执行多个任务。
(2)ImmediateEventExecutor:立即执行调度器,在调用者线程中执行Runnable对象。如果execute()被重新调用,它将会排队,直到原来的Runnable完成执行。主要方法execute(), inEventLoop(), awaitTermination(), isShutdown(), isShuttingDown(), isTerminated(), newPromise(), shutdownGracefully(), terminationFuture()。
(3)GlobalEventExecutor:全局调度器,是单线程、单例的。自动启动线程,当1秒内任务队列中没有挂起的任务时自动停止。注意本调度器不太适于调度大量的任务。
(4)UnorderedThreadPoolEventExecutor:无顺序保证的调度器。提交的任务无执行顺序保证,因为可能有多个线程执行这些任务。比较适用于无需严格顺序的协议。
(4)EventLoop:表示一个事件循环,用于处理Channel上的所有IO操作。一个EventLoop实例通常能注册和处理多个Channel。一个EventLoop可以关联到一个EventLoopGroup。SingleThreadEventLoop表示在单个线程中串行执行所有提交的任务。有三个实现DefaultEventLoop, ThreadPerChannelEventLoop, NioEventLoop。
(5)ThreadPerChannelEventLoop:单线程阻塞式事件循环。用于处理OIO的Channel。每个Channel对应一个ThreadPerChannelEventLoop。该线程和该channel绑定,该Channel的所有任务在线程上串行执行。
(6)NioEventLoop:NIO事件循环线程,SingleThreadEventLoop的核心实现。用于注册Channel到NIO Selector选择器上,并在事件循环中执行多路复用。一个NioEventLoop聚合一个多路复用器Selector,它可以同时注册、监听和轮询成百上千个 Channel,一个IO线程可以同时并发处理N个客户端连接一个。这是高性能关键。它可以作为服务端Acceptor线程,负责处理客户端的请求接入;作为客户端Connecor线程,负责注册监听连接操作位,用于判断异步连接结果;作为IO线程监听网络读操作位,负责从SocketChannel中读取报文;作为IO线程负责向SocketChannel写入报文发送给对方,如果发生写半包,会自动注册监听写事件,用于后续继续发送半包数据,直到数据全部发送完成;作为定时任务线程,可以执行定时任务,例如链路空闲检测和发送心跳消息等;作为线程执行器可以执行普通的Runnable任务线程。主要方法:
getIoRatio()/setIoRatio():获取或设置事件循环中IO任务占的时间百分比。
pendingTasks():等待的任务数
rebuildSelector():用新创建的Selector替换事件循环中的当前Selector。这是为了规避JDK的epoll 100% cpu的bug。
register(channel):注册一个带该事件循环的Netty Channel,返回ChannelFuture。
register():注册一个NIO SelectableChannel到Selector。
selctorProvider():返回使用的SelectorProvider,用来获取Selector。
execute():提交一个要执行的任务。
(7)EventLoopGroup:事件循环线程组,关联一个线程池。允许注册多个Channel,在事件循环中使用线程池同时执行多个任务。ThreadPerChannelEventLoopGroup为每个Channel创建一个EventLoop。子类OioEventLoopGroup用于处理OIO Channel。每个Channel由它自己的EventLoop来处理,不会阻塞其他的Channel。当有海量的客户端连接时,要创建大量的EventLoop,有性能瓶颈。而MultithreadEventLoopGroup则在线程池允许同时处理多个任务。DefaultEventLoopGroup是一个默认的多线程实现,一般用于本地传输。
(8)NioEventLoopGroup:NIO事件循环线程组。MultithreadEventLoopGroup的核心实现,用在基于NIO Selector的Channel上。主要方法:
newChild():创建一个EventExecutor线程,之后通过next()能访问到。
setIoRatio():设置事件循环中IO任务占的时间百分比。
rebuildSelectors():用新创建的Selector替换事件循环中的当前Selector。
execute():提交一个要执行的任务。
register():将通道channel注册到EventLoopGroup中的一个线程上。
next():选择一个EventLoop线程。Netty实现了两个线程选择器,如果线程数是2的幂次方使用2的幂次方选择器(选择索引时使用位操作),否则使用通用选择器。每次选择索引为上一次所选线程索引+1的线程。
terminationFuture():终止线程池,返回异步的Future。
shutdownGracefully():优雅关闭线程池。Netty默认在2秒的静默时间内如果没有任务,则关闭;否则15秒截止时间到达时关闭。
(9)EpollEventLoopGroup:底层用epoll实现的EventLoopGroup,只适用于Linux系统。类似地KQueueEventLoopGroup底层用kqueue,一般只用于Mac系统。

##3. ChannelFuture
ChannelFuture, ChannelGroupFuture, ChannelProgressiveFuture, ScheduledFuture
ChannelPromise, ChannelProgressivePromise
(1)ChannelFuture:一个异步Channel IO操作的结果,是不可变对象。Netty中所有的IO操作都是异步的(读写数据、绑定、连接操作等),返回Future结果。Netty Future扩展了JDK的Future,可以注册监听器,对操作的完成有更详细记录,例如是正常终止、抛出异常、还是用户取消等。主要方法:
addListener()/addListeners()/removeListener()/removeListeners():添加或删除监听器,异步操作完成时回调。
await()/awaitUninterruptibly():等待future执行完成。
sync()/syncUninterruptibly():同步执行,等待执行完成,如果执行失败重新抛出失败异常。
channel():对应的channel。
isDone()/isCancelled()/isCancellable()/isSuccess():判断异步操作的状态。
cause():异步操作失败的原因。
get()/getNow():前者阻塞式地返回结果,后者非阻塞地返回异步结果,如果尚未完成返回null。
(2)ChannelGroupFuture:一个异步ChannelGroup操作的结果,表示一组ChannelFuture。额外方法group()返回关联的ChannelGroup,find()查找特定的ChannelGroup,iterator()返回迭代器,isPartialSuccess()/isPartialFailure()返回是否部分成功或失败。
(3)ChannelProgressiveFuture:特殊的ChannelFuture,用来表示文件块的传输过程。
(4)ScheduledFuture:一个调度的异步操作结果。
(5)ChannelPromise:可写的ChannelFuture。写操作为setSuccess()/trySuccess(), setFailure()/tryFailure(), setUncancellable()。注意Promise从未完成到完成的状态转变有且只能有一次,也就是说setSuccess和setFailure方法最多只会成功一个,此外在setSuccess和setFailure方法中会通知注册到其上的监听者。第二次调用setter方法失败。
(6)ChannelProgressivePromise:特殊的ChannelPromise,表示文件块的传输过程,一旦关联的字节数据传输出去就会收到通知。DefaultChannelProgressivePromise是默认实现,建议用ChannelOutboundInvoker.newProgressivePromise()来创建其实例而不是用构造函数。额外方法checkDeadLock(), flushCheckpoint(), setProgress()用于跟踪文件数据传输过程。

##4. Channel, ChannelOption, ChannelConfig
(1)Channel:表示一个网络Socket连接,或者一个能执行IO操作(read/write/connet/bind)的组件。用户可以使用Channel来查询Channel的状态、配置Channel的参数、进行Channel支持的I/O操作(read/write/connect/bind)、获取对应的ChannelPipeline从而可以自定义处理I/O事件或者其他请求。需要注意,所有的I/O操作都是异步的。Channel是有等级的,如果一个Channel由另一个Channel创建,那么他们之间形成父子关系。比如说当ServerSocketChannel通过accept()方法接受一个SocketChannel时,那么SocketChannel的父亲是ServerSocketChannel,调用SocketChannel的parent()方法返回该ServerSocketChannel对象。某些子类Channel会提供一些所需的特定操作,可以向下转型到这样的子类,从而获得特定操作。比如说,对于UDP的数据报的传输,有特定的join()和leave()操作,我们可以向下转型到DatagramChannel从而使用这些操作。当一个Channel不再使用时,须调用close()或者close(ChannelPromise)方法释放资源。主要操作:
isOpen()/isRegistered()/isActive()/isWritable():状态查询。
eventLoop()/parent()/config()/metadata()/localAddress()/remoteAddress()/pipeline()/alloc()/closeFuture()/voidPromise()/unsafe():getter方法,获取关联到Channel上的相关信息,如事件循环、父Channel、配置、元数据、绑定地址、pipeline处理器链、缓存分配器、内部unsafe的各种操作等。
newPromise()/newProgressivePromise()/newSucceededFuture()/newFailedFuture():异步结果生成。
read()/write()/flush()/writeAndFlush()/bind()/connect()/disconnect()/close()/deregister():IO事件处理,都是outbound出站事件,表示由用户发起,即用户可以调用这些方法产生响应的事件。
(2)ChannelOption:一组Channel的配置选项名称,允许以类型安全的方式配置一个ChannelConfig(setOption操作)。选项包括Netty参数、Socket参数和TCP/IP参数选项。
1)Netty参数:CONNECT_TIMEOUT_MILLIS, ALLOCATOR, RCVBUF_ALLOCATOR, MAX_MESSAGES_PER_READ, AUTO_READ, WRITE_SPIN_COUNT, WRITE_BUFFER_HIGH_WATER_MARK, WRITE_BUFFER_WATER_MARK, MESSAGE_SIZE_ESTIMATOR, SINGLE_EVENTEXECUTOR_PER_GROUP, ALLOW_HALF_CLOSURE, DATAGRAM_CHANNEL_ACTIVE_ON_REGISTRATION。
2)Socket参数:SO_RCVBUF, SO_SNDBUF, SO_TIMEOUT, SO_KEEPALIVE, SO_REUSEADDR, SO_LINGER, SO_BACKLOG, SO_BROADCAST。
3)TCP/IP参数:TCP_NODELAY, IP_TOS, IP_MULTICAST_ADDR, IP_MULTICAST_LOOP_DISABLED, IP_MULTICAST_IF, IP_MULTICAST_TTL。
(3)ChannelConfig:Channel的一组配置属性。不同类型的Channel有不同的ChannelConfig实现,这每种Channel可以直接用对应的ChannelConfig来进行配置。

##5. ServerSocketChannel, SocketChannel
NioServerSocketChannel, OioServerSocketChannel, EpollServerSocketChannel, KQueueServerSocketChannel
NioSocketChannel, OioSocketChannel, EpollSocketChannel, KQueueSocketChannel
(1)NioServerSocketChannel:一个基基于NIO selector实现的ServerSocketChannel,表示服务端的Channel,用于接受进来的TCP/IP连接请求。config()返回本channel的配置。localAdress()返回绑定的本地地址,remoteAddress()返回连接到的远程地址。
(2)OioServerSocketChannel:服务端Channel,接受新请求并创建OioSocketChannel,使用老的阻塞IO。
(3)EpollServerSocketChannel:服务端Channel,使用Linux epoll的边缘触发模式,以达到性能最优化。
(4)KQueueServerSocketChannel:基于Mac系统的kqueue实现的服务端socket channel。
(5)SocketChannel:客户端的channel,用于连接远程服务端。核心实现是NioSocketChannel。

##6. ServerDomainSocketChannel, DomainSocketChannel
EpollServerDomainSocketChannel, KQueueServerDomainSocketChannel
EpollDomainSocketChannel, KQueueDomainSocketChannel
(1)ServerDomainSocketChannel:通过Unix Domain Socket来通信的服务端channel,接受DomainSocketChannel的连接。config()返回本channel的配置。localAdress()返回绑定的本地地址,remoteAddress()返回连接到的远程地址。fd()返回channel使用的文件描述符。
(2)DomainSocketChannel:通过Unix Domain Socket来通信的客户端channel。

##7. DatagramChannel
NioDatagramChannel, OioDatagramChannel, EpollDatagramChannel, KQueueDatagramChannel
(1)NioDatagramChannel:一个NIO UDP数据报Channel,发送和接收一封AddressedEnvelope。DatagramChannel用来发送UDP数据报。UDP有多播功能,因此有一组joinGroup()/leaveGroup()操作用于把一个多播地址加入多播组或从多播组中移除。block()操作对给定远程多播地址阻塞一个发送数据源地址。
(2)OioDatagramChannel:使用OIO实现的数据报Channel,发送和接收一封AddressedEnvelope。
(3)EpollDatagramChannel:使用Linux epoll的边缘触发模式实现的数据报Channel,以达到性能最优化。
(4)KQueueDatagramChannel:基于Mac系统的kqueue实现的数据报Channel。

##8. SctpServerChannel, SctpChannel
NioSctpServerChannel, OioSctpServerChannel
NioSctpChannel, OioSctpChannel
(1)NioSctpServerChannel:基于NIO实现的服务端SCTP Channel,使用非阻塞模式接受进来的SCTP/IP连接。多宿主地址的绑定和解绑通过bindAddress(()/UnbindAddress()来进行。allLocalAddresses()返回所有绑定的本地地址。localAddress()返回绑定的本地主地址。
(2)OioSctpServerChannel:基于OIO实现的服务端SCTP Channel。使用阻塞模式接受进来的OioSctpChannel连接。
(3)NioSctpChannel, OioSctpChannel:客户端的SCTP channel实现。面向消息,传输层支持多宿主连接,一个SCTP连接支持多个流。allLocalAddresses()返回channel的本地地址,allRemoteAddresses()返回所有远程地址。remoteAddress()返回远程主地址。多宿主地址的绑定和解绑通过bindAddress(()/UnbindAddress()来进行。

##9. LocalServerChannel, LocalChannel, EmbeddedChanel
(1)LocalServerChannel:用于本地传输的服务端Channel,适用于VM内部的通信。有很多protected方法doBeginRead(), doBind(), doWrite(), doClose(), doDeregister(), isCompatible(), localAddress0(), newLocalChannel()等,所以一般你要扩展这个类,做自己的定制。
(2)LocalChannel:用于本地传输的客户端Channel。与LocalServerChannel类似,一般需要扩展此类,做自己的定制。
(3)EmbeddedChanel:以嵌入式方式使用的Channel,一般需要扩展此类,做自己的定制。

##10. ChannelPipeline, ChannelHandlerContext, ChannelHandler
DefaultChannelPipeline, @ChannelHandler.Sharable
ChannelInboundHandler, ChannelOutboundHandler, SimpleChannelInboundHandler
ChannelInboundHandlerAdapter, ChannelOutboundHandlerAdapter, ChannelDuplexHandler
(1)ChannelPipeline:线程安全的ChannelHandler处理器链。表示一个ChannelHandler列表,处理Channel上的入站事件或出站操作。它使用责任链模式实现了高级的拦截过滤器模式,让用户可以完全控制怎么处理事件,以及处理器之间怎么交互。每个Channel在创建时会自动创建它自己的pipeline。IO事件会被一个ChannelInboundHandler或ChannelOutboundHandler处理,处理后的数据作为下一个处理器的数据源。事件不会在ChannelPipeline中自动流动,而是处理器中通过调用ChannelHandlerContext中的事件传播方法(诸如fireXXX()或read()/write())将事件转发给下一个处理器。入站事件按pipeline中添加的处理器顺序由头到尾正向传播,出站事件则方向相反。DefaultChannelPipeline是默认实现。要构建处理器链,可以用Channel.pipeline()获取ChannelPipeline对象,然后调用它的各种方法来添加或删除处理器。处理器通常分为协议解码器、协议编码器、业务逻辑处理器三大类。
addFirst()/addBefore()/addAfter()/addLast():在对应位置添加处理器
channel():返回对应的channel
context()/firstContext()/lastContext():返回指定处理器的ChannelContext
first()/last()/get():获取指定的处理器
remove()/removeFirst()/removeLast():移除指定的处理器
replace():替换指定的处理器
(2)ChannelHandlerContext:处理器上下文。用于激活处理器与其他处理器的交互。包括处理器的状态信息、与pipeline中下一个处理器交互的事件传播方法。一个处理器可以被添加到不同的ChannelPipeline中,因此可以有多个ChannelHandlerContext,在不同的pipeline管线中调用时,上下文信息可能不同。方法列表:
1)入站事件传播方法,一般由I/O线程触发,用户也可根据实际情况触发:
ChannelHandlerContext.fireChannelRegistered() // Channel注册到EventLoop
ChannelHandlerContext.fireChannelActive() // Channel激活
ChannelHandlerContext.fireChannelRead(Object) // Channel读取到数据
ChannelHandlerContext.fireChannelReadComplete() // Channel读取数据完毕
ChannelHandlerContext.fireExceptionCaught(Throwable) // 捕获到异常
ChannelHandlerContext.fireUserEventTriggered(Object) // 用户自定义事件
ChannelHandlerContext.fireChannelWritabilityChanged() // Channnel可写性改变,由写高低水位控制
ChannelHandlerContext.fireChannelInactive() // Channel不再激活
ChannelHandlerContext.fireChannelUnregistered() // Channel从EventLoop中注销
2)出站事件传播方法,一般由用户触发:
ChannelOutboundInvoker.bind(SocketAddress, ChannelPromise) // 绑定到本地地址
ChannelOutboundInvoker.connect(SocketAddress, SocketAddress, ChannelPromise) // 连接一个远端机器
ChannelOutboundInvoker.write(Object, ChannelPromise) // 写数据,实际只加到Netty出站缓冲区
ChannelHandlerContext.flush() // flush数据,实际执行底层写
ChannelHandlerContext.read() // 读数据,实际设置关心OP_READ事件,当数据到来时触发ChannelRead入站事件
ChannelOutboundInvoker.disconnect(ChannelPromise) // 断开连接,NIO Server和Client不支持,实际调用close
ChannelOutboundInvoker.close(ChannelPromise) // 关闭Channel
ChannelOutboundInvoker.deregister(ChannelPromise) // 从EventLoop注销Channel
3)其他方法:alloc()返回使用ByteBufAllocator分配器,attr()添加状态属性,hassAttr()判断属性,channel()返回关联的channel,executor()返回使用的线程池执行器,handler()返回关联的处理器,pipeline()返回分配的ChannelPipeline。
(3)ChannelHandler:Channel处理器。处理一个IO事件,或者拦截一个IO操作,并把它转发给下一个处理器。ChannelHandler并没有提供方法来处理事件,而是提供了两个子类,ChannelInboundHandler拦截和处理入站事件,ChannelOutboundHandler拦截和处理出站事件。它们对每个上述事件都声明了一个回调方法,以便用户在事件状态改变时实现自定义逻辑。Netty为这些接口类型提供了方便使用的adapter类型,可以让你方便定义自己的处理器。ChannelInboundHandlerAdapter,ChannelOutboundHandlerAdapter和ChannelDuplexHandler。在Adapter中,事件默认自动传播到下一个Handler,这样用户的Handler类可以继承Adapter且覆盖自己感兴趣的事件实现,其他事件使用默认实现,不用再实现ChannelIn/OutboudHandler接口中所有方法,提高效率。
(4)@ChannelHandler.Sharable:ChannelHandler中有一个@Sharable注解,表示共享式的单个处理器实例,可以添加多个ChannelPipeline中,且使用时不会产生线程竞争。该Handler对象实例只有一个,从而减少Handler对象实例的创建。由于ChannelHandler是非线程安全的,因此@Sharable注解的使用是有限制的,要求该处理器无状态,事件处理方法中不能使用或改变本身的私有变量。因为使用私有变量会造成线程竞争而产生错误结果。
(5)SimpleChannelInboundHandler:继承自ChannelInboundHandlerAdapter,类型参数T显式地指定入站时要处理的消息类型。而ChannelInboundHandlerAdapter中读到的入站消息是未明晰的Object类型。

##11. ByteBuf, ByteBufHolder
ByteBufInputStream, ByteBufOutputStream
UnpooledHeapByteBuf, UnpooledDirectByteBuf, UnpooledUnsafeDirectByteBuf, CompositeByteBuf
(1)ByteBuf:存储字节的缓冲区,带引用计数功能。为字节数据byte[]和NIO ByteBuffer提供了更高级的抽象。一般建议用Unpooled中的工具方法来创建新的ByteBuf,而不是使用ByteBuf自己的构造器。该缓冲区维护了两个索引,读索引和写索引。从而将缓存区分成三个片段,废弃段、可读段和可写段。可读段表示缓冲区实际存储的可用数据。当用户使用readXXX()或者skip()方法时,将会增加读索引。读索引之前的数据将进入废弃段,表示该数据已被使用。此外用户可主动使用discardReadBytes()清空废弃段以便得到跟多的可写空间,对可写段,用户可使用writeXXX()方法向缓冲区写入数据,也将增加写索引。用户在必要时可以使用clear()方法清空缓冲区,此时缓冲区的写索引和读索引都将置0,但是并不清除缓冲区中的实际数据。如果需要循环使用一个缓冲区,这个方法很有必要。此外用户可以使用mark()和reset()标记并重置读索引和写索引。查找单个字节可以用indexOf()和bytesBefore(),更复杂的查找使用forEachByte()。toString(Charset)将缓冲区的字节数据转为字符串时,并不会增加读索引。注意toString()只是覆盖Object的常规方法,仅仅表示缓冲区的常规信息,并不会转化其中的字节数据。如果想拷贝整个缓冲区,此时可使用copy()方法。
1)缓冲区可能在用户空间或内核空间。如果位于用户空间,就是JAVA的堆空间上,用JAVA的基本数据类型byte[]表示,用户可使用array()直接取得该字节数组,使用hasArray()判定该缓冲区是否是用户空间缓冲区。如果位于内核空间,JAVA程序将不能直接进行操作,此时委托给JDK NIO中的直接缓冲区DirectByteBuffer由其操作内核字节数组,用户可使用nioBuffer()取得直接缓冲区,使用nioBufferCount()判定底层是否有直接缓冲区。
2)用户可在已有缓冲区上创建视图即派生缓冲区,这些视图维护各自独立的写索引、读索引以及标记索引,但他们和原生缓冲区共享内部字节数据。创建视图即派生缓冲区的方法有duplicate(),slice()以及readSlice()。它们不会在派生出的缓冲区上调用retain(),因此引用计数不会增加。若要增加引用计数,可以用retainedDuplicate(),retainedSlice(),readRetainedSlice(int)来创建派生缓冲区,这会产生更少的内存垃圾。
(2)ByteBufHolder:表示用来发送或接收的一个数据包。实现ByteBufHolder接口的对象与派生缓冲区有类似的地方,共享所Hold缓冲区的引用计数,所以要注意对象的释放。Netty的各种通信协议数据包一般都实现了ByteBufHolder。如FullHttpRequest, HttpContent, SmtpContent, DatagramPacket, WebSocketframe。
(3)ByteBufInputStream/ByteBufOutputStream:以IO流的方式从ByteBuf中读取数据,或向ByteBuf中写入数据。
(4)UnpooledHeapByteBuf:大端Java堆内缓冲区实现,底层为不使用对象池的字节数组。通常建议用AbstractByteBufAllocator.heapBuffer(int, int), Unpooled.buffer(int)或Unpooled.wrappedBuffer(byte[])来创建这种缓冲区,而不是显示调用它的构造器。
(5)UnpooledDirectByteBuf:基于NIO ByteBuffer的缓冲区实现。不使用对象池。建议用AbstractByteBufAllocator.directBuffer(int, int), Unpooled.directBuffer(int)或Unpooled.wrappedBuffer(ByteBuffer)来创建这种缓冲区,而不是显式调用它的构造器。
(6)UnpooledUnsafeDirectByteBuf:基于NIO ByteBuffer的缓冲区,使用Java的后门类sun.misc.Unsafe来实现,以达到性能最优化。功能与UnpooledDirectByteBuf类似。
(7)CompositeByteBuf:聚合缓冲区,用于把多个ByteBuf聚合成一个ByteBuf,对外提供统一封装后的ByteBuf接口。建议用ByteBufAllocator.compositeBuffer()或Unpooled.wrappedBuffer()来创建。

##12. ByteBufAllocator
PooledByteBufAllocator, UnpooledByteBufAllocator
Unpooled
(1)PooledByteBufAllocator:对象池缓冲区分配器。当对象释放后会归还给对象池,所以可循环使用。当需要大量且频繁创建缓冲区时,建议使用该类缓冲区。Netty4.1默认使用对象池缓冲区,4.0默认使用非对象池缓冲区。主要操作buffer(), heapBuffer(), directBuffer(), compositeBuffer(), compositeHeapBuffer(), compositeDirectBuffer(), ioBuffer(), isDirectBufferPooled()。
(2)UnpooledByteBufAllocator:非对象池缓冲区分配器。每次分配都是一个新的缓冲区,不会复用之前已释放的缓冲区。
(3)Unpooled:创建各种非池化缓冲区的工具类。创建方式有分配新空间、包装或拷贝已有的字节数组、字节缓冲区或一个字符串。主要操作buffer(), compositeBuffer(), copiedBuffer(), directBuffer(), wrappedBuffer(), unmodifiableBuffer()。

##13. LoggingHandler, IdleStateHandler
ReadTimeoutHandler, WriteTimeoutHandler
(1)LoggingHandler:使用日志框架对入站、出站事件进行日志记录。默认所有事件被记录为DEBUG级别。
(2)IdleStateHandler:Channel空闲状态处理器。当Channel上读空闲、写空闲或读写空闲达到指定时间,触发一个用户事件IdleStateEvent,pipeline上的用户自定义处理器中可以处理这个事件,比如关闭该channel,以便释放资源。
(3)ReadTimeoutHandler:读超时处理器。当Channel读数据超过指定时间,抛出一个ReadTimeoutException,并关闭连接。可以在上层用户处理器中处理这个异常。
(4)WriteTimeoutHandler:写超时处理器。当Channel写数据超过指定时间,抛出一个WriteTimeoutException,并关闭连接。可以在上层用户处理器中处理这个异常。

##14. GlobalTrafficShapingHandler
ChannelTrafficShapingHandler, GlobalChannelTrafficShapingHandler
FlowControlHandler
(1)GlobalTrafficShapingHandler:全局流量整形。作用范围是进程级的,无论你创建了多少个Channel,它的作用域针对所有的Channel。用户可以通过参数设置报文的接收速率(bytes/s)、报文的发送速率、整形周期。如果达到整形阈值,则对新接收的ByteBuf进行缓存,放入线程池的消息队列中,由定时任务延时处理。
(2)ChannelTrafficShapingHandler:单链路流量整形。以单个链路为作用域,可以对不同的链路设置不同的整形策略。它的实现原理与全局流量整形类似。
(3)GlobalChannelTrafficShapingHandler:包含全局流量整形和单链路流量整形。
(4)FlowControlHandler:流量控制。确保每次读操作后只有一条消息被发送出去。

##15. ChunkedWriteHandler, FlushConsolidationHandler
(1)ChunkedWriteHandler:大文件传输处理。支持异步发送大的数据流,既不用花费大量内存,也不会有OOM。大文件传输在ChannelHandler中需要复杂的状态管理,ChunkedWriteHandler实现了这些复杂的状态管理。一旦往pipeline中添加该处理器,就可以向channel中写入ChunkedFile,处理器将自动分块地把文件写入网络。
(2)FlushConsolidationHandler:用于合并多个flush操作,以优化性能。通常flush操作比较昂贵,它会在传输层触发一个系统调用。在高吞吐量情况下FlushConsolidationHandler可以把下一个处理器放作为独立的task执行,这样就有机会执行其他的flush,从而合并了多个flush。一般这个处理器应该作为pipeline中的第一个处理器。

##16. RuleBasedIpFilter, UniqueIpFilter
(1)RuleBasedIpFilter:基于IpFilterRule来过滤新的连接Channel。用户要实现IpFilterRule接口创建具体的IP过滤规则,并在构造函数中传给RuleBasedIpFilter。accept()根据过滤规则接受或拒绝连接,它会在Netty注册一个Channel时立即调用。若想在Channel被拒绝时做定制的响应,可以覆盖channelRejected()方法。
(2)UniqueIpFilter:用于确保每个IP地址最多只有一个Channel连接到服务器。

##17. ByteToMessageDecoder
DelimiterBasedFrameDecoder, LineBasedFrameDecoder, FixedLengthFrameDecoder, LengthFieldBasedFrameDecoder
MessageToByteEncoder, ByteToMessageCodec, ReplayingDecoder
MessageToMessageDecoder, MessageToMessageEncoder, MessageToMessageCodec, LengthFieldPrepender, MessageAggregator
DatagramPacketDecoder, DatagramPacketEncoder
(1)ByteToMessageDecoder:消息帧解码器,抽象类。将入站的ByteBuf字节码流解码为含义明确的消息帧,之后的解码器才将消息帧解码为实际的POJO对象。它可以处理TCP的粘包现象。它会在ByteBuf中不断地累积从channelRead()中读到的新数据(必要时候自动扩容),然后通过decode()方法将累积数据解码成消息帧列表。decode()做具体的解码操作,只需实现该方法就可定义自己的解码器。
(2)DelimiterBasedFrameDecoder:基于通用分隔符的解码器。可以指定一个中多个分隔符来分隔接收到的ByteBuf。它特别适用于解码以分隔符(如换行符或NUL符)结束的消息帧。Delimiters类中定义了常用的分隔符,如换行分隔符、NUL分隔符。decode()方法用来实现具体解码操作。
(3)LineBasedFrameDecoder:基于行分隔的解码器LineBasedFrameDecoder是一个特殊的分隔符解码器,该解码器使用的分隔符为:windows的\r\n和类linux的\n。
(4)FixedLengthFrameDecoder:定长消息帧解码器。按照固定长度frameLength解码出消息帧。
(5)LengthFieldBasedFrameDecoder:基于长度字段的消息帧解码器。该解码器可根据数据包中的长度字段动态的解码出消息帧。一个推荐的二进制传输协议可设计为"header_length|header|data_length|data",这样的协议可满足大多数场景使用,但不幸的是很多情况下并不可以设计新的协议,往往要在老旧的协议上传输数据。由此Netty将该解码器设计的十分通用,只要有类似的长度字段便能正确解码出消息帧。
(6)MessageToByteEncoder:消息帧编码器。将出站的POJO消息对象编码为字节数据存储到ByteBuf。用户只需定义自己的编码方法encode()即可。该类有两个成员变量,preferDirect表示是否使用内核的DirectedByteBuf,默认为true。TypeParameterMatcher用于检测泛型参数是否是期待的类型,比如说如果需要编码String类的POJO对象,Matcher会确保write()传入的参数Object的实际切确类型为String。
(7)ByteToMessageCodec:消息帧编解码器。用于传输时的消息帧的解码和编码,组合了ByteToMessageDecoder和MessageToByteEncoder两者的功能。
(8)ReplayingDecoder:重放式解码器。是ByteToMessageDecoder的一个特殊变体,实现了在阻塞IO环境上非阻塞的解码。它与ByteToMessageDecoder最大的不同,是允许你在实现decode()和decodeLast()解码操作时,无需检查ByteBuf中可用的字节数,就好像所有字节数据都已经收到一样。
(9)MessageToMessageDecoder/MessageToMessageEncoder/MessageToMessageCodec:一个消息类型到另一个消息类型的解码和编码。例如解码一个String为一个Integer,代表这个String的长度。
(10)LengthFieldPrepender:添加长度字段的编码器。它可以计算当前待发送消息的二进制字节长度,将该长度添加到ByteBuf的缓冲区头中,编码后的消息组成为长度字段+原消息的方式。
(11)MessageAggregator:消息聚合解码器。将多个消息对象聚合成单一的消息对象。聚合后的消息内容包含了各个消息对象的内容。
(12)DatagramPacketDecoder/DatagramPacketEncoder:UDP数据报文的解码和编码。使用指定的ByteBuf解码器(例如ProtobufDecoder)解码入站的DatagramPacket内容;或者反过来,使用指定的消息编码器(例如ProtobufEncoder)将AdressedEnvelope内容编码成DatagramPacket。

##18. codec.base64
Base64Decoder, Base64Encoder, Base64
(1)Base64Decoder:将base64编码的入站ByteBuf解码到一个ByteBuf中。注意如果使用基于流的传输协议如TCP/IP,则在使用Base64Decoder之前必须先用一个ByteToMessageDecoder(例如DelimiterBasedFrameDecoder)进行解码。
(2)Base64Encoder:将出站的ByteBuf编码成base64格式的ByteBuf。
(3)Base64:工具类,提供一组decode()和encode()方法,ByteBuf用它们来解码或编码base64格式的数据。

##19. codec.bytes
ByteArrayDecoder, ByteArrayEncoder
(1)ByteArrayDecoder:将入站的ByteBuf解码到一个byte[]字节数组中。
(2)ByteArrayEncoder:将出站的byte[]字节数组编码到ByteBuf中。

##20. codec.string
LineEncoder, StringDecoder, StringEncoder
(1)LineEncoder:将行分隔符附加到出站的String数据,然后编码到ByteBuf中。
(2)StringDecoder:将入站的ByteBuf解码到String中。注意在使用StringDecoder之前先用一个ByteToMessageDecoder(例如 LineBasedFrameDecoder)进行解码。
(3)StringEncoder:将出站的String编码到ByteBuf中。

##21. codec.http
HttpMethod, HttpVersion, HttpScheme
QueryStringDecoder, QueryStringEncoder
HttpHeaders, HttpHeaderNames, HttpHeaderValues, HttpResponseStatus, Cookie
FullHttpMessage, FullHttpRequest, FullHttpResponse
(1)HttpMethod/HttpVersion/HttpScheme:定义了Http方法、Http版本信息、Http scheme(http/https)。
(2)QueryStringDecoder:URL解析器。将url进解析成path和一组key-value的url参数对。也可解析Content-Type为application/x-www-form-urlencoded的http post请求参数。path()返回解析出来的URI路径,parameters()返回所有k-v参数对。
(3)QueryStringEncoder:将一个path和一组key-value参数对编码成一个完整的URI。addParam()添加url参数,toUri()转换成URI对象,toString()转换成完整的URI字符串。
(4)HttpHeaders:Http头部信息的容器。包含对header的内容进行封装及操作,如添加、修改、删除、获取Http头部信息。DefaultHttpHeaders是默认的实现类。HttpHeaderNames类中定义了标准的Http头名称,HttpHeaderValues类中定义了标准的Http头的值。
(5)HttpResponseStatus:定义了标准的HTTP响应状态码。
(6)Cookie:表示一个cookie。DefaultCookie是默认的实现类。主要操作name()/value()/setValue()/path()/setPath()/domain()/setDomain()/maxAge()/setMaxAge()/isHttpOnly()/setHttpOnly()/isSecure()/setSecure()/wrap()/setWrap()
(7)FullHttpMessage:联合HttpMessage和LastHttpContent,表示一条完整的HTTP消息。主要操作protocolVersion()/setProtocolVersion()/headers()/decoderResult()/setDecoderResult()/content()/copy()/duplicate()/replace()/retain()/touch()。
(8)FullHttpRequest:联合HttpRequest和FullHttpMessage,表示一个完整的HTTP请求。DefaultFullHttpRequest是默认实现类。主要操作protocolVersion()/setProtocolVersion()/headers()/method()/setMethod()/uri()/setUri()/decoderResult()/setDecoderResult()/content()。
(9)FullHttpResponse:联合HttpResponse和FullHttpMessage,表示一个完整的Http响应。DefaultFullHttpResponse是默认的实现类。主要操作protocolVersion()/setProtocolVersion()/headers()/status()/setStatus()/decoderResult()/setDecoderResult()/content()。

##22. HttpRequestDecoder, HttpObjectAggregator, HttpRequestEncoder
HttpResponseEncoder, HttpContentCompressor, HttpResponseDecoder
HttpServerCodec, HttpClientCodec
HttpServerUpgradeHandler, HttpClientUpgradeHandler
HttpServerKeepAliveHandler, HttpServerExpectContinueHandler
(1)HttpRequestDecoder:Http请求解码器,将入站的ByteBuf解码成HttpRequest和HttpContent。参数maxInitialLineLength指定http请求的初始行(如POST /1.0.0/_health_check HTTP/1.1)的最大长度,maxHeaderSize指定所有headers总的最大长度,maxChunkSize指定请求内容或每个块的最大长度。该解码器先通过InitialLine和Header解析成HttpRequest对象,传入到HttpObjectAggregator。然后再通过body解析出httpContent对象,传入到HttpObjectAggregator。当HttpObjectAggregator发现是LastHttpContent,则代表http协议解析完成,封装FullHttpRequest。对于body内容的读取涉及到Content-Length和trunked两种方式。两种方式只是在解析协议时处理的不一致,最终输出是一致的。
(2)HttpObjectAggregator:Http内容聚合处理器,将一个HttpMessage和后跟着的多个HttpContent聚合成单一的FullHttpRequest或FullHttpResponse。这对transfer encoding为chunked的Http消息特别有用。处理Http请求时要将该处理器插入到处理器链的HttpRequestDecoder和HttpResponseEncoder之后,处理Http响应时要将该处理器插入HttpResponseDecoder之后。
(3)HttpRequestEncoder:Http请求编码器,将一个出站的HttpRequest和HttpContent编码到ByteBuf中。主要用在Http客户端中。
(4)HttpResponseEncoder:Http响应编码器,将出站的FullHttpResponse(包括HttpRequest和HttpContent)编码到ByteBuf中。socket再将ByteBuf数据发送到访问端。对FullHttpResponse按照http协议进行序列化。判断header里面是ContentLength还是Trunked,然后body按照相应的协议进行序列化。
(5)HttpContentCompressor:Http内容压缩编码器。将出站的FullHttpResponse对象按gzip或deflate压缩编码(在Accept-Encoding头部中指定)压缩,如果没有指定压缩格式,则不进行压缩。HttpContentCompressor一般放在HttpResponseEncoder之前,在压缩之后再经过HttpResponseEncoder进行序列化。
(6)HttpResponseDecoder:Http响应解码器,将入站的ByteBuf解码成HttpResponse和HttpContent。用在Http客户端中。
(7)HttpServerCodec:服务端编解码器,是HttpRequestDecoder和HttpResponseEncoder功能的聚合,是更方便的服务端Http实现。
(8)HttpClientCodec:客户端编解码器,是HttpRequestEncoder和HttpResponseDecoder功能的聚合。对HEAD和CONNET请求它还提供了额外的状态管理。
(9)HttpServerUpgradeHandler:服务端协议切换处理器。接收入站HTTP请求,并且可选地执行一个协议切换(如果请求协议支持的话)。切换完成后从处理器链中移除。
(10)HttpClientUpgradeHandler:客户端协议切换处理器。当第一个Http请求发送出去时,本处理添加所有合适的头信息,并执行协议切换。
(11)HttpServerKeepAliveHandler:用于自动关闭持久的连接。如果Channel能处理持久连接,它可能会设置’Connection’头信息,本处理器用于自动关闭收到LastHttpContent后的客户端Channel。本处理器要添加到HttpServerCodec之后,但是在任何会发送HttpResponse的处理器之前。
(12)HttpServerExpectContinueHandler:对包含’expect: 100-continue’的Http请求,发送100 continue的Http响应。它只能用在没有安装HttpObjectAggregator的应用中,被添加到HttpServerCodec之后,但是在任何会发送HttpResponse的处理器之前。

##23. Cookie, Cors
ServerCookieDecoder, ServerCookieEncoder
ClientCookieDecoder, ClientCookieEncoder
CorsConfig, CorsConfigBuilder, CorsHandler
(1)ServerCookieDecoder/ServerCookieEncoder:RFC6265兼容的cookie解码器和编码器,用在服务端。解码器提供decoder()方法将指定的Set-Cookie头中的值解析成Cookie对象列表。编码器提供encode()方法将Cookie列表编码成Set-Cookie头里的值。
(2)ClientCookieDecoder/ClientCookieEncoder:RFC6265兼容的cookie解码器和编码器,用在客户端。解码器提供decoder()方法将指定的Set-Cookie头中的值解析成Cookie对象,编码器提供encode()方法将Cookie列表编码成Cookie头中的值。
(3)CorsConfig:CORS配置。主要方法allowedRequestHeaders()、allowedRequestMethods()、exposedHeaders()、isAnyOriginSupported()、isCorsSupportEnabled()、isCredentialsAllowed()、isNullOriginAllowed()、isShortCircuit()、maxAge()、origins()、preflightResponseHeaders()。
(4)CorsConfigBuilder:用来配置和创建CorsConfig的builder。主要方法allowCredentials()、allowedRequestHeaders()、allowedRequestMethods()、allowNullOrigin()、disable()、 exposeHeaders()、forOrigins()、forAnyOrigin()、maxAge()、preflightResponseHeader()、shortCircuit()、build()。
(5)CorsHandler:用于处理CORS请求的ChannelDuplexHandler。构造时指定一个CorsConfig配置。

##24. http.multipart
DiskFileUpload, MemoryFileUpload, MixedFileUpload
DiskAttribute, MemoryAttribute, MixedAttribute
HttDataFactory
HttpPostRequestDecoder, HttpPostStandardRequestDecoder, HttpPostMultipartRequestDecoder, HttpPostRequestEncoder
(1)DiskFileUpload:文件上传实现。存储文件到实际的文件系统上。FileUpload接口的很多方法类似于java.io.File API。主要操作addContent()/checkSize()/definedLength()/delete()/getByteBuf()/getCharset()/setCharset()/getChunk()/getFile()/getMaxSize()/getString()/isComplete()/length()/renameTo()/getBaseDirectory()/getContentTransferEncoding()/getContentType()/getDiskFilename()。
(2)MemoryFileUpload:默认的文件上传实现,存储文件到内存中。
(3)MixedFileUpload:混合实现,使用内存和固定大小的实际磁盘文件。
(4)DiskAttribute/MemoryAttribute/MixedAttribute:文件上传的属性。Attribute表示multipart/form-data表单里带的各种name=的属性。
(5)HttpDataFactory:创建Http文件数据上传的工厂,默认实现类是DefaultHttpDataFactory,构造时指定具体的Atrribute和FileUpload实现。
(6)HttpPostRequestDecoder/HttpPostStandardRequestDecoder/HttpPostMultipartRequestDecoder:POST Body数据解码器。在完成后必须调用destroy()释放所有资源。
(7)HttpPostRequestEncoder:用于编码带Form表单的POST请求。根据RFC7231,POST, PUT和OPTIONS请求允许有body。本编码器支持各种表单编码操作。主要方法addBodyAttribute()/addBodyFileUpload()/addBodyHttpData()/cleanFiles()/finalizeRequest()/getBodyListAttributes()/isChunked()/isEndOfInput()/isMultipart()/length()/progress()/readChunk()。

##25. ObjectDecoder, ObjectEncoder
CompatibleObjectEncoder
ObjectEncoderOutputStream, ObjectDecoderInputStream
JsonObjectDecoder
XmlDecoder, XmlFrameDecoder
(1)ObjectDecoder:对象反序列化解码器。将入站的ByteBuf反序列化成实现Serializable接口的Java对象。注意这里的反序列化格式并不兼容标准的ObjectOutputStream。可以使用ObjectEncoder或ObjectEncoderOutputStream来确保与本解码器的互操作性。
(2)ObjectEncoder:对象序列化编码器。将实现Serializable接口的出站Java对象序列化成ByteBuf。注意这里的序列化格式并不兼容标准的ObjectInputStream。可以使用ObjectDecoder或ObjectDecoderInputStream来确保与本编码器的互操作性。
(3)CompatibleObjectEncoder:兼容的对象序列化编码器。将实现Serializable接口的Java对象序列成ByteBuf,并且可以与标准的Java对象流互操作,如ObjectInputStream和ObjectOutputStream。
(4)JsonObjectDecoder:Json解码器。它不会做实际的JSON解析或验证,只是将JSON对象/数组的字节流,根据花括号{}或中括号[]分割成独立的对象/数组传给ChannelPipeline。让后续的处理器来把JSON文本解析成POJO。
(5)XmlDecoder:异步的XML解码器,基于Aalto XML解析器。将入站的数据解析成一个XML消息。
(6)XmlFrameDecoder:XML帧解码器。只用于单个独立的XML文档消息流。文档中的每个顶级开始元素和结束元素之间为一帧,解码器根据每个开始元素和对应结束元素将文档解析成多个xml帧片断。
(7)Netty其他编解码框架实现:compression(Bzip2, FastLz, Zlib, JdkZlib, JZlib, Lz4, Lzf, Snappy)、DNS、haproxy、WebSocket、Http2、JBoss Marshalling、memcache、mqtt、protobuf、redis、rtsp、sctp、smtp、socksx、spdy、stomp。

#Netflix Eureka Client库

应用领域:微服务架构,服务注册和发现
##1. InstanceInfo, LeaseInfo
DataCenterInfo, AmazonInfo, MyDataCenterInfo
EurekaInstanceConfig, CloudInstanceConfig, MyDataCenterInstanceConfig
Archaius1AmazonInfoConfig
ApplicationInfoManager
(1)InstanceInfo:应用实例信息,表示向Eureka服务器注册的服务实例。包括instanceId, appName, appGroupName, ipAddr, port, securePort, homePageUrl, statusPageUrl, healthCheckUrl, secureHealthCheckUrl, vipAddress, secureVipAddress, dataCenterInfo, hostName, status, leaseInfo, metadata, lastUpdatedTimestamp, lastDirtyTimestamp。
(2)LeaseInfo:服务租约信息。包括getDurationInSecs(), getEvictionTimestamp(), getRegistrationTimestamp(), getRenewalIntervalInSecs(), getRenewalTimestamp(), getServiceUpTimestamp()。
(3)DataCenterInfo:数据中心信息。目前只有一个name属性。实现类AmazonInfo只用于描述AWS数据中心,而MyDataCenterInfo类则可用于描述用户自己的数据中心。
(4)EurekaInstanceConfig:应用实例配置接口,抽象基类。例如应用名、ipAddress、端口等。使用该配置类来配置并创建具体的InstanceInfo实例对象。其他重要有属性还有:
getLeaseRenewalIntervalInSeconds():租约续租频率,默认为30秒
getLeaseExpirationDurationInSeconds():租约过期时间,默认为90秒
getDataCenterInfo():数据中心信息
getNamespace():配置命名空间,默认使用eureka。每个属性最前面的eureka即是配置命名空间,一般情况无需修改。
isInstanceEnabledOnit():应用初始化后是否开启。
(5)CloudInstanceConfig:AWS数据中心实例的配置实现类。从EurekaInstanceConfig继续。
(6)MyDataCenterInstanceConfig:非AWS数据中心的Eureka应用实例配置实现类。一般情况下使用MyDataCenterInstanceConfig配置Eureka应用实例。在Spring-Cloud-Eureka里,直接基于EurekaInstanceConfig接口重新实现了配置类,实际逻辑差别不大。
(7)Archaius1AmazonInfoConfig:加载Amazon EC2元数据时的相关配置,基于Archaius实现。只适用于Amazon EC2。
(8)ApplicationInfoManager:应用信息管理器。初始化并管理一个应用实例InstanceInfo和关联的配置EurekaInstanceConfig。如实例状态变更、属性更改等。主要操作initComponent(), getEurekaInstanceConfig(), getInfo(), refreshDataCenterInfoIfRequired(), refreshLeaseInfoIfRequired(), registerAppMetadata(), registerStatusChangeListener(), unregisterStatusChangeListener(), setInstanceStatus()。

##2. EurekaClientConfig, EurekaClient
EurekaTransportConfig, EurekaHttpClient
MetricsCollectingEurekaHttpClient, RedirectingEurekaHttpClient, RetryableEurekaHttpClient, SessionedEurekaHttpClient
(1)EurekaClientConfig:Eureka-Client配置接口,包含EurekaClient的各种配置信息。默认实现类为DefaultEurekaClientConfig。主要的配置属性:
getRegion():Eureka-Client所在区域(region)。
getAvailabilityZones():Eureka-Client所在地区(region)可用区(zone)集合。该参数虽然是数组,第一个元素代表其所在的可用区。
getEurekaServerDNSName():Eureka-Server的DNS名。
getEurekaServerPort():Eureka-Server的端口。
getEurekaServerURLContext():Eureka-Server的URL Context。
getEurekaServiceUrlPollIntervalSeconds():轮询获取Eureka-Server地址变更频率,默认是300秒。
shouldPreferSameZoneEureka():优先使用相同区(zone)的Eureka-Server。
getEurekaServerServiceUrls():Eureka-Server的URL集合。
getRegistryFetchIntervalSeconds():从Eureka-Server拉取注册信息频率,默认是30秒。
shouldFilterOnlyUpInstances():是否过滤,只获取状态为开启(Up)的应用实例集合。
getRegistryRefreshSingleVipAddress():只获得一个vipAddress对应的应用实例们的注册信息。
getInstanceInfoReplicationIntervalSeconds():向Eureka-Server同步应用实例信息变化频率。
getInitialInstanceInfoReplicationIntervalSeconds():向Eureka-Server同步应用信息变化初始化延迟。
getHeartbeatExecutorThreadPoolSize():心跳执行线程池大小。
getHeartbeatExecutorExponentialBackOffBound():心跳执行超时后的延迟重试的时间。
(2)EurekaClient:Eureka客户端的接口,默认实现为DiscoveryClient。用于与Eureka-Server交互,包含注册实例到服务中心、续订服务实例的租约、取消服务实例的租约、从服务中心查询可用的服务实例列表。Eureka客户端需要指定一个可连接的Eureka服务器URL列表。创建DiscoveryClient时要指定ApplicationInfoManager和EurekaClientConfig配置信息。它提供多种方法获取InstanceInfo实例信息集合、提供获取本地Client数据(region)的方法、提供注册和访问Client健康检查处理器的方法。如getInstancesById(), getInstancesByVipAddress(), getAllKnownRegions(), getApplication(), getApplications(), getHealthCheckHandler(), getNextServerFromEureka()。
1)注册实例:Eureka-Client向Eureka-Server发起注册应用实例需要配置eureka.registration.enabled=true。每次InstanceInfo发生属性变化时,标记isInstanceInfoDirty属性为true,表示InstanceInfo在Eureka-Client和Eureka-Server数据不一致,需要注册。另外InstanceInfo刚被创建时,在Eureka-Server不存在,也会被注册。当符合条件时,InstanceInfo不会立即向Eureka-Server注册,而是后台线程定时注册。当InstanceInfo的状态(status)属性发生变化时,并且配置eureka.shouldOnDemandUpdateStatusChange=true时,则立即向Eureka-Server注册。因为状态属性非常重要,一般情况下建议开启,当然默认情况也是开启的。
2)租约续租:Eureka-Client向Eureka-Server发起注册应用实例成功后获得租约(Lease)。Eureka-Client固定间隔向Eureka-Server发起续租(renew),避免租约过期。默认情况下租约有效期为90秒,续租频率为30秒。两者比例为1:3,保证在网络异常等情况下,有三次重试的机会。
3)下线实例:应用实例关闭时,Eureka-Client向Eureka-Server发起下线应用实例。需要配置eureka.registration.enabled=true和eureka.shouldUnregisterOnShutdown=true。
4)查询注册实例:Eureka-Client获取注册信息,分成全量获取和增量获取。默认配置下Eureka-Client启动时,首先执行一次全量获取进行本地缓存注册信息,而后每30秒增量获取刷新本地缓存(非“正常”情况下会是全量获取)。
(3)EurekaTransportConfig:传输层的配置接口。默认实现类DefaultEurekaTransportConfig。主要配置属性:
getSessionedClientReconnectIntervalSeconds():EurekaHttpClient会话周期性重连时间。
getRetryableClientQuarantineRefreshPercentage():请求失败的Eureka-Server隔离集合占比Eureka-Server全量集合占比,超过该比例,进行清空。
etAsyncResolverRefreshIntervalMs():异步解析EndPoint集群频率。
getAsyncResolverWarmUpTimeoutMs():异步解析器预热解析EndPoint集群超时时间。
getAsyncExecutorThreadPoolSize():异步解析器线程池大小。
applicationsResolverUseIp()/getWriteClusterVip()/getReadClusterVip()/getBootstrapResolverStrategy()。
(4)EurekaHttpClient:低级别的Eureka HTTP客户端接口。主要实现类有MetricsCollectingEurekaHttpClient, RedirectingEurekaHttpClient, RetryableEurekaHttpClient和SessionedEurekaHttpClient。主要方法getApplication(), getApplication(), getInstance(), getVip(), getDelta(), register(), cancel(), deleteStatusOverride(), statusUpdate(), sendHeartBeat()。

#ZipKin/Brave

应用领域:分布式链路跟踪和监控
##1. Span, Annotation
BinaryAnnotation, Endpoint
(1)Span:一个调用的跟踪跨度。用Span.Builder来构建。包含的属性有traceId, traceIdHigh, spanId, parentId, name, timestamp, duration, annations, binaryAnnotations。跨度通常由RPC客户端来创建,也可以表示一个进程内的活动。annotations注释用于及时记录事件。一个标注可以理解成span生命周期中重要时刻的数据快照,比如一个标注中一般包含发生时刻(timestamp)、事件类型(value)、端点(endpoint)等信息。有四种核心注释用于定义RPC请求的开始和结束,包括cs, sr, ss, cr。binaryAnnotations中二进制注释,旨在提供有关RPC的额外信息。
(2)Annotation:跨度的注释信息,用来记录关键事件。用Annotation.Builder来构建。包括timestamp, value, endpoint三个属性。因此create()创建注释时要指定这三个参数。value表示事件类型,有cs, sr, ss, cr这四种。
(3)BinaryAnnotation:二进制注释,记录调用跟踪的额外信息。用BinaryAnnotation.Builder来构建。属性value为byte[]类型,还有key, type, endpoint属性。
(4)Endpoint:端点,通常表示RPC调用的源或目的地址和端口、服务名等。用Endpoint.Builder来构建。属性包括ipv4, ipv6, port, serviceName属性。

##2. Collector, CollectorSampler
ZooKeeperCollectorSampler, InMemoryCollectorMetrics
KafkaCollector, RabbitMQCollector, ScribeCollector
(1)Collector:跨度的收集器接口。用于接收从一个传输层(如HTTP,Kafka)发送过来的span,然后进行处理。比如反序列化、采样、或保存到持久存储中等。接收span时支持注册回调处理函数。主要操作accept(), acceptSpans(), builder(), decodeList(), idString(), isSampled(), record()。
(2)CollectorSampler:收集过程的采样器,抽象基类。用于确定一个跟踪是否应该采样,例如记录到永久存储中。它通过比较traceId的绝对值是否在动态边界办来接受一定比例的traceId。例如isSampled==abs(traceI)<=boundary。此实现的采样率不会完全匹配输入速率,因为traceId在64位上并不是完美的分布。 例如当100K traceId是随机的时,测试显示错误率为3%。
(3)ZooKeeperCollectorSampler:基于ZK的自适应采样器。在流量激增时可以防止压垮zipkin存储层。它的工作方式是协调多个实例的采样速率与单个存储层的存储速率(每分钟跨度个数spans/minute)。它假定每个实例存储它采样的所有span,并且存储速率是一个有用的度量。如果存储层能够达到10k 跨度/分钟,您可以将ZooKeeper中的目标速率设置为10000。考虑到这一点,写入速率为10k跨度/分钟的10个负载均衡的收集器最终会看到0.10的采样速率,从而使速度降低到匹配存储的能力。该对象产生一个单一的调度线程,根据更新频率报告其span采样速率。算法和默认值被调整为有利于降低采样率或增加采样率。例如写入激增会比写入下降更快地进行速率调整。操作boundary(), builder(), close(), isSampled()。
(4)InMemoryCollectorMetrics:收集器指标的度量。操作bytes(), clear(), forTransport(), incrementBytes(), incrementMessages(), incrementSpans(), messages(), spans()。
(5)KafkaCollector:span的kafka收集器。用KafkaCollector.Builder来构建。它会轮询kafka topic,从中获取用TBinaryProtocol大端字节编码的span列表消息。这些span被推送给span的消费方。操作builder(), check(), start(), close()。
(6)RabbitMQCollector:该收集器从一个RabbitMQ队列中消费编码的二进制消息。操作builder(), check(), start(), close()。
(7)ScribeCollector:span的Sribe收集器。它接收Scribe日志消息。每条日志包含单个span,用TBinaryProtocol大端字节编码,然后用base64编码。这些span被推送到异步的span消费者进行消费。操作builder(), check(), start(), close()。

##3. InMemorySpanStore, GuavaSpanStore
InMemoryStorage, GuavaStorageComponent, LazyGuavaStorageComponent
(1)InMemorySpanStore:基于内存的span存储。提供直接从内存中查找span的操作。主要操作getRawTrace(), getRawTraces(), getServiceNames(), getSpanNames(), getTrace(), getDependencies()。
(2)InMemoryStorage:基于内存的存储组件类,用于方便构建span的内存存储。主要操作accetedSpanCount(), asnycSpanConsumer(), asyncSpanStore(), builder(), check(), clear(), close(), spanConsumer(), spanStore()。
(3)GuavaSpanStore:与SpanStore类似的跨度存储接口,但方法返回的类型是一个ListenableFuture,以允许异步操作。
(4)GuavaStorageComponent:基于Guava的存储组件类,抽象基类。主要操作asyncSpanConsumer(), asyncSpanStore(), guavaSpanConsumer(), guavaSpanStore(), spanStore()。
(5)LazyGuavaStorageComponent:基于Guava的惰性存储组件,抽象基类。操作computeGuavaSpanConsumer(), computeGuavaSpanStore(), guavaSpanConsumer(), guavaSpanStore()。

##4. MySQLStorage, ElasticsearchStorage
ElasticsearchHttpStorage, CassandraStorage
(1)MySQLStorage:跨度span的MySQL存储实现。用MySQLStorage.Builder来构建。操作asyncSpanConsumer(), asyncSpanStore(), builder(), check(), close(), datasource(), spanStore()。
(2)ElasticsearchStorage:跨度span的elasticsearch存储实现。用ElasticsearchStorage.Builder来构建。操作check(), clear(), close(), flush(), flushOnWrites(), hostsSupplier(), http(), indexNameFormatter(), maxRequests(), newBuilder(), pipeline(), spanConsumer(), spanStore(), stricttTraceId(), version()。
(3)ElasticsearchHttpStorage:基于HTTP客户端的Elasticsearch跨度存储实现。使用ElasticsearchHttpStorage.Builder来构建。操作builder(), check(), close(), spanStore(), spanConsumer(), toBuilder()。
(4)CassandraStorage:跨度span的Cassandra存储实现。操作builder(), check(), close(), computeGuavaSpanConsumer(), computeGuavaSpanStore(), session()。

##5. AsyncReporter, Sender
URLConnectionSender, OkHttpSender, KafkaSender, RabbitMQSender, LibthriftSender
(1)AsyncReporter:异步reporter,用于异步编码和发送span数据到传输客户端(如HTTP或Kafka)。由AsyncReporter.Builder来创建。主要操作builder(), create(), flush(), v2(), close()。Builder构建时的配置操作messageMaxBytes(), queuedMaxBytes(), queuedMaxSpans(), messageTimeout(), closeTimeout(), metrics(), build()。跨度数据在异步发送时会先添加到一个挂起队列中。当调用flush()时发送任务开始在一个独立的线程中运行。span数据基于字节数或一个超时时间被编码成消息。
(2)URLConnectionSender:发送器通用接口Sender用于发送已编码的span列表到传输客户端例如kttp或kafka。URLConnectionSender使用URLConnection POST端点来发送span到Zipkin,这个发送器是线程安全的。主要操作check(), close(), create(), json(), encoding(), messageMaxBytes(), messageSizeInBytes(), sendSpans(), builder()。
(3)OkHttpSender:使用OkHttp POST端点发送spans到Zipkin,这个发送器是线程安全。主要的操作与URLConnectionSender类似。实例由OkHttpSender.Builder来创建。
(4)KafkaSender:用来发送通过TBinaryProtocol大端编码的span到kafka topic,这个发送器是线程安全的。主要操作与上面类似。
(5)RabbitMQSender:用来发送json v2编码的span到RabbitMQ队列。注意它不会使用RabbitMQ Publisher确认机制,消息发送完后不会确认消费者是否收到消息。为了线程安全,每个spendSpans()线程会创建一个独立的channel。
(6)LibthriftSender:阻塞式的reporter,通过Scribe发送span到Zipkin,是非线程安全的。

##6. Span(Brave), Tracer
TraceContext, Tracing, CurrentSpanCustomizer
(1)Span:表示一个调用的跟踪跨度。包括要跟踪的数据,如调用的微秒耗时clock、spanId、traceId、parentId、RPC方法名称、描述信息等。一个Span一般由Tracer来创建。Span在完成时由Tracer报告数据返回Zipkin,或者如果未采样则不做任何事情。开始跨度后,您可以注释感兴趣的事件或添加包含详细信息或查找键的标签。跨度有一个上下文,其中包含跟踪标识符,将其放置在代表分布式操作的树中的正确位置。主要操作:
name():设置名称,通常是调用的服务名。
tag():为跨度添加标签,以方便查找、分析等。
start()/finish():开始和结束一个跨度。
flush():报告当前span,无论它是否结束。
abandon():直接丢弃当前的span。
annotate():关联一个表示当前故里的注释事件。
remoteEndpoint​():远程端点地址。对客户端span,这将是远程服务器的地址。
kind():跨度类型Span.Kind,包括CLIENT, SERVER, PRODUCER, CONSUMER类型。
context():返回跨度的上下文信息TracerContext,其中包括tracerId, spanId, parentId, 采样数据等信息。
customizer():返回当前跨度的定制器SpanCustomizer。
(2)Tracer:一条调用链路的跟踪。表示一组span,它们有父子关系或后继关系,共享一个root span。Tracer对象由Tracking来创建。主要操作:
newTrace():创建一个新的跟踪跨度span。
newChild():在指定的跟踪跨度下创建一个子span。
nextSpan():在当前span下返回一个新的子span,如果当前没有span,则直接返回新的根span。
joinSpan​():加入一个指定span中。对新进来的RPC调用的跟踪上下文,复用它的traceId和spanId。
currentSpan​():返回当前跟踪跨度。
currentSpanCustomizer​():返回当前span定制器。
toSpan():将指定跟踪上下文信息转换成一个span对象。
(3)TraceContext:跟踪上下文。包括跟踪跨度的标识符、采样数据等。主要方法traceId(), traceIdHigh(), traceIdString(), spanId(), parentId(), debug(), sampled(), extra()。
(4)Tracing:为跟踪过程提供一组工具方法。用Tracing.Builder构建器来配置和创建Tracing对象。主要操作newBuilder(), tracer(), propagation(), clock(), current(), currentTracerContext(), currentTracer(), close()。另外Tracing.Builder构建器的主要方法有clock(), currentTraceContext(), endpoint(), localEndpoint(), localServiceName(), propagationFactory(), sampler(), spanReporter(), supportsJoin(), traceId128Bit()。
(5)CurrentSpanCustomizer:跟踪跨度的定制器。允许用户通过定制器定制当前的span。主要方法name(), create(), tag(), annotate()。

##7. Propagation, Sampler
B3Propagation, ExtraFieldPropagation
BoundarySampler, CountingSampler, DeclarativeSampler, ParameterizedSampler
(1)B3Propagation:传播接口Propagation用于注入或提取TraceContext中的跟踪标识符到请求实体中,然后在进程间进行传播。标识符通常被编码为消息或RPC请求头。对Http请求,一般是客户端(injector)通过特定的拦截器把跟踪标识符注入到请求的HTTP头中,服务端(extractor)从HTTP头中提取跟踪标识符。B3Propagation定义了要传播的B3属性。B3属性最常传播为Http标头。所有的B3头文件都遵循了X-B3-${name}针对标志的特殊外壳的惯例。必需的HTTP头有X-B3-TraceId、X-B3-SpanId,可选的头有X-B3-ParentSpanId(子span需要这个头)、X-B3-Sampled、X-B3-Flags。主要操作keys()返回定义的传播属性列表,injector​()用指定的值替换一个传播属性。extractor​()用于提取传播属性值。
(2)ExtraFieldPropagation:用于传播额外预定义的请求作用域内的属性,例如额外的HTTP头。主要操作newFactory(), newFactoryBuilder(), injector(), extractor(), keys(), get(), getAll(), set()。
(3)BoundarySampler:采样器用于确定一个跟踪是否应该采样。采样可以用来减少收集和报告的过程数据。如果跨度未采样则不会增加开销(noop)。采样是预先决定的,这意味着报告数据的决定是在一次跟踪中的第一次操作中做出的,并且该决定会向下游传播。默认情况下有一个全局采样器将单一速率应用于所有跟踪的操作。Tracing.Builder.sampler用来表明这一点,它默认跟踪每个请求。BoundarySampler是有界采样器,适用于高流量请求的跟踪(例如每个服务器接收大于100K请求数的web服务)。它提供随机的跟踪ID,并且只进行一次采样决策,以防止群集中的节点选择完全相同的ID。它使用模10000的计算,允许最小采样率为0.01%。在Twitter前端群集的实践中,注意到了跟踪ID的冲突。随机种子在这里是为了防止同一个集群中的节点采样相同的traceId子集。 操作为create()创建采样器,isSampled()判断指定traceId是否已被采样。
(4)CountingSampler:计数器采样器,适用于低流量请求的跟踪(例如每个服务器接收小于100K请求数)。它不提供随机的traceId,不能用于采样决策不幂等(基于traceID)的收集器。它初始化一个大小为100的随机位集(对应于1%的粒度)。 这意味着它以100条跟踪为单位是准确的。在运行时它会循环bitset,根据计数器返回相应的值。
(5)DeclarativeSampler:声明式采样器。用于决定是否跟踪一个在java方法使用了注解的请求。
(6)ParameterizedSampler:参数化采样器。用于决定是否跟踪一个使用了顺序规则的请求。

##8. HttpTracing
HttpClientParser, HttpServerParser
HttpRuleSampler
HttpClientAdapter, HttpServerAdapter
HttpClientHandler, HttpServerHandler
(1)HttpTracing:用于跟踪Http请求的组件。包含Http客户端和服务端跨度span的解析、采样等。用HttpTracing.Builder来创建。主要操作create(), clientOf(), tracing(), clientParser(), serverParser(), clientSampler(), serverSampler(), serverName()。
(2)HttpClientParser, HttpServerParser:Http客户端、服务端span的解析器。把http请求和响应解析成合理的跨度span。操作request(adapter, req), response(adapter, res)。
(3)HttpRuleSampler:基于http请求属性(如路径)的跟踪采样器。HttpRuleSampler用于为指定的路径分配采样率。
(4)HttpClientAdapter, HttpServerAdapter:Http客户端或服务端的适配器,可以适配多种客户端或服务端,如OkHttp3。主要操作method(), path(), requestHeader(), stausCode(), url()。
(5)HttpClientHandler, HttpServerHandler:提供标准化的方式来跟踪和处理Http客户端或服务端的span。主要操作create(), handleReceive(), handleSend(), nextSpan()。

##9. TracingHttpClientBuilder, TracingHttpAsyncClientBuilder
TracingCallFactory, TracingInterceptor
NettyHttpTracing, TracingHttpServerHandler
TracingFilter
(1)TracingHttpClientBuilder:跟踪Apache HttpClient 4.4+客户端。在http请求中添加跟踪span的header,并且可以给span添加标签,然后报告给zipkin服务器。
(2)TracingHttpAsyncClientBuilder:跟踪Apache HttpAsyncClient客户端。在http请求中添加跟踪span的header,并且可以给span添加标签,然后报告给zipkin服务器。
(3)TracingCallFactory:跟踪OkHttpClient客户端。在http请求中添加跟踪span的header,并且可以给span添加标签,然后报告给zipkin服务器。
(4)TracingInterceptor:跟踪OkHttpClient客户端的拦截器。它是在OkHttpClient上通过addNetworkInterceptor()添加的拦截器。拦截器对每个出站的请求会创建相应的span。
(5)NettyHttpTracing, TracingHttpServerHandler:跟踪Netty Http Codec。主要方法create(tracing), serverHandler()返回TracingHttpServerHandler处理器,在ChannelPipeline中添加这个处理器,就可以生成http请求的span。
(6)TracingFilter:跟踪Servlet。标准的Servlet Filter,添加了跟踪span的功能。

##10. TracingProducer, TracingConsumer, kafkaTracing
GrpcTracing, GrpcClientParser, GrpcServerParser, TracingClientInterceptor, TracingServerInterceptor
TracingStatementInterceptor
(1)TracingProducer:跟踪Kafka生产者。对每条kafka记录生成一个生产者span,并通过header进行传播。
(2)TracingConsumer:跟踪Kafka消费者。在poll上生成一个消费者span,并且恢复header中已存在的跟踪。
(3)kafkaTracing:跟踪Kafka请求的组件。用于创建TracingProducer和TracingConsumer。主要操作producer(), consumer(), joinSpan(), nextSpan()。
(4)GrpcTracing:跟踪grpc请求的组件。包括clientParser, serverParser, clientInterceptor, serverInterceptor。
(5)TracingStatementInterceptor:跟踪MySQL语句。对MySQL statement添加拦截器,拦截器对每个出站的SQL语句请求会创建相应的span。
(6)其他的zipkin跟踪实现:JAX-RS, jersey-server, sparkjava, spring-rabbit, spring-web, spring-webmvc, vertx-web等。

#Apache HttpClient库

##1. HttpRequest, HttpResponse, HttpEntity
HttpVersion, HttpHeaders, HttpStatus
BasicHttpRequest, BasicHttpEntityEnclosingRequest, BasicHttpResponse
BufferedHttpEntity, ByteArrayEntity, StringEntity, FileEntity, BasicHttpEntity, InputStreamEntity, SerializableEntity
HttpHost
(1)HttpRequest:Http请求消息接口。包含Http请求行,即请求方法、资源标识、协议版本。BasicHttpRequest是基本的Http请求实现。BasicHttpEntityEnclosingRequest则还包含请求的实体内容。主要方法getRequestLine(), addHeader/setHeader/getHeaders/removeHeader, getParams/setParams, getProtocolVersion。
(2)HttpResponse:Http响应消息接口。BasicHttpResponse是基本的响应实现。主要方法getStatusLine/setStatusLine, getEntity/setEntity, getStatusCode/setStatusCode, getProtocolVersion, getReasonPhrase。
(3)HttpVersion, HttpHeaders, HttpStatus:包括Http版本信息、所有标准头部、所有Http状态码。
(4)HttpEntity:Http消息实体,可以是二进制和字符内容,支持字符编码,支持Java文件流式读写。实现类BufferedHttpEntity, ByteArrayEntity, StringEntity和FileEntity是自包含的、可重复读取的实体。实现类BasicHttpEntity和InputStreamEntity是流式的、不可重复读取的实体。SerializableEntity是流式的实体,从一个Serializable获取内容,它可以被缓存在一个字节数组中,以便自包含并且可以重复读取。主要操作getContent(), getContentEncoding(), getContentLength(), getContentType(), isChunked(), isRepeatable(), isStreaming(), writeTo()。为了确保正确释放系统资源,最后必须关闭与实体关联的内容流。
(5)HttpHost:描述Http连接主机的信息,包括remoteAddress, port, scheme, hostname。

##2. HttpRequestInterceptor, HttpResponseInterceptor, HttpContext
HttpProcessor, HttpProcessorBuilder
RequestContent, RequestConnControl, RequestDate, RequestExpectContinue, RequestTargetHost, RequestUserAgent
ResponseContent, ResponseConnControl, ResponseDate, ResponseServer
BasicHttpContext, HttpCoreContext
(1)HttpRequestInterceptor:Http协议请求拦截处理器。通常协议拦截器额头于对输入消息的一组特定报头起作用,或者用一组相关报头填充输出报文。只有一个process()方法。主要实现类:
RequestContent:出站请求最重要的拦截器。用于添加Content-Length或Transfer-Content头,以便界定内容长度。它是客户端协议处理器正确运行所必需的。
RequestConnControl:负责将Connection头部添加到出站请求中,这对管理HTTP/1.0连接的持久性至关重要。该拦截器推荐用于客户端协议处理器。
RequestDate:负责将Date头部添加到传出的请求。这个拦截器对于客户端协议处理器是可选的。
RequestExpectContinue:负责通过添加Expect头来启用’expect-continue’握手。该拦截器推荐用于客户端协议处理器。
RequestTargetHost:负责添加Host头部。它是客户端协议处理器所必需的。
RequestUserAgent:负责添加User-Agent头。该拦截器推荐用于客户端协议处理器。
(2)HttpResponseInterceptor:Http协议响应拦截处理器。主要实现类:
ResponseContent:出站响应最重要的拦截器。用于添加Content-Length或Transfer-Content头,以便界定内容长度。它是服务器端协议处理器正确运行所必需的。
ResponseConnControl:负责将Connection头添加到传出响应,这对管理HTTP/1.0连接的持久性至关重要。此拦截器推荐用于服务器端协议处理器。
ResponseDate:负责将Date头部添加到传出响应。此拦截器推荐用于服务器端协议处理器。
ResponseServer:负责添加Server头。此拦截器推荐用于服务器端协议处理器。
(3)HttpProcessor:包含了请求拦截器和响应拦截器的Http协议处理器。由HttpProcessorBuilder.create()来创建。
(4)HttpContext:Http协议执行上下文。类似于一个Map,包含一组逻辑上相关的命名值。用于在连续的多个请求之间共享处理状态信息。实现类为BasicHttpContext和HttpCoreContext。

##3. HttpConnection
HttpClientConnection, DefaultBHttpClientConnection
HttpServerConnection, DefaultBHttpServerConnection
HttpConnectionMetrics, HttpConnectionMetricsImpl
HttpService, HttpRequestExecutor
(1)HttpClientConnection:客户端Http连接,用于发送请求和接收响应。DefaultBHttpClientConnection是缺省实现。主要操作isOpen(), isStale(), getSocketTimeout()/setSocketTimeout(), close(), shutdown(), getMetrics(), flush(), isResponseAvailable(), receiveResponseEntity(), receiveResponseHeader(), sendRequestEntity(), sendRequestHeader()。
(2)HttpServerConnection:服务端Http连接,用于接收请求和发送响应。DefaultBHttpServerConnection是缺省实现。主要操作sOpen(), isStale(), getSocketTimeout()/setSocketTimeout(), close(), shutdown(), getMetrics(), flush(), receiveRequestEntity(), receiveRequestHeader(), sendResponseEntity(), sendResponseHeader()。
(3)HttpConnectionMetrics:Http连接的度量指标接口。HttpConnectionMetricsImpl是缺省实现。主要的指标有getReceivedBytesCount(), getRequestCount(), getResponseCount(), getSentBytesCount()。
(4)HttpService:基于阻塞IO的服务器端HTTP协议处理器。实现了RFC 2616描述的服务器端HTTP消息处理的基本需求。它依赖HttpProcessor实例为所有传出消息生成强制协议头,并对所有传入和传出消息使用通用的消息转换。主要方法doService(), handleException()和handleRequest()。构造函数还需要参数ConnectionReuseStrategy,HttpResponseFactory,HttpRequestHandlerMapper。在完全初始化和配置后,HttpService用于执行和处理对活动HTTP连接的请求。HttpService#handleRequest()方法读取传入的请求,生成响应并将其发送回客户端。此方法可以在循环中执行以处理持久连接上的多个请求。该方法可以安全地从多个线程执行。这允许同时处理多个连接上的请求,只要该HttpService线程使用的所有协议拦截器和请求处理程序都是线程安全的。
(5)HttpRequestExecutor:基于阻塞IO的客户端HTTP协议处理器。该模型实现了客户端HTTP消息处理的基本要求。HttpRequestExecutor依赖HttpProcessor实例为所有传出生成强制协议头消息并对所有传入和传出的消息应用通用的交叉消息转换。主要方法preProcess(), execute()和postProcess()。HttpRequestExecutor的方法在多个线程中执行是安全的。这允许同时在多个连接上执行请求,只要所使用的协议拦截器都是线程安全的。

##4. ConnPool, PoolEntry
BasicConnPool, BasicPoolEntry, PoolStats
ServerBootstrap, HttpServer
ConnectionConfig, SocketConfig
(1)ConnPool:客户端Http连接池接口。缺省实现为BasicConnPool,表示一个由HttpHost实例标识的阻塞式HttpClientConnection连接构成的连接池。默认情况下池中有20个并发连接总数,每个唯一路由允许2个并发连接。注意连接池无法知道租用连接是否仍在使用中。用户有责任确保在连接不再需要时将连接释放回池中。主要方法lease(), release(), closeExpired(), closeIdle(), getRoutes(), getStats(), getTotalStats(), shutdown(), isShutdown(), getDefaultMaxPerRoute()/setDefaultMaxPerRoute(), getMaxPerRoute()/setMaxPerRoute(), getMaxTotal()/setMaxTotal(), getValidateAfterInactivity()/setValidateAfterInactivity(), validate()。注意连接池不会主动驱逐过期的连接。即使过期的连接不能租借给请求者,池可能会随着时间积累过时的连接,特别是在一段时间不活动之后。通常建议在长时间不活动后用closeExpired(), closeIdle()强制从池中逐出过期和空闲连接。
(2)PoolEntry:池内的连接对象实体,缺省实现为BasicPoolEntry,表示一个由ttpHost实例标识的阻塞式HttpClientConnection连接对象,还包含它的连接状态。主要方法getConnection(), getCreated(), getExpiry(), getId(), getRoute(), getState(), getUpdated(), getValidityDeadLine(), close(), isClosed(), isExpired(), setState()。 updateExpiry()。
(3)PoolStats:连接池的统计信息。包括getAvailable(), getLeased(), getMax(), getPending()。
(4)HttpServer:一个基于上述阻塞IO的嵌入式Http服务器。主要方法start(), stop(), shutdown(), awaitTermination(), getInetAddress(), getLocalPort()。需要用ServerBootstrap来创建这个HttpServer,并配置服务器的相关参数,例如添加拦截器、Http处理器、连接重用策略、监控端口、连接配置ConnectionConfig,套接字配置SocketConfig等。
(5)ConnectionConfig:Http连接配置,包括bufferSize, charset, fragmentSizeHint, messageConstraints如maxHeaderCount和maxLineLength。
(6)SocketConfig:套接字配置。包括backlogSize, rcvBufSize, sndBufSize, soKeepAlive, soLinger, reuseAddress, soTimeout, tcpNoDelay。

##5. IOReactor, IOEventDispatch
BaseIOReactor, DefaultConnectingIOReactor, DefaultListeningIOReactor
DefaultHttpClientIODispatch, DefaultHttpServerIODispatch
IOSession, IOSessionImpl, SSLIOSession
IOReactorConfig, IOReactorStatus
(1)ListeningIOReactor:能侦听一个或多个端口上的入站连接的I/O反应器。DefaultListeningIOReactor是缺省实现。IOReactor接口就反应器模式实现的接口。在内部IOReactor实现封装了NIO的功能java.nio.channels.Selector。I/O反应器通常会使用少量的调度线程(通常只有一个)来将I/O事件通知分派给更多(通常多达数千)的I/O会话或连接。一般建议每个CPU核有一个调度线程。主要方法execute(), getStatus(), shutdown(), getEndpoints(), listen(), pause(), resume()。方法execute()利用IOEventDispatch接口向客户端通知特定会话上的未决事件。
(2)ConnectingIOReactor:表示一个能与远程主机建立连接的I/O反应器。DefaultConnectingIOReactor是缺省实现。打开与远程主机的连接通常往往是一个耗时的过程,可以通过SessionRequest接口监视和控制会话初始化过程。主要方法execute(), getStatus(), shutdown(), connect()。
(3)IOEventDispatch:IO事件调度分派器。用于向客户端通知特定会话上的未决事件。所有的方法都在I/O反应器的调度线程上执行。其中DefaultHttpClientIODispatch支持明文和SSL加密的HTTP客户端连接,DefaultHttpServerIODispatch支持明文和SSL加密的HTTP服务端连接。主要方法connected(), disconnected(), inputReady(), outputReady(), timeout()。
(4)IOSession:IO会话,代表两个端点之间的逻辑相关的数据交换序列。IOSessionImpl是缺省实现。SSLIOSession是基于SSL/TLS协议对其他IOSession的装饰。I/O会话没有绑定到执行线程,因此不能使用线程的上下文来存储会话的状态。关于特定会话的所有细节必须存储在会话本身内。可以通过设置其事件掩码来声明对特定I/O会话的特定类型的I/O事件的兴趣。I/O会话需要维护内部I/O缓冲区,以便在将输入/输出数据返回给使用者或将其写入底层通道之前转换输入/输出数据。
(5)IOReactorConfig:I/O反应器的配置信息。包括backlogSize, connectTimeout, ioThreadCount, rcvBufSize, selectInterval, shutdownGracePeriod, sndBufSize, soLinger, soTimeout, interestOpQueued, soKeepAlive, soReuseAddress, tcpNoDelay。
(6)IOReactorStatus:枚举类型,表示I/O反应器的内部状态。有ACTIVE, IN_ACTIVE, SHUT_DOWN, SHUTDOWN_REQUEST, SHUTTING_DOWN。

##6. NHttpConnection, HttpAsyncContentProducer
DefaultNHttpClientConnection, DefaultNHttpServerConnection
HttpAsyncService, HttpAsyncRequestExecutor
NByteArrayEntity, NFileEntity, NStringEntity
BasicNIOConnPool, BasicNIOPoolEntry
(1)NHttpClientConnection:非阻塞的客户端Http连接,用于发送HTTP请求和异步地接收HTTP响应。DefaultNHttpClientConnection是缺省实现。每个非阻塞HTTP连接都有一个HttpContext与之关联的实例,可用于维护处理状态。该HttpContext实例是线程安全的。主要方法getContext(), getHttpRequest(), getHttpResponse(), getStatus(), isRequestSubmitted(), resetInput(), resetOutput(), submitRequest()。
(2)NHttpServerConnection:非阻塞的服务端Http连接,用于接收HTTP请求和异步地发送HTTP响应。DefaultNHttpServerConnection是缺省实现。主要方法getContext(), getHttpRequest(), getHttpResponse(), getStatus(), isResponseSubmitted(), resetInput9), resetOutput(), submitResponse()。
(3)HttpAsyncService:基于非阻塞IO(NIO)的异步HTTP服务端协议处理器,它将HTTP协议事件传播给HTTP协议处理程序。它定义的服务器端HTTP I/O事件有connected, requestReceived, inputReady, responseReady, outputReady, endOfInput, exception, timeout, closed。
(4)HttpAsyncRequestExecutor:基于非阻塞IO的异步HTTP客户端协议处理器。它定义的客户端HTTP I/O事件有connected, requestReady, outputReady, responseReceived, inputReady, exception, timeout, closed。
(5)HttpAsyncContentProducer:异步的HTTP内容实体生产者接口。基本实现有NByteArrayEntity, NFileEntity, NStringEntity。主要方法isRepeatable(), produceContent()。
(6)BasicNIOConnPool:非阻塞的HTTP连接池。它与阻塞连接池非常相似,但有一个明显区别,即它必须回复I/O反应器以建立新连接。因此从非阻塞池租用的连接将返回完全初始化并已绑定到特定的I/O会话。由连接池管理的非阻塞连接不能绑定到任意I/O会话。主要方法createEntry(), lease()。

##7. HttpUriRequest
HttpGet, HttpPost, HttpPut, HttpDelete, HttpHead,HttpTrace, HttpOptions
(1)HttpUriRequest:Http请求接口,它提供获取请求属性的方便操作,例如请求URL,请求方法类型。方法getMethod(), getURI(), abort(), isAborted()。具体的实现类包括所有的HTTP方法类型,有HttpGet, HttpPost, HttpPut, HttpDelete, HttpHead,HttpTrace, HttpOptions。

##8. CloseableHttpClient
HttpClientBuilder, HttpClients
RequestConfig
UrlEncodedFormEntity, DecompressingEntity, DeflateDecompressingEntity, GzipDecompressingEntity
(1)CloseableHttpClient:基本了HTTP客户端实现,实现了Closeable。抽象基类,可以用HttpClientBuilder或HttpClients来创建具体的CloseableHttpClient对象。主要方法execute()用于执行各种HTTP请求,如HttpGet, HttpPost, HttpPut等,返回CloseableHttpResponse响应。close()方法关闭与其关联的连接管理器。
(2)HttpClientBuilder:Http客户端构建器,有很多配置参数。包括RequestConfig, ConnectionConfig, SocketConfig等。
(3)RequestConfig:Http客户端的请求配置参数。包括connectionRequestTimeout, connectTimeout, cookieSpec, maxRedirects, socketTimeout, isAuthenticationEnabled, isCircularRedirectsAllowed等,其他方法getLocalAddress(), getProxy(), getProxyPreferredAuthSchemes(), getTargetPreferredAuthSchemes()。
(4)UrlEncodedFormEntity:包括一组NameValuePair的HTTP实体,主要用于HTTP POST表单数据的生成。
(5)DecompressingEntity:用于解压的HttpEntity通用实现。具体实现有DeflateDecompressingEntity, GzipDecompressingEntity。

##9. RouteInfo, HttpClientConnectionManager
HttpRoute, RouteTracker
BasicHttpClientConnectionManager, PoolingHttpClientConnectionManager
(1)RouteInfo:表示到多个中间步骤或跳跃的目标主机的确定路由信息。HttpRoute是一个具体的实现。
(2)HttpClientConnectionManager:HTTP连接管理器,管理持久连接的生命周期,并同步对持久连接的访问​​,以确保一次只有一个线程可以访问连接。BasicHttpClientConnectionManager是一个简单的连接管理器,一次只能维护一个连接。即使这个类是线程安全的,它应该只被一个执行线程使用。它将努力重复使用相同路由的后续请求的连接。但是,如果持久连接的路由与连接请求的路由不匹配,它将关闭现有连接并为给定路由重新打开它。PoolingHttpClientConnectionManager是一个更复杂的实现,它管理客户端连接池并能够处理来自多个执行线程的连接请求。它保持每个路由和总共的最大连接限制。默认情况下将为每个给定路由创建不超过2个并发连接,总共不会有20个连接。主要操作closeExpiredConnections(), closeIdleConnections(), connect(), releaseConnection(), requestConnection(), routeComplete(), shutdown(), upgrade()。

##10. Cookie, CookieStore
BasicClientCookie, BasicClientCookie2
BasicCookieStore
(1)Cookie:表示一个Cookie。最简单的形式是HTTP cookie只是一个名称/值对,通常还包含许多属性,例如有效的域,应用此cookie的源服务器上URL子集路径以及Cookie有效的最长时间。具体实现为BasicClientCookie和BasicClientCookie2。
(2)CookieStore:表示持久性cookie存储的接口。BasicCookieStore是缺省实现,后端用一个ArrayList来存储。

#Kafka客户端库

应用领域:分布式数据流平台,常用于消息系统、网站活动追踪、监控数据、日志数据、事件的采集和存储等
##1. ProducerConfig, KafkaProducer
ProducerRecord, RecordMetadata
Cluster, Node, PartitionInfo, TopicPartition
(1)ProducerConfig:Kafka生产者配置信息。新的Java Producer重要配置项有bootstrap.servers, acks, retries, compression.type, batch.size, linger.ms, buffer.memory, key.serializer, value.serializer。老的Scala Producer最重要的配置项有metadata.broker.list, request.required.acks, compression.codec, producer.type。
(2)KafkaProducer:Kafka生产者,将记录发送到kafka集群的客户端。是线程安全的,最好全局只有一个单例。它由缓冲区池和后台I/O线程组成,保存要发送到服务器的消息。send()方法是异步的,提交的记录放到缓冲池中由后台线程异步提交。它支持幂等模式和事务模式。幂等模式由enable.idempotence配置来启用,它将记录交付语义从至少一次加强为有且只有一次,特别是重试不会再导致消息重复。事务模式允许应用自动发送消息到多个分区和topic主题,它必须设置transactional.id配置属性。事务型的API都是阻塞的,并会在失败时抛出异常。主要方法:
initTransactions():事务开始前的初始化
beginTransaction():开始事务
commitTransaction():提交所有事务操作
abortTransaction​():中断当前事务
close​():关闭producer
flush​():刷新缓存,让记录可以立刻发送出去
send():异步发送记录到一个主题。主要的过程包括确认topic和metadata是可用的;序列化记录的key和value;获取要发送到的partition;向accumulator中追加记录数据,数据会先进行缓存;如果追加完数据且RecordBatch达到batch.size大小,则唤醒sender线程发送数据。
partitionsFor​():获取给定主题的分区元数据。
sendOffsetsToTransaction​():发送一系列指定偏移列表到指定消费者组,并标记这些偏移作为当前事务的一部分。
metrics​():获取内部的监控度量信息。
(3)ProducerRecord:生产者要发送的Kafka记录。构造时包括要发送的主题名称、分区号、时间戳、键key和值value。如果没有指定分区但存在key,则使用key的hash值来选择分区。如果分区和key都没指定,则使用round-robin轮询方式分配分区。记录关联一个时间戳,如果用户没有提供时间戳,则producer将给记录加盖当前时间戳。主要方法equals()/hashCode(), headers(), key()/value(), topic(), partition(), timestamp()。
(4)RecordMetadata:Kafka记录的元数据信息。包括主题名topic、分区号partition、偏移值offset、时间戳timestampe、校验和checksum、序列化key的大小、序列化value的大小。
(5)Cluster:表示一个kafka集群信息,包括clusterId,一组Node节点集、PartitionInfo分区集、topics主题集合。主要方法availablePartitionForTopic(), bootstrap(), clusterResource(), controller(), internalTopics(), leaderFor(), nodeById(), nodes(), partition(), partitionCountForTopic(), partitionsForNode(), partitionsForTopic(), topics(), unauthorizedTopics()。
(6)Node:表示一个kafka节点信息,包括id, host, port, rack。
(7)PartitionInfo:表示一个kafka分区信息,包括topic主题名、分区号、leader节点、replicas复本节点列表、后备leader节点列表。
(8)TopicPartition:包含主题名和分区号。

##2. ConsumerConfig, KafkaConsumer
ConsumerRecords, ConsumerRecord
OffsetAndMetadata, OffsetAndTimestamp
(1)ConsumerConfig:配置Kafka消费者。新的Java Consumer重要配置项有bootstrap.servers, group.id, enable.auto.commit, fetch.min.bytes, fetch.max.bytes。老的Scala Consumer重要配置项有group.id, zookeeper.connect, fetch.message.min.bytes, fetch.message.max.bytes。
(2)KafkaConsumer:Kafka消费者,从kafka集群消费记录的客户端。它透明地处理broker代理的错误,使用消费组来负载均衡地消费消息。它是非线程安全的。Kafka使用消费组来划分消息处理和消费的工作,共享同一个groud.id的所有消费者进程属于同一个消费组。组中的每个消费者可以动态地设置要订阅的主题列表,Kafka会将主题中的每条消息分发给消费组中的一个进程。这是通过平衡消费用户组中所有成员之间的分区来实现的,以便每个分区只能分配给组中的一个用户。具体的分配策略有RangeAssignor,RoundRobinAssignor,StickyAssignor。主要方法:
assign()/assignment():为该消费者手动分配一个分区列表,获取当前分配的分区集。
beginningOffsets()/endOffsets():获取给定分区的第一个偏移量、最后一个偏移量。
offsetForTimes():按时间戳查找给定分区的偏移量。
subscribe()/unscribe()/subscription():订阅(或取消订阅)给定的主题列表,以获取动态分配的分区。subscription()则获取当前订阅的主题集。
poll():从订阅的主题或分区上获取消息数据,返回ConsumerRecords记录集。
commitAsync()/commitSync()/committed():异步或同步提交最近一次的对所有主题的poll()返回的偏移量。committed()则获取给定分区上最后一次提交的偏移量信息。
pause()/paused():暂停从请求的分区中获取数据。paused​()则获取暂停的分区集。
resume():恢复已暂停的指定分区。
wakeup():唤醒当前消费者。
seek()/seekToBeginning()/seekToEnd():用指定偏移量覆盖下一次poll()将要使用的偏移值;查找每个给定分区的第一个或最后一个偏移量。
close():关闭消费者,等待30秒的默认超时时间以进行任何所需的清理。
listTopics():获取用户有权查看的所有主题的分区元数据。
partitionsFor():获取给定主题的分区元数据。
position():获取下一个将要消费的记录的偏移量。
(3)ConsumerRecords:是一个容器,持有消费的ConsumerRecord记录列表,来自特定主题的每个分区。它是由Consumer.poll(long)操作返回的消费记录列表。主要方法count(), isEmpty(), iterator(), partitions(), records()。
(4)ConsumerRecord:表示从kafka集群接收到一条键/值型消费记录。除了key和value,还包含它所属的主题名、分区号、偏移量、时间戳。
(5)OffsetAndMetadata:提交的偏移量信息,还包括描述它的额外元数据(字符串格式),例如提交的节点、时间等。
(6)OffsetAndTimesamp:包含偏移量和时间戳数据的容器类。

##3. AdminClientConfig, AdminClient
(1)AdminClientConfig:管理客户端的配置信息。主要有bootstrap.servers, connections.max.idle.ms, reconnect.backof.max.ms, request.timeout.ms, retry.backoff.ms
(2)AdminClient:Kafka的管理客户端,用于管理和检查主题、broker代理、配置和ACL。所需的最低broker版本是0.10.0.0。具有更严格要求的方法将指定所需的最低broker版本。该客户端在0.11.0.0中引入。主要方法:
alterConfigs():使用默认选项更新指定资源的配置,返回AlterConfigsResult。
alterReplicaLogDirs():更改指定副本的日志目录,返回AlterReplicaLogDirsResult。
close():关闭AdminClient,并释放所有关联的资源。
create():用给定的配置创建一个新的AdminClient。
createAcls()/deleteAcls():创建绑定到特定资源的访问控制列表(ACL)。或根据提供的过滤器删除访问控制表。
createPartitions():根据给定的主题和要增加的分区信息,增加其分区数。
createTopics()/deleteTopics():使用指定选项创建或删除一批主题。
deleteRecords():删除偏移量小于相应分区给定偏移量的记录。
describeAcls():根据提供的过滤器列出访问控制表。
describeCluster():根据指定选项获取集群中的节点信息。
describeConfigs():获取指定资源的配置。
describeLogDirs():查询给定代理集上所有日志目录信息。
describeReplicaLogDirs():查询指定副本的副本日志目录信息。
describeTopics():查询集群中一些主题的描述信息。
listTopics():列出集群中可用的主题。

##4. StreamsConfig, KafkaStreams
StreamMetadata, ThreadMetadata, TaskMetadata
Consumed, StreamsBuilder
Topology, TopologyDescription, KeyValue
(1)StreamsConfig:配置kafka流。重要配置项有bootstrap.servers, application.id, processing.guarantee, isolation.level, enable.idempotence。
(2)KafkaStreams:Kafka流客户端,用于启动或关闭Kafka的流处理。允许对来自一个或多个输入主题的输入执行连续计算,并将输出发送到零个、一个或多个输出主题。计算逻辑可以通过Topology定义Processor的DAG拓扑来指定,或通过StreamsBuilder提供的高级DSL定义的转换来指定。一个KafkaStreams实例可以与其他有相同application.id的实例(在本机上的其他进程或远程机器上的实例)进行协调,组成单个的分布式流处理应用。这些实例将会根据输入主题分配的分区来划分工作负载,以便所有的分区都能被消费。如果实例添加或失败,则所有(剩余的)实例将重新平衡其中的分区分配,以平衡处理负载并确保处理所有输入主题分区。KafkaStreams实例内部包含一个用于读取输入和写入输出的常规KafkaProducer和KafkaConsumer实例。主要方法:
start():通过启动它的所有线程来启动当前KafkaStreams实例。
close():关闭本实例,通过发送信号通知所有线程停止,等等它们加入。
state():返回当前流实例的状态。流的状态有CREATED, ERROR, NOT_RUNNING, PENDING_SHUTDOWN, REBALANCING, RUNNING。
store():获取指定名称的本地StateStore实例的一个包装。
allMetadata():查询使用相同application.id的所有正在运行的KafkaStreams实例,并返回每个实例的StreamsMetadata元数据。
allMetadataForStore():查询使用相同application.id的、包含给定的状态存储StateStore的、所有正在运行的流实例,并返回每个实例的StreamsMetadata元数据。
cleanUp():清理本地StateStore目录,删除所有相关的数据。
localThreadsMetadata():返回当前实例的本地线程运行信息,返回ThreadMetadata信息集。
metadataForKey():根据状态存储名和key信息查询当前运行的KafkaStreams实例,返回它的StreamsMetadata元数据。
(3)StreamsMetadata:Kafka流实例的元数据描述。包括主机地址和端口的HostInfo、可用的状态存储名称集stateStoreNames()、可用的主题分区集topicPartitions()。注意这只是流实例在某个时间点的快照,当重新平衡时,元数据信息会改变。
(4)ThreadMetadata:表示KafkaStreams实例中运行的单个线程的状态信息。包括activeTasks()活动的任务集信息TaskMetadata, standByTasks(), threadName(), threadState()。TaskMetadata表示单个任务的状态信息,包括taskId, 所在的topicPartitions集。
(5)Consumed:定义了一些可选参数,让StreamsBuilder用于创建KStream,KTable和GlobalKTable流实例。可选参数包括key和value的序列化反序列器Serde,时间戳提取器TimestampExtractor,拓扑的偏移量自动重置策略Topology.AutoOffsetReset。
(6)StreamBuilder:Kafka流构建器,提供高级别的DSL来指定Kafka流的拓扑。它构建在低级别的Streams Processor API之上,大部分数据处理操作都可以用几行DSL代码表示。主要方法:
stream():从指定的主题和可选参数创建一个KStream流。
table():从指定的主题、可选参数、可选状态存储实现方式创建一个KTable流。
globalTable():从指定的主题、可选参数、可选状态存储实现方式创建一个GlobalKTable流。
build():构建代表当前各个流处理逻辑的Topology拓扑实例,可以用KafkaStreams客户端来启动这个拓扑实例。
addGlobalStore():向拓扑中添加全局的状态存储StateStore。
addStateStore():向拓扑中添加一个状态储存。
(7)Topology:流处理器拓扑关系的逻辑表示。它是源处理器、中间处理器和接收处理器构成的非循环图。源处理器节点消耗一个或多个Kafka主题并将它们转发给其后继处理器节点。中间处理器节点接收来自上游节点的输入记录,处理记录,并可选地将新记录转发给其一个或所有下游节点。最后接收节点接收来自上游节点的记录并将它们写入Kafka主题。Topology允许你构造这些节点的非循环图,并把它传递给KafkaStreams实例,然后启动记录的消费、处理、并产生新的记录。主要方法:
addSource():添加一个消费指定主题的新源处理器,并将记录转发到子处理器或接收节点。
addSink():添加一个新的接收器,将来自上游父处理器或源节点的记录转发给已命名的Kafka主题。
addProcessor():添加一个新的处理器节点,用于接收和处理由一个或多个父源或处理器节点输出的记录。
addGlobalStore()/addStateStore():向拓扑中添加全局的或普通的StateStore。
connectProcessorAndStateStores​():连接处理器和状态存储。
describe():返回拓扑的描述TopologyDescription。
(8)TopologyDescription:拓扑的元描述。拓扑中相互连接的节点被分组成子拓扑sub-topologies。子拓扑中的节点通过状态存储直接或间接地相连。两个子拓扑没有连接但可以通过主题相互链接,例如一个子拓扑写入主题而另一个子拓扑从相同的主题中读取记录。当KafkaStreams.start()被调用时,不同的子拓扑将会构造并作为独立的任务来执行。拓扑描述中有不同的内嵌描述类型,包括GlobalStore, Node, Processor, Sink, Source, Subtopology。主要方法globalStores(), subtopologies()。
(9)KeyValue:为Kafka流记录定义的键/值对。如果记录直接来自于Kafka主题,则它就是消息的key/value。

##5. KStream, KTable, GlobalKTable
KGroupedStream, KGroupedTable, TimeWindowedKStream, SessionWindowedKStream
TimeWindows, JoinWindows, SessionWindows, UnlimitedWindows
Materialized, Produced, Printed, Serialized, Joined, Windowed
(1)KStream:表示一个KeyValue记录流。每条记录是真实世界中的独立实体或事件。一个KStream可以从一个或多个输入主题中读入并按消息进行消费;也可以来自一个KStream的转换。一个KTable也可以转换成KStream。一个KStream可以按记录进行转换,可以与另一个KStream, KTable, GlobalTable连接,可以聚合成一个KTable。Kafka流DSL可以通过process(), transform(), transformValues()等操作与处理器API混合使用。

无状态的转换操作:
branch():分支操作。根据提供的谓词将KStream中的记录分流成多个KStream实例,有多个谓词时按顺序进行评估。分支操作常用于将记录路由到不同的下游主题。
filter():过滤操作。为每条记录计算谓词函数,保留函数返回true的记录,生成新的KStream。
filterNot():反向过滤操作。为每条记录计算谓词函数,删除函数返回true的记录。
map():转换操作。根据映射函数将输入流的每条记录转换为输出流中的新记录(键和值类型可以任意更改)。map后使用group或join会导致对记录重新分区。尽量使用mapValues,它不会对数据重分区。
mapValues():对值的转换操作。将每个输入记录的值转换为输出记录的新值(可能为新的值类型)。
flatMap():扁平化转换操作。将输入流中每条记录转换为输出流中的零个或多个记录(键和值类型可以任意更改)。
flatMapValues():对值的扁平化转换操作。将输入流中每条记录的值转换成输出流中零个或多个值,键不变。它不会导致数据的重新分区。
merge():合并操作。将此流和给定流合并成一个更大的流。
groupByKey():分组操作。按现有key对记录进行分组,生成KGroupedStream以便后续进行聚合操作。分组是聚合流或表的先决条件,并确保数据正确分区以供后续操作使用。
groupBy():分组操作。根据KeyValueMapper生成的新key对记录进行分组(可能是不同的key类型),生成KGroupedStream以便后续进行聚合操作。分组KTable时也可以指定新的值和值类型。该操作总是导致数据重新分区。因此尽量用groupByKey,它只在需要时才重新分区。
peek():窥视操作。对每条记录执行无状态操作,并返回未更改的流。
selectKey():键更新操作。为每条记录设置一个新的key,可能是新的类型。
through():穿越操作。将输入流中的记录写入到一个主题中,并从该主题创建新的输出流。本质上相当于先KStream.to()后StreamsBuilder.stream()。
foreach():遍历终止操作。对每条记录执行一个无关的动作。
print():打印终止操作。使用Printed提供的选项打印流中的记录。如打印到控制台、文件等。
to():终止操作,将输入流写入到一个主题中。

有状态的转换操作:
aggregate():一般聚合操作。按分组key聚合记录的值,返回KTable。aggregate是reduce的泛化,允许聚合的结果具有与输入值不同的类型。结果写入本地KeyValueStore,可以使用queryableStoreName来查询。参数Initializer指定聚合时初始值,Aggregator指定聚合操作器。本操作可用来计算汇总函数例如count()。
windowBy():窗口聚合操作。按分组key聚合每个窗口的记录值。在KGroupedStream上使用。有基于时间的窗口策略TimeWindows、基于会话的窗口策略SessionWindows。这里只是根据窗口策略分别返回TimeWindowedKStream或SessionWindowedKStream流实例,由它们完成真正的aggregate, count, reduce等聚合操作。
count():计数聚合操作。按分组key计数输入流中的记录总数,返回KTable<K,Long>。
reduce():组合聚合操作。按分组key组合输入流中记录的值。返回KTable。组合表示聚合的结果与输入值类型相同。结果写入本地KeyValueStore。参数Reducer指定聚合计算过程,当前记录值与最后一个聚合值结合在一起,并返回一个新的聚合值。本操作可用于计算汇总函数,例如sum, min, max。
join():内连接操作。支持KStream-KStream(基于窗口),KStream-KTable,KStream-GlobalKTable,KTable-KTable的内连接。将窗口内的左边流记录与key相等的右边流记录进行连接,用ValueJoiner计算连接后的值,返回KStream/KTable。
leftJoin():左连接操作。支持KStream-KStream,KStream-KTable,KStream-GlobalKTable,KTable-KTable的左连接。将窗口内的左边流记录与key相等的右边流记录进行连接,若右边没有匹配记录则用null连到左边,用ValueJoiner计算连接后的值,返回KStream/KTable。
outerJoin():外连接操作。支持KStream-KStream,KTable-KTable的外连接。将窗口内的左边流记录与key相等的右边流记录进行连接,若一边没有匹配记录则用null代替,用ValueJoiner计算连接后的值,返回KStream/KTable。
transform():通用的转移操作。根据转换器将输入流的每条记录转换为输出流中的新记录(键和值类型可以任意更改)。转换后使用group或join会导致对记录重新分区。尽量使用transformValues,它不会对数据重分区。本质上相当于通过Topology.addProcessor()将Transformer添加到流处理拓扑中。
transformValues():对值的转换操作。将每个输入记录的值转换为输出记录的新值(可能为新的值类型)。本质上相当于通过Topology.addProcessor()将ValueTransformer添加到流处理拓扑中。
process():处理终止操作。使用指定的处理器处理输入流中每条记录。本质上相当于通过Topology.addProcessor()将Processor添加到流处理拓扑中。

(2)KTable:表示一个流式的有主键的表,记录被解释成changelog流。流中具有相同键的记录被解释为针对该键的INSERT/UPDATE或DELETE。KGroupedTable是执行分组操作后的KTable中间表示。一个KTable可以从单个的输入主题中读入并按消息进行消费;也可以来自一个KTable的转换。每个本地KTable实例消费输入主题一个分区子集的数据。KStream的一个聚合操作也可以产生KTable。一个KTable可以按记录进行转换,可以与另一个KTable或KStream连接,也可以重新分区和聚合成一个新的KTable。KTable在创建时一般要为内部状态存储(ReadOnlyKeyValueStore)提供一个名称,这对于支持对表的交互式查询是必需的。有内部状态的KTable可以通过交互式查询API来查询表中的数据。支持的转换有filter,filterNot,groupBy,join,leftJoin,outerJoin,mapValues,through,foreach,print,to,toStream。
(3)GlobalKTable:表示一个流式的有主键的全局表,记录被解释成changelog流。流中具有相同键的记录被解释为针对该键的INSERT/UPDATE或DELETE。GlobalKTable只能用作流式表连接的右侧输入。与KTable在所有KafkaStreams实例上进行分区相比,GlobalKTable在每个KafkaStreams实例上都完全被复制。每个GlobalKTable实例消费输入主题的所有分区的数据,因此每个KafkaStreams实例都可以使用完整的数据集。这提供了在不必对输入流进行重新分区的情况下与KStream执行连接的能力。所有与GlobalKTable的连接需要提供一个KeyValueMapper映射器,这个映射器能把左边KStream的KeyValue映射成右边GlobalKTable的key。在用StreamBuilder创建GlobalKTable实例时,要指定后端ReadOnlyKeyValueStore状态存储的名称,这样才能通过交互式查询API进行查询。注意相比于KTable,一个GlobalKTable的状态保存了主题的完整副本,因此所有的按键可以在本地查询。主要方法queryableStoreName()。
(4)KGroupedStream:表示一个分组的记录流。它是KStream执行分组操作后的中间表示,以便后续进行聚合操作。它只能通过KStream的groupByKey()或groupBy()获取。支持的转换有aggregate,count,reduce,windowBy。
(5)KGroupedTable:表示对重新分组后的changelog流式表。它KTable执行分组操作后的中间表示,以便后续进行聚合操作。它只能通过KTable的groupBy()获取。支持的转换有aggregate,count,reduce。
(6)TimeWindowedKStream:表示一个基于时间的窗口记录流。它是KGroupedStream执行WindowBy后的中间表示,以便后续进行进一步的聚合操作。支持转换aggregate,count,reduce。
(7)SessionWindowedKStream:表示一个基于会话的窗口记录流。它是KGroupedStream执行WindowBy后的中间表示,以便后续进行进一步的聚合操作。支持转换aggregate,count,reduce。
(8)TimeWindows:固定大小的、基于时间的窗口规范。其语义是每前进advance=T1毫秒,计算size=T2毫秒内的聚合总数。若advance==size则定义了一个固定大小、不重叠、无间隙的滚动窗口,它将一个流离散化为非重叠窗口,这意味着一条记录属于一个且仅一个滚动窗口中。滚动窗口"与时期对齐",也即第一个窗口从时间戳零开始。例如size为5000ms的滚动窗口[0;5000),[5000;10000),…。滚动窗口只有一个属性即窗口大小。若advance<size则定义了一个固定大小、可能重叠的跳跃窗口,也叫滑动窗口。它将一个流离散化为重叠窗口,这意味着一个记录可能包含在一个或多个相邻窗口中。跳跃窗口由两个属性定义,即窗口大小size和前进间隔advance。前进间隔指定窗口相对于前一个窗口向前移动多少。例如大小为5000毫秒,前进3000毫秒的跳跃窗口[0;5000),[3000;8000),…。主要方法of()创建指定大小的滚动窗口,advanceBy()按指定前进时间创建跳跃窗口,until()设置窗口维持时间,size()返回窗口大小,maintainMs()返回维持时间,windowFor()创建包含指定时间戳的所有窗口。
(9)JoinWindows:用于连接操作的窗口规范,是一个固定大小的滑动窗口。两条记录时间戳的差值如果在窗口大小内,则认为它们在相同的窗口中。因此连接窗口不与时期对齐,而是与记录的时间戳对齐。它的上下窗口时间都包括在内,是闭区间。主要方法of()创建指定大小的连接窗口,before()只修改窗口开始时间,after()只修改窗口结束时间, until()设置窗口维持时间,maintainMs()返回维持时间。
(10)SessionWindows:基于会话的窗口规范,用于将事件聚合到会话中。会话代表了一段活动时间段,由一段确定的不活动时间间隔分开。在不活动间隙内处理的任何事件都会合并到现有会话中。如果该事件超出会话间隔,则将创建新的会话。会话窗口与其他窗口类型不同的是它按key独立进行跟踪,不同键的会话窗口通常有不同的开始和结束时间。会话窗口不是固定大小的,会话的长度由会话中数据的时间戳来驱动。会话窗口的主要应用领域是用户行为分析。基于会话的分析可以从简单的度量标准(例如新闻网站或社交平台上的用户访问量)到更复杂的度量标准(例如客户转换渠道和事件流程)。主要方法with()按不活动时间间隔创建会话窗口,inactivityGap​()返回不活动间隔长度,until()设置窗口维持时间,maintainMs()返回维持时间。
(11)UnlimitedWindows:无限大小的窗口规范,也叫界标窗口。它有一个固定的开始时间,而结束时间是无限的。主要方法of()创建一个从0时刻开始的无限窗口,startOn()创建一个指定开始时间的无限窗口,size()返回窗口大小即Long.MAX_VALUE,until()设置窗口维持时间,maintainMs()返回维持时间。
(12)Materialized:描述状态存储StateStore实现方式。在创建Kafka流时要用到。你可以指定自定义的StateStore实现,或只提供存储名称来使用缺省的RocksDB后端存储。主要方法as()创建指定的存储实现方式,可以指定storeName来使用缺省实现。可以实现键值存储KeyValueStore,它支持put/get/delete/range查询。可以实现会话存储SessionStore,用于存储会话中聚合的值。可以实现窗口存储WindowStore,支持窗口聚合的值。设置可选参数的方法有with(), withCachingDisabled(), withCachingEnabled(), withKeySerde(), withValueSerder(), withLoggingDisabled​()。
(13)Produced:使用流生成新主题时的可选参数。包括keySerde, valueSerde, streamPartitioner。在使用KStream.through()或KStream.to()创建新主题时要用到。
(14)Printed:打印KStream流时的选项。包括toFile(), toSysOut()。打印时可以附加转换器withKeyValueMapper(), withLabel()。
(15)Serialized:对流进行分组操作时指定键和值的Serde。包括keySerde, valueSerde。在使用KStream.groupByKey()或KStream.groupBy()时要用到。
(16)Joined:对流连接操作的可选参数。包括keySerde, valueSerde, otherValueSerde。在join, leftJoin, outerJoin时要用到。
(17)Windowed:对流的窗口聚合操作时得到的key类型,是一个Windowed<K>。

##6. Processor, StateStore
ProcessContext, Punctuator
KeyValueStore, SessionStore, WindowStore, Stores
(1)Processor:流处理器接口,用于处理key-value型记录。用户自已定义流处理器时要实现这个接口。它在拓扑中是一个节点,表示一个处理步骤。要实现的方法有init(ProcessContext), process(), close()。其中init()方法在任务构建阶段由Kafka Streams库调用。用来执行任何所需的初始化。它传入一个ProcessorContext实例,该实例提供对当前处理记录的元数据的访问,包括其源Kafka主题和分区,相应的消息偏移量和其他此类信息。可以使用此ProcessContext实例来调度punctuate间断性任务(通过ProcessorContext#schedule()),将新记录作为键值对转发给下游处理器(通过ProcessorContext#forward()),并提交当前处理进度(通过ProcessorContext#commit())。process()方法用于记录处理逻辑,close()于关闭该处理器。
(2)ProcessContext:处理器上下文。主要操作schedule(), forward(), commit(), reegister(),元数据appConfigs(), applicationId(), getStateStore(), keySerde()/valueSerde(), offset(), partition(), stateDir(), taskId(), timestamp(), topic()。
(3)Punctuator:提供让ProcessContext.schedule()调度的punctuate()操作。上下文实例按PunctuationType指定的时间类型周期性的触发punctuate(),有两种时间类型,流时间STEAM_TIME和挂钟时间WALL_CLOCK_TIME。使用流时间时,punctuate()纯粹由数据触发,因为流时间由输入数据通过TimestampExtrator导出的时间戳确定,根据记录的时间戳向前推进。当没有新的输入数据到达时,流时间不会向前,因此punctuate()不会被调用。当使用系统挂钟时间时,punctuate()纯粹由挂钟时间触发,它按流的poll轮询间隔poll.ms向前推进,与消息是否到达无关。注意如果所有输入主题上的所有输入分区都有新数据(具有较新的时间戳),则流时间会前进。如果至少有一个分区没有可用的新数据,则流时间将不会前进,因此使用流时间的punctuate()不会触发。
(4)StateStore:状态存储接口。你可用这个接口实现自定义的状态存储类,然后状态存储实例的创建一般用StoreBuilder。KeyValueStore, SessionStore, WindowStore是Kafka提供的几个状态存储方式,可以用Stores工厂类来创建它们,它们都默认启用了容错功能。接口方法有init(), persistent(), flus(), close(), name(), isOpen()。
(5)Stores:状态存储工厂,可用于创建各种状态存储实现。包括inMemoryKeyValueStore​,persistentKeyValueStore​,keyValueStoreBuilder​,lruMap​,persistentSessionStore​,sessionStoreBuilder​,persistentWindowStore​,windowStoreBuilder​。

##7. Connector, Task
ConnectorRecord, SourceConnector, SinkConnector
SourceTask, SinkTask
ConnectorContext, SourceRecord, SinkRecord, Schema
(1)Connector:连接器接口。用于管理Kafka与其他系统的集成。或者作为源连接器SourceConnector,从另一个系统拉取数据并发送到Kafka;或者作为接收连接器SinkConnector,将Kafka数据发送到其他系统。具体的实现应该从SourceConnector或SinkConnector继承。连接器有两个主要任务。首先,他们负责为分割数据处理的一组工作任务创建配置。例如数据库连接器可以通过在任务之间均匀地分配一组表来创建这些任务。其次,他们负责监控需要更新配置的输入改变,并通过ConnectorContext通知Kafka连接运行时。连接器会定期检查新的表,通知Kafka连接进行添加或删除。然后Kafka连接将请求新的配置并更新正在运行的任务。主要方法:
config():定义连接器的配置。
initialize():使用提供的ConnectorContext初始化此连接器,以通知运行时输入配置更改。
reconfigure():重新配置此连接器。
start():启动此连接器。
stop():停止连接器。
taskClass():返回连接器的任务实现类。
taskConfigs():根据当前配置返回任务组的配置集合,从而生成大多数配置配置。
validate():根据配置定义验证连接器配置值
version():获取连接器的版本。
(2)Task:连接器要执行的任务接口,包含具体数据导入或导出逻辑的代码。具体实现应该从SourceTask或SinkTask继承。SourceTask的方法流程有initialize(), start(), stop(), poll(), commit(), commitRecord(), stop()。SinkTask的方法流程有initialize(), open(), put(), preCommit(), flush(), close(), stop()。
(3)ConnectorContext:连接器上下文。允许连接器与Kafka连接运行时进行交互。方法requestTaskReconfiguration()请求运行时重新配置当前源的任务。可用于向运行时表明输入输出的改变,例如分区的增加或删除,然后正在运行的任务将做出改变。raiseError()抛出一个不可恢复的异常,这将导致连接器的状态变为FAILED。
(4)ConnectorRecord:连接器记录类型。它类似于ProducerRecord或ConsumerRecord。参数包含主题名、分区号、key/value的数据模式、时间戳、头部信息、key/value的数据值、偏移量等。具体实现为SourceRecord和SinkRecord。核心方法newRecord()用指定的参数创建一条SourceRecord或SinkRecord。
(5)Schema:数据模式,定义了一个抽象数据类型。缺省实现为ConnectSchema。一般用SchemaBuilder来创建具体的数据类型。常见的有原始类型整型、float浮点型、boolean类型、byte类型、string类型;复合类型array, map, date, timestamp, struct。

##8. Transformation
InsertField, ReplaceField, MaskField
ValueToKey, HoistField, ExtractField
SetSchemaMetadata, TimestampRouter, RegexRouter
Flatten, Cast, TimestampConverter
(1)Transformation:消息转换器接口,用于对kafka连接的记录类型进行单个转换操作。用户自定义转换器时要实现这个接口。接口方法有apply()应用转换器,close()关闭转换器,configure()配置转换器,每个转换器实现可以定义很多配置信息,config()返回配置列表。连接器可以配置转换器(在连接器配置中指定)来实现轻量级的一次一条消息的修改。常用于消息转换和事件路由。Kafka Connector提供了很多内置的、广泛适用的数据和路由转换器,例如InsertField, ReplaceField,HoistField, TimestampRouter, RegexRouter等。
(2)InsertField:使用静态数据或记录的元数据来添加一个字段。对记录的key和value一般使用具体的内嵌转换实现InsertField K e y , I n s e r t F i e l d Key, InsertField Key,InsertFieldValue。主要配置有offset.field, partition.field, static.field, static.value, timestamp.field, topic.field。
(3)ReplaceField:过滤或重命名字段。具体使用ReplaceField K e y 或 R e p l a c e F i e l d Key或ReplaceField KeyReplaceFieldValue。主要配置有blacklist, renames, whitelist。
(4)MaskFiled:用有效的空值(如0,空字符串)替换一些特定的字段。具体实现使用MaskField K e y 或 M a s k F i e l d Key或MaskField KeyMaskFieldValue。
(5)ValueToKey:用记录的value中一些字段作为新key替换记录现有的key。
(6)HoistField:包装字段,将记录的数据作为Struct或Map中的单个字段进行包装。
(7)ExtractField:从Struct和Map中提取特定的字段,并在结果中只包含该字段。
(8)SetSchemaMetadata:修改字段(key或value)的模式名称或版本。配置有schema.name, schema.version。
(9)TimestampRouter:根据记录的原始主题和时间戳来修改该记录的主题字段。这在需要按时间戳写入不同表格或索引的接收连接器中非常有用。配置有timestamp.format, topic.format。
(10)RegexRouter:根据原始主题、替换字符串和一个正则表达式来修改记录的主题字段。配置有regex, replacement。
(11)Flatten:拼合嵌套的数据结构。根据配置的分隔符连接输入记录中的每个字段名称,产生一个新的输出字段名称。
(12)Cast:将字段或整个键或值转换为特定类型,例如强制整数字段的宽度更小。只支持简单的基本类型 - 整数,浮点数,布尔值和字符串。
(13)TimestampConverter:在不同格式之间转换时间戳,例如Unix时间戳格式、字符串格式、连接器的Date/Timestamp类型,适用于单个字段或整个值。配置有target.type, field, format。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值