偶然中在应用层望见了一个微内核的操纵体系调理器

[复制链接]
发表于 6 天前 | 显示全部楼层 |阅读模式
你好呀,我是歪歪。
近来碰到一个业务上的题目,在网上看到一个对应场景下的办理方案,我感觉这个场景还挺有通用性的,分享一下。
以后碰到雷同题目,大概当它以口试场景题出现的时间,你可以拿去就用。
事变是如许的。
步伐内里有一条“线路”,这个“线路”是购买的外部服务,使用起来是要收费的。
为了更好的明确这个“收费的线路”,你可以假设为这是一个付费的 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/
而且它的思绪很简单,简单到让我以为如果让我深入的思索一下,大概我也能想到这个方案。
它的核心思绪,用文章中的这张图就能说清楚:
给每个生产者分配一个存放 messages 的队列,同时给每个生产者分配一个 client id。
然后你留意看这里:
把 client id 放在一个 Round Robin Queue。
这是个什么玩意?
着实就是一个简单的轮询战略。
先从队首取出 client id。
然后由选择出的 client id 找到对应的 work 去从对应的队列中取出消息来消耗。
末了视情况而定,是否必要把这个 client id 放在队尾。
由于轮询机制,以是会确保各个生产者的消息是瓜代实行。
作者使用 Rust 语言实现了上面的逻辑,并取名叫做:Broccoli。
翻译过来是一个我不喜好吃的蔬菜:西兰花。
这是对应的堆栈链接:
https://github.com/densumesh/broccoli
这个“西兰花”的核心架构非常简单,紧张有两个紧张组件:每个客户端的专用队列和单个轮转调理器。
对于根本组件来说,筹划越简单,就越可靠。
作者在文章中也先容了核心逻辑的伪代码:
并不复杂,只有几行代码,我带你盘一盘。
核心逻辑分为两坨。
第一坨逻辑是产生新消息,对应插入操纵。
起首,将某个生产者新产生的消息存储在一个专门的对应生产者的队列中。
然后,查抄这个生产者对应的 client id 是否已经在轮询队列中。
如果在,那就完事了。
如果不在,那就把这个 client id 加在轮询队列的末端。
只要放到轮询队列内里去了,就只必要等着被调理就行了。
第二坨逻辑是消耗消息。
起首,从轮询队列中获取队首的 client id。
然后,从这个 client id 的专属队列中获取一条消息举行处理惩罚。
处理惩罚完毕后,查抄这个 client id 的专属队列是否另有消息。
如果专属队列空了,这个 client id 就不必要放回到轮询队列了。
如果专属队列另有消息,那把这个 client id 放回到轮询队列的队尾,就完事了。
看起来逻辑确实非常简单、清楚。
这个方法的优点在于它完万能自我均衡。
“喧华的邻人”会留在轮询队列中,“空闲的邻人”会主动退出,而且无论他们列队的工作量有多少,每个人都能公平地得随处理惩罚时间。
看到这里有的小搭档大概会产生一个疑问:前面不是说了如果为每一个消耗者都提供一个单独的队列,即付费“线路”,本钱太高了吗?那为什么这里就可以一人一个呢?
我把上面的图,再多画一点出来,你就明确了:
这里的“一人一个”是真的就一个队列而已。
颠末这套逻辑之后,各个生产者的消息会出现出交织串行的形态,再穿过真正的“付费线路”。
“付费线路”只有一条,并没有产生额外的费用。
代码

思绪有了,代码不是手到擒来的事儿吗?
我这里也不给你粘代码了,直接给你上个代码截图:
但是我可以告诉你怎么去获取对应的代码实现。
去问大模子就行了。
我把流程表现图和伪代码形貌直接扔给 DeepSeek:
让它给我一份 Java 代码,就行了:
如果你让我按照上面的思绪去敲代码,我以为我至少得写 30 分钟才气把初版写好,而且这都算是快的。
如今,大模子会在一分钟内给你安排的显着白白:
你只必要终极查抄一下代码逻辑就行了。
哎,我已经忘记前次纯古法手工敲代码是什么时间的事儿了。
眼熟吗?

别的,你有没有发现这个“Broccoli”方案,有点眼熟?
这不就是操纵体系的历程调理器玩了几十年的经典套路吗?
早期的操纵体系或某些简单场景下,CPU 调理使用先来先服务(FCFS)战略。
先到的历程先得到 CPU,实行完了才轮到下一个。
如果一个“盘算麋集型”的历程(比如 A 用户)拿到 CPU,它大概实行很长时间(比如一个耗时循环),导致反面全部“交互麋集型”的历程(比如 B、C 用户的轻量使命)都被壅闭,体系相应速率急剧降落。
这不就是“喧华邻人”题目的翻版吗?
A 历程就是谁人喧华邻人。
为了办理 FCFS 的公平性题目,操纵体系引入了时间片轮转调理算法。
这险些和“Broccoli”的方案千篇划一。
焦颔首脑是为每个历程分配一个固定的时间片。
历程在 CPU 上运行一个时间片后,就会被欺压剥夺 CPU 使用权,并排到停当队列的末端,让下一个历程运行。
对应“西兰花”来说:

  • CPU 时间片 ->你的调理器每次从用户专属队列里取出一个使命举行处理惩罚。
  • 停当队列 -> 你的 Round Robin Queue(轮询队列),内里放的是有使命待处理惩罚的用户 ID。
  • 剥夺 CPU 并排到队尾 -> 处理惩罚完一个用户的一个使命后,如果他另有使命,就把他的用户 ID 重新放回轮询队列的队尾。
如今看这张图,是不是感觉它就是一个微型的操纵体系调理器?
而且,操纵体系另有更高级的玩法——多级反馈队列。
这可以给“西兰花”将来的优化提供方向:

  • 多队列:设置多个差别优先级的队列。新来的历程先辈入最高优先级队列。
  • 时间片差别:高优先级队列的时间片短(包管相应快),低优先级队列的时间片长(进步吞吐量)。
  • 反馈机制:如果一个历程在一个时间片内用完了还没竣事,分析它大概是“长使命”,就把它降级到低优先级队列。如果一个历程在时间片用完前主动放弃 CPU(比如举行I/O操纵),分析它大概是交互式的“短使命”,就让它留在高优先级队列。
别的,操纵体系调理磁盘 I/O 哀求时,也会碰到千篇划一的题目。
如果完全按照 FIFO,某个历程的大量序次读写哀求会霸占磁头,导致其他历程的随机读写哀求饥饿。
办理方案之一就是电梯算法(SCAN) 或其变体,其核心也是将单个 FIFO 队列拆解,重新排序哀求,以在公平性和服从之间取得均衡。
这和我们前面的思绪,可以说是同宗同源。
以是,恭喜你,偶然中在应用层望见了一个微内核的操纵体系调理器!
末了,在上个代价。
盘算机科学中许多看似复杂的底层原理,其焦颔首脑都具有极强的普适性。
真正良好的筹划模式,会反复出如今从硬件到应用、从底层到高层的各个层面。
下次再有人问你怎样办理资源争抢题目,你不光可以甩出“西兰花”方案,还可以淡定地增补一句:
这着实就是操纵体系级的时间片轮转调理算法在分布式体系中的应用。我们不外是在业务层,用最低的本钱,复刻了操纵体系几十年来验证过的公平性聪明。
好了,就到这里了。
这个方案之前是别人的,厥后变成了我的,如今是你的了。
不客气,来个三连就行。

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

×
回复

使用道具 举报

×
登录参与点评抽奖,加入IT实名职场社区
去登录
快速回复 返回顶部 返回列表