一、前言
因为 surging 的版本都是基于dotnetty ,因为停更加上性能上的不稳定,让我和客户都很烦心,后面打算修改源码,但是我看了源码发现buffer,EventLoop内部封装都不是很好,很难进行修改,为了节约时间后面在github找到spannetty,然后下载源码,替换之后的引用发现性能上有了很大的进步,视频直播推流不卡顿,但是发现还是有内存泄漏的问题,然后通过dump文件修正了问题,然后我把网关访问的 JSON编解码组件由原来的Json.net 改成了system.text.json, 然后明天发布凯亚物联网测试版本提供下载,等后面做完北向输出将发布正式版本
HttpFlv:http://117.72.121.2:281/httpflv.html (黑衣人)
HttpFlv:http://117.72.121.2:281/httpflv1.html (大红包)
rtmp:rtmp://117.72.121.2:76/live1/livestream2 (黑衣人)
rtmp:rtmp://117.72.121.2:76/live1/livestream3 (大红包)
凯亚 (Kayak) 是什么?
凯亚(Kayak)是基于.NET6.0软件环境下的surging微服务引擎进行开发的, 平台包含了微服务和物联网平台。支持异步和响应式编程开发,功能包含了物模型,设备,产品,网络组件的统一管理和微服务平台下的注册中心,服务路由,模块,中间服务等管理。还有多协议适配(TCP,MQTT,UDP,CoAP,HTTP,Grpc,websocket,rtmp,httpflv,webservice,等),通过灵活多样的配置适配能够接入不同厂家不同协议等设备。并且通过设备告警,消息通知,数据可视化等功能。能够让你能快速建立起微服务物联网平台系统。
凯亚物联网平台:http://117.72.121.2:3100(用户名:fanly 密码:123456)
链路跟踪Skywalking V8:http://117.72.121.2:8080/
surging 微服务引擎开源地址:https://github.com/fanliang11/surging(后面surging 会移动到microsurging进行维护)
二、dump分析
有了vs 就不需要什么windbg了,可视化界面寻找托管内存对象一目了然,首先看下dump 文件分析
全部托管对象
从托管对象来看,除了autofac, object[] ,byte[],ArrayPool都很可疑,然后我们先来看看object[],byte[]是什么玩意
看object[] 里面还有ArrayPool,这让我有怀疑对象了
看byte[] 里面还有ArrayPool,在我印象当中,surging 只有httpkestrel 文件上传下载功能的时候,在StreamCopyOperation类中使用过,其它一概也没有使用,对于ArrayPool<byte>.Shared.Rent获取的buffer,我后面都 ArrayPool<byte>.Shared.Return掉了啊。是不是dotnetty 出现的问题呢?然后我全局寻找到了,在ArrayPooled和ArrayPooledByteBuffer文件下buffer 没有return 还回去
ArrayPooledByteBuffer文件
ArrayPooled文件,这里没引用,应该没有对象调用,关键还是ArrayPooledByteBuffer
还有DotNetty.Transport.Libuv.Native.Tcp 关闭的时候导致内存增加没有释放,因为是非托管资源,需要调用uv_close和强制垃圾回收
三、优化编解码
因为surging 是支持通过接口代理和routepath 两种方式访问,因为网关在调用runtime时是不知道调用类型,所以传递返回的都是object ,所以内容必然是json 对象,所以必然需要JSON编解码组件,之前是Json.net ,后换成了system.text.json
然后在httpkestrel的HttpMessageListener 类中,bodyParams也缓存了sytem.text.json ,以为解码返回的是object, 所以必然要写转换,object 转换代码如下:
public class JsonElementJsonConverter : System.Text.Json.Serialization.JsonConverter<object> { private const string DateTimeFormat = "yyyy-MM-dd HH:mm:ss"; public override object Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { if (reader.TokenType == JsonTokenType.String && DateTime.TryParseExact(reader.GetString(), DateTimeFormat, CultureInfo.InvariantCulture, DateTimeStyles.None, out DateTime dateTime)) { return dateTime; } if(reader.TokenType==JsonTokenType.String) { return reader.GetString(); } if (reader.TokenType == JsonTokenType.Number) { var num = reader.GetDecimal(); return num; } return JsonElement.ParseValue(ref reader); } public override void Write(Utf8JsonWriter writer, object value, JsonSerializerOptions options) { var jsonEl = (JsonElement)value; writer.WriteStringValue(jsonEl.ValueKind.ToString(DateTimeFormat)); } }
JsonOption 代码
public class JsonOption { public static JsonSerializerOptions SerializeOptions { get; set; } = new JsonSerializerOptions() { WriteIndented = true, Converters = { new JsonElementJsonConverter() } }; }
修改的代码如下图所示