MoreRSS

site iconOilbeater修改

灵雀云技术合伙人, Kube-OVN Malacca 项目发起人,维护者
请复制 RSS 到你的阅读器,或快速订阅到 :

Inoreader Feedly Follow Feedbin Local Reader

Oilbeater的 RSS 预览

GoBGP 快速上手

2025-07-09 06:48:00

在做 MetalLB 和 Calico 的一些测试时需要验证 BGP 相关的功能,然而每次测试要去联系运维团队配合网络变更是不太现实的,并且大多数情况我们只要验证 BGP 信息正常交换就可以了,不需要真的去改变物理网络。于是就找到了 GoBGP 这个软件路由器进行模拟。

GoBGP 本身有着很复杂的配置,但是如果你只是像我一样只是想有个虚拟的路由器,让客户端把 BGP 信息发送过来,检查路由表信息是否正确更新,那看这篇文章就可以了。

下载 GoBGP 二进制文件

Release 制品列表里找到对应系统的制品解压即可,重要的只有两个二进制文件: gobgpd 虚拟路由器进程,gobgp命令行工具,用来查看路由对不对。

启动虚拟路由器

创建一个 gobgp.toml 文件,最简单的配置就照着我下面这个就好了,大部分基础的云原生领域 BGP 相关的软件测试用这个就够了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
[global.config]
as = 65000 # 测试环境随便写一个就好
router-id = "10.0.0.1" # 测试环境随便写一个就好,写 GoBGP 所在节点 IP 日志清晰一些

[[dynamic-neighbors]] # 被动连接模式,省去了配固定客户端
[dynamic-neighbors.config]
prefix = "192.168.0.0/24" # 允许哪个 IP 范围内的客户端来连接
peer-group = "ext-ebgp"

[[peer-groups]] # 复制粘贴就好了
[peer-groups.config]
peer-group-name = "ext-ebgp"
peer-as = 65000
[[peer-groups.afi-safis]]
[peer-groups.afi-safis.config]
afi-safi-name = "ipv4-unicast"

启动 gobgpd

1
./gobgpd -f gobgp.toml

在另一个终端观察当前的路由表

1
./gobgp global rib

这样基本上 MetalLB,Calico 的基础 BGP 能力就可以测试了。如果想更配更复杂的模式,比如 Router ReflectorEVPN 那就再去翻 GoBGP 的文档吧。

怎样的开源文档规范最合适?

2025-07-06 21:00:10

最近打算把 Kube-OVN 的文档整理一遍,同时思考怎样的文档规范能尽可能做到:

  1. 降低 Maintainer 的维护成本(用户看完文档后不会再去找 Maintainer )。
  2. 能够充分复用(不看文档的人找过来可以直接甩文档)。
  3. 同时对社区的用户也尽可能有帮助(少走弯路)。

我决定先按照下面的结构重构一下文档,来看看效果。

  1. 概要:一两句话描述这个功能达到什么效果,解决什么问题,有什么优势。之前很多文档都是以技术细节开头,反而把真正能实现的效果给模糊掉了。明确功能是什么后,用户就可以确认自己是否还需要继续往下看了。
  2. 局限性:这个功能不是什么,什么没做到,解决不了什么问题,使用有什么限制条件。这个其实和第一部分一样重要,不然用户可能有不切实际的预期等到很靠后的时候才知道某个功能其实是不符合预期的或者限制条件不满足,也浪费了双方很多时间。有人问为什么不能用的时候也可以甩文档。
  3. 实现原理:我们用到的 OVN/OVS 的哪些能力,简要的介绍以及对应功能的参考文档。到这里我们其实期望用户有一些更深的理解,不至于出了问题毫无思路再去扒代码或者找到 Maintainer。我们也建议真在生产使用 Kube-OVN 的用户要有一些从底层开始排查的能力,Kube-OVN 虽然做了很多抽象让使用变得简单,但是在用户的环境里使用的异常还是需要用户自己有能力排查。
  4. 使用步骤:之前的常规内容,有了前面的铺垫,这一部分可以尽可能简化,只需要步骤即可。

大家有什么其他的建议也可以一块来讨论一下。

