1案例一般线上系统OOM,都不会是简单的由你的业务代码导致,大多可能因为系统使用的某开源技术内部源码有问题。

2系统架构服务间RPC通信时,采用基于xxx框架封装的RPC框架。

3事故现场日常服务A通过RPC框架调用服务B,但某天,负责服务A的工程师更新一些代码,然后将服务A重新上线后,服务B突然宕机!明明修改代码的是A,重新部署的也是A,怎么B挂了?别忘了,立即登录到服务B的机器查看日志,发现OOM:java.lang.OutOfMemoryErrorJavaheapspaceB为什么会OOM?难道是服务B自己的问题?那重启下B,很快又OOM宕机,这怪了,因为在A修改代码部署前,B从未出现过这种情况!都是A修改代码部署后才导致B出现这情况。

初步查找内存溢出的故障发生点一般内存溢出时,务必先找故障发生点,也就看日志,发现引发OutOfMemory居然就是我们自研的RPC框架:java.lang.OutOfMemoryError:Javaheapspacexx.xx.xx.rpc.xx.XXXClass.read()xx.xx.xx.rpc.xx.XXXClass.xxMethod()xx.xx.xx.rpc.xx.XXXClass.xxMethod()初步确定,就是自研RPC框架在接收请求的时候引发OOM。

分析内存快照,找到占用内存最大对象MAT分析OOM,发现占用内存最大的是一个大byte[]数组。

当时我堆内存就4G,而内存快照发现,一个大byte[]数组就占了4G。

这byte[]数组哪来的?分析byte[]数组的引用者,发现该数组就是RPC框架内部的类引用的。

分析源码,找出原因通过日志定位谁导致了OOM,往往可能就是某技术框架,如Tomcat、Jetty或RPC框架用MAT之类的工具去分析内存快照,找到当时占用内存最大的对象是谁,可以找找都是谁在引用他,当然一般第一步通过看日志就大概知道导致内存溢出的类是谁,日志的异常栈里都会告诉你的。

对那个技术的源代码进行分析,比如对Tomcat、Jetty、RPC框架的源代码去进行追踪分析于是就结合日志的异常栈分析自己写的RPC框架源码,接收请求时的流程A请求时,会序列化传输过来的对象,将RequestDTO等对象变成一个byte[]数组:对于B,首先根据自定义序列化协议反序列化发过来的数据:接着把请求数据读取到一个byte[]缓存中去,然后调用业务逻辑代码处理请求,最后请求处理完毕,清理byte[]缓存。

我们也在下面的图中反映出来服务B的处理流程。

想必大家都已经看明白上面RPC框架运行的原理了,接着我们自然在源码中要寻找一下,为什么用来缓冲请求的byte[]数组会搞成几个GB那么大?正常情况下,这个数组应该最多不超过1MB的。

RPC框架的类定义原来当时有特殊情况,因为RPC框架要进行对象传输,就必须得让服务A和服务B都知道有这么个对象。

举个例子,比如A要把一个Request对象传给B,首先需使用ProtoBuf定义一个对象文件:然后会通过上面那个特殊语法写的文件反向生成一个对应的Java类出来,此时会生成一个Java语法的Request类,类似下面这样:接着这个Request类你需要在服务A和服务B的工程里都要引入,他们俩就知道,把Request交给服务A,他会自己进行序列化成字节流,然后到服务B的时候,他会把字节流反序列化成一个Request对象引入Request类:服务A和服务B都必须知道有Request类的存在,然后才能把Request对象序列化成字节流,也才能从字节流反序列化出来一个Request类的对象。

RPC框架的一个bug:过大的默认值!上图中,B在接到请求后,会先反序列化,接着把请求读出来放入一个byte[]数组。

一旦发现对方发过来的字节流反序列化失败,这往往是因为A对Request类做了修改,但服务B不知道这次修改,Request还是老版本。

结果A的Request类有15个字段,序列化成字节流给你发送过来了,B的Request类只有10个字段,有的字段名还不一,反序列化时就会失败。

