这个微内核操作系统调度器是如何实现调度的?
摘要:你好呀,我是歪歪。 最近遇到一个业务上的问题,在网上看到一个对应场景下的解决方案,我感觉这个场景还挺有通用性的,分享一下。 以后遇到类似问题,或者当它以面试场景题出现的时候,你可以拿去就用。 事情是这样的。 程序里面有一条“线路”,这个“线
你好呀,我是歪歪。
最近遇到一个业务上的问题,在网上看到一个对应场景下的解决方案,我感觉这个场景还挺有通用性的,分享一下。
以后遇到类似问题,或者当它以面试场景题出现的时候,你可以拿去就用。
事情是这样的。
程序里面有一条“线路”,这个“线路”是购买的外部服务,使用起来是要收费的。
为了更好的理解这个“收费的线路”,你可以假设为这是一个付费的 AI 接口。
然后你可以把“线路”简单的理解为一个 FIFO 的公共队列,对应着多个生产者。
也就是同时有很多人,即消费者,在使用这个“AI 接口”提问。
画个示意图是这样的:
理想情况下,我们期望大家和和气气轮流用,你一个我一个,节奏均匀得像心跳。
但是,实际使用过程中,可能会出现一个卷王 A 生产者,突然快速的生产了大批量的数据,导致 B、C 生产者产生的少量的数据排在队列的最后面,等到天荒地老:
整个队列呈现出的短时间内只为 A 生产者服务的效果。
即 A 生产者“长时间霸占”了整个队列。
很明显,这样对其他生产者不友好。
我在网上查询了一下,这个现象还有一个专门的名词,叫做吵闹邻居问题(Noisy Neighbor Problem)。
主要是指在多租户环境中,单个用户过度占用资源导致其他用户服务质量下降的现象。
常见的方案
针对这个问题,常见的方案一般有两个。
第一个是把队列,即“线路”分来,就像这样:
各玩儿各的,互不干扰。
没有邻居,也就不存在“吵闹邻居”的问题。
这样可以解决问题,但是会带来一个新的问题。
前面说了,这个“线路”是有购买成本的。
如果为每一个消费者都提供一个单独的队列,即上面说的“线路”,那成本就太高了。
那你可能会反驳一句:不需要为每个人提供单独的队列,只为高频使用的人员提供就行了嘛。
是的,这样也没有毛病。
但是实际情况是,高频使用的人, 也只是在某个小段时间内高频使用,随后就是长期的闲置,浪费购买成本。
而且,在实际情况中,还会出现一个情况是,某个低频使用的用户,突然在某一段时间出现业务高峰。
那这种情况为了不影响其他用户,还得紧急给业务高峰的用户搞个专门的队列。
运营成本太高。
所以,这个方案适用于长期稳定都是高频用户的情况。
第二个方案是限制生产者的生产速度。
这个方案在解决问题的同时也带来了新问题。
第一个问题是我需要实现一个限流功能,提升了基础组件的复杂度。
第二个问题是由于下游有限流机制,那上游必然就要有重试机制,增加了整体系统的复杂度。
这两个常见的方案,一个烧钱,一个烧脑。
我了解了之后,发现和我的场景都不太匹配,不能直接使用。
Amazon SQS
在我向大模型求助的时候,它给了我这样一个关键词:
智能调度算法:正如Amazon SQS所使用的公平队列(Fair Queueing) 机制,在软件层面确保资源被公平地分配给所有用户,防止任何一个用户垄断资源。
于是我在网上找到了 Amazon 官方网站中这个文章:
https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/sqs-fair-queues.html
从文章中的描述看,它有一个识别谁是“吵闹邻居”的机制:
当识别到 A 是一个“吵闹邻居”之后,Amazon SQS 会把其他租户(B、C 和 D)的消息放在最前面。
这里的“租户”,你可以认为就是我们前面提到的生产者。
这种优先级有助于保持安静租户 B、C 和 D 的低停留时间,而租户 A 的消息停留时间会延长,直到队列积压被消耗,而不会影响其他租户:
看起来确实能解决我的问题。
于是追问了一下大模型关于它的问题,想要进一步了解一下底层原理:
从大模型的回答来看,它核心逻辑是有一个“动态权重调整机制”。
“动态权重调整机制”的目的,我个人理解是为了给每个生产者一个合适的权重,从而决定这次生产的任务是应该放在队列的前面还是后面。
大概是这个意思:
初步了解之后,感觉它底层实现还有点复杂,我把握不住。
有一种杀鸡用牛刀的感觉,所以我不打算使用它。
但是也不算白忙活,至少知道了 Amazon SQS 这个东西的存在。
换个思路
于是我在网上继续搜索,找到了这篇文章,它描述的思路,完美解决了我的问题:
https://densumesh.dev/blog/fair-queue/
而且它的思路很简单,简单到让我觉得如果让我深入的思考一下,也许我也能想到这个方案。
