Netty设计特点:

1. io线程模型
使用reactor模式,同步非阻塞。这决定了可以用最少的资源做更多的事。
2. 内存零拷贝
使用直接缓存
3. 内存池设计
申请的内存可以重用,主要指直接内存。
内部实现是用一颗二叉查找树管理内存分配情况。
4. 串形化处理socket读写,避免锁,即一个指定socket的消息是串形化处理的。这样性能比多个线程同时 处理一个socket对应消息要好,因为多线程处理会有锁。
5. 提供对protobuf等高性能序列化协议支持
 
https://blog.csdn.net/tanga842428/article/details/52463248
上下文切换的原因:
  • I/O等待:在多任务系统中,进程主动发起I/O请求,但I/O设备还没有准备好,所以会发生I/O阻塞,进程进入Wait状态。
  • 时间片耗尽:在多任务分时系统中,内核分配给进程的时间片已经耗尽了,进程进入Ready状态,等待内核重新分配时间片后的执行机会。
  • 硬件中断:在抢占式的多任务分时系统中,I/O设备可以在任意时刻发生中断,CPU会停下当前正在执行的进程去处理中断,因此进程进入Ready状态。

netty优化方向:

  • 线程数控制:高并发下如果线程较多时,Context Switch会非常明显,超过CPU核心数的线程不会带来任何好处。不是特别耗时的操作的话,业务线程池也是有害无益的。Netty 5为我们提供了指定底层线程池的机会,这样能更好的控制整个中间件的线程数和调度策略。
  • 非阻塞I/O操作:要想线程少还多做事,避免阻塞是一定要做的。
  • 减少系统调用:虽然Mode Switch比Context Switch的开销要小得多,但我们还是要尽量减少频繁的syscall。
  • 数据零拷贝:从内核空间的Direct Buffer拷贝到用户空间,每次透传都拷贝的话累积起来是个不小的开销。
  • 共享状态保护:中间件内部的并发处理也是决定性能的关键。
    private void doStartNettyServer(int port) throws InterruptedException {
EventLoopGroup bossGroup = new NioEventLoopGroup();
EventLoopGroup workerGroup = new NioEventLoopGroup(4);
try {
ServerBootstrap b = new ServerBootstrap()
.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class)
.localAddress(port)
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
public void initChannel(SocketChannel ch) throws Exception {
ch.pipeline().addLast(...);
}
}); // Bind and start to accept incoming connections.
ChannelFuture f = b.bind(port).sync(); // Wait until the server socket is closed.
f.channel().closeFuture().sync();
} finally {
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
}

透传不需要完整解析消息,只需要知道消息要转发给下游哪个系统就足够了。所以透传时,我们可以只解析出部分消息,消息整体还原封不动地放在Direct Buffer里,最后直接将它写入到连接下游系统的Channel中。所以应用层的Zero Copy实现就分为两部分:Direct Buffer配置和Buffer的零拷贝传递。

    ServerBootstrap b = new ServerBootstrap()
.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class)
.localAddress(port)
.childOption(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT)
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
public void initChannel(SocketChannel ch) throws Exception {
ch.pipeline().addLast(...);
}
});

Netty是用引用计数的方式来判断是否回收的,所以要想继续使用ByteBuf而不让Netty释放的话,就要增加它的引用计数。只要我们在ChannelPipeline中的任意一个Handler中调用ByteBuf.retain()将引用计数加1,Netty就不会释放掉它了。我们在连接下游的客户端的Encoder中发送消息成功后再释放掉,这样就达到了零拷贝透传的效果

public class RespEncoder extends MessageToByteEncoder<Resp> {

    @Override
protected void encode(ChannelHandlerContext ctx, Msg msg, ByteBuf out) throws Exception {
// Raw in Msg is retained ByteBuf
out.writeBytes(msg.getRaw(), 0, msg.getRaw().readerIndex());
msg.getRaw().release();
} }

http://laolinshi.iteye.com/blog/2341729

netty在服务器初始化的时候需要设置两个线程池,一个是用来接收客户端的连接(1),另一个是用来处理客户端的读写(一般设置成CPU核数的两倍到三倍)

