求助, jvm线程一直增加, 堆内存也不释放

allanzjp 2021-04-09 06:44:52

如图1, 线程和堆内存一直增加, 资源也无法释放, 最终会导致内存溢出;


如图2, JProfiler查看最大的对象


如图3, JProfile传入引用视图, 我看不懂


如图4, new CallWebSocketMongo() 代码处, 然后调用 callWsDataBatch() 方法


如图5, CallWebSocketMongo类的构造方法, 和 callWsDataBatch() 详细代码, 此方法内 new SimpleWss() 的内部类即JProfiler中的最大对象: CallWebSocketMongo$3


如图6, SimpleWss 具体实现, 继承了WebSocketClient类


如图7, WebSocketClient类, 实现了 Runnable 接口


如图8, CallWebSocketMongo$3 内部类编译后的class文件详解


菜鸟看了一整天了, 没有思路, 多谢各位大佬帮忙看看, 万分感谢!!
...全文
2700 27 打赏 收藏 转发到动态 举报
写回复
用AI写文章
27 条回复
切换为时间正序
请发表友善的回复…
发表回复
冰思雨 2021-04-19
  • 打赏
  • 举报
回复
引用 24 楼 老王就是我 的回复:
[quote=引用 22 楼 冰思雨 的回复:][quote=引用 19 楼 老王就是我 的回复:] 也可能只是普通的聊天信息,不需要处理只需要转发或者广播的。 由于需要ws的场景都是强交互性的,异步操作无法确保结果,服务端提交异步任务后只能直接返回提交任务成功信息,但无法确保任务一定能执行完成。举个例子,游戏中(游戏通常用socket通信),玩家交易、分解装备,必须向玩家告知此事件的结果,而不能单纯告知,服务端处理中,请稍后查看装备栏的变化或者邮件箱的新邮件,这是不合理的。所以,是否需要异步操作,是要看产品需求是否为强交互性而不是看技术瓶颈。单纯解决并发量的问题非常简单,加钱——要么给机器加配置要么上集群加机器(不需要分布式,单体集群+负载均衡就足以)
你说的这种情况不是不存在,只是,太绝对了。 现在要做的是找出问题出现的原因。我认为是批量数据操作太耗时产生,所以,才会有这个方案。 谁告诉你ws的场景中不能做异步操作的?谁又告诉你异步操作无法保证结果的? 1. ws 只是建立了一个客户端和服务端的通信渠道,至于你用它做同步数据处理,还是做异步数据处理,并不会由 ws 技术本身所限制; 2. 从开发模式上来看,ws 的开发模式,恰巧使用的是事件处理模型,而事件处理模型几乎都是采用多线程异步处理的; 3. 采用同步消息处理有一个优点就是编程难度很低(逻辑简单直接),异常状况可以及时捕获处理。采用异步消息处理也有一个优点,可以增加通信渠道的数据吞吐量; 4. 如果业务数据的处理过程与时间参数无关的话,同步处理和异步处理的结果是完全相同的,不存在操作结果无法保证的情况; 5. 异步处理的过程中,可以通过回调函数来完成业务闭环。与同步处理的编程思路是有所不同的。 6. 当然,不是所有的业务场景都适用异步处理方式,但是,大批量的数据处理操作,异步比同步更有优势。你向聊天室发送了一个聊天消息,你以为服务端的广播行为采用的是同步处理么?那样的话,你发一句话,要等待聊天室里面所有人都收到你的消息之后,你才能干其他事情了。当然,你开发的程序中可以这样干,但是,我要说的是,在这种场景下,服务端广播操作,采用异步处理更具有优势。数据通路没有等待,意味着它可以继续传输其他数据了。[/quote] 至于异步可以保证结果?那就更可笑了,如果需要异步保证结果,就必须弄个死循环的递归,报错就继续进入方法,直到正确处理完。而同步中,处理结果不是预期值是可以提供报错信息让客户端重新发送请求来确保正确的响应。异步操作,只要成功提交任务就会返回正确的结果,而无论任务的执行过程中是否出错。 异步和同步的差异并不只有编程难度的优劣(编程的优劣并不应该是主要考虑的问题,主要考虑的是该技术是否适合业务),还有可用性的差别。还是游戏,一个玩家A攻击了玩家B,客户端收到正确的结果,按照你所说的异步操作,假设异步操作过程中出错,攻击的事件没能走完,是写个死循环让它走完才退出还是直接不管呢?那问题来了,如果后续还有攻击事件产生,那之前错误的攻击事件怎么处理?直接按照双方当前的状态处理?这很明显是不符合业务要求的[/quote] 我觉得,你的编程水平还是有待提高的。我一直说的内容,你都没有理解到位。所以,也没有什么好和你说的了。 如果,你有机会参与几年的关于异步处理程序的开发的话,就会理解我上述说的几个回复了。 你对异步处理的编程实现,还停留在递归和死循环的思想中,很多东西,都没法和你聊了。因为,理解的层次确实是有些局限性。 最后,我并没有说同步处理不好,是适用场景的问题。你举的例子很好,游戏当中很多环节都要进行同步处理的,但是,有些环节是既可以用同步处理,也可以用异步处理的,而有些环节,使用异步处理更适合。但是,基于你狭隘的理解下,万事都要用同步处理,我就无话可说了。以及异步处理保证结果这个话题,我也是无语了。歧义应该是对结果这个词的理解不同吧。还是编程经验的问题,你要是多开发几年异步处理的程序,就不会说这样的话了。 另外,我觉得,你还是控制一下情绪,等什么时候,心平气和的看完我的回复,真正理解我表达的内容,就能学到一些你没有想到的知识了。争吵,对于你来说,学不到什么有用的内容,也解决不了问题。如果把争吵改为讨论,你的成长途径就又多了一条。
老王就是我 2021-04-19
  • 打赏
  • 举报
