高伸缩性Go调度器设计(译)

阅读该文档前假设你已经对go语言及其当前调度实现的有所了解

当前调度器所存在的问题

当前的调度器限制了go并发的伸缩性,特别是在高吞吐量和并行计算方面.在一台8核的机器中跑 Vtocc 服务, cpu占用率高达70%, 性能分析数据显示14%cpu占用用在runtime.futex()上.通常,调度器可能会禁止用户在性能至关重要的地方使用惯用的细粒度并发。

当前调度器的不足:

  1. 全局锁和中心化状态, 协程相关的操作(创建、执行完成、重新调度等等) 都需要依赖锁的保护.
  2. 协程迁移, 协程在各个工作线程M之间频繁迁移,这可能会增加延迟和额外的开销.每个M必须能够执行任何可运行的协程,特别是刚刚创建协程的M.
  3. 线程存在本地缓存(M.cache),所有的M中都会有内存缓存和堆栈缓存, 然而只有当M在运行协程的时候才需要用到它们(处于系统调用中的线程M由于被阻塞而不要使用本地缓存). 真正在执行协程的线程M和所有的线程M比例高达1:100.这会导致过度资源消耗(每个MCache占用2MB的内存)和非常差的内存亲和性.
  4. 线程频繁的阻塞唤醒,处于系统调用中的线程会频繁阻塞和唤醒,这会增加很多性能开销.

新的调度器设计

Processors

总得来说就是在运行时引入P(处理器)的概念,并在处理器之上实现窃取工作的调度机制.

M是表操作系统线程, P提供所有G执行所需的资源环境, 当M执行G时, M会绑定一个P,当M处于空闲或者系统调用时(这种情况下, M 和 P解绑了),M需要一个P.

有一个跟P数量的相关的变量GOMAXPROCS, 所有的P会放到一个数组中, work-stealing(工作窃取)机制会用到这个变量.GOMAXPROCS的修改会调整运行时P的数量.

全局sched中的一些变量现在移到了P中, M中的一些变量(与协程执行相关的)也移到了P中.

struct P
{
Lock;
G *gfree; // freelist, moved from sched
G *ghead; // runnable, moved from sched
G *gtail;
MCache *mcache; // moved from M
FixAlloc *stackalloc; // moved from M
uint64 ncgocall;
GCStats gcstats;
// etc
...
};

P *allp; // [GOMAXPROCS]

还有一个空闲p列表

P *idlep; // lock-free list

当M将要执行G时, 它从p的空闲列表中取出一个p. 当M结束G的执行时, 把P放回空闲列表中,因此 当M要执行G时, M一定要绑定一个P, 这种机制代替了之前全局 sched的原子操作 (mcpu/mcpumax ).

调度

当一个新创建的G或者旧的G变成runnable状态时, 这个G会被放到P的本地队列中,当P执行完一个G后,会从自己的本地队列中取出下一个G继续执行, 如果本地队列为空, 则随机从其他P的本地队列中窃取一半G过来执行.

系统调用(M 挂起/唤醒)

当M创建一个G时,M必须确保有其他的M来执行这个G(如果有空闲的M),同样的,当M进入系统调用时,确保有其他M来执行G.

有两种选择, 我们可以迅速挂起和唤醒M, 或者使M自旋.这是在性能和消耗不必要的CPU周期之间做的选择,其思想是使M空转并消耗CPU周期.但是,当我们把GOMAXPROCS 设置成1时, 这种方式不能影响命令行等程序的运行.

自旋有两种: 1.一个绑定了P的空闲M在自旋,目的是寻找G来执行 2. 没有绑定P的M自旋等待可用的P.最多有GOMAXPROCS 个M自旋(包括第一种和第二种).当存在第二种空闲M时,第一种的空闲M不会被阻塞.

当有一个新的G创建时,或者M进入系统调用时,或者M从空闲便成繁忙时,确保至少有一个处于自旋的M(所有的p都处于忙碌中).这确保了没有任何可以运行的G;同时避免了过多的M在频繁阻塞唤醒.

cpu空转是没有意义的

终止/死锁检测

在分布式系统中,终止/死锁检测问题更大,通用的做法是仅在所有P空闲时进行检查(空闲P的全局原子计数器),这允许执行更昂贵的检查,包括每P状态的聚合。

锁定操作系统线程

此功能不是性能关键.

  1. 当M锁定的G会变成非运行态(Gwaiting). M会立刻把P放到空闲列表中, 唤醒其他的M,然后阻塞住.
  2. 当M锁定的G变成可运行状态(G在runq的头部),当前M将自己的P和锁定的G交给与G关联的M,并唤醒M,当前M变为空闲。

空闲G

此功能不是性能关键.

有一个全局G队列,M在多次窃取G失败后会检查这个队列

实现计划

我们的目标是将整个事情分解成可以独立审查和提交的最小部分.

  1. 定义P结构体;实现 allp/idlep 队列(idlep 需要使用互斥锁保护);M执行G的的代码时要绑定一个P,全局互斥锁和原子状态仍然保留.
  2. 把G的freelist 移到P中.
  3. 把mcache移到P中.
  4. 把stackalloc移到P中
  5. 把ncgocall/gcstats移到P中
  6. 分散运行队列,实现工作窃取.取消G在M之间的轮转.仍然使用全局互斥
  7. 移除全局锁,实现分散终止检测, 锁定操作系统线程
  8. 实现自旋代替立即阻塞/唤醒.

这项计划可能行不通,因为还有很多未经探索的细节。

潜在的进一步改进

  1. 尝试后进先出的调度, 这将改善局部性.然而,它必须提供一定程度的公平性,并优雅地处理让出cpu的goroutine。

  2. G和栈的内存分配应该等到它即将执行时来进行, 对于一个新创建的G,只需要callerpc, fn, narg, nret 和 args 参数, 占用大约6个机器字的内.这将允许创建大量从运行到完成的goroutine,并显著降低内存开销。

  3. G和P更好的亲和性,尝试将未阻塞的G排队到它上次运行的P.

  4. P和M更好的亲和性,尝试在上次运行的M上执行P

  5. 创建M的限制,调度器可以很容易地每秒创建数千个M,直到操作系统拒绝创建更多线程. 在达到k*GOMAXPROCS个M之前,M可以快速创建,之后可以通过计时器添加新的M。

其他事项

GOMAXPROCS不会因为这项改进而消失

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 220,137评论 6 511
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,824评论 3 396
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 166,465评论 0 357
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 59,131评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,140评论 6 397
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,895评论 1 308
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,535评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,435评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,952评论 1 319
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,081评论 3 340
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,210评论 1 352
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,896评论 5 347
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,552评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,089评论 0 23
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,198评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,531评论 3 375
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,209评论 2 357