Kube-OVN 是如何自动修复 CVE 的

2025-06-28 08:02:21

这篇博客是内部分享的一个提示文稿,并没有做仔细整理,大体思路就是捕获所有 Kube-OVN 的依赖:操作系统,Golang,程序依赖,环境组件(k8s,kubevirt 等),然后激进的实时更新所有依赖做到动态清零。

Kube-OVN CVEs 问题修复的流程经历了如下几个阶段:

  • 发版/按需统一进行手动修复
  • 每次 commit 检测可修复安全漏洞,手动进行修复
  • master 依赖自动更新,发版分支部分依赖自动更新,少量手动修复
  • 未来目标:所有依赖自动更新,避免手动修复

按需修复

优势:

  • 相比每个安全漏洞单独修复,整体修复频次低
    劣势:
  • 发版集中修复,研发还要兼顾发版期间赶进度,测试,bug 修复,时间压力大
  • 依赖更新没有经过日常验证,存在未知的风险
  • 大部分安全修复工作没有实际意义还需要花费人工精力

每次 Commit 检测修复

增加工作:

优势:

  • 将 CVE 修复打散到平时,发版时时间压力较低
  • 可以快速发版
  • 大部分依赖更新已经得到了日常自动化测试的验证,风险也较低
    劣势:
  • 最后一次提交和发版扫描之间存在时间差,理论上会遗漏一部分 CVE
  • 会干扰平时正常功能提交,bug 修复,提交经常因为不相关的 CVE 问题被阻塞
  • 大量的手动修复

所有依赖自动更新

只要依赖更新版本就尝试更新,不考虑是否是安全更新。尝试解决比 CVE 修复更大的一个问题,自动就解决了 CVE 问题的修复。

我们的依赖项:

  • OS 镜像及其依赖:ubuntu:24.04, apt-get install ....
  • Go 语言版本,以及代码依赖库
  • 上游依赖:OVS, OVN
  • 其他协作组件依赖: kubernetes, kubevirt,multus, metallb, cilium, talos
  • 采用比较激进的更新策略,依赖大版本更新我们也会尝试更新

要做的事情:

优点:

  • 大部分 CVE 会在不知道情况下被修复,少量可在一天内自动修复,特殊情况再手动修复
  • 大量上游的 bugfix,性能提升和新功能被自动合入,软件整体稳定性提升
  • 大量的版本适配验证工作,如 k8s 版本更新,KubeVirt 版本更新的适配验证也都自动进行,风险提前知晓
  • 人工干预量较少

劣势:

  • 依赖更新多比较吵,需要设置聚合策略
  • 更新量太大无法人工测试,需要有自动化测试保证
  • 需要积极适配上游版本变化
  • 存在上游新版本不稳定风险,目前两年内遇到过两次

renovate 相比 dependabot 优势

  • 可以自定义依赖捕获,Dockerfile、Makefile 里的非标准依赖可以捕获
  • 可以在非 master 分支运行
  • 有 auto merge 能力

还未解决的问题

关于培训

2025-05-24 18:40:04

这两天接了个 Kube-OVN 培训的任务,事实上这已经是这几年第三次给这家公司培训相同的内容了,形式也从线上转到线下还要求手把手的敲命令,可想而知之前几次的最终效果怎样。我可以理解需求方的技术焦虑,但我认为培训这种形式是极其低效的,更多的只是培训当时能获得一些虚假的满足感,不会产生什么长期收益。

一方面培训是一种被动学习方式,完全由老师带节奏前进,那听讲的人只是被动的吸收,很难有深度的思考。另一方面需要等到培训才了解的知识大概率是实际上用不到的知识,如果每天都用的话根本来不及等这种一年一次的培训。如果实际用不到,那么哪怕当场掌握了,很快也会什么都剩不下。

我觉得这和我们一直以来的教育理念有些关系,传统上我们认为认真听老师讲课,努力记笔记,不会的问题堵着老师问,都是优秀的学习习惯。但这些都是偏被动的学习方法,我们很多年的教育过程中其实缺乏主动学习的机会。这种被动的方式早期的效果可能会很好,因为早期学校里的知识难度不大,而且我们展示学习成果的方式就是考试,而考试是可以通过过拟合的方式来提升效果的,并不能真正反映你对知识的掌握程度。