回复
引用 28 楼 冰思雨 的回复:
[quote=引用 24 楼 老王就是我 的回复:][quote=引用 22 楼 冰思雨 的回复:][quote=引用 19 楼 老王就是我 的回复:] 也可能只是普通的聊天信息,不需要处理只需要转发或者广播的。 由于需要ws的场景都是强交互性的,异步操作无法确保结果,服务端提交异步任务后只能直接返回提交任务成功信息,但无法确保任务一定能执行完成。举个例子,游戏中(游戏通常用socket通信),玩家交易、分解装备,必须向玩家告知此事件的结果,而不能单纯告知,服务端处理中,请稍后查看装备栏的变化或者邮件箱的新邮件,这是不合理的。所以,是否需要异步操作,是要看产品需求是否为强交互性而不是看技术瓶颈。单纯解决并发量的问题非常简单,加钱——要么给机器加配置要么上集群加机器(不需要分布式,单体集群+负载均衡就足以)
你说的这种情况不是不存在,只是,太绝对了。 现在要做的是找出问题出现的原因。我认为是批量数据操作太耗时产生,所以,才会有这个方案。 谁告诉你ws的场景中不能做异步操作的?谁又告诉你异步操作无法保证结果的? 1. ws 只是建立了一个客户端和服务端的通信渠道,至于你用它做同步数据处理,还是做异步数据处理,并不会由 ws 技术本身所限制; 2. 从开发模式上来看,ws 的开发模式,恰巧使用的是事件处理模型,而事件处理模型几乎都是采用多线程异步处理的; 3. 采用同步消息处理有一个优点就是编程难度很低(逻辑简单直接),异常状况可以及时捕获处理。采用异步消息处理也有一个优点,可以增加通信渠道的数据吞吐量; 4. 如果业务数据的处理过程与时间参数无关的话,同步处理和异步处理的结果是完全相同的,不存在操作结果无法保证的情况; 5. 异步处理的过程中,可以通过回调函数来完成业务闭环。与同步处理的编程思路是有所不同的。 6. 当然,不是所有的业务场景都适用异步处理方式,但是,大批量的数据处理操作,异步比同步更有优势。你向聊天室发送了一个聊天消息,你以为服务端的广播行为采用的是同步处理么?那样的话,你发一句话,要等待聊天室里面所有人都收到你的消息之后,你才能干其他事情了。当然,你开发的程序中可以这样干,但是,我要说的是,在这种场景下,服务端广播操作,采用异步处理更具有优势。数据通路没有等待,意味着它可以继续传输其他数据了。[/quote] 至于异步可以保证结果?那就更可笑了,如果需要异步保证结果,就必须弄个死循环的递归,报错就继续进入方法,直到正确处理完。而同步中,处理结果不是预期值是可以提供报错信息让客户端重新发送请求来确保正确的响应。异步操作,只要成功提交任务就会返回正确的结果,而无论任务的执行过程中是否出错。 异步和同步的差异并不只有编程难度的优劣(编程的优劣并不应该是主要考虑的问题,主要考虑的是该技术是否适合业务),还有可用性的差别。还是游戏,一个玩家A攻击了玩家B,客户端收到正确的结果,按照你所说的异步操作,假设异步操作过程中出错,攻击的事件没能走完,是写个死循环让它走完才退出还是直接不管呢?那问题来了,如果后续还有攻击事件产生,那之前错误的攻击事件怎么处理?直接按照双方当前的状态处理?这很明显是不符合业务要求的[/quote] 我觉得,你的编程水平还是有待提高的。我一直说的内容,你都没有理解到位。所以,也没有什么好和你说的了。 如果,你有机会参与几年的关于异步处理程序的开发的话,就会理解我上述说的几个回复了。 你对异步处理的编程实现,还停留在递归和死循环的思想中,很多东西,都没法和你聊了。因为,理解的层次确实是有些局限性。 最后,我并没有说同步处理不好,是适用场景的问题。你举的例子很好,游戏当中很多环节都要进行同步处理的,但是,有些环节是既可以用同步处理,也可以用异步处理的,而有些环节,使用异步处理更适合。但是,基于你狭隘的理解下,万事都要用同步处理,我就无话可说了。以及异步处理保证结果这个话题,我也是无语了。歧义应该是对结果这个词的理解不同吧。还是编程经验的问题,你要是多开发几年异步处理的程序,就不会说这样的话了。 另外,我觉得,你还是控制一下情绪,等什么时候,心平气和的看完我的回复,真正理解我表达的内容,就能学到一些你没有想到的知识了。争吵,对于你来说,学不到什么有用的内容,也解决不了问题。如果把争吵改为讨论,你的成长途径就又多了一条。[/quote] 异步与同步最大的不同不在于执行过程和线程,而在于客户端是否可知该任务执行完后的结果,如果是类似抢购或者邮件类的弱交互,异步并没有问题,哪怕半小时后告知客户端处理失败都不会有任何问题(大不了再点一次),但如果该事件类型为强交互(上述回帖中举的几个例子),客户端必须明确知道该事件的处理结果(哪怕是错误的结果),异步处理就不合适。你之前的发言都是在谈论异步同步的优劣和使用方式,并没有说明两者的使用场景的不同 同步异步并不存在优劣的问题,也没有优缺点之分
allanzjp 2021-04-16
  • 打赏
  • 举报
