接入层接受app的请求,解包数据重新封装数据包,把app数据包做为包体,同时再加上接入层的包头数据,根据app数据包头的协议号转发到后端业务服务器。
所有app端的请求都先经过接入层,因此接入层的性能是至关重要。
为了性能上的保证,使用到netty的PooledDirectByteBuf,顾名思义就是池化的堆外直接内存,堆外直接内存就是jvm堆以外申请的内存,这里为什么考虑用堆外内存?看下图就明白了:
上图中是没有使用堆外内存的例子,运行在内核态的socket接收到的数据放在堆外直接内存中,java进程要得到这份数据,选 通过jvm把数据复制到jvm的堆内存,java进程发送数据时,jvm会把堆内存数据复制到堆外直接内存,再用socket发送堆外直接内存数据。
使用了PooledDirectByteBuf后如下:
堆外直接内存减少jvm的GC造成的停顿时间,但是创建和销毁的开销较大,PooledDirectByteBuf对堆外直接内存进行池化,先申请一大块的堆外内存,创建PooledDirectByteBuf时从池子里拿到一块空间写入数据,使用完后再把空间归还。
堆外直接内存在java里用DirectByteBuffer,netty的PooledDirectByteBuf是基于DirectByteBuffer进行池化封装,DirectByteBuffer的父类是MappedByteBuffer,MappedByteBuffer源码里注释有一行描述A direct byte buffer whose content is a memory-mapped region of a file,内容是个内存映射文件,内存映射文件,是由一个文件到一块内存的映射。内存映射文件与虚拟内存有些类似,通过内存映射文件可以保留一个地址空间的区域,同时将物理存储器提交给此区域,内存文件映射的物理存储器来自一个已经存在于磁盘上的文件,而且在对该文件进行操作之前必须首先对文件进行映射。两个或多个进程映射同一文件映射对象的视图,即它们在共享同一物理存储页。这样,当一个进程向内存映射文件的一个视图写入数据时,其他的进程立即在自己的视图中看到变化