最近将自己负责的一个核心接口系统从. Net Framework 迁移到了. Net Core.
整体过程, 从业务层面说一般般吧 (整体还好但还是搞的业务有感, 没出严重故障) 但是技术层面上感觉其实并没有达到要求, 不过预期也是应该不会那么顺利, 接下来可能还需要几个小 Fix 来处理各种奇奇怪怪的问题.
回顾下迁移时候遇到的若干个坑, 希望对后续有此类操作的人所有帮助.
1.NetCore 下的路由行为和 web API 的不一致
我们回顾下在 Web API 里时候的一个路由定义
这个配置下可以让
Get RootUrl/123 和 Get 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 种
1强制在方法参数的 id 里加上 [FromQuery], 但是这个会有个咖喱是 Swagger 生成的文档里会有 2 个 Id 字段(Path 里有一个, 你强制了 Query 里有一个) 但是接口能正常工作;
2将 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 让连接不上的时候也继续跑着先吧
进行中的解决方案
根据
试着将代码内频繁查询的 Redis 读取转 Async 试试.
4.NetCore 下的 Http 请求不稳定(时而报 SocketException)
到 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 里但是都没发生这个问题), 有概率跟请求压力有关系.
目前的临时解决方案
参考官方文档 先将 core2.1 引入的 SocketHttpHandler 禁用了
可以直接 Powershell 执行
- [sourcecode language='powershell' padlinenumbers='true']
- [environment]::SetEnvironmentvariable("DOTNET_SYSTEM_NET_HTTP_USESOCKETSHTTPHANDLER", "false", "Machine")
- [/sourcecode]
但是现在也是零星会偶尔冒一下出来(感觉并没有什么卵用)
进行中的解决方案
基于 HttpClientFactory 构造 HttpClient 外加 Polly 如果失败就再来一次的模式.
5. 迷之超时
现在发觉有一部分机器会有超时的现象, 而这个现象比较诡异在于 IIS 日志里是有记录到这次请求的(超时的请求), 而作为我们站点监控的 Application Insights 是没收到这个请求的
暂时想法是不是因为现在 IIS 只是一个 Reverse Proxy 的角色, 而 IIS 到达真正承载站点的 kestrel 的时候这个过程有问题
因为我们当前是基于 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 下是没什么卵用的, 参考
来源: https://www.cnblogs.com/leolaw/p/10740678.html