回复
版本升级后可见线程数量明显下降.
allanzjp 2021-04-16
  • 打赏
  • 举报
回复
接上文, 刚刚一个enter按快了, 还没写完就直接回复了 还是感谢大家的各种建议和回复, 虽然因为工作忙没有时间一一尝试了, 但我也学到了很多东西, 非常感谢!
allanzjp 2021-04-16
  • 打赏
  • 举报
回复
引用 20 楼 maradona1984 的回复:
这个又不知道他用的什么框架,如果性能压力较大可以考虑用netty,nio也能充分发挥CPU的性能,我也没用过其他ws框架,难道还有不是nio实现?
引用 24 楼 老王就是我 的回复:
至于异步可以保证结果?那就更可笑了,如果需要异步保证结果,就必须弄个死循环的递归,报错就继续进入方法,直到正确处理完。而同步中,处理结果不是预期值是可以提供报错信息让客户端重新发送请求来确保正确的响应。异步操作,只要成功提交任务就会返回正确的结果,而无论任务的执行过程中是否出错。 异步和同步的差异并不只有编程难度的优劣(编程的优劣并不应该是主要考虑的问题,主要考虑的是该技术是否适合业务),还有可用性的差别。还是游戏,一个玩家A攻击了玩家B,客户端收到正确的结果,按照你所说的异步操作,假设异步操作过程中出错,攻击的事件没能走完,是写个死循环让它走完才退出还是直接不管呢?那问题来了,如果后续还有攻击事件产生,那之前错误的攻击事件怎么处理?直接按照双方当前的状态处理?这很明显是不符合业务要求的
引用 22 楼 冰思雨 的回复:
你说的这种情况不是不存在,只是,太绝对了。 现在要做的是找出问题出现的原因。我认为是批量数据操作太耗时产生,所以,才会有这个方案。 谁告诉你ws的场景中不能做异步操作的?谁又告诉你异步操作无法保证结果的? 1. ws 只是建立了一个客户端和服务端的通信渠道,至于你用它做同步数据处理,还是做异步数据处理,并不会由 ws 技术本身所限制; 2. 从开发模式上来看,ws 的开发模式,恰巧使用的是事件处理模型,而事件处理模型几乎都是采用多线程异步处理的; 3. 采用同步消息处理有一个优点就是编程难度很低(逻辑简单直接),异常状况可以及时捕获处理。采用异步消息处理也有一个优点,可以增加通信渠道的数据吞吐量; 4. 如果业务数据的处理过程与时间参数无关的话,同步处理和异步处理的结果是完全相同的,不存在操作结果无法保证的情况; 5. 异步处理的过程中,可以通过回调函数来完成业务闭环。与同步处理的编程思路是有所不同的。 6. 当然,不是所有的业务场景都适用异步处理方式,但是,大批量的数据处理操作,异步比同步更有优势。你向聊天室发送了一个聊天消息,你以为服务端的广播行为采用的是同步处理么?那样的话,你发一句话,要等待聊天室里面所有人都收到你的消息之后,你才能干其他事情了。当然,你开发的程序中可以这样干,但是,我要说的是,在这种场景下,服务端广播操作,采用异步处理更具有优势。数据通路没有等待,意味着它可以继续传输其他数据了。
感谢大家的分析和回复, 大家的建议我都认真看了, 而且也一楼一楼的根据建议尝试去修复这个问题. 由于前几天太忙了, 而且暂时采用了深夜重启和服务器脚本监控重启的方式避免了内存溢出异常, 所以也没来得及回复大家的跟帖. 今天一看就回复到3页, 真的非常感谢大家的热情帮助. 我尝试了 @maradona1984 在第8楼的建议, 将java-webSocekt的依赖版本由1.3.0升级到1.5.1, 问题竟然神奇的解决了!
老王就是我 2021-04-16
  • 打赏
  • 举报
