Caladan: Mitigating Interference at Microsecond Timescales
1 场景
交互式、数据密集型Web服务 —— 可变负载。在真实场景,资源使用以及干扰频繁变化的情况下,隔离分区式的解决方案存在低CPU利用率(负载低)和长尾时延(负载高)的问题。即便有些方案增加了CPU资源流动的设计,但是从负载变化到资源流动收敛,需要毫秒级甚至是秒级的时间,无法应对短时的负载突变。
2 技术概述
基于调度时延、内存带宽、LLC未命中率等指标,实现上层任务的调度,以及CPU的流动,保持高CPU利用率和严格的性能隔离(吞吐量和尾时延)。 从负载突变到CPU流动收敛可以达到微妙级别。
1、微妙级的性能指标监控(调度时延、内存带宽、LLC未命中率),实时反馈当前系统负载,迅速应对负载突变的情况。 调度时延的测量基于runtime来实现。所有的业务进程都运行在caladan定制的runtime上,业务进程需要划分线程类别(高、低优先级,用于配置调度策略) ,并完全由caladan调度器管理。调度时延由线程在调度队列中等待的时间来确定。内存带宽的测量依赖于intel的性能监控器 (https://intel-pcm-api-documentation.github.io/classServerPCICFGUncore.html),直接调用intel的API(getMCCounter),然后加以分析判断。
2、微妙级的响应和CPU资源流动,迅速收敛应对负载突变。 caladan的调度器每10us检查一次负载情况,响应速度很快。同时caladan舍弃了传统的资源隔离分区的做法,CPU资源流动不需要通过硬件或者linux CPU热插拔 机制来完成,而是通过业务线程的调度(原线程迁移,目标线程运行,这个过程实际上就完成了一次CPU资源流动),大大降低了开销。调度由用户态调度器和内核模块ksched共同完成,舍弃sched_setaffinity这种长路径实现。用户态指定调度策略,通过ioctl下发调度命令,并通过mmap共享内存减少用户态内核态同步开销,ksched则在接收到用户态的调度命令后,使用IPI中断在目标核上快速完成调度切换。
3 方案缺陷
1、兼容性问题。业务进程需要运行在定制的runtime上,调度时延的测量以及线程调度都依赖于runtime对业务进程的拦截和封装。并且runtime不完全兼容linux, 包含自定义的线程、互斥锁、条件变量和同步I/O机制等。业务进程需要将内部的线程信息传递给runtime,这可能需要对现有代码进行修改。 2、暂时没有做numa节点之间干扰的优化。
4 延伸思考
caladan衡量负载情况的指标直接有效,值得参考。但是对性能指标的高效监控是定制化的(runtime+intel API),定制化的垂直优化很容易带来性能提升, 但往往有兼容性问题,需要根据实际场景来取舍。在去除runtime这一层的情况下,寻求达到负载的快速感知和CPU资源快速流动的方法也是一个可以思考的方向。