背景
现有SSD特点
优点:读/写速度越来越快
缺点:内部的逻辑越发复杂,导致延迟高。(GC、buffer flush、wearing leveling、read repair等导致了延迟高,都是FTL的一些模块)
三种处理SSD不可预测性延迟的方法
白盒
- 方法:重构device内部代码。
- 结果:不能掩饰SSD的不可预测性。
- 影响:很难修改底层,同时开销很大(除非供应商支持这种操作)。
灰盒
- 方法:将部分设备级别的修改与OS或应用程序级别的更改结合起来。
- 结果:缓解了SSD延迟的不可预测性
- 影响:很难修改底层,同时开销很大(除非供应商支持这种操作)。
黑盒:
- 方法:不修改底层硬件及其抽象级别。
- 结果:掩饰SSD的不可预测性。
- 影响:不修改底层硬件,开销小。
现状
延迟不可预测:(本文考虑的是read latency,因为write latency由于内部存在buffer flush,只有buffer full的时候才会影响write latency,所以write latency比较稳定)
左图(a):
- Model A:长尾延迟在P98。
- Model B:长尾延迟在P90。
- Model C:长尾延迟在P75。
右图(b):
- 因为write latency由于内部存在buffer flush,只有buffer full的时候才会影响write latency,所以write latency比较稳定。
- read latency会受到write latency的影响,因此变得不可预测。
内部复杂性:
- 内部复杂性会影响延迟,因此很难推断出闪存驱动器何时出现长尾延迟。例如如果I / O落入同一芯片或通道,则它们相互竞争,这取决于隐藏的条带化和分区逻辑。由于write buffer操作并定时刷新,在内部争用资源时会影响1%-25%的read操作。
- 内部执行“wait-then-speculate”操作,当处理IO超过了P95,则会发一个额外的相同I/O给其他device,来快速相应。这种方法对粗粒度的任务(几十到几百秒)效果很好,但是对于闪存存储却没有效果,因为当预期的响应时间少于几毫秒时,等待的代价很高。
机器学习方法:
- 利用机器学习的可预测性,LinnOS想将不可预测的latency变成可以预测的latency,将latency进行分类,分成fast/slow在进行处理。
挑战(准确率和性能不能兼得,只能trade off)
- 准确率高
- 快速推断(性能好)
- 异质性(不同的device会有所不同,因此inference point value应该在不同的device有所不同,所以应该以device为单位训练单独的light neural network,但是存在的问题就是每个device维护一个模型会不会对CPU性能产生影响)
LinnOS
那么现在引出这篇文章的主要贡献和一个整体的架构。(架构如下图figure 3所示)
主要包含五个组件:
- 模型:轻量级的神经网络,轻量级体现在尽可能的减少feature的个数,只选择重要的feature,而把无关或者是对预测延迟关系不大的feature删除。输出主要是一个二分类(fast/slow)。
- 抓取数据集(tracing):主要是使用blktrace抓取不同device的负载,其中抓取到的内容包括(时间戳,write/read,block offset,block size,IO操作等)。应该保证训练数据集和测试数据集不重合,因为重合会影响效果的对比,因为模型因为是根据训练数据集得到的,测试集中包含部分训练数据,模型预测这部分数据对应的accuracy会很高,不符合随机性。
- Labeling with inflection point analysis:使用inflection point作为阈值对数据进行打标,低于infection point的部分label为fast,高于inflection point的部分label为slow。(LinApp实现了一个确定inflection point的算法来区分fast/slow)。
- 训练(training):给每条数据打好label(fast/slow)之后需要做的工作就是根据features + label进行监督学习训练模型了。应该保证模型符合通用型可以运行在不同的协处理器上(CPU、GPU、TPU等)。(本文使用了tensorflow,但是个人感觉使用tensorflow对底层CPU处理IO性能会影响很大)
- 上传权重:上传权重的主要目的就是支持在线预测,只有不断的加载、更新、保存权重才可以重现模型,直接通过O(1)的时间复杂度实现模型的直接预测。
使用场景
主要分为以下几个步骤(如figure 2所示):
- 当存储应用通过系统调用处理一个I/O请求的时候,LinnOS会增加1 bit的flag(latency-critical(LC) = false/true)。
- 在将I/O提交给底层SSD时,会先将I/O信息输入到训练好的神经网络模型中,然后会得到一个结果(fast/slow)。
- 如果得到的结果是fast,就直接将I/O提交给device。
- 如果得到的结果是slow,就revoke I/O,并返回“slow”的错误码。
- application接收到错误码之后,就会发送一个相同的I/O给另一个replica。
- 最差的情况是遍历到最后一个replica,但是最后这个replica返回的retry将不设置LC,主要是为了让最后这个replica被处理并不被继续的revoke。
LinnOS设计:
- 训练数据的收集:当然真实数据量越多,在训练模型时对应的模型准确率会更高,但是训练的数据越多占用的CPU资源会越多。考虑到现代ssd能够提供的低开销跟踪工具和数百kiop的工作负载,因此抓取数据本身难度不大。使用blktrace抓取busy时的IO负载信息。因为busy时的IO数据可以很好的代表其他时间,即inflection point没有太大偏离。
- Labeling(打标):无非就是对每一条抓取的IO数据标记fast还是slow,因为light neural network本身是监督模型,需要有label去训练,用于标记预测时是不是实际预测值和实际值相同,如果不相同会进行误差回传,更新模型中的权重值。
- Inflection Point算法设计:将t个不同的负载分别运行在不同的SSD设备上。为了找到对对应的optimal Inflection Point value。(由于设备的异质性,每个SSD都要训练得到不同的最佳值)获取和更新该值的步骤:
- 随机找一个包含想要数据的replica对应的SSD,然后运行负载模拟。
- 假设延迟在SSD之间是独立的。
- 更新Inflection Point value的步骤是:the current IO request:
- 1)找到斜率是45度的点a,a.x就是Inflection Point value。
- 2)当current latency < a.x时,.latency = current latency;当current latency > a.x时,撤销的同时将相同的IO request随机故障转移到包含相同的replica的node上。
- 3)分别计算原始的和新的latency围成的CDF面积,比较面积之间的差异。
- 4)当初始的Inflection point value在+/-10%范围内波动时移动+/-0.1%。然后重复执行1),2),3)。
- 找到optimal Inflection Point value用作模型区分slow/fast的阈值。
- 轻量级的神经网络模型
- 输入的feature(尽可能减少不必要的input feature,从而较少训练开销)
- 1)即将到来的I/O到达时挂起的还未被处理的I/O数。
- 2)R个最近完成的I/O的延迟,我们将R设置为4。
- 3)每个R个完成的I/O到达时挂起的I/O的数量。
- 将输入feature格式化:
- 挂起的I/O数量:用3位十进制数值表示,比如:15 {0, 1, 5}
- I/O延迟:用4位十进制数值表示,比如:240 {0, 2, 4, 0} 9999 {9, 9, 9, 9}
- 所以模型得到31个feature。(31 = 3 + 4 * 4 + 3 * 4) 对应输入的feature顺序1), 2), 3)。
- 神经网络模型(accuracy 和 performance 折衷)
- 全连接
- 三层(因为为了减少训练开销,因此本文仅仅使用三层神经网络,1) 输入层:(31, ); 2) 隐藏层:(256, ReLU); 3) 输出层:(2, argmax))
- 所有的神经单元都是线性回归计算()
- 分为两个模块:离线部分用于训练,在线部分用于实时预测。
- 输入的feature(尽可能减少不必要的input feature,从而较少训练开销)
- 提高准确性(下图所示)
- 尽可能减少false submit,因为这样会增大延迟;false revoke是可以容忍的,也就是说尽可能多判断为slow也没关系,因为revoke并failover产生的开销会比submit到SSD上排队产生的latency小。
- 模型要定时的retraining和retracing。
- Inaccuracy masking。主要的方法就是尽可能的规避false submit带来的影响,通过machine learning + hedging尽可能提高准确率,减少延迟。如果6%的false sumbit,那么设置hedging为 P94,如果小于等于5%的false submit,那么就设置hedging为95%,虽然此时会因为revoking 产生额外的IO但是还是可以进一步提高性能,减少latency。
- 提高推断时间:
- 浮点权重变为3位的十进制整型。准确率损失0.1%左右。
- 协处理器:
- 使用更先进的硬件(GPU、TPU) 的推测延迟提升。
- 可以使用协处理器,通过使用一个额外的CPU内核进行2线程优化矩阵乘法,将平均推理时间从6μs减少到4μs。