回复
引用 22 楼 冰思雨 的回复:
[quote=引用 19 楼 老王就是我 的回复:] 也可能只是普通的聊天信息,不需要处理只需要转发或者广播的。 由于需要ws的场景都是强交互性的,异步操作无法确保结果,服务端提交异步任务后只能直接返回提交任务成功信息,但无法确保任务一定能执行完成。举个例子,游戏中(游戏通常用socket通信),玩家交易、分解装备,必须向玩家告知此事件的结果,而不能单纯告知,服务端处理中,请稍后查看装备栏的变化或者邮件箱的新邮件,这是不合理的。所以,是否需要异步操作,是要看产品需求是否为强交互性而不是看技术瓶颈。单纯解决并发量的问题非常简单,加钱——要么给机器加配置要么上集群加机器(不需要分布式,单体集群+负载均衡就足以)
你说的这种情况不是不存在,只是,太绝对了。 现在要做的是找出问题出现的原因。我认为是批量数据操作太耗时产生,所以,才会有这个方案。 谁告诉你ws的场景中不能做异步操作的?谁又告诉你异步操作无法保证结果的? 1. ws 只是建立了一个客户端和服务端的通信渠道,至于你用它做同步数据处理,还是做异步数据处理,并不会由 ws 技术本身所限制; 2. 从开发模式上来看,ws 的开发模式,恰巧使用的是事件处理模型,而事件处理模型几乎都是采用多线程异步处理的; 3. 采用同步消息处理有一个优点就是编程难度很低(逻辑简单直接),异常状况可以及时捕获处理。采用异步消息处理也有一个优点,可以增加通信渠道的数据吞吐量; 4. 如果业务数据的处理过程与时间参数无关的话,同步处理和异步处理的结果是完全相同的,不存在操作结果无法保证的情况; 5. 异步处理的过程中,可以通过回调函数来完成业务闭环。与同步处理的编程思路是有所不同的。 6. 当然,不是所有的业务场景都适用异步处理方式,但是,大批量的数据处理操作,异步比同步更有优势。你向聊天室发送了一个聊天消息,你以为服务端的广播行为采用的是同步处理么?那样的话,你发一句话,要等待聊天室里面所有人都收到你的消息之后,你才能干其他事情了。当然,你开发的程序中可以这样干,但是,我要说的是,在这种场景下,服务端广播操作,采用异步处理更具有优势。数据通路没有等待,意味着它可以继续传输其他数据了。[/quote] 至于异步可以保证结果?那就更可笑了,如果需要异步保证结果,就必须弄个死循环的递归,报错就继续进入方法,直到正确处理完。而同步中,处理结果不是预期值是可以提供报错信息让客户端重新发送请求来确保正确的响应。异步操作,只要成功提交任务就会返回正确的结果,而无论任务的执行过程中是否出错。 异步和同步的差异并不只有编程难度的优劣(编程的优劣并不应该是主要考虑的问题,主要考虑的是该技术是否适合业务),还有可用性的差别。还是游戏,一个玩家A攻击了玩家B,客户端收到正确的结果,按照你所说的异步操作,假设异步操作过程中出错,攻击的事件没能走完,是写个死循环让它走完才退出还是直接不管呢?那问题来了,如果后续还有攻击事件产生,那之前错误的攻击事件怎么处理?直接按照双方当前的状态处理?这很明显是不符合业务要求的
老王就是我 2021-04-16
  • 打赏
  • 举报
回复
引用 22 楼 冰思雨 的回复:
[quote=引用 19 楼 老王就是我 的回复:] 也可能只是普通的聊天信息,不需要处理只需要转发或者广播的。 由于需要ws的场景都是强交互性的,异步操作无法确保结果,服务端提交异步任务后只能直接返回提交任务成功信息,但无法确保任务一定能执行完成。举个例子,游戏中(游戏通常用socket通信),玩家交易、分解装备,必须向玩家告知此事件的结果,而不能单纯告知,服务端处理中,请稍后查看装备栏的变化或者邮件箱的新邮件,这是不合理的。所以,是否需要异步操作,是要看产品需求是否为强交互性而不是看技术瓶颈。单纯解决并发量的问题非常简单,加钱——要么给机器加配置要么上集群加机器(不需要分布式,单体集群+负载均衡就足以)
你说的这种情况不是不存在,只是,太绝对了。 现在要做的是找出问题出现的原因。我认为是批量数据操作太耗时产生,所以,才会有这个方案。 谁告诉你ws的场景中不能做异步操作的?谁又告诉你异步操作无法保证结果的? 1. ws 只是建立了一个客户端和服务端的通信渠道,至于你用它做同步数据处理,还是做异步数据处理,并不会由 ws 技术本身所限制; 2. 从开发模式上来看,ws 的开发模式,恰巧使用的是事件处理模型,而事件处理模型几乎都是采用多线程异步处理的; 3. 采用同步消息处理有一个优点就是编程难度很低(逻辑简单直接),异常状况可以及时捕获处理。采用异步消息处理也有一个优点,可以增加通信渠道的数据吞吐量; 4. 如果业务数据的处理过程与时间参数无关的话,同步处理和异步处理的结果是完全相同的,不存在操作结果无法保证的情况; 5. 异步处理的过程中,可以通过回调函数来完成业务闭环。与同步处理的编程思路是有所不同的。 6. 当然,不是所有的业务场景都适用异步处理方式,但是,大批量的数据处理操作,异步比同步更有优势。你向聊天室发送了一个聊天消息,你以为服务端的广播行为采用的是同步处理么?那样的话,你发一句话,要等待聊天室里面所有人都收到你的消息之后,你才能干其他事情了。当然,你开发的程序中可以这样干,但是,我要说的是,在这种场景下,服务端广播操作,采用异步处理更具有优势。数据通路没有等待,意味着它可以继续传输其他数据了。[/quote] 没有业务场景谈什么技术解决方案?如果lz的问题只是单纯地客户端发送了大量的消息呢导致并发数过高呢?或者有大量的客户端连接到服务端导致服务端爆炸呢?如果场景中不能做熔断降级呢? 没有业务场景谈什么用哪些技术,技术是服务于业务的。在游戏项目中,是聊天的异步任务多还是必须同步的装备修改、人物属性修改、人物装饰修改、打架事件多?
maradona1984 2021-04-15
  • 打赏
  • 举报