在我的经历里,到了初中阶段,最出色的那批人就不再是认真听课,努力记笔记那批人了。而是换成了那批给人感觉平时一直玩,考试成绩还很好的一批人,事实上越往后这批人的比例越高。我认为这里并不是智商的区别而是被动学习和主动学习模式的区别。主动学习的人会更多依赖自己思考来解决问题,而不是依赖老师的讲解,这个方法看似低效其实最终效果会更好。想象一下同样一道题,一个人是老师之前讲过所以考试的时候做出来了,另一个人是上课没听到但是考试的时候临场也做出来了。从考试的结果来说两个人是一样的,但两个人的实际能力是天差地别的。后者实际上拥有更好的学习方法和能力,并且在更难的问题上有更好的泛化能力,自然可以显得游刃有余。就好比前者一直在用冒泡算法去排序,后者则是不断用快排,在小规模上前者可能更简单更不容易出错,效果会比后者好,但是后者一旦调整好了,在更大规模的数据上会有指数级别的优势。

这也是为什么有些转行的程序员的表现会比科班的表现好。一方面他们采用的是主动学习这种高速方法,另一方面科班的被动学习学到的大量都是实际中毫无用处的知识,两者的基础差距本身就没那么大,用一个更高速的方法很容易短期就实现超越。

