• 欢迎访问web前端中文站,JavaScript,CSS3,HTML5,web前端demo
  • 如果您觉得本站非常有看点,那么赶紧使用Ctrl+D 收藏web前端中文站吧

.NET Core 迁移躺坑记

JavaScript web前端中文站 5个月前 (04-21) 172次浏览 已收录 0个评论

最近将自己负责的一个核心接口系统从.Net Framework 迁移到了.Net Core。

更多精彩内容请看 web 前端中文站
http://www.lisa33xiaoq.net 可按 Ctrl + D 进行收藏

整体过程,从业务层面说一般般吧(整体还好但还是搞的业务有感,没出严重故障)但是技术层面上感觉其实并没有达到要求,不过预期也是应该不会那么顺利,接下来可能还需要几个小 Fix 来处理各种奇奇怪怪的问题。

回顾下迁移时候遇到的若干个坑,希望对后续有此类操作的人所有帮助。

 

1.NetCore 下的路由行为和 Web Api 的不一致

我们回顾下在 Web Api 里时候的一个路由定义

.NET Core 迁移躺坑记

这个配置下可以让

Get RootUrl/123Get RootUrl?id=123 同时映射到 GetThirdPartyChannel 方法里。

但是,假如在不做改动前提下直接将这个 Controller 定义变为 Core 的话,Get RootUrl?id=123 这个路由将无法正常运作 (而 Get RootUrl/123 则依然可以正常运行)。

原因是在 AspNetCore 下他发现了[Route(“{Id}”)]就会认为 Id 是 Path 的一部分,然后相当于隐式给 id 这个参数默认了[FromPath],但是[Route(“”)]这里并没有定义 id 作为 Path。

会导致一旦调用 Get RootUrl?id=123 的时候,首先路由是能匹配上 [Route(“”)]的,但是参数里的 id 恒定是空(即代码里获取到的 id 字段永远是 null)。

 

解决方案有 2 种

①强制在方法参数的 id 里加上[FromQuery],但是这个会有个咖喱是 Swagger 生成的文档里会有 2 个 Id 字段(Path 里有一个,你强制了 Query 里有一个)但是接口能正常工作;

②将 2 个路由拆开来分别对应 2 个方法。

 

总结:

按照我们组内规范,定义 Url 是不能放 Path 的,这些都是一些早期设计的,没有遵照规范将其替换完一直遗留着,规范不严格,代码两行泪。

 

2.NetCore 下加载程序集的时候会识别版本号

我们有使用到部分的类库会依赖动态程序集加载,目前有:

Hangfire 用于实现 Fire-and-Forgot 模式异步执行以及延迟任务;

Protobuf-net 用于存储到 Redis 的时候转 Protobuf 更快更小。

 

这类程序集有个特点是他要将你要执行的东西序列化为某种类型(我不管 json 还是二进制的信息),然后需要时候在加载程序集。

而他们序列化的时候对程序集的处理统统都是用了 Type.AssemblyQualifiedName 方法,改方法可能会产生类似“ClassLibrary1.Class1, ClassLibrary1, Version=1.2.0.0, Culture=neutral, PublicKeyToken=null”的字符串。

而我们自己在 CI 的时候有一个机制是,每次 TFS 编译的时候会自动修改 dll 的版本号,具体可以参考以前写的文章 Azure Devops/Tfs 编译的时候自动修改版本号

以前.Net Framework 加载一个程序集的时候,比如程序集的信息是 “ClassLibrary1.Class1, ClassLibrary1, Version=1.2.0.0, Culture=neutral, PublicKeyToken=null”   其中的 Version 的值他是不认的,随便 Version 是什么他都能加载(咱不讨论 StrongName 模式)

而到 Core 之后如果 Version 不匹配,则会报错(他会认可 Version 的值了)

 

解决方案:

暂时去掉了自动修改版本号机制,固定版本号到某个值。

 

3.NetCore 下的 Redis 有点诡异(不稳定)

具体体现在好像迁移到 Core 之后连接 Redis 的链接更不稳定了,无论是链接超时还是首次建立链接的成功率都显著下降。

也是因为这个问题导致这次发布闹出了不该有的动静。

发布那会的临时解决方案:

Redis 的链接字符串加了,abortConnect=false 让连接不上的时候也继续跑着先吧

进行中的解决方案

根据 https://stackoverflow.com/questions/42956377/stackexchange-redis-timeout-exception-in-net-core

试着将代码内频繁查询的 Redis 读取转 Async 试试。

 

4.NetCore 下的 Http 请求不稳定(时而报 SocketException)

到 Core 之后我们的未知知识库里又新增了一个全新异常模式

.NET Core 迁移躺坑记

这个异常看起来像如下几个地址里提到的情况

https://github.com/dotnet/corefx/issues/30691 

https://github.com/dotnet/corefx/pull/32903 

https://github.com/dotnet/corefx/issues/32902

但是要说 3.0 才 fix,等不了那么久……

 

另外已知在小访问量下好像不容易出现这个(我们之前已经有几个小站点已经是 core 里但是都没发生这个问题),有概率跟请求压力有关系。

 

目前的临时解决方案

参考官方文档 https://docs.microsoft.com/en-us/dotnet/api/system.net.http.socketshttphandler?view=netcore-2.2 先将 core2.1 引入的 SocketHttpHandler 禁用了

可以直接 Powershell 执行

[environment]::SetEnvironmentvariable("DOTNET_SYSTEM_NET_HTTP_USESOCKETSHTTPHANDLER", "false", "Machine")    

但是现在也是零星会偶尔冒一下出来(感觉并没有什么卵用)

进行中的解决方案

基于 HttpClientFactory 构造 HttpClient 外加 Polly 如果失败就再来一次的模式。

 

5.迷之超时

现在发觉有一部分机器会有超时的现象,而这个现象比较诡异在于 IIS 日志里是有记录到这次请求的(超时的请求),而作为我们站点监控的 Application Insights 是没收到这个请求的

暂时想法是不是因为现在 IIS 只是一个 Reverse Proxy 的角色,而 IIS 到达真正承载站点的 kestrel 的时候这个过程有问题

.NET Core 迁移躺坑记

 

因为我们当前是基于 Net Core 2.1(因为是 LTS),并没有 2.2 所引入的进程内托管这种模式,这个问题目前还在定位中

 

另外有人建议(包括网上寻找资料得到的信息)是 IIS 里调整下

Start Mode 改为 Always Runing

Idel Time-out Action 改为 Suspend

但是这都是 Win 2012 才引入的功能,而我们家是 08R2,两行泪的羡慕隔壁好多家都是 2016 的!

 

临时解决方案:

看到超时的机器就下掉

而且发现这个超时现象主要集中在某几个服务器上

之后在看看系列的解决方案

后面转 Linux 后的话直接 kestrel 硬扛,IIS 一边去

 

最后

好像在.Net Framework 里经常推崇的在异步方法里加ConfigureAwaiter(false)在.Net Core 下是没什么卵用的,参考

http://blog.stephencleary.com/2017/03/aspnetcore-synchronization-context.html

【注:本文源自网络文章资源,由站长整理发布】


web 前端中文站 , 版权所有丨如未注明 , 均为原创丨本网站采用BY-NC-SA协议进行授权
转载请注明原文链接:.NET Core 迁移躺坑记
喜欢 (0)
发表我的评论
取消评论
表情 贴图 加粗 删除线 居中 斜体 签到

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址