回复
引用 19 楼 老王就是我 的回复:
[quote=引用 18 楼 冰思雨 的回复:][quote=引用 15 楼 老王就是我 的回复:]还有给可能,我怀疑是前端不端发送消息,然后服务器就炸了,这个没办法解决
他这个情况很明显就是前端不停的发请求,后端服务器过载了。主要原因还是因为每次请求的处理流程上面,都会花费很长的时间,而且,这个时间长度还不固定。因为是服务端模拟websocket客户端向另外的服务器发送批量的数据请求,所以,对端的服务器也有可能会产生过载的情况。 解决这种情况的办法没有一步搞定的,都要综合来看。 1. 将接收的客户端请求,由于处理需要的时长不确定,所以,把同步处理的业务流程改为异步处理的流程,客户端不能当时就得到处理结果的响应,要把每次请求生成一个任务,每个任务都要一个唯一的识别码,将任务加入队列(可以用数据库的表保存队列),然后,应答给客户端这个任务的唯一识别码。客户端通过这个识别码来查看任务的执行状况和执行结果。 2. 额外编写一个后台任务处理的线程,最好是可以针对队列中的数据采用线程池的技术来处理(注意不要将任务重复处理),这样的话,后台处理线程的数量就受控了。 3. 当任务加入队列的时候,要有一个业务逻辑,丢弃那些没有必要处理的任务,减少后序后台线程的工作量。比如,相同参数的请求,任务的执行内容是重复执行的,在入队的时候就可以查看当前队列中是否以前存在了,如果存在就没有必要入队了。 4. 后台处理线程的并发量 和 websocket-client 的调用频率,最好也能控制在一定的范围内,以免对端服务器发生过载,毕竟是批量数据的处理请求,数据的传输和处理都要考虑在内的。 5. 不要小瞧传输的数据量,websocket 为了开发方便,传输的数据一般都编码成为字符串来传输,不是二进制形式的,也没有经过压缩,数据条数越多,传输的数据量越大,传输也就会占用很多时间,毕竟,网络也是有带宽的。 6. 任务的时效性,也就是任务队列中的任务,是否要设置超时。使用队列主要目的有两个:一个是同步变异步,避免请求处理线程长时间占用而造成服务端假死,当请求处理线程耗尽后就不能再处理进入的请求了,而客户端的请求不仅仅只有当前这个数据批量处理的请求;另外一个目的是数据处理的伸缩性,有时候请求很密集,大多数时段就没有那么多批量数据处理的请求,这样的话,可以先将任务记录下来,以一个相对平稳的速度来处理这些任务,请求密集时任务不丢失,请求松散时或没有请求时,也可以持续的处理那些没来得及处理的任务。如果请求生成的任务数量一直持续的大于后台任务的处理量,说明出现了严重的过载情况,要么给任务设置超时,丢弃长时间未处理的任务,要么,再次升级处理架构,加大计算机系统的整体的数据吞吐量。[/quote] 也可能只是普通的聊天信息,不需要处理只需要转发或者广播的。 由于需要ws的场景都是强交互性的,异步操作无法确保结果,服务端提交异步任务后只能直接返回提交任务成功信息,但无法确保任务一定能执行完成。举个例子,游戏中(游戏通常用socket通信),玩家交易、分解装备,必须向玩家告知此事件的结果,而不能单纯告知,服务端处理中,请稍后查看装备栏的变化或者邮件箱的新邮件,这是不合理的。所以,是否需要异步操作,是要看产品需求是否为强交互性而不是看技术瓶颈。单纯解决并发量的问题非常简单,加钱——要么给机器加配置要么上集群加机器(不需要分布式,单体集群+负载均衡就足以)[/quote] 这个又不知道他用的什么框架,如果性能压力较大可以考虑用netty,nio也能充分发挥CPU的性能,我也没用过其他ws框架,难道还有不是nio实现?
老王就是我 2021-04-15
  • 打赏
  • 举报
回复
引用 18 楼 冰思雨 的回复:
[quote=引用 15 楼 老王就是我 的回复:]还有给可能,我怀疑是前端不端发送消息,然后服务器就炸了,这个没办法解决
他这个情况很明显就是前端不停的发请求,后端服务器过载了。主要原因还是因为每次请求的处理流程上面,都会花费很长的时间,而且,这个时间长度还不固定。因为是服务端模拟websocket客户端向另外的服务器发送批量的数据请求,所以,对端的服务器也有可能会产生过载的情况。 解决这种情况的办法没有一步搞定的,都要综合来看。 1. 将接收的客户端请求,由于处理需要的时长不确定,所以,把同步处理的业务流程改为异步处理的流程,客户端不能当时就得到处理结果的响应,要把每次请求生成一个任务,每个任务都要一个唯一的识别码,将任务加入队列(可以用数据库的表保存队列),然后,应答给客户端这个任务的唯一识别码。客户端通过这个识别码来查看任务的执行状况和执行结果。 2. 额外编写一个后台任务处理的线程,最好是可以针对队列中的数据采用线程池的技术来处理(注意不要将任务重复处理),这样的话,后台处理线程的数量就受控了。 3. 当任务加入队列的时候,要有一个业务逻辑,丢弃那些没有必要处理的任务,减少后序后台线程的工作量。比如,相同参数的请求,任务的执行内容是重复执行的,在入队的时候就可以查看当前队列中是否以前存在了,如果存在就没有必要入队了。 4. 后台处理线程的并发量 和 websocket-client 的调用频率,最好也能控制在一定的范围内,以免对端服务器发生过载,毕竟是批量数据的处理请求,数据的传输和处理都要考虑在内的。 5. 不要小瞧传输的数据量,websocket 为了开发方便,传输的数据一般都编码成为字符串来传输,不是二进制形式的,也没有经过压缩,数据条数越多,传输的数据量越大,传输也就会占用很多时间,毕竟,网络也是有带宽的。 6. 任务的时效性,也就是任务队列中的任务,是否要设置超时。使用队列主要目的有两个:一个是同步变异步,避免请求处理线程长时间占用而造成服务端假死,当请求处理线程耗尽后就不能再处理进入的请求了,而客户端的请求不仅仅只有当前这个数据批量处理的请求;另外一个目的是数据处理的伸缩性,有时候请求很密集,大多数时段就没有那么多批量数据处理的请求,这样的话,可以先将任务记录下来,以一个相对平稳的速度来处理这些任务,请求密集时任务不丢失,请求松散时或没有请求时,也可以持续的处理那些没来得及处理的任务。如果请求生成的任务数量一直持续的大于后台任务的处理量,说明出现了严重的过载情况,要么给任务设置超时,丢弃长时间未处理的任务,要么,再次升级处理架构,加大计算机系统的整体的数据吞吐量。[/quote] 也可能只是普通的聊天信息,不需要处理只需要转发或者广播的。 由于需要ws的场景都是强交互性的,异步操作无法确保结果,服务端提交异步任务后只能直接返回提交任务成功信息,但无法确保任务一定能执行完成。举个例子,游戏中(游戏通常用socket通信),玩家交易、分解装备,必须向玩家告知此事件的结果,而不能单纯告知,服务端处理中,请稍后查看装备栏的变化或者邮件箱的新邮件,这是不合理的。所以,是否需要异步操作,是要看产品需求是否为强交互性而不是看技术瓶颈。单纯解决并发量的问题非常简单,加钱——要么给机器加配置要么上集群加机器(不需要分布式,单体集群+负载均衡就足以)
冰思雨 2021-04-15
  • 打赏
  • 举报
