前两个星期公司系统从.net framwork升级到了.net core 2.2,被客户投诉系统变慢,刚开始我们把问题归咎于数据库驱动,还在园子里面发博问求助,主要是因为自己看到一些文章说过数据库驱动的问题,而且我们监控打点的地方不是直接在只访问数据库的点,还包含了json反序列化,所以先入为主的把问题直接定位在了数据库驱动,后来发现,程序运行一段时间后,那些没有访问数据库的地方也变慢,直接看代码发现,特殊的地方就是里面用了json反序列化。果然,在程序启动一段时间,json反序列化性能没有任何问题,序列化一个比较大的对象也就几毫秒,甚至不到1毫秒。运行一段时间后,继续监控,开始出现几十毫秒。直到发现访问越来越慢,json反序列化居然差不多要1秒。
图1,是程序刚开始启动,图2,是很慢的时候。
至此,可以说终于找到问题的根本原因了,接下来是找到办法解决这个问题了,针对这种情况,不知道大家是怎么解决的?
我们是想尝试升级到.net core 3.0,使用内置json库,但是看了dudu大佬提的这个博问,这个库好像序列化中文是编码过的,不知道最后解决了没有?
我们引用的Newtonsoft.Json库版本为12.0.1
果然还是我们自己使用的问题,我们在应用启动的时候设置了一个全局的Setting:
var setting = new Newtonsoft.Json.JsonSerializerSettings();
Newtonsoft.Json.JsonConvert.DefaultSettings = new Func<Newtonsoft.Json.JsonSerializerSettings>(() =>
{
setting.NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore;
setting.Converters.Add(new GuidJsonConverter());
return setting;
});
就是上面代码setting.Converters.Add(new GuidJsonConverter()) 的这一设置导致应用跑着跑着,序列化反序列化越来越慢,这一段代码根本没什么用,里面是解决读取json字符串时,解析那些不是合法的Guid的转换问题,而且里面居然用了正则去判断,前端传过来的Guid不合法,在后端解决,这也是一种奇葩的解决方案!把这段代码注释掉之后,到目前为止,再也没有出现序列化反序列化慢的问题了。
为什么一开始不慢呢?很奇怪这个convert做了什么还有累积效应。
恭喜啊。不过有一点不同意你的观点。前端需要判断是否合法,后端也需要判断的,前端比较容易越过判断,双重判断比较保险。
@会长: 我们前端同事使用ext框架,生成的Id都是ext-xxx的id,后端实体类对应的属性类型为Guid,所有反序列化提交的数据就出错了,后来为了处理这个id,专门写了这个类去解决,如果我们实体类是的属性是Guid?可为空的Guid就不会。
这种同事 改打死 2333
我写了一段代码运行需要11秒(我的电脑比较老旧了),没有你说的那么慢,可否写个能重现问题的demo发上来?这是我写的:
using Newtonsoft.Json;
using System;
using System.Diagnostics;
namespace JsonTest
{
class Program
{
static void Main(string[] args)
{
var wang = new Person
{
Name = "老王",
Age = 35,
Gender = "男",
Degree = "本科",
Address = "北京市海淀区东北旺中路菊园小区2号楼2单元302"
};
string json = JsonConvert.SerializeObject(wang);
Stopwatch watch = new Stopwatch();
watch.Start();
for (int i = 0; i < 2000000; i++)
{
var copyWang = JsonConvert.DeserializeObject<Person>(json);
}
watch.Stop();
Console.WriteLine(watch.ElapsedMilliseconds / 1000); // 11
Console.ReadLine();
}
}
class Person
{
public string Name { get; set; }
public int Age { get; set; }
public string Gender { get; set; }
public string Degree { get; set; }
public string Address { get; set; }
}
}
我的版本:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp2.2</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Newtonsoft.Json" Version="12.0.2" />
</ItemGroup>
</Project>
我还怀疑你们是不是有什么的地方比较耗cpu或者内存,是不是因为运行的时间久了把服务器的资源耗尽了,所以变慢了?
这是我们反序列化的代码(上面deserializeObject部分):
var sw = new System.Diagnostics.Stopwatch();
sw.Start();
var systemFuncMenus = JsonConvert.DeserializeObject<List<systemFuncMenu>>(jsonArrayText);
sw.Stop();
jsonArrayText的字符串比较大,有将近10k,开始启动我们也很快啊,但是运行了几个小时后,就出现上面说的反序列化要那么长时间,在系统慢的时候,我看cpu、内存、线程数都正常的,我从负载均衡移除了,cpu 0,内存500多M,线程数 80多,跟启动差不多,然后就在这台机测试,还是慢,每一个调试都慢。我们系统是To B的,很多接口返回的数据都比较大。
这是2019-8-8 11:10分,我从负载均衡移除了这台机,等了一段时间后,再在这台机内部调用上面那段代码的接口:
@Alan_Liu: 你有没有单独写一个demo?看问题能重现不,如果能说明类库有问题,如果不能说明其它的地方有问题。
@Alan_Liu: 如果实在不行,换一个其它库试试,又不是只有这一个
@会长: 嗯,我专门写个控制台,只执行上面那段代码试试
@会长: 好的,我现在不能100%确定是不是它的问题,还是我们使用有问题,但是反序列化是调用这个接口JsonConvert.DeserializeObject没错吧
@Alan_Liu: 应该没错,官网上的实例就是掉的这个了
是不是累计的json处理导致了gc的问题?我记得3.0 有dotnet-counters 和dotnet-dump工具可以用了,不知道2.2环境能用不。https://github.com/dotnet/diagnostics
好的,我研究一下
图裂 重新修改下
– winds_随风 5年前@winds_随风: 改了,可以吗
– Alan_Liu 5年前