`

高吞吐高并发Java NIO服务的架构(NIO架构及应用之一)

阅读更多

Java NIO成功的应用在了各种分布式、即时通信和中间件Java系统中。证明了基于NIO构建的通信基础,是一种高效,且扩展性很强的通信架构。

基于Reactor模式的高可扩展性架构这个架构的基本思路在“基于高可用性NIO服务器架构”(http://today.java.net/pub/a/today/2007/02/13/architecture-of-highly-scalable-nio-server.html
)中有了清晰的论述。经过几年实际运营的经验,这种架构的灵活性得到了很好的验证。我们注意几点,

1,一个小的线程池负责dispatch NIO事件。
2,注册事件,即操作selecter时,要使用一个同步锁(即Architecture of a Highly Scalable NIO-Based Server一文中的guard对象),即对同一个selector的操作是互斥的。
3,这个小的线程池不处理逻辑业务,大小可以是Runtime.getRuntime().availableProcessors() + 1,即你系统有效CPU个数+1。这是因为我们假设有一个线程专门处理accept事件,
而其他线程处理read/write操作。
4,用另一个单独的线程池处理逻辑业务

 

在淘宝网团队博客上分析Netty架构的时候也谈到了这个思路,我决定说的比较好。这里引用一段:

 

http://rdc.taobao.com/team/jm/archives/423 写道
Netty提供了NIO与BIO(OIO)两种模式处理这些逻辑,其中NIO主要通过一个BOSS线程处理等待链接的接入,若干个WORKER线程(从worker线程池中挑选一个赋给Channel实例,因为Channel实例持有真正的 java网络对象)接过BOSS线程递交过来的CHANNEL进行数据读写并且触发相应事件传递给pipeline进行数据处理,而BIO(OIO)方式服务器端虽然还是通过一个BOSS线程来处理等待链接的接入,但是客户端是由主线程直接connect,另外写数据C/S两端都是直接主线程写,而数据读操作是通过一个WORKER 线程BLOCK方式读取(一直等待,直到读到数据,除非channel关闭)。

网络动作归结到最简单就是服务器端bind->accept->read->write,客户端 connect->read->write,一般bind或者connect后会有多次read、write。这种特性导致,bind,accept与read,write的线程分离,connect与read、write线程分离,这样做的好处就是无论是服务器端还是客户端吞吐量将有效增大,以便充分利用机器的处理能力,而不是卡在网络连接上,不过一旦机器处理能力充分利用后,这种方式反而可能会因为过于频繁的线程切换导致性能损失而得不偿失,并且这种处理模型复杂度比较高。
 

那么如果是我们自己开发基于NIO实现高效和高可扩展服务,还有哪些构架方面的问题需要考虑呢?
NIO构架中比较需要经验和比较复杂的主要是2点:1,)是基于提高的性能的线程池设计;2)基于网络通讯量的通讯完整性校验的构架。

1. 基于提高的性能的线程池设计
既然有一个单独处理逻辑业务的线程池,这个线程池的大小应该由你的业务来决定。对于高效服务器来说,这个线程池大小会对你的服务性能产生很大的影响。设置多少合适呢?

这里真的有很多情况需要考虑,换句话说,这里水很深。我只能根据自己的经验举几个例子。真正到了运营系统上,一边测试一边调整一边总结吧。

假设消息解析用时5毫秒,数据库操作用时20毫秒,其他逻辑处理用时20毫秒,那么整个业务处理用时45毫秒。
因为数据库操作主要是IO读写操作,为使CPU得到最大程度的利用,在一个16核的服务器上,应该设置 (45/ 25)
* 16 = 29 个线程即可。

假设不是所有的操作都是在平均时间内完成,比如数据库操作,假设是在12~35毫秒区间内。即有线程会不断的被某些操作block住,为了充分利用CPU能力,因设置为((35 + 25)/ 25)* 16 = 39个线程。

所以原则上,如果应用是一个偏重数据库操作的应用,则线程数应高些;如果应用是一个高CPU应用,则线程数不用太高。

假设逻辑处理中,对共享资源的操作用时5毫秒。此时同时只能有一个线程对共享资源进行操作,那么在一个16核的服务器上,应该设置 (37 / 5) * 1 = 8 个线程即可。

假设只有一部分操作对共享资源有写,其他只是读。这样采用乐观锁,使写操作降为所有操作的10%,那么有90%的业务,其合适的线程数可为39个线程。10%的业务应为8个线程。平均则为 35 + 1 = 36个线程。可见仔细的分析共享资源的使用,能很好的提高系统性能。

根据线程CPU占用率和CPU个数来设置线程数的假设前提是所有线程都要要运行。但实际系统中线程处理要处理不同时间达到的请求。

场景:假设线程处理不是同时进行的
假设有一个消息服务器,每秒处理500个消息,即认为平均每2ms接受一个新请求。假设处理一个请求需要100ms,那么当接收到第51个请求时,第一个线程就已经空闲。这个请求可以由第一个线程处理,而不需要新线程。这样,需要50个线程。如果每个消息请求CPU空闲时间为10ms,那么为对于每个线程,并发的数量为 100/90 = 1.1;因此合适的线程为 50 * 1.1 * 核数。

跑一个小测试程序,code见附件
执行一个task耗时1000ms,其中50%CPU占满。每100毫秒处理一个task。CPU4核。
这样计算 (1000/100) * 2 * 4 = 40

测试结果,设置不同的线程数执行100个task,结果
线程数 | 全部执行使用时间
100   | 14484
80    | 14097
40    | 14407
20    | 16016
10    | 16548

在线程数达到40之后,再增加线程,因为CPU已经被充分使用,因此处理速度没有得到响应增加。反而有线程开销有可能下降。因此在CPU占用率和处理task间隔恒定的情况下,使用以上公式计算适合的线程数量可以得到较优结果。

2. 基于网络通讯量的通讯完整性校验

先看看READ事件的触发条件:
If the selector detects that the corresponding channel is ready for reading, has reached end-of-stream, has been remotely shut down for further reading,
or has an error pending, then it will add OP_READ to the key's ready-operation set and add the key to its selected-key set.

就是说,NIO构架中不能保证每次READ事件发生时从channel中读出的数据就是完整。例如,在通讯数据量较大时,网络层write buffer很容易被写满。此时读到的数据就是不完整的。
从构架角度,应根据应用场景设计三种不同的处理方式。

基本上有三种类型的应用,

1. 较低的通信量应用。这类应用的特点是所有的通信量不是很大,而且数据包小。所有数据都能在一次网络层buffer flush中全部写出。比如ZooKeeper client对cluster的操作。这种通信模式是完全不需要进行数据包校验的。

2. 基于RPC模式的应用。比如Hadoop,每次NameNode和DataNode之间的通讯都是通过RPC框架封装,转变成client对server的调用。所有的操作都是通过Java反射机制反射成方法调用,这样操作的特点是每次读到的数据都是可以通过ObjectInputStream(new ByteArrayInputStream(bytes)).readObject()操作的。这样的应用,应该在第一种应用的架构基础上增加对ObjectInputStream的校验。如果校验失败,则说明这次通信没有完成,应和下次read到数据合并在一起处理。

3. 基于大量数据通信的应用。这种应用的特点是基于一种大数据量通信协议,比如RTSP。数据包是否完整需要经过通信协议约定的校验符进行校验。这样就必须实现一个校验类。如果校验失败,则说明这次通信没有完成,应和下次read到数据合并在一起处理。


本文纯属原创,欢迎转载,请注明原网址;

 

  • Test.rar (657 Bytes)
  • 下载次数: 568
1
8
分享到:
评论
7 楼 叮咚可乐名 2018-04-08  
Java并发编程和高并发解决方案视频课程
网盘地址:https://pan.baidu.com/s/19tUBliZIYy2HQ0LiVfCw-A 密码: d9fb
备用地址(腾讯微云):https://share.weiyun.com/5grRNnM 密码:e324w9

学会高并发处理思路与手段,让跳槽面试从容不迫,并发与高并发是面试的重要考察点,常问面试问题与答案都在这里了!

无论面试还是实际开发,几乎都会涉及并发相关知识及高并发相关场景处理,如果你想系统的学习一下并发编程
并了解一下实际的高并发场景及应对方案,那这门课就是为你准备的。
6 楼 chenxuezhou_yzl 2016-07-29  
完全没看懂诶
5 楼 miraclestar 2015-03-04  
maoyidao 写道
Yiyang说的对,不过这只是一个理论上的评估值。真正在系统中使用,还是需要注意线程间的调度和上下文切换的代价也是很高的。比如我有一个服务,主流程很简单就是调用其他http服务,整个主流程用时50ms,调用其他http服务用时也解决50ms,cpu时间~=1ms,这么算起来12核cpu要给:600个线程??

其实很多要求高吞吐的场景下,以上情况是通过水平扩展服务器而不是通过增加线程解决的。

或者可以通过别的方法来提高吞吐,比如把线程池规划成高速和低速。高速线程池可以处理重要或延时要求严格的业务,而把相对迟缓或者次要的业务剥离到另外的线程池去。这也和Actor模式类似,接收线程专门负责接收而不处理,把可能导致处理延时的处理工作交给另外的线程池来处理。这样别的“快”业务就不会被卡住,慢业务慢一点也不会对系统造成影响。


赞;

线程切换的确很耗时;并不是线程数越多性能越高,反而会降低;16核最好16个线程;
据测试,核数*4线程的是较优的
4 楼 linbzh 2012-11-22  
跑一个小测试程序,code见附件
执行一个task耗时1000ms,其中50%CPU占满。每100毫秒处理一个task。CPU4核。
这样计算 (1000/100) * 2 * 4 = 40


计算有错误!!!!!
不是80吗??
3 楼 maoyidao 2012-06-20  
Yiyang说的对,不过这只是一个理论上的评估值。真正在系统中使用,还是需要注意线程间的调度和上下文切换的代价也是很高的。比如我有一个服务,主流程很简单就是调用其他http服务,整个主流程用时50ms,调用其他http服务用时也解决50ms,cpu时间~=1ms,这么算起来12核cpu要给:600个线程??

其实很多要求高吞吐的场景下,以上情况是通过水平扩展服务器而不是通过增加线程解决的。

或者可以通过别的方法来提高吞吐,比如把线程池规划成高速和低速。高速线程池可以处理重要或延时要求严格的业务,而把相对迟缓或者次要的业务剥离到另外的线程池去。这也和Actor模式类似,接收线程专门负责接收而不处理,把可能导致处理延时的处理工作交给另外的线程池来处理。这样别的“快”业务就不会被卡住,慢业务慢一点也不会对系统造成影响。
2 楼 Shen.Yiyang 2012-06-19  
yangxinxyx 写道
引用
(45/ 25)* 16 = 29


这个公式没看懂,为什么要这样算呢? 求解释一下~


(总业务过程时间/CPU实际计算时间)*CPU核数,想想很容易明白
1 楼 yangxinxyx 2012-06-19  
引用
(45/ 25)* 16 = 29


这个公式没看懂,为什么要这样算呢? 求解释一下~

相关推荐

    高吞吐高并发Java NIO服务的架构

    Java NIO成功的应用在了各种分布式、即时通信和中间件Java系统中。证明了基于NIO构建的通信基础,是一种高效,且扩展性很强的通信架构。

    JAVA高性能高并发服务器架构pdf文档视频资源

    在IT行业中,Java是一种广泛应用的编程语言,尤其在构建高性能、高并发的服务器架构方面具有显著优势。本资源集合包含了关于“JAVA高性能高并发服务器架构”的PDF文档和视频,旨在帮助开发者深入理解如何利用Java...

    Java NIO与IO性能对比分析.pdf

    本文将分析Java NIO与Java IO在性能上的对比,并尝试找出性能差异的原因,以及探讨哪种编程模型更适合高并发的应用场景。 Java IO模型是一种阻塞型I/O模型,在数据的读写过程中,如果线程在等待数据,将会一直被挂...

    Java NIO通信框架在电信领域的实践

    综上所述,Java NIO框架不仅解决了电信业务应用软件在高性能和高并发场景下的技术难题,还促进了电信软件架构的不断演进和发展。未来,随着5G和物联网等新兴技术的崛起,Java NIO框架及其衍生技术将继续在电信领域...

    Java架构专题,高并发架构下性能提升千倍内幕揭秘

    而Java作为目前最主流的企业级开发语言之一,在构建高并发架构方面具有得天独厚的优势。 #### 高并发系统的定义 高并发系统通常指的是能够同时处理大量并发请求的系统。这些系统具备以下特点: - **高可用性**:...

    构建JAVA大型分布式电商项目实战高并发集群分布式系统架构PDF+视频.rar

    本项目实战教程涵盖了高并发、集群以及分布式系统架构等关键知识点,旨在帮助Java架构师提升技能,实现高性能、高可用和可扩展的电商系统。 1. **Java基础与高级特性** - Java的基础语法、面向对象编程、异常处理...

    利用Java开发高性能、高并发Web应用

    在Java开发领域,构建高性能、高并发的Web应用是一项核心任务。...理解并掌握这些知识点,是开发高性能、高并发Java Web应用的基础。实践中,还需要根据具体业务场景灵活运用,不断优化和调整,以实现最佳性能。

    JAVA NIO学习笔记.docx

    NIO不仅提高了Java的I/O性能,还引入了非阻塞I/O模型,适合于开发高并发的服务器应用,比如网络服务器、数据库连接池等。通过NIO,开发者能够设计出更为灵活、高效的系统架构,充分利用硬件资源,提升系统吞吐量。

    【项目实战】Netty源码剖析&NIO;+Netty5各种RPC架构实战演练三部曲视频教程(未加密)

    Netty是一款基于Java NIO的高性能服务器端编程框架,用于快速开发可维护的网络应用程序。它简化了网络编程的复杂性,使开发者能够更加专注于业务逻辑的实现。Netty提供了事件驱动模型、异步处理能力以及丰富的API...

    JAVA架构师进阶之路核心知识整理.pdf

    在Java架构师进阶之路上,需要掌握的核心知识点涵盖了编程基础、集合框架、JVM原理、并发编程、框架原理、微服务架构、网络编程以及分布式系统等多个方面。以下是详细的知识点概述: ### 基础知识 Java基础是架构师...

    如何利用Java开发高性能、高并发Web应用

    以上是构建高性能、高并发Java Web应用的核心知识点。通过合理运用这些技术和工具,可以有效地提升系统的吞吐量和响应速度,同时保证系统的稳定性和可扩展性。在实际开发中,应根据项目需求灵活选择并整合这些技术,...

    Java高并发高性能分布式框架从无到有微服务架构设计.docx

    在构建大型互联网应用时,Java高并发高性能分布式框架和微服务架构设计是至关重要的技术环节。本文将深入探讨如何从零开始构建这样的系统,旨在帮助开发者理解并掌握相关的技术和实践。 首先,我们要明白高并发意味...

    高性能网络架构Mina框架 下载

    Mina通过采用多线程模型和异步I/O技术来提高网络应用的并发处理能力,从而实现高吞吐量、低延迟的服务。 #### 二、Mina框架的特点 ##### 2.1 高性能与可扩展性 Mina采用了多线程异步处理机制,能够有效利用系统...

    从Jetty、Tomcat和Mina中提炼NIO构架网络服务器的经典模式

    Jetty、Tomcat和Mina都是Java领域中著名的Web服务器和应用服务器,它们在NIO架构上有着相似的设计模式。本文将从这三个框架中提炼出NIO构架网络服务器的经典模式,并逐一解析它们的核心机制。 首先,Jetty的NIO实现...

    httpcore-nio-4.4.6.zip

    2. **微服务通信**:在微服务架构中,HTTPCore-NIO可以作为服务间通信的基础,提供低延迟、高吞吐量的通信保障。 3. **分布式系统**:在分布式系统中,HTTPCore-NIO可以作为客户端库,实现与服务器的高效交互,减少...

    Java高级架构必备知识点

    ### Java高级架构必备知识点 #### 一、高可用与负载均衡 **1.1 负载均衡(负载均衡算法)** 负载均衡是通过分配网络负载来提高系统的响应能力和资源利用率的技术。它能够将大量的访问请求均匀地分散到多个服务器...

    Java服务器数据采集框架

    Java服务器数据采集框架是一种用于高效收集、处理和传输大量数据的软件架构,尤其适用于高并发环境。在这种框架中,Netty作为一个高性能、异步事件驱动的网络应用框架,扮演着核心角色。Netty是由Java编写,广泛应用...

Global site tag (gtag.js) - Google Analytics