回复
引用 15 楼 老王就是我 的回复:
还有给可能,我怀疑是前端不端发送消息,然后服务器就炸了,这个没办法解决
他这个情况很明显就是前端不停的发请求,后端服务器过载了。主要原因还是因为每次请求的处理流程上面,都会花费很长的时间,而且,这个时间长度还不固定。因为是服务端模拟websocket客户端向另外的服务器发送批量的数据请求,所以,对端的服务器也有可能会产生过载的情况。 解决这种情况的办法没有一步搞定的,都要综合来看。 1. 将接收的客户端请求,由于处理需要的时长不确定,所以,把同步处理的业务流程改为异步处理的流程,客户端不能当时就得到处理结果的响应,要把每次请求生成一个任务,每个任务都要一个唯一的识别码,将任务加入队列(可以用数据库的表保存队列),然后,应答给客户端这个任务的唯一识别码。客户端通过这个识别码来查看任务的执行状况和执行结果。 2. 额外编写一个后台任务处理的线程,最好是可以针对队列中的数据采用线程池的技术来处理(注意不要将任务重复处理),这样的话,后台处理线程的数量就受控了。 3. 当任务加入队列的时候,要有一个业务逻辑,丢弃那些没有必要处理的任务,减少后序后台线程的工作量。比如,相同参数的请求,任务的执行内容是重复执行的,在入队的时候就可以查看当前队列中是否以前存在了,如果存在就没有必要入队了。 4. 后台处理线程的并发量 和 websocket-client 的调用频率,最好也能控制在一定的范围内,以免对端服务器发生过载,毕竟是批量数据的处理请求,数据的传输和处理都要考虑在内的。 5. 不要小瞧传输的数据量,websocket 为了开发方便,传输的数据一般都编码成为字符串来传输,不是二进制形式的,也没有经过压缩,数据条数越多,传输的数据量越大,传输也就会占用很多时间,毕竟,网络也是有带宽的。 6. 任务的时效性,也就是任务队列中的任务,是否要设置超时。使用队列主要目的有两个:一个是同步变异步,避免请求处理线程长时间占用而造成服务端假死,当请求处理线程耗尽后就不能再处理进入的请求了,而客户端的请求不仅仅只有当前这个数据批量处理的请求;另外一个目的是数据处理的伸缩性,有时候请求很密集,大多数时段就没有那么多批量数据处理的请求,这样的话,可以先将任务记录下来,以一个相对平稳的速度来处理这些任务,请求密集时任务不丢失,请求松散时或没有请求时,也可以持续的处理那些没来得及处理的任务。如果请求生成的任务数量一直持续的大于后台任务的处理量,说明出现了严重的过载情况,要么给任务设置超时,丢弃长时间未处理的任务,要么,再次升级处理架构,加大计算机系统的整体的数据吞吐量。
冰思雨 2021-04-15
  • 打赏
  • 举报
