云原生与AI漫谈
写完上次的 MLOps 主题文章后,接下来计划写一篇机器学习与云原生结合的文章。不过个人在这块的经验并不多,还在各种学习和素材积累中。今天先来闲聊一些最近一阵子对云原生这个火热话题的一些发散性遐想。
云原生的定义
对于云原生的标准定义,可以参考 CNCF 列举的四点:
微服务 容器化 DevOps 持续交付
关于这块内容,已经有很多书籍和文章来介绍了,我就不班门弄斧了。主要结合自己对云原生的认识,来聊聊一些开脑洞的想法。
云原生时代的应用开发
在跟算法工程师们一起工作时,经常会吐槽很多同学好像计算机基础比较一般,对于代码的内存开销,计算复杂度等没有多少概念。更不用说我们早年做性能优化时,还需要考虑程序是不是符合 CPU 的流水线架构,是不是 cache friendly,怎么消除 false sharing 等等……
但最近突然有个想法,那就是到了云原生时代,程序员可能都不需要再了解 CPU,内存,硬盘这些概念了。取而代之的是只需要了解自己的业务特性需求,以及提供不同需求的云计算价格即可。
例如我们做数据处理,按照现在的开发逻辑,我们可能需要了解数据量的大小,计算时间的要求,然后来评估我们可能需要用什么样的算法和数据结构,需要申请多少 CPU 和内存的虚拟机/容器。而在未来,大家只需要知道我需要对 1 亿条数据进行计算,如果希望 1 分钟内算完,可能需要多少钱,如果可以放宽到 1 小时,那么价格可以降低到多少。
关注点分离
这个想法其实跟关注点分离的思想很像,这样可以让应用开发人员专注在业务逻辑,成本和业务价值回报等方面,不再需要分精力去了解计算存储的细节,以及各种基础设施结构,运维方面的考量。
就好比我们只需要知道我们要从 A 地到 B 地,需要在多少时间内到达即可,其它的交给“云”来打理即可。希望云平台能帮我们选择,如果是高峰期,还需要很短时间到达,就给我们派架直升机,如果是半夜,可能普通出租车就可以了。
对新编程范式的需求
如果按这个方向发展,那么我们需要一种新的编程范式,跟从命令式到声明式编程类似,我们这里需要一种新的“云原生声明语言”。可能会长这样:
def my_logic(data):
ret = do_some_job(data)
return ret
function: my_logic
performance: 60s
availability: region
consistency: soft
因为是遐想,所以代码也是有点乱来。大致分两部分,一块是你要做的操作逻辑定义,另一块是各种计算属性的声明,包括希望响应性能如何,可用性希望达到数据中心 level,还是 region level,一致性需要多强等等。对于这个代码的执行方式,则通过“云原生编译器”去进行编排,到底是跑在单容器上,还是利用 serverless,还是需要用 Spark/Flink 等引擎,开发者都不需要 care。怎么做高可用,性能优化,弹性扩缩容,也都不需要管。想想就很美好吧?
对新操作系统的需求
这类程序如何跑起来,除了前面假想的编译器,我们还需要运行时,操作系统等。其实从上面的伪代码可以看出,这个操作系统很可能就是现在火热的 k8s,而运行时嘛可能是 CRD 基础上封装的一个中间层,可以将一些原语转化为分布式的计算和存储过程,比如批流处理走 Flink,数据的 mutation 和持久化走 cloud DB……
云原生时代的系统开发
对于系统开发人员来说(比如云数据库,云 AI 平台),云原生的趋势也会产生相应的影响。
Trade-off 的变化
对系统开发者来说,架构上的思考会从原先的固定计算池的 trade-off(比如空间换时间),转变成云服务 cost 的 trade-off(用钱换性能)。
例如经典的 MySQL 索引优化,大家为了加快读的性能,会构建索引,而过多的索引,一方面会增加存储开销,另一方面会增加写入时的计算开销,因此经常需要有经验的 DBA 来进行各种权衡优化。这是非常典型的资源池思想,假定我们的 CPU,内存,磁盘是相对固定的一个值。
但是到了云原生时代,我们可以完全打破这个固有框架,我们拥有的计算,存储都可以理解为是“无限”的,只要有钱就可以!例如为了读取速度够快,我干脆对所有的数据做索引,这样可能需要更多的存储成本(x 元);为了在写入时的性能不受影响,我在写入时利用一些弹性扩展的计算资源做超大规模的并行计算(又多花了 y 元)。但只要低延迟的读取,例如全量索引的 DB 能让业务的大量读取请求变得飞快,从原先的频繁全表扫描到现在的命中索引,计算资源可以减少 n 元,最终达到 n > x + y 的情况,那么这个设计就是合理有效的。
上面这个例子不全是我异想天开,而是有真实的案例[1]支持哦。
软硬一体化
另外一个想象空间是在云原生时代,越来越多的云计算都是以服务化的产品形式提供出来,而不再像以前那样是用户单独购买虚拟机,再部署自己的应用。这就给软硬件的联合优化打开了一扇大门。
当用户采购通用计算设备时,往往需要考虑各种硬件架构,指令集,上层的操作系统,运行环境等各个层面的通用化,所以导致很多针对性的优化无法开展。但如果用户采购的是一种专门解决某个问题的云服务,那么只要提供的接口是相对标准化的,内部的软硬件栈都可以由系统开发者来自行选择和优化。
举几个简单的例子,比如大家现在常用的 s3 存储,其实我们都不知道 AWS 在底层具体用了什么样的软件或者硬件,我们只关心它能提供稳定可靠的存储服务即可。因此 AWS 如果在底层做了很复杂的软硬件优化,使得 s3 的存储成本低于 Azure, GCP,那么就会有很大的竞争优势。最近还看了个 TinyML 的软硬件一体优化,能够在非常有限的 FPGA 硬件资源上跑复杂的 CV 模型,感觉这里面的机会和想象空间着实巨大!
多租户
沿着上面云服务产品化的思路,多租户也将变成一种趋势。在多租户的情况下,也会诞生出很多新的挑战和机会。例如如何去安排多租户的具体计算调度,存储形式,来降低系统整体的资源开销;通过多租户不同 workload 数据的积累,构建一些智能模型来做系统层面的优化;甚至在用户许可的情况下,我们可以做一些类似联邦学习的手段来构建一些领域模型,优化所有用户的使用体验等等。
具体的例子比如我们可以通过用户的数据查询看到经常使用的过滤维度,来重新安排数据的排序和分区,这样在同样的数据量情况下,系统可以花更少的计算资源来完成查询,增加系统的利润 :)
云原生+AI
最后再来看下跟 AI 相关的部分。Andrej 之前提出了 Software 2.0 的概念,对应到我们上面的图景主要是针对应用开发层面,从原先的过程式编程,转变向以数据和优化目标驱动的声明式编程。在数据智能越来越重要的今天,这个趋势在不断改变我们开发应用的方式,包括出现了很多交互式开发,可视化,data-centric,low-code/no-code 等形式。而前面讲的“云原生语言”,则更关注在程序具体执行层面的关注点分离。
把两者结合起来看,云原生时代的 AI 平台开发会是一片巨大的未开垦之地,对于云和算法各自都有很宽很长的路可以走。举几个随便想到的例子:
在计算资源“无限”的前提下,设计灵活的 ML 执行框架。我可以用 1 台机器训练 100 小时或 100 台机器训练 1 小时达到相同的结果。 AutoML cost 成本优化,在不改变算法效率的前提下,或许我们可以通过大规模利用 spot instance 的低计算成本来承载 autoML 的搜索计算,在某些场景上或许能实现一些正收益。而且 autoML 的优化目标,也可以不仅仅是 accuracy,而可以同时考虑各种 cost。 Cloud 与边缘计算结合的应用,比如在云端跑 teacher model,客户端跑 student model,实现持续的模型更新与端上运算的低资源开销。 在应用开发方面,我们可以利用云原生的计算弹性,实现更好的无缝开发体验。例如在做原型开发时,可以利用本地硬件做小数据量的调试。而当 pipeline 跑通之后,又可以灵活切换到使用云端算力,进行全量数据的实验与后续的发布上线。 云原生编译这块,也可以充分考虑机器学习类任务的特性,比如异构硬件,MPI 计算框架,pipeline 模式等,实现软硬一体优化,让算法任务能更好的在云操作系统上来执行。 算法的各类优化,反过来也可以应用于系统本身的优化。比如经典的通过机器学习来优化 DB 索引的构建。通过算法来做自动的代码优化[2]等。 多租户情况下的联邦学习,多任务/元学习的可能性。
目前云原生跟 AI 结合的一个比较好的学习样例是 Kubeflow,之前春节期间读了一本《Kubeflow for Machine Learning[3]》,感觉收获还是挺多的,如Istio,CRD的应用等。
总体来说,这块我的思考还非常有限,接下来会持续关注和学习,再与大家做更系统性的分享。也欢迎对这方面有兴趣有经验的同学来一起交流探讨,需要给位大佬的多多指导。
参考资料
真实的案例: https://rockset.com/blog/space-time-tradeoff-and-your-snowflake-compute-cost/
[2]自动的代码优化: https://proceedings.mlsys.org/paper/2021/hash/3def184ad8f4755ff269862ea77393dd-Abstract.html
[3]Kubeflow for Machine Learning: https://book.douban.com/subject/35054012/