而代码逻辑是,一旦反序列化失败,此时就会开辟一个byte[]数组,默认大小是4GB,然后把对方的字节流原封不动的放进去。

所以问题就是,A工程师修改了很多Request类字段,结果没告诉B工程师。

所以A上线后,序列化的Request对象到B就无法反序列化成功,B就会直接开辟一个默认4G的byte[]数组,直接OOM:解决方案当时那人为何把异常情况下的数组默认大小设为几G?这也没办法,因为当时写这段代码的刚好是应届生,当时他考虑万一反序列化失败,那就原封不动的封装字节流到数组,让我们自行处理。

但他又不知道对方字节流里数据到底有多少,所以直接开辟特大数组,保证一定能放下字节流。

而且一般测试的时候都不会测到这种异常情况。

解决方案:把RPC框架中那个数组的默认值从4GB调整为4MB即可,一般请求都不会超过4MB,不需要开辟那么大的数组让服务A和服务B的Request类定义保持一致即可

  • 记载
年轻的母亲4免费 2023-05-26 21:57:37

1案例一般线上系统OOM,都不会是简单的由你的业务代码导致,大多可能因为系统使用的某开源技术内部源码有问题。

2系统架构服务间RPC通信时,采用基于xxx框架封装的RPC框架。

3事故现场日常服务A通过RPC框架调用服务B,但某天,负责服务A的工程师更新一些代码,然后将服务A重新上线后,服务B突然宕机!明明修改代码的是A,重新部署的也是A,怎么B挂了?别忘了,立即登录到服务B的机器查看日志,发现OOM:java.lang.OutOfMemoryErrorJavaheapspaceB为什么会OOM?难道是服务B自己的问题?那重启下B,很快又OOM宕机,这怪了,因为在A修改代码部署前,B从未出现过这种情况!都是A修改代码部署后才导致B出现这情况。

初步查找内存溢出的故障发生点一般内存溢出时,务必先找故障发生点,也就看日志,发现引发OutOfMemory居然就是我们自研的RPC框架:java.lang.OutOfMemoryError:Javaheapspacexx.xx.xx.rpc.xx.XXXClass.read()xx.xx.xx.rpc.xx.XXXClass.xxMethod()xx.xx.xx.rpc.xx.XXXClass.xxMethod()初步确定,就是自研RPC框架在接收请求的时候引发OOM。

分析内存快照,找到占用内存最大对象MAT分析OOM,发现占用内存最大的是一个大byte[]数组。

当时我堆内存就4G,而内存快照发现,一个大byte[]数组就占了4G。

这byte[]数组哪来的?分析byte[]数组的引用者,发现该数组就是RPC框架内部的类引用的。

分析源码,找出原因通过日志定位谁导致了OOM,往往可能就是某技术框架,如Tomcat、Jetty或RPC框架用MAT之类的工具去分析内存快照,找到当时占用内存最大的对象是谁,可以找找都是谁在引用他,当然一般第一步通过看日志就大概知道导致内存溢出的类是谁,日志的异常栈里都会告诉你的。

对那个技术的源代码进行分析,比如对Tomcat、Jetty、RPC框架的源代码去进行追踪分析于是就结合日志的异常栈分析自己写的RPC框架源码,接收请求时的流程A请求时,会序列化传输过来的对象,将RequestDTO等对象变成一个byte[]数组:对于B,首先根据自定义序列化协议反序列化发过来的数据:接着把请求数据读取到一个byte[]缓存中去,然后调用业务逻辑代码处理请求,最后请求处理完毕,清理byte[]缓存。

我们也在下面的图中反映出来服务B的处理流程。

想必大家都已经看明白上面RPC框架运行的原理了,接着我们自然在源码中要寻找一下,为什么用来缓冲请求的byte[]数组会搞成几个GB那么大?正常情况下,这个数组应该最多不超过1MB的。

RPC框架的类定义原来当时有特殊情况,因为RPC框架要进行对象传输,就必须得让服务A和服务B都知道有这么个对象。