回复
引用 19 楼 老王就是我 的回复:
也可能只是普通的聊天信息,不需要处理只需要转发或者广播的。 由于需要ws的场景都是强交互性的,异步操作无法确保结果,服务端提交异步任务后只能直接返回提交任务成功信息,但无法确保任务一定能执行完成。举个例子,游戏中(游戏通常用socket通信),玩家交易、分解装备,必须向玩家告知此事件的结果,而不能单纯告知,服务端处理中,请稍后查看装备栏的变化或者邮件箱的新邮件,这是不合理的。所以,是否需要异步操作,是要看产品需求是否为强交互性而不是看技术瓶颈。单纯解决并发量的问题非常简单,加钱——要么给机器加配置要么上集群加机器(不需要分布式,单体集群+负载均衡就足以)
你说的这种情况不是不存在,只是,太绝对了。 现在要做的是找出问题出现的原因。我认为是批量数据操作太耗时产生,所以,才会有这个方案。 谁告诉你ws的场景中不能做异步操作的?谁又告诉你异步操作无法保证结果的? 1. ws 只是建立了一个客户端和服务端的通信渠道,至于你用它做同步数据处理,还是做异步数据处理,并不会由 ws 技术本身所限制; 2. 从开发模式上来看,ws 的开发模式,恰巧使用的是事件处理模型,而事件处理模型几乎都是采用多线程异步处理的; 3. 采用同步消息处理有一个优点就是编程难度很低(逻辑简单直接),异常状况可以及时捕获处理。采用异步消息处理也有一个优点,可以增加通信渠道的数据吞吐量; 4. 如果业务数据的处理过程与时间参数无关的话,同步处理和异步处理的结果是完全相同的,不存在操作结果无法保证的情况; 5. 异步处理的过程中,可以通过回调函数来完成业务闭环。与同步处理的编程思路是有所不同的。 6. 当然,不是所有的业务场景都适用异步处理方式,但是,大批量的数据处理操作,异步比同步更有优势。你向聊天室发送了一个聊天消息,你以为服务端的广播行为采用的是同步处理么?那样的话,你发一句话,要等待聊天室里面所有人都收到你的消息之后,你才能干其他事情了。当然,你开发的程序中可以这样干,但是,我要说的是,在这种场景下,服务端广播操作,采用异步处理更具有优势。数据通路没有等待,意味着它可以继续传输其他数据了。
老王就是我 2021-04-15
  • 打赏
  • 举报
回复
引用 20 楼 maradona1984 的回复:
[quote=引用 19 楼 老王就是我 的回复:][quote=引用 18 楼 冰思雨 的回复:][quote=引用 15 楼 老王就是我 的回复:]还有给可能,我怀疑是前端不端发送消息,然后服务器就炸了,这个没办法解决
他这个情况很明显就是前端不停的发请求,后端服务器过载了。主要原因还是因为每次请求的处理流程上面,都会花费很长的时间,而且,这个时间长度还不固定。因为是服务端模拟websocket客户端向另外的服务器发送批量的数据请求,所以,对端的服务器也有可能会产生过载的情况。 解决这种情况的办法没有一步搞定的,都要综合来看。 1. 将接收的客户端请求,由于处理需要的时长不确定,所以,把同步处理的业务流程改为异步处理的流程,客户端不能当时就得到处理结果的响应,要把每次请求生成一个任务,每个任务都要一个唯一的识别码,将任务加入队列(可以用数据库的表保存队列),然后,应答给客户端这个任务的唯一识别码。客户端通过这个识别码来查看任务的执行状况和执行结果。 2. 额外编写一个后台任务处理的线程,最好是可以针对队列中的数据采用线程池的技术来处理(注意不要将任务重复处理),这样的话,后台处理线程的数量就受控了。 3. 当任务加入队列的时候,要有一个业务逻辑,丢弃那些没有必要处理的任务,减少后序后台线程的工作量。比如,相同参数的请求,任务的执行内容是重复执行的,在入队的时候就可以查看当前队列中是否以前存在了,如果存在就没有必要入队了。 4. 后台处理线程的并发量 和 websocket-client 的调用频率,最好也能控制在一定的范围内,以免对端服务器发生过载,毕竟是批量数据的处理请求,数据的传输和处理都要考虑在内的。 5. 不要小瞧传输的数据量,websocket 为了开发方便,传输的数据一般都编码成为字符串来传输,不是二进制形式的,也没有经过压缩,数据条数越多,传输的数据量越大,传输也就会占用很多时间,毕竟,网络也是有带宽的。 6. 任务的时效性,也就是任务队列中的任务,是否要设置超时。使用队列主要目的有两个:一个是同步变异步,避免请求处理线程长时间占用而造成服务端假死,当请求处理线程耗尽后就不能再处理进入的请求了,而客户端的请求不仅仅只有当前这个数据批量处理的请求;另外一个目的是数据处理的伸缩性,有时候请求很密集,大多数时段就没有那么多批量数据处理的请求,这样的话,可以先将任务记录下来,以一个相对平稳的速度来处理这些任务,请求密集时任务不丢失,请求松散时或没有请求时,也可以持续的处理那些没来得及处理的任务。如果请求生成的任务数量一直持续的大于后台任务的处理量,说明出现了严重的过载情况,要么给任务设置超时,丢弃长时间未处理的任务,要么,再次升级处理架构,加大计算机系统的整体的数据吞吐量。[/quote] 也可能只是普通的聊天信息,不需要处理只需要转发或者广播的。 由于需要ws的场景都是强交互性的,异步操作无法确保结果,服务端提交异步任务后只能直接返回提交任务成功信息,但无法确保任务一定能执行完成。举个例子,游戏中(游戏通常用socket通信),玩家交易、分解装备,必须向玩家告知此事件的结果,而不能单纯告知,服务端处理中,请稍后查看装备栏的变化或者邮件箱的新邮件,这是不合理的。所以,是否需要异步操作,是要看产品需求是否为强交互性而不是看技术瓶颈。单纯解决并发量的问题非常简单,加钱——要么给机器加配置要么上集群加机器(不需要分布式,单体集群+负载均衡就足以)[/quote] 这个又不知道他用的什么框架,如果性能压力较大可以考虑用netty,nio也能充分发挥CPU的性能,我也没用过其他ws框架,难道还有不是nio实现?[/quote] 我没提过框架的问题,我说的是业务场景,技术是服务于业务的,而不是业务服务于技术
老王就是我 2021-04-14
  • 打赏
  • 举报
