乐观锁和悲观锁
最近晓靖给 skynet 提了一个 pr 。
提之前我们讨论了好久,据说是因为查另外一个问题时改写了 skynet 的消息调度部分发现在某些情况下可以提高 CPU 的使用率。
之前 skynet 的消息调度采用的是基于 cas 的无锁结构。但本质上,并发队列这种数据结构,无论是采用 spin-lock 还是 cas 无锁结构,为了保证时序,进队列或出队列的部分都必须是依次进行的,也就是说,多核心无助于提高队列的性能。
使用无锁结构,无非是对发生冲突保有乐观态度,觉得大多数情况下冲突不会发生,一旦发生就采取重来一次的策略。
而使用 spin lock ,则是对冲突采取悲观策略,认为冲突经常发生,所以在操作共享字段时,锁住资源独享操作。
最终,都必须等前一件事情做完,才能接着做下一件事。
无锁结构的程序逻辑往往显得复杂,那么它的好处是什么呢?
无锁结构在乐观情况下,可以让处理过程尽量并行,只在可能发生冲突的那一刻才用系统的原子指令锁住一个字长的内存写入,然后立即放开。加锁和解锁是原子的,这样就可以回避死锁的问题。同时也不会因为 spin lock 锁住的指令过多(如果线程数多于核心数,就有可能在锁住的过程中发生线程挂起),而导致其它线程等待时间过长。
在 skynet 的核心消息队列调度模块中,无锁结构能获得的好处其实非常有限。为了简化代码,我们甚至不需要单独去锁队列的两端。因为在 skynet 的消息队列分两级。在运行过程中,如果此级队列有消息时,它根本不会进入全局主队列(用锁保证次序的那个队列)。
由于不再使用无锁队列,数据结构也可以大大简化。使用一个简单的单向链表就可以管理这个队列。之前为了解决队列长度问题,已经把次级队列设计成一个侵入式链表,这次要做的只是把那个数组部分去掉就可以了。
修改过后,一个明显的好处是突发的大量服务启动(往往是瞬间大量连接涌入造成的 agent 启动需求)变快了。这解答了之前的一个疑问 。
12 月 12 日补充:
这篇不在于讨论用乐观锁还是悲观锁的性能好坏. 上文最后提到的问题的解释, 并不是因为提高了锁的性能, 而是因为:
之前认为在 skynet 的多个 worker 竞争全局队列时, 抢到操作权是乐观的. 因为处理消息本身的时间远远长过操作全局队列的时间. 当多个 worker 竞争时, 我们认为几乎是不会冲突的.
所以在 worker 竞争全局锁时做了这样的处理: 如果失败, 就认为队列为空, 而不是重新尝试. 这样做可行是因为 worker 本身是对等的, 每个 worker 的职责是完全相同的。
一旦发生竞争,说明 worker 没有什么复杂的事情做(当消息处理时间足够短时,竞争的概率会上升),所以让竞争失败的 worker 暂时放弃更有助于节约系统的资源。即:如果任务不多,退化成单核处理更好。
这样实现倒不是为了提高性能,而是代码更简单(不需要再重试)。
这次发现在某些特定情况下,这个策略是错误的。至于改成 spinlock ,是因为代码量要小的多。而在队列实现上,无论采取怎样的策略,对系统的性能影响及其有限,那么选择一个代码更简单的实现更好。
Comments
Posted by: Pslydhh | (15) May 6, 2018 10:37 PM
Posted by: 丁大头 | (14) December 15, 2014 11:21 AM
Posted by: 丁大头 | (13) December 15, 2014 11:13 AM
Posted by: cloud | (12) December 15, 2014 10:41 AM
Posted by: 丁大头 | (11) December 15, 2014 12:35 AM
Posted by: 丁大头 | (10) December 15, 2014 12:31 AM
Posted by: cloud | (9) December 14, 2014 11:58 PM
Posted by: 杨博 | (8) December 14, 2014 10:09 PM
Posted by: 丁大头 | (7) December 14, 2014 07:43 PM
Posted by: Cloud | (6) December 14, 2014 01:26 PM
Posted by: spin6lock | (5) December 14, 2014 11:04 AM
Posted by: Cloud | (4) December 12, 2014 02:50 PM
Posted by: 杨博 | (3) December 12, 2014 01:08 PM
Posted by: 杨博 | (2) December 12, 2014 12:52 PM
Posted by: 杨博 | (1) December 12, 2014 12:48 PM