前言
也许大伙还有印象吧。前几个月,我曾经大张旗鼓地介绍了Garnet。《Garnet开发实战:准备好跟Redis说拜拜了吗?》
如果不记得,或者没看过的话,建议先回顾一下。因为很多概念和知识点,我都不会在这里“炒冷饭”。
开讲正题之前,我还是忍不住插播一则消息:我公司的项目已经成功把缓存中间键,从Redis和Memecached迁移到Garnet了!迁移的过程非常顺利,并且项目版本上线运行超过1个月相当稳定!我也算是业内比较敢于“吃螃蟹”的人了。
如果有时间,我会另外写一篇文章,来总结一下这个迁移的过程。但今天我准备探讨的是另外一个话题:假如将Garnet用NativeAOT来发布,能成功吗?
正题
首先我问了一下,搜索引擎。发现早在4月的时候,有人在Github上讨论过,甚至还有人实践过了,并没得到让我欣喜的答案!
最终,我决定亲自尝试一下,看看几个月过去了Garnet有没有悄悄地给我们惊喜。
1、升级Garnet
首先,将Garnet升级到最新版本(1.0.19)。
<PackageReference Include="Microsoft.Garnet" Version="1.0.19" />
2、项目启用NativeAOT
修改一下原来的工程配置文件(*.csproj),增加PublishAot
配置节点。参考如下:
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<PublishAot>true</PublishAot>
</PropertyGroup>
3、编译发布
执行发布命令:
dotnet publish GarnetServer.csproj -o $PWD/build -c Release -r osx-x64
4、执行
编译发布后,得到一个大小30M左右的可执行文件。
迫不及待,执行一下。
./GarnetServer
结果,奇迹并未出现。报错了,而且还是一个非常经典报错提示: Object reference not set to an instance of an object。
仔细看编译发布的log,从一堆warning消息,可以初步判断,似乎是Garnet以及其所依赖的库并不支持NativeAOT的编译裁剪,导致生成的执行文件运行报错。
总结
我暂时没有解决问题的思路和线索,只能到此为止。直接宣布:当NativeAOT遇到Garnet,得到的结果会是“Object reference not set to an instance of an object”。
NativeAOT对编译代码是有要求的,在JIT上能够变异运行的代码不能保证100%能AOT化。其中一个很大的限制来源于:.NET 的动态功能不可用(例如,动态实例化类型、使用 C# dynamic 关键字、或动态加载代码等)而动态化是当今C#主流写法,最大的矛盾点在此。
不像golang或Rust,它们本就是面向静态编译而生的,因此编译成Native应用易如反掌。
希望微软继续努力,如果把Garnet的NativeAOT补上,那就真的非常完美了!同样,这也是一件任重道远的事情。