回复
还有给可能,我怀疑是前端不端发送消息,然后服务器就炸了,这个没办法解决
老王就是我 2021-04-14
  • 打赏
  • 举报
回复
callxxxResources哪里调用?
冰思雨 2021-04-13
  • 打赏
  • 举报
回复
楼主使用 JProfile 查看一下线程栈,看看你关注的哪些线程,都卡在哪里? 我看楼主的截图,有一个线程卡在了 OnMessage 方法的调用上了,你再看看,是不是所有的线程,都卡在这个方法上面了,如果是的话,就着重查看这个OnMessage方法;如果不是的话,就逐个排查一下到底是卡在哪个方法的调用上。这种方案,简单粗暴,但需要经验。要多次尝试才好。 刚刚仔细看了一下楼主的代码,貌似是模拟客户端发送消息的程序。感觉程序对功能的封装做的不太好。 线程持续增加,要看看具体增加的是否是同一个线程组的线程,如果没有增加上限,说明底层线程池的配置有问题,或者,线程调用的代码(类对象的方法)没有及时返回。后者是要重点关注的,因为,服务端的线程几乎都会采用线程池来进行维护和管理,出问题的可能性不大。 将批量逻辑放后台服务执行,websocket 线程就应该不会持续增加了,除非你的这个批量逻辑没有彻底改成异步的,还存在多线程协作等相关的问题。 另外, 1.你有没有考虑过,你发送过去的数据,对端的处理也需要时间?对端在处理的过程中, websocket 线程对 Message 的收发是采用 BIO 还是 NIO 的方式? 2. 线程池是具有伸缩性的,一般都会设置一个上限值,没有超出上限的话,都应该算是正常情况,没有设置上限应该是不正常的。 3. 模拟的ws客户端和对端的通信也是要相互配合的,之所以要创建后台任务,目的是将这些通信任务构成一个队列,开启额外的专用线程来逐个处理这些任务,而不是由 websocket 触发的并发的通信模式,楼主可能没有明白我的意思。
maradona1984 2021-04-13
  • 打赏
  • 举报
回复
引用 11 楼 allanzjp 的回复:
[quote=引用 8 楼 maradona1984 的回复:]如果是你写的代码,那就审视下逻辑,看是否有对象/线程未释放,建议使用线程池,而不是自开线程,特别是循环/在请求中new thread,如果是依赖的开源框架,升级/降级几个小版本
我尝试过将webSocket线程放入SingleThreadExecutor中执行并在结束后shutdown, 但是也无法解决此问题; 我这里依赖的是开源的java-websocket框架, 我也怀疑是否是框架的问题, 稍后尝试一下升级版本, 看一下是否有效. 多谢回复![/quote] 如果是引用比较多的开源框架,一个小版本也许就会修复这种问题,比较少的那就不知道了
allanzjp 2021-04-13
  • 打赏
  • 举报
回复
引用 8 楼 maradona1984 的回复:
如果是你写的代码,那就审视下逻辑,看是否有对象/线程未释放,建议使用线程池,而不是自开线程,特别是循环/在请求中new thread,如果是依赖的开源框架,升级/降级几个小版本
我尝试过将webSocket线程放入SingleThreadExecutor中执行并在结束后shutdown, 但是也无法解决此问题; 我这里依赖的是开源的java-websocket框架, 我也怀疑是否是框架的问题, 稍后尝试一下升级版本, 看一下是否有效. 多谢回复!
allanzjp 2021-04-13
  • 打赏
  • 举报
回复
引用 7 楼 luguangxu68 的回复:
status 变量加 volatile 试试
好的, 多谢回复, 我尝试一下!
allanzjp 2021-04-13
  • 打赏
  • 举报
回复
引用 6 楼 冰思雨 的回复:
[quote=引用 5 楼 allanzjp 的回复:]如下图, webSocket调用一旦完成, status状态会变更为 >2 , 这块代码反复debug测试过, 应该是没有问题的. 每次进入while循环之后, debug一段时间后都能正常跳出.
能够正常结束循环,不代表能够及时退出。while 循环结束的条件要看 batch 执行的时长,如果batch出了问题导致status无法更新的话,while所在的线程就永远无法结束了。这是一个很明显的隐患。一般我们遇到这种情况,有两种方案:一种是把同步处理改成异步处理;另一种是添加超时机制,循环退出的条件除了状态还要有超时时间,以防batch出现异常状况而导致状态不同步的情况。还有,多线程的代码,要注意一下线程安全的问题。 [/quote] 多谢回复, 昨天已经尝试过拆解逻辑, 去除了while循环, 将批量逻辑放后台服务执行, 然而还是无法解决线程和堆内存持续增加的问题. 现在我怀疑是否是webSocket线程结束后仍然在其他地方被引用了, 导致一直无法释放资源?
maradona1984 2021-04-13
  • 打赏
  • 举报
回复
如果是你写的代码,那就审视下逻辑,看是否有对象/线程未释放,建议使用线程池,而不是自开线程,特别是循环/在请求中new thread,如果是依赖的开源框架,升级/降级几个小版本
加载更多回复(7)

50,531

社区成员

发帖
与我相关
我的任务
社区描述
Java相关技术讨论
javaspring bootspring cloud 技术论坛(原bbs)
社区管理员
  • Java相关社区
  • 小虚竹
  • 谙忆
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