组态:
&lt; task:executor id =“myTaskExecutor” 池大小=“4-8” 队列容量=“0” 拒绝- 政策 </跨度> =“CALLER_RUNS”/&gt;
&lt; int-ip:tcp-connection-factory id =“serverTcpConFact” type =“server ” 端口= “60000” 使用-NIO = “真” 单次使用的=“假” 所以超时=“300000” 任务- 执行者 </跨度> =“myTaskExecutor”/&gt;
&lt; int-ip:tcp-inbound-channel-adapter id =“tcpInboundAdapter” 频道
昨天我写了一个样本只是为了使用spring集成创建tcp高性能服务器代码。我使用JMeter TCP采样器成功测试了1000个并发客户端请求。
这是代码 - https://github.com/rajeshgheware/spring-integration-samples 包括JMeter测试配置文件。
我成功测试了具有Intel核心i5 M520 2.4GHz的64位笔记本电脑上的1000个并发tcp客户端请求(服务器代码和在此机器上运行的JMeter测试)
我还尝试了1500个并发客户端请求,但发现服务器无法承认许多请求。我将继续尝试增强此代码以服务10000个并发客户端请求(我知道我可能需要从亚马逊获得这个测试的好EC2机器:))
我知道问题是什么,请打开一个 JIRA问题 。
问题是 CALLER_RUNS 拒绝政策 0 执行程序中的长度队列。
CALLER_RUNS
0
有一个线程可以处理所有IO事件(通常是 myTaskExecutor-1 );当读取事件触发时,他将执行排队以读取数据;读者线程将执行命令排队以组装数据(这将阻塞直到完整的消息 - 在您的情况下由CRLF终止 - 到达)。
myTaskExecutor-1
在这种情况下,当没有线程可用时, CALLER_RUNS 策略意味着IO选择器线程执行读取,并成为汇编程序线程,它阻止等待因为被阻止而无法到达的数据,并且稍后在调度要阻止的其他线程之后读取数据。由于他被封锁,他无法处理新的接受事件。
这是我的测试中的日志,显示了这个问题......
TRACE: [May-18 10:43:38,923][myTaskExecutor-1] tcp.connection.TcpNioServerConnectionFactory - Port 60000 SelectionCount: 2 DEBUG: [May-18 10:43:38,923][myTaskExecutor-1] tcp.connection.TcpNioConnection - localhost:58509:60000:bdc36c59-c31b-470e-96c3-6270e7c46a2f Reading... DEBUG: [May-18 10:43:38,924][myTaskExecutor-1] tcp.connection.TcpNioConnection - localhost:58509:60000:bdc36c59-c31b-470e-96c3-6270e7c46a2f Running an assembler TRACE: [May-18 10:43:38,924][myTaskExecutor-1] tcp.connection.TcpNioConnection - localhost:58509:60000:bdc36c59-c31b-470e-96c3-6270e7c46a2f Nio message assembler running... DEBUG: [May-18 10:43:38,926][myTaskExecutor-1] tcp.serializer.ByteArrayCrLfSerializer - Available to read:0
第二行显示用于执行读取的选择器线程;他检测到此套接字需要汇编程序,并成为汇编程序,阻塞,等待数据。
你真的相信使用无界任务执行者会有问题吗?这些事件通常都很短暂,所以线程很快就会被回收。
将执行程序的队列容量增加到0以上也应该有所帮助,但它不能完全确保不会发生问题(尽管不大可能会遇到大的队列大小)。
我还不确定如何解决这个问题,除了为IO选择器和读取器线程使用专用的任务执行程序,因此它们永远不会用作汇编程序。