为了方便系统BUG 的解决,可以为每个线程池设置一个自定义的ThreadFactory,这个factory的作用是根据线程池的类型为创建的线程设置一个特殊的名称,如boss线程的名称是NettyBoss_,工作线程的名称是NettyServerSelector_%d_%d,这样可以在以后的问题排除过程中利用这个名称识别不同的线程,分析这些线程的资源占用率,便于找到问题的根源。

Linux, 在选中worker线程池的时候可以考虑用epoll代替传统的select,前者对应netty提供的EpollEventLoopGroup,后者对应的是NioEventLoopGroup。之所以要这样做,是因为传统的select基于轮询的方式来进行事件处理,随着fd数量的增加,导致轮询的处理开销增大,实际的事件处理效率就会下降。而epoll是基于通知的方式,每当事件准备就绪的时候,epoll就会通知线程进行处理,这样可以保证及时性的同时也不会随着fd的数量的增加而降低效率。

SO_BACKLOG,这个值通常设置1024,意味着当服务器请求处理线程全满时,用于临时存放已完成三次握手的请求的队列的最大长度。这样就可以服务器处理能力达到饱和的情况下用队列来暂存用户取得请求,等服务器空闲的时候再从队列中取出请求来处理,而不是马上拒接掉。

SO_SNDBUF和SO_RCVBUF,两者可以设置成1048576,即是128K,在性能优化是通常都设置成这样

内存池,需要内存时就从内存池中分配,使用完了再归还给内存池以便可以重复利用。这样就可以避免每次使用内存所带来的内存创建和销毁开销,而且还不容易形成内存碎片。基于这样的目的可以使用netty提供的PooledByteBufAllocator分配器,需要注意的是使用这个分配器分配的内存使用完后必须手动进行释放,否则会造成内存泄漏

WRITE_BUFFER_WATER_MARK,他的作用是限制netty向channel写数据时使用的缓冲区边界。当netty需要往channel中写入数据时会先把数据写入一个Buffer缓冲区,这个缓冲区是各个channel独占的,不共享。等到channel空闲的时候就从缓冲区中读取数据进行发送,当Buffer的数据超过高水位线时就停止写入数据,设置channel的isWritable为false。等到buffer中的数据由于被消费而低于低水位线时设置channel的isWritable为true,又可以重新接受写入的数据。所以设置了这个参数之后,对应用的要求是,每次写数据时先判断channel的isWritable,在 true时才进行写入。

考虑到具体的业务逻辑处理可能涉及到耗时的数据库操作或远程RPC调用,因而在具体的业务处理Handler中启动一个新的线程来处理相关逻辑,如上图的NettyServerHandler。这样可以让这些耗时的操作不阻塞处理Handler的线程,让线程可以及时返回来处理新的操作,同样可以起到提高服务器并发处理能力的目的

class NettyServerHandler extends SimpleChannelInboundHandler<RemotingCommand> {
@Override
protected void channelRead0(ChannelHandlerContext ctx, RemotingCommand msg) throws Exception {
Runnable run = new Runnable() {
@Override
public void run() {
//具体的业务逻辑处理
}
}
submit(run);//在线程池中提交处理任务
}
}

