使用Medes实现serverless计算的内存重复数据删除
主要贡献
当今的serverless平台在资源使用和用户感知的性能之间进行了严格的权衡。通过在热状态和冷状态之间切换沙箱以及保持活动状态提供的有限控制,迫使操作员牺牲大量资源来实现良好的性能。我们提出了一个serverless的框架Medes,它打破了僵化的权衡,允许运营商平滑地导航权衡空间。
Medes利用了这样一个事实,即在serverless平台上运行的温沙箱在其内存占用中具有很高的重复比例。我们利用这些冗余区块来开发一种新的沙箱状态,称为重复数据删除状态,它比热状态更节省内存,比冷状态恢复速度更快。我们开发了新颖的机制,以最小的开销识别内存冗余,同时确保重复数据删除容器的内存占用量很小。最后,我们开发了一个简单的沙箱管理策略,该策略为操作员提供了一个狭窄、直观的界面,以便通过联合控制热沙箱和重复数据删除沙箱来权衡性能和内存。
背景介绍
如今的serverless平台通过在两种状态之间切换沙箱来管理性能和效率:冷和热(或暂停)。
- “冷”沙箱不使用任何存储器资源,但是由于在沙箱中可以执行函数实例之前需要初始化和加载函数的执行环境,所以导致长时间的冷启动延迟(这可能是秒的数量级,取决于平台和运行时)。
- “热”或暂停的沙箱在函数执行完成后会在内存中保留一段时间(保持活动),从而消耗大量内存。它们支持沙箱重用-在保持活动过期之前到达的后续函数调用在这些沙箱上运行,经历“热启动”所用时间明显更短(根据运行时间从1ms到20ms不等)。
热沙箱占用了明显重复的内存,具体来说:
- 沙箱相同的函数可以有高达85%的重复记忆状态
- 即使在沙箱的不同的功能,也有高达80 - 90%重复
大致做法
通过引入一种新的沙箱状态来改善目前的权衡空间,这种沙箱状态的内存占用和启动性能介于冷状态和热状态之间。第三种状态是建立在将“可重用沙箱”结构扩展到可重用沙箱块(RSC,reusable sandbox chunk)的基础上的。
新沙箱状态叫做删除处理状态(简称dedup 2 state)。在这种状态下,所有的冗余内存块的沙箱被“删除”,留下“独特”的块存储在内存中。具体而言:
- 在”基础”沙箱中仅存储RSC的一个副本,并且处于dedup状态沙箱的内存中包含作为多个远程基础沙箱中的本地完全唯一块和冗余RSC;
- 在启动功能之前,通过将唯一的本地块与通过网络从远程基础沙箱读取的冗余RSC放在一起来恢复处于dedup状态的沙箱。
Medes (Memory Deduplication for Serverless),利用一种新颖的重复数据删除机制,可以识别潜在的相似块记忆的跨集群沙箱。因为集群中沙箱数量可能会很多,并且每个沙箱所占用的内存都可能包含巨大数量的页,因此Medes使用了三个技术:
- 首先,为了确保扩展和降低重复数据删除的计算成本,虽然我们在块级识别冗余(因为它是最有效的),但我们在页粒度上执行重复数据删除:对于dedup沙箱的每个页面,Medes识别集群上的类似(基础)内存页,并计算与之相关的 “补丁”。
- 其次,为了进一步提高扩展性,我们通过划定某些沙箱为基础沙箱,只使用这些基础沙箱的内存页作为计算补丁的参考,来限制需要跟踪的基础页数量。
- 第三,利用value-sampled fingerprints[9]来降低冗余识别的计算和存储成本–这导致了整体上比冷启动更快的函数启动时间,从而承诺更好的函数性能。
Medes还允许serverless平台运营商通过一种新颖的沙箱管理策略轻松控制内存-性能权衡并导航权衡空间。
测试场景
内存冗余情况:
ASLR(address space layout randomization, 地址空间布局随机化)
具体做法
Medes由一个控制器和几个节点组成。架构如下:
控制器有四个主要部分:
- 与客户的接口,通过该接口提交功能请求,并检索结果;
- 调度器,跟踪整个系统的状态(例如,每个节点上的资源使用情况以及温暖和重复数据删除沙箱),产生一个新的沙箱或分配一个现有的沙箱来服务一个传入的请求,并决定是否将已经完成的沙箱过渡到warm或dedup状态;
- 指纹注册表,它是一个哈希表,包含RSC的哈希值和它们在集群中的相应位置,用于重复数据删除;
- 策略模块,存储策略参数,如延迟和内存限制。
节点包括两个部分:
- daemon 守护进程,其根据控制器的指令操纵本地沙箱,并更新节点状态的控制器;
- dedup agent 负责删除重复数据,并且负责从dedup状态恢复;
基本工作流
- 客户端通过RPC给控制器发送请求;
- 调度器选择一个可用的节点中的warm或者dedup状态的沙箱,并且发送请求给该节点中的daemon,如果不存在一个可用的则创建一个新的容器。如果选中一个dedup的沙箱则通过恢复(restore)操作来唤醒。
- 当function结束后,沙箱变为warm状态,然后控制器可以决定将沙箱是否把沙箱转为dedup状态;
Dedup和Restore操作
Dedup操作将一个warm状态的沙箱转为dedup状态的沙箱,大致分为冗余识别和冗余消除两步:
- 冗余识别:粒度为一个内存块64B。首先把容器内存状态保存为一个检查点,然后给集群的控制器去查重,并且以RSC的形式返回给agent。
- 冗余消除:粒度为一个页4KB。收到从控制器返回的所有RSC信息后,agent会读取每一个RSC的信息并且把RSC的物理地址与占用大小的作为一个补丁(patch)替换原内存。
Restore操作将一个处于dedup状态的沙箱转为warm状态的沙箱。这个操作读取那些补丁的内存页重建原始内存页,并且保存为存档点,最后通过存档点转为warm状态。
一些关键技术
- Page Fingerprints:页面指纹,相当于提取内存页面的特征,通过几种不同的方法来计算哈希值,一个页面4KB,每64B内存块计算一个哈希值指纹,然后对比一页中指纹相同的个数可以知道两页之间的相似度。
- Base Page:基页,在指纹注册中心查重的时候找到页相似度最高的页,从而在后续dedup的时候能替换最多的内存块从而节省最多的内存。
- Base Sandbox:基础沙箱,用于向指纹注册中心注册内存块,因为运行两个相同函数的容器之间重复的内存是相同的,所以我们基于一个阈值T来选择基础沙箱,对于运行函数a的所有容器,假设处于dedup状态的容器的数量为D,是基础沙箱的容器的数量为B,如果 D/B > T 的话就增加一个基础沙箱。
实现结果
不同策略对比
冷启动次数与端到端的延迟
占用的内存大小与冷启动次数
对比冷启动的时间
内存占用的节省
总结与个人理解
Medes就是在沙箱warm和cold两种状态中加了一种中间态dedup,这样可以减少冷启动的次数并且节省空间。实现方式类似于指针,把重复的内存替换为指针,这样在恢复的时候可以直接用RDMA访问重复的内存以节省内存。
用unikernel实现的不同或相同的函数在内存中也会包含很多相同的库或者数据,因此感觉也可以使用这种方法来节省内存。