所以还是要主动学习,学点有用的。(不要再折腾供应商搞什么高级培训了

如何超越 OpenShift

2025-04-23 18:40:43

OpenShift 作为容器平台的标杆产品,同时也是开源商业化的标杆,一直是被人试图追赶或者超越的对象。但是如果只是照着 OpenShift 的产品模仿,那么当追上 OpenShift 时只可能有一种情况,那就是 OpenShift 停止发展,过了一年后你终于追上了,然后会因同样原因被淘汰。

那么有没有什么方法能够追上甚至超越 OpenShift 呢?我认为要从 OpenShift 本身商业模式的选择和技术路线上的选择入手,从他们在这种选择下不可避免的缺点入手,做出差异化,才有超越的可能。

OpenShift 并不 Open

OpenShift 里的 Open 可能和 OpenAI 里的 Open 是同一个 Open。如果你尝试不通过 RedHat 的销售自己去部署一套 OpenShift 就会知道我在说什么了。

OpenShift 的所有组件确实是开源的,但如果你是一个纯粹的社区用户会步步受挫。一个功能你可能找不到对应组件,找到组件可能找不到对应源码,找到源码又没有文档指导如何编译使用。这些现象在那些完全是 OpenShift 自己使用的组件里已经见怪不怪了。大概 OpenShift 这部分的社区只是对客户和合作伙伴开放的。

而对于那些非 OpenShift 专属的组件,OpenShift 采取的策略会是一旦选择就大举投入,争取到对应组件的社区的主导权。所以会看到的一个现象是有些社区很出名的项目 OpenShift 的人完全不投入,而一个项目在平稳发展了几年后会突然涌入大量 OpenShift 的人。

这些都是 OpenShift 在商业化与开源之间权衡后的选择,并没有对错之分,但这会给更开放的项目留出机会。如果新的产品能够降低参与门槛,收取更广泛的反馈,让更多的贡献者来参与创新,那么我认为它的上限将会超越 OpenShift。

OpenShift 的技术并不先进

受限于第一点因素,OpenShift 并不能广泛的吸收整个生态的最新成果。在生态内某个组件和 OpenShift 专属的组件功能重叠情况下,OpenShift 内部的研发人员是很难有动力切换到另一个社区或者另一个公司主导的开源组件。

以我比较了解的网络为例,OpenShift 早期通过 Haproxy 实现了 Route 来打通集群外访问集群内的流量。在当时 Ingress 还不成熟,Route 是一个相比社区先进的多的方案,OpenShift 的方案在当时是绝对领先的。但是随着 Ingress 的成熟,社区生态内各种网关都在飞速发展,而 OpenShift 受限于自己早期的实现和用户用法很长时间都没有去支持 Ingress 这个在社区已经标准化的功能。现阶段 Ingress 规范已经进化到 GatewayAPI 有一段时间了,大量 AI Gateway 的新场景都在通过 GatewayAPI 进行扩展,而 OpenShift 现如今还没有支持 GatewayAPI,最近正在计划在之前的 Haproxy 上同时支持 Route,Ingress 和 GatewayAPI。

类似的案例在 OpenShift 内还有很多,早期可能还是一个优秀的方案,但由于 OpenShift 专属导致不开放,随着社区的发展,原先优势的方案反而变成了阻碍前进的障碍。就像现在在 Kubernetes 上做 Ingress Gateway 不会有人去参考 OpenShift 的实现,在很多细分领域 OpenShift 已经并不是最先进的解决方案了,尤其是在那些由 OpenShift 专属组件提供服务的领域。现在的 OpenShift 在我看来就是一个覆盖面积很广,但平庸且无趣的平台。

容器平台的生产过程其实和手机的生产很像,都是从成百上千个供应链供应商那里选择需要的配件,然后组装成一个成品。如果能够保持开放,选择供应链上最先进的那些配件,或者根据场景快速组合出一个针对特定场景的产品,那么在技术竞争力上应该会远超 OpenShift。

总结

要想真正追赶甚至超越 OpenShift,关键不是在已有功能上亦步亦趋,而是要做到更开放、更领先。这样才能摆脱追随者路径,真正形成对 OpenShift 的差异化优势,成为下一轮技术浪潮的主导者。

DeepSeek MLA -- 为成本优化而生的注意力机制

2025-04-15 01:10:03

DeepSeek 第一次出名是因为 DeepSeek V2 做到了一百万 Token 只要 0.14 美元。同期的 GPT-4 是 30 美元,当时被认为极具性价比的 GPT-3.5 也要 1.5 美元。这个突破性价格的出现在国内引发了一轮价格战,大批大厂模型大幅降价甚至免费。然而和其他大厂烧钱补贴的逻辑不同,DeepSeek 是通过一系列的技术创新实现了成本数量级的下降。这篇文章就来介绍一下这背后最关键的一个技术创新 —— MLA(Multi-Head Latent Attention)。

MLA 最本质的数学技巧并不复杂,论文里也是一段话就说完了,看完让人感叹竟然还有如此精妙的解法。但是由于和整个 Transformer 架构耦合会导致理解起来有些困难,我这里会尽量简化描述,哪怕你之前完全不了解 Transformer 应该也可以领会到这个方法的精妙。

当然还是需要有一些线性代数的基础,如果你还记的一个形状为 5*4 的矩阵乘形状为 4*3 的矩阵,结果是一个形状为 5 * 3 的矩阵就可以继续了。

KVCache

大模型推理的成本的瓶颈在哪里?答案可能会出乎意料 —— 是显存。显卡有大量计算单元,而推理任务又是线性的一次只能出一个 Token,为了充分利用显卡的计算资源达到最大的吞吐,一般会同时运行尽可能多的生成任务。而每个任务在推理过程中都会占用大量显存,如果想运行尽可能多的任务就需要运行时显存占用足够小。而 MLA 在运行时的显存占用是原始注意力机制的 6.7%,你没看错,不是降低了 6.7%,是降低了 93.3%。打个比喻这一刀下去不是腰斩,而是脚踝斩。在不考虑模型本身的显存占用情况下,近似可以认为 MLA 在相同显存下可以容纳 15 倍的生成任务。

虽然 MLA 的论文里没有细说这个灵感的来源,但我认为他们是从原先的 KVCache 倒推,诞生了一种全新的注意力机制。到这里就不得不说下 KVCache 是什么。

大模型每生成一个 Token 都需要对之前所有的 Token 进行计算,来得出最新的一个 Token 是什么。但是一般任务不会生成一个 Token 就结束,往往要一直生成到结束符号,这就会导致前面的 Token 每一次都要重复计算。于是 KVCache 的作用就是把之前每个 Token 计算生成的中间结果保存下来,这样就可以避免重复计算了。你可以理解为每个 Token 都被映射成了一个 1000 * 1000 的矩阵,那么我们有没有什么办法来减少这个矩阵的内存占用呢?

MLA

这里有意思的事情终于可以开始了,我们可以用两个小矩阵相乘来近似一个大矩阵。这里刚才你还记得的线性代数知识可以用上了,1000 * 2 的矩阵乘一个 2 * 1000 的矩阵也可以得到一个 1000 * 1000 的矩阵,而这两个矩阵总共只有 4000 个元素,是 1000 * 1000 矩阵元素数量的 0.4%。

这就是 MLA 在数学上最核心的思路了,在 DeepSeek V2 中,本来一个 Token 应该被映射为一个 1*16k 的向量,而在使用 MLA 后会先通过一个压缩矩阵将这个 Token 映射为 1*512 的向量,等到需要的时候再通过一个 512 * 16k 的解压矩阵还原成 1*16k 的向量。在这里压缩矩阵和解压矩阵都是通过训练得来,是模型的一部分只会占用固定的显存,而运行时针对每个 Token 的显存占用就只剩这个 1*512 的向量,只有原来的 3%。

一个完整的对比如下图所示,原先的 MHA 需要 Cache 完整矩阵,而 MLA 只需要 Cache 中间压缩后的一个向量,再还原出完整矩阵。


这一切真的这么美好嘛?让我们想想 KVCache 的最初目的是什么,是为了减少 Token 的重复中间计算,MLA 虽然压缩了 KVCache,但是每次还需要一个解压操作,计算量又回来了。

这里就是一个更精彩的故事了,按照 Transformer 的计算,中间的 Cache 乘一个解压矩阵后还要再乘一个输出矩阵得到最终的结果,可以粗略理解为最终计算的公式是 Cache * W解压 * W输出 ,根据矩阵计算的结合率,可以先计算后两个矩阵的乘积,将后两个矩阵融合乘一个新的矩阵。由于 W解压 和 W输出 在训练后是确定的,因此做个简单的后处理把这部分提前算出来就好了。作者在论文中也用 Fortunately 来形容这件事情。

也就是说我们最初是出于压缩 KVCache 的思路去做了压缩和解压,但在实际推理过程中根本不存在解压的过程。在大幅压缩了显存的同时由于过程中的矩阵都变小了,推理所需的计算量也变小了。

模型能力

但在这里我其实还有个疑问没有解开,本质上 MLA 是用两个小矩阵相乘得到一个大矩阵,但是并不是所有的大矩阵都能完美分解成两个小矩阵。MLA 实际的搜索空间是小于 MHA 的,理论上来讲 MLA 的模型能力应该更弱。但是按照 DeepSeek 论文里的评测,MLA 的模型能力是要略强于 MHA 的。

这个事情其实就不太好理解了,我倾向于认为 MLA 虽然搜索空间降低了,但是最优解的概率反而变大了,收敛到了一个相比 MHA 更优的解。另外虽然 MLA 的优化是从 MHA 出发,但最终的结果其实是一套全新的注意力机制,模型的架构都发生了很大的变化,或许 DeepSeek 真的发现了一个更有效的注意力机制。

总结

有不少性能优化方案其实是在玩跷跷板游戏,比如用 GPU 计算时间交换显存空间,或者牺牲模型能力来换成本下降。而 MLA 在把显存打脚踝斩的情况下同时还做到了计算需求下降和模型能力提升,简直匪夷所思。

另一个感触是在经历了国内移动互联网时代的我们很容易认为价格战就是要赔本赚吆喝,却忘了技术创新才应该是那个最大的杠杆。

这篇博客只是介绍了 MLA 最核心的理念,在实际应用中还有很多具体的问题,例如:如何处理旋转位置编码?K 和 V 的解压矩阵融合其实略有不同,一个是直接应用结合律,一个是转置后再结合,等等。还是建议大家阅读 DeepSeek V2 的原始论文,有这篇文章做基础应该容易理解很多。

博客里部分图片源自 DeepSeek-v2 MLA 原理讲解,也建议大家看下这个视频。