Netty - 1的更多相关文章

  1. 谈谈如何使用Netty开发实现高性能的RPC服务器

    RPC(Remote Procedure Call Protocol)远程过程调用协议,它是一种通过网络,从远程计算机程序上请求服务,而不必了解底层网络技术的协议.说的再直白一点,就是客户端在不必知道 ...

  2. 基于netty http协议栈的轻量级流程控制组件的实现

    今儿个是冬至,所谓“冬大过年”,公司也应景五点钟就放大伙儿回家吃饺子喝羊肉汤了,而我本着极高的职业素养依然坚持留在公司(实则因为没饺子吃没羊肉汤喝,只能呆公司吃食堂……).趁着这一个多小时的时间,想跟 ...

  3. 从netty-example分析Netty组件续

    上文我们从netty-example的Discard服务器端示例分析了netty的组件,今天我们从另一个简单的示例Echo客户端分析一下上个示例中没有出现的netty组件. 1. 服务端的连接处理,读 ...

  4. 源码分析netty服务器创建过程vs java nio服务器创建

    1.Java NIO服务端创建 首先,我们通过一个时序图来看下如何创建一个NIO服务端并启动监听,接收多个客户端的连接,进行消息的异步读写. 示例代码(参考文献[2]): import java.io ...

  5. 从netty-example分析Netty组件

    分析netty从源码开始 准备工作: 1.下载源代码:https://github.com/netty/netty.git 我下载的版本为4.1 2. eclipse导入maven工程. netty提 ...

  6. Netty实现高性能RPC服务器优化篇之消息序列化

    在本人写的前一篇文章中,谈及有关如何利用Netty开发实现,高性能RPC服务器的一些设计思路.设计原理,以及具体的实现方案(具体参见:谈谈如何使用Netty开发实现高性能的RPC服务器).在文章的最后 ...

  7. Netty构建分布式消息队列(AvatarMQ)设计指南之架构篇

    目前业界流行的分布式消息队列系统(或者可以叫做消息中间件)种类繁多,比如,基于Erlang的RabbitMQ.基于Java的ActiveMQ/Apache Kafka.基于C/C++的ZeroMQ等等 ...

  8. 基于Netty打造RPC服务器设计经验谈

    自从在园子里,发表了两篇如何基于Netty构建RPC服务器的文章:谈谈如何使用Netty开发实现高性能的RPC服务器.Netty实现高性能RPC服务器优化篇之消息序列化 之后,收到了很多同行.园友们热 ...

  9. Netty构建分布式消息队列实现原理浅析

    在本人的上一篇博客文章:Netty构建分布式消息队列(AvatarMQ)设计指南之架构篇 中,重点向大家介绍了AvatarMQ主要构成模块以及目前存在的优缺点.最后以一个生产者.消费者传递消息的例子, ...

  10. JAVA通信系列三:Netty入门总结

    一.Netty学习资料 书籍<Netty In Action中文版> 对于Netty的十一个疑问http://news.cnblogs.com/n/205413/ 深入浅出Nettyhtt ...

随机推荐

  1. git基本的使用原理

    一:Git是什么? Git是目前世界上最先进的分布式版本控制系统. 二:SVN与Git的最主要的区别? SVN是集中式版本控制系统,版本库是集中放在中央服务器的,而干活的时候,用的都是自己的电脑,所以 ...

  2. JavaScript、CSS样式收集

    JS集: //给from一个名字然后在JavaScript的地方就可以用form的名字来调用form表单里input元素的value属性可以得到值 var val=form_name.input_na ...

  3. restful 涵义

    REST,即Representational State Transfer的缩写: "表现层状态转化" REST的名称"表现层状态转化"中,省略了主语.&quo ...

  4. kafka的几个简单操作

    怎么安装解压kafka这里就不多说了,从配置文件说起 我这里搭建的是三节点集群 master  slave1 slave2 修改server.properties 文件 把自己本地安装的zookeep ...

  5. 快速部署MySQL数据库

    一.下载对应的软件版本 下载地址:http://mirrors.sohu.com/mysql/MySQL-5.6/ [root@localhost ~]# wget -q http://mirrors ...

  6. 记一次http接口格式摸索

    有一个需求,需要用到内部通讯工具的一个ERP转发接口,虽然有接口文档,但是对中文的编码格式没有提示,中间几经周折,最后才想起来通过F12查看提供的测试接口发送请求时的数据格式来分析,经过解析中文只有被 ...

  7. redis 的简单用法

    使用  :下载完后 打开任务管理器 把redis_server 进程关掉, 切换到   E:\redis 中 redis-server.exe redis.windows.conf 打开一个 cmd ...

  8. 【Jmeter自学】Jmeter脚本录制(二)

    ==================================================================================================== ...

  9. hadoop2.4集群的搭建

    hadoop中的三大组件: hdfs:分布式文件管理系统 (namenode管理所有的datanode) yarn:资源调度系统(ResourceManager管理所有的nodemanager) ma ...

  10. 安装hyperledger fabric V1.0.1

      安装文档位置: https://github.com/hyperledger/fabric   fabric代码托管地址 https://hyperledger-fabric.readthedoc ...