关注了就能看到更多这么棒的文章哦~
Popcorn Linux pops up on linux-kernel
By Jonathan Corbet
May 5, 2020
原文来自:https://lwn.net/Articles/819237/
主译:DeepL
4月底的时候在kernel mailing list上看到了一个非常复杂的patch set,名为 "Popcorn Linux distribution thread execution"。Popcorn Linux(http://popcornlinux.org/)是一个2013年左右开始的学术项目,这也是它首次出现在内核mailing list上。这个项目的目标之一,就是将一组用网络密切连接起来的计算机变得看起来像单一系统——即一种NUMA机器,只是各个node间的通讯开销甚至比普通NUMA node间还要大。发出来的代码仅仅是这个大规模项目的一部分,主要实现了跨机器间进行进程迁移内存共享。这是一个有趣的演示版本,不过也别太高兴,目前的版本完全看不到合入kernel的希望。
Popcorn系统中的每个节点都是一个独立的Linux主机,通过网络连接起来。Popcorn本身启动时加载一个内核module,负责将这个大规模系统连接在一起。这个module直接从一个文件(默认情况下是/etc/popcorn/nodes)中读取出IP地址列表(仅限IPv4)。每台机器都会对这个文件中列在它自己前面的每个节点主动发起TCP连接,然后等待后面列出的每个节点的对自己发起的TCP连接。这样一来,每个节点都有一个整数ID来代表它自己,这个ID其实就是它在nodes文件中的位置。
代码里限制了最多可以有62个节点。对传入的TCP连接没有进行任何认证,这可能会有安全问题。事实上,patch set里面也专门提醒大家不要在连接到互联网的机器上运行Popcorn。代码里似乎没有任何关于增加、减少或者节点完全不存在情况的处理。patch set中的comment说,目前使用基于TCP的通信系统是"仅用于Popcorn的测试和开发目的",这说明今后会有人实现更合适的协议来进行替代。
System calls
不出意料,需要增加新的系统调用来让应用程序可以在大规模的Popcorn Linux系统中工作。首先,应用程序可以通过这个新的系统调用来查询可用节点集:
struct popcorn_node_info {
unsigned int status;
int arch;
int distance;
};
int popcorn_get_node_info(int *my_nid, struct popcorn_node_info *nodes, int len);
返回时,my_nid就包含了调用此API的进程目前正在运行的节点ID,而nodes则是一个以节点ID为索引的 popcorn_node_info结构的数组,其中将会包含有首len个节点的详细信息(当然,无论len怎么设置,最多只能是实际存在的节点数)。如果对应的节点是下线状态,每个条目中的status字段将为0,否则为1。arch字段描述了节点的体系架构(当前patch set中只有POPCORN_ARCH_X86,因为x86是目前唯一支持的架构),distance取值为0。
可以使用下面的系统调用来把当前线程迁移到另一个节点:
int popcorn_migrate(int node_id, void *uregs);
其中,node_id指出了线程应该被移动到哪个节点,而uregs是当线程在新节点上恢复运行时要预先设置好的CPU寄存器的值。专门传递处理器寄存器可能是为了Popcorn未来的一个功能(目前patch set还没有实现):可以将线程移动到具有不同处理器体系架构的远程节点。在发布的patch set中,线程只能自己主动迁移;但底层代码的实现方式可以看出今后也允许其他进程强迫此线程迁移。
虽然popcorn_migrate()看起来像是一个迁移线程的万能函数,但实际上,它有不少局限。被移动过的(也就是"remote")线程保留了与它的 "origin "节点的关联。事实上,原线程在原点上仍然存在,只是在remote线程运行的同时,origin节点上这个线程会被禁止执行。一个remote线程只能被移回origin节点,因此在两个远程节点之间迁移线程是要分两步来做:首先将其移回origin节点,然后再移到新节点。
线程的当前执行状态可以通过这个补丁集中的最后一个新增系统调用来获得:
struct popcorn_thread_status {
int current_nid;
int peer_nid;
pid_t peer_pid;
};
int popcorn_get_thread_status(struct popcorn_thread_status *status);
这个系统调用会在status里面填充好信息,包括calling thread的当前节点ID、它所关联的其他节点以及它在该节点上的PID。如果线程当前没有被迁移,那么current_nid和peer_nid都将是origin节点的ID。
Supporting remote threads
一旦某个线程被迁移到另一个节点,就必须做更多的同步工作。比如,在remote线程退出时,就必须让origin线程也退出。发送给origin线程的信号必须传递到实际工作正在进行的remote线程上。所有这些能够实现,都是靠拦截各种操作并通过节点间的TCP connection来发送消息,从而能让程序正常执行。还有一些特别复杂的代码,似乎主要是让futex能够跨机器仍然生效。
迁移一个线程虽然设置好了线程运行所需的基本信息,但还有很多工作要做。尤其是几乎所有线程的memory-layout信息都还在origin节点上,甚至很可能在与那里的其他线程共享。不出意料,Popcorn补丁集中一些非常复杂的代码,主要都是为了实现内存管理。
描述线程地址空间布局的这组virtual memory areas (VMAs)是与同一进程中运行的任何其他线程共享的。这些线程很可能还没有被迁移到同一节点。因此,虽然被迁移的线程需要能在remote端重建该VMA布局,但如果不与origin节点协调交互的话,它几乎完全无法改变VMA。对于VMA来说,所谓的协调工作,其实就是在origin节点执行几乎所有的VMA操作。
因此,如果迁移走的线程调用了mmap(),那么这个调用将被拦截并传递回origin节点执行。origin节点将发送执行结果给remote。然后,迁移走的线程的内存布局将被调整到相同设置。包括brk()和madvise()等其他调用也都会以同样的方式处理。
不过,实际内存中的各种page的处理方式则跟上面的方式不同,否则性能会受到严重影响。Popcorn实现了一个协议,允许page的ownership在节点之间移动,就像cache line的所有权可以在处理器之间传递一样。page的只读副本可以传递给多个节点,但在同一时刻只能有一个节点修改这同一个page。大部分协调工作同样都是由origin节点处理的,比如协调send和recieve各个page的副本、invalidate remote节点上的page、收回某个page页面的所有权等等。
patch set中还增加了一个新的madvise()操作MADV_RELEASE,它会明确释放remote节点对若干page的所有权。
Will it pop soon?
Popcorn Linux还有很多代码尚未发到mailing list中。比如说,有一种机制可以在同一台机器上运行多个内核,这是利用了修改过的kexec机制。Popcorn Linux中还有一个名为fault-tolerance project的项目正在开发过程中。还有一种机制可以将那些需求不高的虚拟机转移到速度较慢(但省电)的嵌入式开发板上,甚至可以是运行不同处理器架构的。还有更多其他功能。Popcorn Linux网站上有丰富的学术论文,对这些功能都有介绍。
Popcorn Linux似乎是一个有趣的项目,所以不熟悉内核开发工作原理的读者可能会惊讶地发现,虽然这组patch set在4月29日发布后在各种互联网网站上引起了大量的关注,但在邮件列表上却没有看到任何回应。原因其实很简单:发到mailing list上的是一堆代码,而没有按照规则来分割成适合人们认真review和思考的patch series。比如说,patch 1加入了新的系统调用,但它们所依赖的结构定义直到patch 5才出现。而作为整个功能基石的消息传递基础架构(messaging infrastructure)则是在最后的patch里面出现的。编者可以作证,以这种方式组织的patch set很难阅读,那些忙碌的内核开发者不太可能认真去review。
经常听到有人抱怨说,在学术环境中完成的工作几乎从来没有进入Linux。这似乎很矛盾,因为Linux所基于的开放式开发过程应该是天然适合学院里的开发者的。但是,这套patch set恰恰说明了这中间的问题在哪里。这个patch set代表了多年的工作结晶,但看起来没有花任何功夫来改善这组patch set从而让它能更适合合入mainline。
要想让这项工作有可能推到upstream,Popcorn Linux 开发者必须得做一些事情。要把这些patch重新制作一下,编程一个可分割多个patch(bisectable series,意思是说按顺序每个patch打上去都要能正常编译和运行),这样一来每个patch都是独立的,可以专注于考虑它本身是否有价值。现在使用的临时messaging system得换成证明过健壮性、安全性和性能的方案。必须准备好性能指标,同时也要证明Popcorn Linux对于没有使用它功能的场景是否会有影响。在内核开发中,文档确实一直很不受重视,但至少有几页介绍性的资料就能帮助开发者review patch。诸如此类的工作都会很有帮助。
这么多工作要做,甚至都还没有开始牵涉到reviwe过程中可能需要对代码进行的修改。这些工作都很耗时,却完全无法帮助发表论文。不难理解为什么学术研究着都对推送复杂代码到Linux upstream上的工作不感兴趣了。因此,这些工作很少有人真正去做,去做成。
可悲的是,这很可能也是 Popcorn Linux 的命运,除非有人能拿出资金和动力来把它适配到 (不那么学术性的)Linux 内核上。即使无法被合入,Popcorn Linux 也可能会激发出一些热情的开发者来采用它的一些好主意,并以某种其他形式将其推到upstream。在这个项目中可以找到很多有趣的工作。希望其中的一些工作最终能从学术环境中毕业,进入我们的日用系统中。
全文完
LWN文章遵循CC BY-SA 4.0许可协议。
欢迎分享、转载及基于现有协议再创作~
长按下面二维码关注,关注LWN深度文章以及开源社区的各种新近言论~