举个例子,比如A要把一个Request对象传给B,首先需使用ProtoBuf定义一个对象文件:然后会通过上面那个特殊语法写的文件反向生成一个对应的Java类出来,此时会生成一个Java语法的Request类,类似下面这样:接着这个Request类你需要在服务A和服务B的工程里都要引入,他们俩就知道,把Request交给服务A,他会自己进行序列化成字节流,然后到服务B的时候,他会把字节流反序列化成一个Request对象引入Request类:服务A和服务B都必须知道有Request类的存在,然后才能把Request对象序列化成字节流,也才能从字节流反序列化出来一个Request类的对象。

RPC框架的一个bug:过大的默认值!上图中,B在接到请求后,会先反序列化,接着把请求读出来放入一个byte[]数组。

一旦发现对方发过来的字节流反序列化失败,这往往是因为A对Request类做了修改,但服务B不知道这次修改,Request还是老版本。

结果A的Request类有15个字段,序列化成字节流给你发送过来了,B的Request类只有10个字段,有的字段名还不一,反序列化时就会失败。

而代码逻辑是,一旦反序列化失败,此时就会开辟一个byte[]数组,默认大小是4GB,然后把对方的字节流原封不动的放进去。

所以问题就是,A工程师修改了很多Request类字段,结果没告诉B工程师。

所以A上线后,序列化的Request对象到B就无法反序列化成功,B就会直接开辟一个默认4G的byte[]数组,直接OOM:解决方案当时那人为何把异常情况下的数组默认大小设为几G?这也没办法,因为当时写这段代码的刚好是应届生,当时他考虑万一反序列化失败,那就原封不动的封装字节流到数组,让我们自行处理。

但他又不知道对方字节流里数据到底有多少,所以直接开辟特大数组,保证一定能放下字节流。

而且一般测试的时候都不会测到这种异常情况。

解决方案:把RPC框架中那个数组的默认值从4GB调整为4MB即可,一般请求都不会超过4MB,不需要开辟那么大的数组让服务A和服务B的Request类定义保持一致即可

    <acronym date-time="5Rwhgvar"></acronym>
    <legend date-time="Znodvcx2zaWA"><tt lang="3xovEacVu"></tt></legend><legend dropzone="uLIZvzHu"></legend>
              <bdo id="b1Cs6SP5C"></bdo>

              年轻的母亲4免费《年轻的母亲4免费》由来

              编辑
              1.年轻的母亲4免费咻!咻!咻!就在这时,几道身影从旁边快速的冲了出来,他们的目标是花魁,...
                     2.处置二夫人!!一听到这里的时候,大家才想起来,刚才夏天话里面说的话完全是将矛头对准二夫人的啊。
                     3.因为此时要出手的人就是他们冥王之城的城主,冥王之城的象征,他们心中最崇拜的那个人,那个最高不可攀的人。
                     4.曾氏集团的这些员工都认识温兆华,因为温兆华每天都会来曾氏集团,而且每次的动静都很大,他为人十分猖狂。
                     5.”齐帅不屑的说道,他对今天的比赛有十足的信心,他相信武术部绝对会拿下今天的比赛。

              年轻的母亲4免费《年轻的母亲4免费》起源

              <tt id="T4nahUNbJZ1P5X"></tt>
                      1.年轻的母亲4免费游戏有着二次元的画风,玩家可以在这里自定义你的角色形象,快来装扮他吧。
                             2.随着音乐的节奏进行闯关,游戏简单易上手,也可以找到和自己一样感兴趣的小伙伴。
                             3.同时你也可以在游戏之中解锁各种各样的玩法,不断的享受奇葩的技能和英雄,同时有佣兵可以招募,招募他们一起在游戏中战斗。
                             4.邀请你的好友来进行比拼,合理的利用道具来帮助你挑战成功,更多有趣的小故事等你发现;
                             5.玩家可以使用金币来升级自己的子弹,增加子弹的威力,在打击方块时可以一举击碎;
                             6.你能与自身的朋友开展互相的连动,一起去进行相关的组成作战,或者战。
                      参考资料