`
benni82
  • 浏览: 123130 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

贪吃的jetty被撑死了

阅读更多

在大量请求并且请求处理时间较长的情况下,jetty的nio模式会导致容器运行缓慢。

 

测试方法:

用apache ab对jetty容器发出大规模持续的并发请求,

用命令“jstat -gcutil -h 10 PID 1000"查看GC情况,等到young、old区到100%时停止施压。

 

用“jmap -histo PID | less" 可以看到大量的SelectChannelEndPoint对象。


分析一下原因:

首先介绍一下jetty的nio模式,如下图

 

mainReactor:jetty从线程池中分配一个线程用于接受用户的连接请求(ServerSocketChannel.accpet()),

这个线程就做一件事,接受用户的连接,将channel注册到selector中。

 

_manager.dispatch(new Runnable()
{
	public void run()
	{
		final ServerSocketChannel server=_acceptChannel;
		while (isRunning() && _acceptChannel==server && server.isOpen())
		{
			try
			{
				SocketChannel channel = server.accept();
				channel.configureBlocking(false);
				Socket socket = channel.socket();
				configure(socket);
				_manager.register(channel);
			}
			catch(IOException e)
			{
				Log.ignore(e);
			}
		}
	}
});
    

 

而jetty的subReactor线程询注册进来的channel,将channel包装成SelectChannelEndPoint对象加入到_endPoints。(可以把endpoint看作是一个连接)

 

private ConcurrentMap<SelectChannelEndPoint,Object> _endPoints = new ConcurrentHashMap<SelectChannelEndPoint, Object>();  
public void doSelect() throws IOException {
...
    else if (change instanceof SocketChannel)
	{
		// Newly registered channel
		final SocketChannel channel=(SocketChannel)change;
		SelectionKey key = channel.register(selector,SelectionKey.OP_READ,null);
		SelectChannelEndPoint endpoint = createEndPoint(channel,key);
		key.attach(endpoint);
		endpoint.schedule();
	}
...
}
 

 

为什么要加入到_endPoints,为了对所有的endpoint做空闲检查。

 

public void doSelect() throws IOException {
。。。
// Idle tick
if (now-_idleTick>__IDLE_TICK)
{
	_idleTick=now;
	
	final long idle_now=((_lowResourcesConnections>0 && selector.keys().size()>_lowResourcesConnections))
		?(now+_maxIdleTime-_lowResourcesMaxIdleTime)
		:now;
		
	dispatch(new Runnable()
	{
		public void run()
		{
			for (SelectChannelEndPoint endp:_endPoints.keySet())
			{
				endp.checkIdleTimestamp(idle_now);
			}
		}
	});
}
。。。
}
 

 

这里有个问题,回收动作需要从线程池中分配线程处理,而如果线程池中没有空闲的线程时,那么回收动作将无法正常进行。所以尝试修改__IDLE_TICK到30毫秒(默认是400),希望能提高空闲检查频率,却无法起效。

 

还有这个可恶的_endPoints对象,它将持有大量的endpoint,而这些endpoint又得不到及时处理,内存都被它消耗光。

 

我配置的最大线程池为250,任务队列长度无限制

 

<Set name="ThreadPool">
  <!-- Default queued blocking threadpool -->
  <New class="org.eclipse.jetty.util.thread.QueuedThreadPool">
	<Set name="minThreads">10</Set>
	<Set name="maxThreads">250</Set>
  </New>
</Set>

在jvm的young、old区达到100%时,250线程也都已经分配(可以用命令"jstack PID | grep "\"qtp" | wc -l"查看),但是很多都block住了;因为线程运行过程中也会有对象创建,也需要一点内存空间,可已经没有内存空间,杯具就这样发生了。

 

如果把mainReactor比作人在吃东西,那么subReator就是他的胃在消化,

大部分情况都是吃个7分饱,此时胃的消化能力很强,

一旦出现暴饮暴食,就会出现胃胀,消化能力反而减弱。


一个解决方案:

分析下来觉得jetty缺了胃反射功能,胃胀信息没有即使反馈给大脑。

可以适当扩展一下mainReactor,看下面的代码:

_manager.dispatch(new Runnable()
{
	public void run()
	{
		final ServerSocketChannel server=_acceptChannel;
		while (isRunning() && _acceptChannel==server && server.isOpen() && !_manager.isLowResourcesConnections())
		{
			try
			{
				SocketChannel channel = server.accept();
				channel.configureBlocking(false);
				Socket socket = channel.socket();
				configure(socket);
				_manager.register(channel);
			}
			catch(IOException e)
			{
				Log.ignore(e);
			}
		}
	}
});

 添加了_manager.isLowResourcesConnections()方法,嘴巴准备吃的时候要先问一下胃先。

 

subReactor添加一个新方法:

public boolean isLowResourcesConnections() {
// 这里的判断阀值是个大概的值。
// 拿配置的阀值和第一个selector的keys大小做比较
// 任何情况下第一个selector都是存在的,所以这个比较还是靠谱的。
	return _lowResourcesConnections < _selectSet[0].getSelector().keys().size();
}
 

 

分享到:
评论
1 楼 lingqi1818 2014-10-12  
<New class="org.eclipse.jetty.util.thread.QueuedThreadPool">
      <Arg>
           <New class="java.util.concurrent.ArrayBlockingQueue">
              <Arg type="int">6000</Arg>
           </New>
      </Arg>
        <Set name="minThreads">10</Set>
        <Set name="maxThreads">200</Set>
        <Set name="detailedDump">false</Set>
      </New>

可以配置自定义队列的。

相关推荐

    初中语文文摘社会被撑死的杜甫

    初中语文文摘社会被撑死的杜甫

    初中语文文摘人生撑死自己的蚊子

    6. 心灵的力量与制度建设:奥勒留在选择继承人上的失误提醒我们,单靠个人的道德力量是有限的,需要有健全的法律和教育体系来约束和引导人们的行为,避免“撑死自己的蚊子”现象,即过度贪婪导致自我毁灭的情况发生...

    “南非大饼”撑死“现代”.doc

    标题中的“南非大饼”指的是韩国现代集团在南非市场的投资,而“撑死‘现代’”则意味着现代集团因过度扩张导致在南非的业务失败。这个案例揭示了企业在国际化过程中可能遭遇的风险和挑战。 首先,现代集团在南非...

    html5贪吃兔子大吃月饼移动端游戏.rar

    HTML5兔子吃月饼大战,移动端游戏源码范例,在手机上操作很方便,手指滑动控制兔子左右移动,接到掉下来的月饼即可,不过这里提醒下,好像不能吃太多,吃太多兔子就撑死了,可以邀请请小伙伴吃月饼,最短时间内吃的...

    2022金鱼观察话题日记例文.docx

    - 另一条黑色的小金鱼因为吃得太多而被撑死,这提示我们金鱼可以忍受饥饿,但不能让它们吃得过饱。 2. **日记例文**: - 7月30日至8月1日期间,作者连续几天观察并记录了小金鱼的生活状态。 - **7月30日**:描述...

    [江苏]现代风格高层住宅楼设计方案文本(双语文本)

    在城市建设的过程中,应处理好人与人、人与社会、人与自然之间的关系,关心人的需求、注重城市的生态环境、关注撑死地域特色和历史文化特色演绎,合理有序地进行城市建设、使人、社会、环境和谐共生。 图纸包含:...

    初中圣诞节搞笑小品剧本.doc

    6. **情节转折**:小品中的情节出乎意料,如公主并非被pizza噎死而是撑死,以及最后王子和女巫的“爱情”线,这些转折增添了戏剧性。 7. **结尾的反转**:最后工作人员的出现打破了第四面墙,提醒观众这只是一个...

    软件开发综合项目——辛德瑞拉婚纱礼服定制网站,使用SSM框架和Maven管理工具,开发环境为EclipseJeePhot.zip

    11. **部署**:完成开发后,项目可能被打包成WAR或EAR文件,部署到Tomcat、Jetty或其他应用服务器上,供用户访问。 综上所述,“辛德瑞拉婚纱礼服定制网站”项目涵盖了Java Web开发的多个重要方面,从框架选择、...

    非瘟背景下各村的常见疾病的发病情况 2023-5-26 134249 4.docx

    这些消毒剂被用于养殖场、合作社、散养户、防疫卡点及交通道路,确保了多方位的卫生防护。 在疫苗接种上,无论是春季还是秋季的预防接种,所有抽样的猪、牛、羊和鸡都进行了100%的口蹄疫、高致病性禽流感和小反刍...

    胆机输出变压器制作图解

    所以叫烂牛,是因为铁心是采用经挑选的二手旧铁心,全部材料成本撑死不足100元,设备也落后,一台不足30元的手动绕线机,绕制手法也比较原始与传统。但以价论声,性价比倒也不俗,效果不说出色,也过的去,可以满足...

    使用Camshift算法做目标跟踪,当目标目标被屏蔽后,用Bp神经网络+卡尔曼联合预测.zip

    本项目探讨了一种结合Camshift算法、反向传播(BP)神经网络和卡尔曼滤波器的方法来实现这一目标,特别是在目标被遮挡的情况下进行有效的预测。下面将详细解释这些技术以及它们如何协同工作。 **Camshift算法** ...

    异步并行加载工具Asyncload.zip

    单次请求的响应时间在50ms左右,所以tps也不会太高,测试环境压力测试过程,受限于环境因素撑死只能到200tps,20并发下。I/O目前一般的I/O的访问速度: L1 &gt; L2 &gt; memory -&gt; disk or network常见的IO:nas上文件 ...

    桌面运维小知识+笔记本无法开机无法关机初步解决方法,笔记本电脑如何正确的保养电池

    1. **理解电池“生死”**:电池有两种最常见的“死亡”方式:过度充电(“撑死”)和过度放电(“饿死”)。电池电量长期维持在100%会导致电池性能下降,而长时间放电至电量低于20%也会对电池造成损害。因此,保持...

    四川省宜宾市南溪四中中考语文 现代文阅读分类复习汇编 散文部分 美丽乌龟.doc

    然而,故事的转折在于乌龟在朋友离开期间因过度进食香蕉而撑死,引发了作者对生死、忍耐与节制的深思。 故事的核心可以简单概括为:一只长途跋涉幸存的乌龟因过量饮食死亡。这个情节让人惊讶,也让人深感遗憾。 ...

    thrift的各种服务和各种源代码

    1、 支持以servlet方式嵌入web容器(tomcat/weblogic/jboss之类)运行 2、 也可以直接用嵌入式jetty直接从jar包运行 2.3支持javascript调用 支持js直接调用,post的json格式为: 以下格式无需手动拼写,thrift生成的js...

    一个基于SSM框架的个人日志系统(个人技术博客)_JavaScript_CSS_源码_下载.zip

    10. **部署与运行**:项目通常被打包成WAR文件,部署到Tomcat、Jetty等Servlet容器中运行。开发者可能使用Maven或Gradle进行项目构建和依赖管理。 这个个人日志系统提供了学习SSM框架以及前后端交互的好机会,对于...

    验证过程的后端实现_Java_下载.zip

    Java应用通常被打包成WAR或JAR文件,然后部署到应用服务器如Tomcat或Jetty。Spring Boot提供了一种简化部署的方式,可以直接运行jar文件启动服务。 8. **测试** 良好的测试实践对于保证代码质量至关重要。在Java...

    stomach的用法总结大全.doc

    4. To be stuffed 或 to have had one's fill 意为“撑死了”,表示吃得很饱。 5. To win someone's heart through their stomach 指的是“要想抓住男人的心先要抓住男人的胃”,强调美食在人际关系中的重要性。 ...

    X86/X64硬件断点管理器

    为了建立硬件断点,类HardwareBreakpoint必须被实例化。构造函数有两个参数。 争论 描述 单线程 确定断点是否应该只存在于当前线程上,如果设置为 false,则包括新生成的线程在内的每个线程都将被修改。 运行一次 ...

Global site tag (gtag.js) - Google Analytics