eBPF on Go

本篇内容是根据2021年10月份#201 eBPF and Go音频录制内容的整理与翻译

eBPF(已有 7 年历史)是一个可以在 Linux 内核中运行代码的沙箱。它最初是一种构建防火墙的技术,随着时间的推移不断发展,包含一系列新功能。

本期大家讨论了 eBPF 的起源及其工作原理,并深入研究了一些实际用例。虽然 eBPF 程序本身不是用 Go(更像 C)编写的,但我们将了解如何从 Go 代码与 eBPF 程序进行通信。


过程中为符合中文惯用表达有适当删改, 版权归原作者所有.


Mat Ryer:大家好,欢迎来到 Go Time。我是 Mat Ryer,今天我们要聊聊 eBPF。eBPF 是一项技术,它允许你在沙盒中安全地运行程序,而不需要更改内核、代码或安装模块等。这通常是解决诸如网络、安全或可观察性问题的理想之地,因为内核控制一切,它能看到一切……所以可以说它非常完美。但是,由于它是一个如此核心的组件,意味着它实际上很难更改。设想一下你自己的代码,如果你有一个核心服务或其他系统的依赖项,你就会明白这种情况有多难更改;而当你无法更改某些东西的时候,你就无法在这里进行创新。

这通常就是更改内核的故事---它基本上是不可行的,直到 eBPF 出现,似乎改变了规则。让我们更多了解它吧,因为我们现在就做一期关于它的节目。今天和我一起的有 Derek Parker。你好,Derek!

Derek Parker:你好。

Mat Ryer:Derek,你创建了 Delve,对吧?你直接就创建了 Delve…

Derek Parker:是的,没错。

Mat Ryer:是的。而且你现在是 Red Hat 的高级软件工程师,没错吧?

Derek Parker:是的,没错。

Mat Ryer:非常酷。欢迎来到 Go Time。我们还邀请到了 Grant Seltzer。Grant 是 Aqua Security 开源工程团队的一员。

Grant Seltzer Richman:是的。

Mat Ryer:他住在纽约市布鲁克林。那是个很酷的地方。感谢你加入我们,Grant。

Grant Seltzer Richman:谢谢你邀请我。

Mat Ryer:荣幸之至。荣幸是我们所有人的,一半是我的,一半是---Johnny Boursiquot 也在这。你好,Johnny。

Johnny Boursiquot:你好,兄弟。我在这儿准备问一些关于 eBPF 的愚蠢问题。

Mat Ryer:哦,很好,很好,这样我就不用问了。

Johnny Boursiquot:我会让你看起来很棒。我会问所有的---

Mat Ryer:是的。[笑] 我其实刚才只是从 Wikipedia 上写了这个介绍,兄弟。接下来的---今天我是冒牌货。我不介意这些我不太懂的主题,因为我真的可以深入探讨,并且总能学到很多,尤其当我们邀请到像今天这样的尊贵嘉宾时。

那么,谁愿意给我们讲讲 eBPF 的背景?它从何而来,究竟是什么?

Grant Seltzer Richman正如你所说,eBPF 是一项技术,它允许你编写一些小片段的代码,然后把它们放入 Linux 内核中的特定位置,在某些钩子触发时运行。所以你可以把它看作是为一个网络服务注册一个 webhook;同样的,你也可以为你的实际系统做这件事。这些小片段---你可以把它们看作是脚本;这些响应的事件可以是内核函数被调用,比如 Linux 内核源代码中的某些事件。你可以将它们附加到函数上,诸如此类的事情……你可以将这些 eBPF 程序附加到网络套接字上,让它们对进出数据包作出响应。你还可以将它们附加到用户空间函数上,所以如果你在运行一个编译好的 Go 程序,一些服务,即使是长时间运行的服务,你可以将它们附加到实际的---其实你并不是附加到源代码上,而是附加到你编译后的二进制文件中的符号,这些符号对应于实际的函数。你可以让 eBPF 程序对此作出响应。 这是 Derek 肯定可以阐述的东西。

Johnny Boursiquot:等一下---我说过我要问一些愚蠢的问题。让我用一个对我来说更简单的方式说你刚才说的内容……

Grant Seltzer Richman:当然。

Johnny BoursiquoteBPF 就像---内核就像 HTML,而 eBPF 就像你的 JavaScript……当有人点击 HTML 上的按钮时,你的 JavaScript 可以对该事件的发生作出反应。

Grant Seltzer Richman:完全正确。这是很多人---我想这个类比最早是 Brendan Gregg 提出的,但这是人们喜欢解释 BPF 的经典方式。这个类比非常好。

Johnny Boursiquot:那它只是一个观察工具吗?你只能监听事件,还是可以更改事情?

Grant Seltzer Richman:不,你实际上可以更改事情,你可以作出响应。当然有一些限制,因为安全性肯定是一个问题……你不希望能够随意在运行的操作系统中放入任何东西,尤其是在生产环境中……但是的,你可以做很多事情。你可以采取行动,阻止某个进程的发生……在网络路由的情况下,你可以按照自己的意愿重新路由数据包……

Johnny Boursiquot:我的各种警觉感官都在作响,不过我们稍后再谈……[笑]

Derek Parker:是的,我见过纯 eBPF 的负载均衡实现,我觉得这非常酷,也非常有趣。而且关于 eBPF 程序本身的另一个有趣之处是---你基本上用 C 语言编写它们,但这就像是简化版的 C。与典型的 C 编译器作斗争不同,你得和 BTF 验证器作斗争,它会抱怨“你不能在 BPF 程序中使用循环。”你需要非常小心地分配栈空间,因为有非常严格的要求……因为它必须是安全的,毕竟它运行在内核中;即使它是在沙盒中运行,程序仍然必须终止,所以你不能有循环等验证器无法验证程序是否会实际终止的情况。

因此,在编写程序时,为了绕过这些限制,你需要做一些有趣的事情。

Mat Ryer:这些事情是得到内核许可的吗?这是内核明确允许的,还是某种对内核进行的操作?

Grant Seltzer Richman:BPF 确实存在于内核中。它是 Linux 内核的一部分虚拟机,伴随所有系统发布。在加载实际程序以及程序能做什么方面,是有权限体系的。你必须有 root 访问权限,或者加载 BPF 程序的进程要有特定的能力。

Mat Ryer:对。所以你不能对任何内核都这么做。这是一项明确支持的技术。

Grant Seltzer Richman没错。你不能在 macOS 上这样做。这是特定于 Linux 的。而且所有 Linux 发行版都支持它。还有一些我无法详细说明的事情,不过微软确实有在努力将 BPF 移植到 Windows 上。

Derek Parker:是的,我也听说过很多,但我没有在 Windows 上开发,所以我不清楚它的状态……不过我觉得这很酷,因为---看到 Linux 中的一些创新传播到其他地方很棒。我真希望我们能在 macOS 上进行更多原生的容器化工作,而不是“哦,我们赶紧安装个 Linux 虚拟机,假装我们在 macOS 上做容器化工作,但实际上并没有。”如果微软真的在内核中采用这种技术,我觉得这很酷,而不是---我不知道这是否真的是在内核中,还是他们在幕后通过“WSL赶快把你的 eBPF 程序传那边”来做。

Grant Seltzer Richman:我认为它目前是基于用户空间的,但我不想误解……不过我觉得你说的没错。我觉得如果防作弊软件能够通过 BPF 程序检测到发现的新作弊手段,并应用于 Windows 上的游戏,那会非常酷。

Derek Parker:就像是---叫什么来着,Punk Buster 吧?这是一些大型游戏的防作弊系统……像 Punk Buster eBPF 版。

(译者注: 是一款游戏防作弊软件,通常被玩家简称为PB)

Grant Seltzer Richman:是的。没错。

Johnny Boursiquot:我试图将用户空间、内核空间等概念可视化……对于那些仍在努力理解的人来说---通常当你和我用我们喜欢的编程语言写程序时,比如 Go,我们写的是用户空间程序。当它们需要在操作系统级别做某些事情时,它们会发出系统调用,比如“嘿,我想打开一个文件。”

对我们来说,开发者是使用标准库。Go 会说“嘿,我想打开这个文件,因为我想读取内容”或其他操作。所以这是一个系统调用,然后操作系统会处理所有的事情,接着返回结果给我们。但这一切都发生在用户空间,对吧?而我们现在讨论的是编写程序的能力,让它们在内核空间中运行。这就深入了一层,实际上能监听、响应,甚至可能更改内核正在做的事情。

Grant Seltzer Richman:完全正确。这样做有很多优势。让我们以系统调用为例,事件的流程是你的 Go 程序尝试写入一个文件;在底层,Go 的标准库使用的是 write 系统调用。在系统调用之前,你的 Go 程序会把所需的信息放到正确的寄存器中,然后执行系统调用指令,内核接管,执行系统调用,返回用户空间,告诉你“嘿,我们成功写入了文件”或其他信息。

在 eBPF 的世界中,你可以写一个 eBPF 程序,它在每次调用系统调用时触发。所以如果你有一个 eBPF 程序,它在每次 write 系统调用被调用时触发……所以在原始事件流程上增加了一步,Go 程序设置系统调用,执行它……就在执行之前,eBPF 程序运行;它可以检查传递给系统调用的所有参数,并做任何它想做的事情……一旦它完成了,系统调用执行,然后返回到用户空间,等等。而 BPF 这一边对实际触发它的应用程序是完全不可见的。

Johnny Boursiquot:有意思。

Mat Ryer那么它是作为一种后台进程运行在主要任务的旁边,还是一种阻塞代码?当它看到某个调用时,它到底是如何运行的?

Derek Parker:如果探针附加在某个函数或类似的地方,它会阻塞。在那个时刻,触发探针的程序执行将暂停,以便 eBPF 程序可以执行任何需要的检查。这也是为什么在追踪的上下文中---这是让我对 eBPF 感兴趣的地方---涉及到系统调用的开销以及追踪的总体开销。

类似的事情也会发生---我对它感兴趣的原因是我想让 Delve 的追踪后端更高效,减少开销,这样你也许可以在生产环境中使用它。我曾经发过一条推文,当我刚开始研究这个时,我展示了它增加的开销。我有一个程序,运行时间是一些奇怪的微秒数… 然后使用基于 eBPF 的追踪,它从大约 20 微秒增加到了 300-400 微秒左右… 这听起来像是一个显著的开销,但我们谈论的是微秒。

然后我使用 Delve 之前基于 ptrace 的追踪进行了计时,时间增加到了 2.3 秒。所以你从微秒增加到实际的秒,这种开销在生产环境中是不可接受的。这让我对它产生了兴趣,写出一些非常小型、目标明确的程序,它们可以作为某些事件的结果被调用,不会在内核和用户空间之间进行上下文切换,尽可能短的时间内暂停程序,获得高效、详细但又灵活的追踪数据。

另一个难点是如何实现灵活性。很多时候,当人们编写 eBPF 程序时,它们非常有针对性。你在编写函数时已经知道它会附加到哪个对应的函数上;可能是内核函数,或者其他函数……你通常已经知道,所以你大概知道要期待哪些参数。但在 Delve 的情况下,我有点滥用了它,因为我想将探针附加到完全随机的函数上,我不知道它有多少参数或返回值。我对它一无所知,但我想从中获取所有信息。我该怎么做呢?

这引发了很多问题,比如如何编写一个通用的 eBPF 程序,以及如何在不引入我试图消除的慢速问题的前提下,在内核空间和用户空间之间进行通信。

Johnny Boursiquot:你之前提到你使用了一种受限的 C 语言;显然出于性能原因,有些事情是不允许的。那么开发流程是什么样的?如果我要使用 eBPF,我必须用 C 吗?还是有包装器或 SDK?开发流程是什么样的?

Grant Seltzer Richman:eBPF 程序本身,从高层次来看---实际上就是这样,你有两部分。你有 eBPF 程序本身,然后你有用户空间程序,它将 eBPF 程序加载到内核中,并监听反馈……本质上是与 eBPF 程序交互的代理。

在 BPF 这一侧,我的经验仅限于用 C 编写。我听说过有一个库可以让你用 Rust 编写实际的 BPF 程序,因为它的后端是 LLVM。LLVM 控制着 eBPF 字节码的规范,类似于 Windows 的 BPF,不过我对此一无所知,不想详细讨论……而且 Rust 是竞争语言,所以我们不能讨论它……

Mat Ryer:[笑]

Grant Seltzer Richman:是的,你用 C 编写 BPF 程序,所以大多数情况下你只是在将这些定义在 BPF 世界中的 helper 函数串联起来。它们是定义在头文件中的 BPF helper 函数,使用起来并不复杂。如果你是 Go 开发者,这不会花太长时间让你上手,尤其是看看例子……而且有很多入门指南。

在用户空间这一侧,你可以用多种语言写程序。你可以使用 C 标准库,它叫做 libbpf。还有一个项目叫做 BCC,虽然不推荐使用,但它可以让你使用 Python 或 Go 版本,甚至还有一个旧的、不再维护的 Lua 版本,当然也有 Rust 的版本。用 Go 也有很多不同的库可以使用。我偏好一个叫做 libbpfgo 的库,它是 libbpf 的包装器。还有一个 Go 原生实现,它是 Cilium 项目的一部分……但我维护 libbpfgo 并在我帮助维护的项目中使用它,所以我偏好这个。

Johnny Boursiquot:你有点偏心。

Grant Seltzer Richman:是的,我对此很坦诚。

Johnny Boursiquot:显然你提到这是个 Linux 专属的东西,除了正在进行的 Windows 版本……所以如果我在 Mac 上需要编写这些程序,我得用某种虚拟机来测试和运行它们。

Grant Seltzer Richman:是的,暂时如此。

Derek Parker:我记得以前有 DTrace,用于 Darwin 内核,类似的东西。

Grant Seltzer Richman:是的,macOS 有一个---我不记得确切名字,但最近版本的 macOS 有一个类似的安全框架,不过它们之间没有互操作性。



Johnny Boursiquot:我们来谈谈使用场景吧。我对 eBPF 程序的最佳应用场景很感兴趣。我们谈到过可观察性,知道某些事件何时发生,Derek 提到这是一个非常有针对性的工具,对吧?所以你已经知道想要获取哪些系统调用的回调,除了你想获取所有信息的情况……我猜这种情况下写这些程序的方式会非常不同,而不是只是寻找某个文件是否被打开,或者类似的事情。

所以我很好奇使用场景……我听说过可观察性,似乎是个不错的用例……我还听说过网络故障排查、写负载均衡器的情况,我对这方面尤其感兴趣……eBPF 能帮你解决哪些问题?你在解决哪些问题?

Grant Seltzer Richman:当然。我最常用的场景是安全性。我帮助维护一个叫做 Tracee 的项目,它挂钩到数百个不同的事件,试图关联所有这些在内核中发生的事情,以确定是否有入侵或恶意软件……它允许你在上面应用策略,做一些很酷的事情,比如当程序或进程被执行时,尝试捕获实际运行的二进制文件以供以后检查……你可以做很多安全方面的事情。

可观察性---你可以在生产中使用 BPF 来确定你的 web 服务的健康状况。你可以附加到网络套接字或某种网络机制上……BPF 支持多种机制,以确定丢包数量或数据包的路由位置;你可以通过这种方式获取大量信息。

Johnny Boursiquot:我们谈论的这种可观察性,和我们现在常用的术语“可观察性”有些不同。我们通常想到的可观察性是“我需要一个仪表盘,我需要 Honeycomb 或 DataDog,看我的服务是否运行,延迟是多少”等等。而我们现在谈论的是一种不同层级的可观察性,没错吧?

Grant Seltzer Richman: 是的,确实不同。在大多数情况下,甚至可以说所有情况下,你可以访问到原始内存。你可以看到数据包的全部内容,或者用户空间程序的全部内存内容。不过即便你不检查内存,你仍然可以让这些 BPF 程序触发并报告“嘿,发生了这个事”,就像你在 Go 程序中添加一行代码,然后重新编译并运行它一样……比如 println,而不是编辑源代码并重新编译,你可以添加一个 BPF 程序,附加到内存中的某个地方,看看某行代码何时执行。这就是 Delve 所做的。

Mat Ryer:那么我们需要自己编写所有这些东西吗?是否已经有一些现成的工具?有没有工具可以监控内存分配,比如收集到 Prometheus 中并显示在仪表盘上?有没有现成的工具在围绕这个技术发展?是否有一个生态系统?

Derek Parker:是的,我知道有一些工具---从系统管理员的角度来看,Grant 之前提到的 Brendan Gregg,来自 Netflix,他是 DevOps 的专家……他有一整套基于 eBPF 的工具、脚本和单行代码,可以用来检查系统。我记得他有一篇很棒的博客,介绍如何在五分钟内调试生产问题,里面也提到了很多基于 eBPF 的脚本和工具。

但我觉得你提到的问题是这些工具的产品化,以及如何将它们集成到指标收集系统中……我知道在这个领域有很多努力正在进行。

Mat Ryer:是的,这很有趣。那么当你说在生产环境中运行这些东西时,是不是需要提前计划、启用、构建功能?还是可以直接附加到正在运行的进程上?因为它是在内核中;几乎在所有进程的底层。

Derek Parker:是的。我认为大多数准备工作在于确保你有一个可以加载这些程序的内核,我认为只要你运行的是现代内核,应该没有问题。但在用户空间程序方面,你不需要做任何协调。你只需要与内核协调,并让你正在运行的程序加载 eBPF 程序。但你不需要与用户空间程序进行协调。对于 Delve 或类似的工具来说,这就像是一个普通的调试会话,我们只是请求内核允许我们做一些事情,程序不需要参与决策。

Mat Ryer:是的,这很有趣。这对于调试或任何类型的检查都非常有用;你几乎不需要额外运行任何东西……我可以理解为什么会有一系列单行代码工具,因为这在工具箱中非常有用。非常有趣。我们会尝试找到它并把链接放在节目笔记中。这听起来非常有趣。至少我们可以看到一些真实的 eBPF 程序示例。

Grant Seltzer Richman:是的。我还想补充一下,关于之前的问题,关于生态系统……我会说,如果这项技术让你兴奋,或者说拥有这种可见性让你兴奋,但你可能会被吓到,甚至不想自己编写 eBPF 代码,实际上有一个正在发展和成熟的生态系统围绕着这个技术。许多产品正在开发中,以获得这种可见性。

另外,你完全不需要重新编译代码,这对 SRE 或安全人员来说非常好用。你可以运行服务并在不重启服务的情况下,编写 BPF 程序,检查不同的内存区域,这非常有价值。

Mat Ryer:那么稍微高层一点的呢?比如你是一个 web 开发者,想实现文件监控,自动重载的功能。你能不能写一个 eBPF 程序监控某个路径下的文件变化,然后采取行动,提醒你刷新?

Grant Seltzer Richman:是的,绝对可以。我觉得 Derek 说得很好,Brendan Gregg 有很多工具可以非常出色地完成非常特定的任务。我记得有一个工具叫 OpenSnoop,它可以告诉你每次文件被打开时的信息。或者一个更强大的工具……我再一次推荐我参与的项目 Tracee,你可以运行它并获得所有你想要的信息,还可以过滤不同的事件,而无需编写 eBPF 代码。

Mat Ryer:那就是 Tracee,对吧?

Grant Seltzer Richman:没错,它在 Aqua Security 的 GitHub 上。

Johnny Boursiquot:顺便提一下,你和 Liz Rice 一起工作,对吧?

Grant Seltzer Richman:我曾经和她一起工作。她在我加入后不久就离开了,很遗憾……

Johnny Boursiquot:[笑] 我本来想问你和一位摇滚明星(我用了一个敏感词)……一位我们社区中知名且受人尊敬的成员一起工作是什么感觉?[笑]

Mat Ryer:……她还玩摇滚。

Johnny Boursiquot:她还玩摇滚。[笑声]

Grant Seltzer Richman:当她在的时候感觉很棒。我在社区里仍然经常与她互动。她为 eBPF 社区做了很多工作,所以我仍然常与她合作。

Mat Ryer:你是说她在你加入后就离开了,还是之前?

Grant Seltzer Richman:在我加入后不久。我可能把她吓跑了……[笑声]

Mat Ryer:很可疑。这是个可能性,是吧?我就是这么想的。

Derek Parker:Johnny,你之前提到对我提到的基于 eBPF 的负载均衡感兴趣……

Johnny Boursiquot:是的。

Derek Parker:我知道 Liz Rice 做过一次关于如何实现负载均衡的非常好的演讲。如果你感兴趣,我强烈推荐你去找找她的演讲,真的非常棒。

Johnny Boursiquot:我会去找的,谢谢你。

Mat Ryer:很酷,我们也会找到并把它放在节目笔记中。

Grant Seltzer Richman:eBPF 周围有一个很棒的社区。虽然有很多东西需要学习,也有很多让人困惑的地方,但整个生态系统真的在不断发展,变得越来越容易接触……有很多人对它感到兴奋,并且乐于提供帮助。如果你访问 eBPF.io,那上面有一个 Slack 频道,你可以加入,非常有帮助。而且有很多相关的演讲……Derek 和我即将参加一个会议发表演讲。学习资料可以说是丰富多样。

Mat Ryer:是的。那么这个社区主要在哪里?是不是都集中在那个 Slack 频道里?如果有人想参与,eBPF 的社区还存在于哪些地方?

Derek Parker:我认为 eBPF 的技术,尤其是在云原生和 CNCF(云原生计算基金会)领域非常流行;云原生、Kubernetes 生态系统是社区主要的聚集地。此外,它也涉足了一些编程语言社区,针对那些想要实现相关功能的人们。但总体而言,大部分兴趣和社区活动都集中在云原生领域。

Johnny Boursiquot: 我在短暂了解 eBPF 的过程中,发现大多数示例似乎都围绕着 BCC(BPF Compiler Collection),主要用 Python 编写。我看过一些这样的例子,当时我心里想,“好吧,我们在这里写了一些 Python 代码,然后在某个地方插入了一大段 C 代码……” 我们可以看到代码中的钩子,但这让我回想起之前提到的开发体验。我很好奇,在 Go 中编写这些程序的体验是什么样的?在 Go 生态系统中,你通常用哪些库来与这些程序交互并编写它们?

Derek Parker:我先来回答这个问题……我也要为 libbpfgo 框架做个宣传,因为我在 Delve 中使用它来实现基于 eBPF 的追踪后端。对于编写和加载 eBPF 程序并将其应用到 Go 程序中,已经有非常不错的工具。不过在某些 eBPF 特性上与 Go 结合时会遇到一些挑战……回到正题,毕竟这是 Go Time 播客……例如,当你在 Go 程序中使用探针时可能会遇到一些棘手的情况,有两种探针。对于用户空间探针,有 uprobes 和 uretprobes。uprobes 可以附加到函数的入口点,而 uretprobes 则附加到函数的返回点。因此,你可以在函数入口和返回时分别进行钩取。

但这在 Go 中非常棘手,因为 uretprobes 的工作机制是修改一些数据,比如 goroutine 栈上的某些地址。如果你不熟悉,goroutine 的栈通常非常小,并会随着时间增长。而在栈增长过程中,Go 运行时需要遍历栈中的指针,移动它们并进行更新等操作。

所以,如果你不小心使用 uretprobes,可能会导致 Go 程序崩溃,因为当 Go 运行时试图复制栈时,会发现一个它无法识别的地址,然后程序就会崩溃。

在 Delve 中,我们不得不做一些非常巧妙的事情,用 ptrace 监控 Go 运行时何时准备复制栈,然后临时取消 uretprobe,让它完成操作后再重新附加探针。因此,涉及到 Go 运行时时需要多加小心。对于带有运行时的语言,或者像 Go 这种自检查的语言,使用 uretprobes 可能会带来一些奇怪的问题,这也是你在做这些低级别探查时需要注意的地方。

Mat Ryer:是的,我相信遇到这种崩溃会非常奇怪。如果你有一个小型的 eBPF 程序,它可能会发出一些有趣的信息,例如统计内存分配之类的,那你该如何提取这些信息呢?首先,这些信息会存储在哪里?eBPF 程序有自己的内存吗?Go 程序如何获取这些信息?

Grant Seltzer Richman:当然。也许我们在讨论 BPF 程序时遗漏了一个关键点,那就是 BPF 程序到底能做些什么。BPF 程序主要与各种形式的映射(map)交互;就像 Go 中的 map 一样,BPF 中也有不同类型的映射,你可以用它们来存储信息。这些 map 可以在用户空间和内核空间之间共享,或者在多个 BPF 程序之间共享。

例如,你可以有一个环形缓冲区(ring buffer),假设你有一个简单的 BPF 程序,它在每次某个函数被调用时触发,或者每次触发一个系统调用。在这个 BPF 程序中,你可以创建一个小消息,比如“系统调用被触发了”,然后将这个消息放入一个字符串中,使用环形缓冲区发送到用户空间。在用户空间中,你可以有一个 goroutine 来监听这些事件并将它们打印到屏幕上。这些缓冲区和映射使得在用户空间和 BPF 程序之间可以共享内存。

Mat Ryer:那么在 Go 端能否获得一个通道(channel)接口,可以通过 for range 来读取这些内容?

Grant Seltzer Richman:我会说是的,但这取决于你使用的库。实际上,底层的原语是不同的接口,但在使用 libbpfgo 的情况下,你确实可以得到一个通道。所以你可以像与其他 Go 程序一样与它交互。

Mat Ryer:这也包括发送数据吗?

Grant Seltzer Richman:发送数据有点不同,因为你是更新共享映射中的值。虽然有一个接口或 API 可以做到这一点,但环形缓冲区更适合从 BPF 向用户空间发送数据。

Mat Ryer:我明白了。所以这些 map 就像对象一样,它们是键值对。内核是否已经有了这种概念?或者这是 eBPF 模型化出来的?

Grant Seltzer Richman:不深入讨论不同特性的话---因为有很多我也不太了解的东西---eBPF 提供了对内核的可见性,这个概念并不新鲜,但它确实让事情变得更简单。

以前,可能你需要编写一个内核模块来实现的功能,那些模块没有太多安全保证,并且要求你重启,甚至有时候需要重新编译 Linux 内核,然后重启,整个过程耗时很长。而 BPF 让这一切变得更快、更安全,并且更容易接触。

Mat Ryer:是的,作为一个 Go 程序员,能够通过一个通道接收关于系统内部详细信息的实时数据,光是这种机制就足够让人兴奋了。因为谁知道你能构建出什么样的东西呢……我刚想到的一个用例是文件监控,但我相信,如果你能深入了解内核中的实际情况,可能会有很多其他的应用场景。

Grant Seltzer Richman:可能性是无穷的! [笑声]

Mat Ryer:是的,我对此感到非常兴奋。我们已经听说了很多关于 libbpfgo 的内容,我们一定会提供相关链接。我在查看仓库时,发现它确实提供了一个不错的 API。很有趣的是,即使使用这个库,我是否也可能会遇到我们之前提到的那些崩溃问题?如果我要编写这样的代码,是不是应该避免使用 goroutine?

Derek Parker如果你要在 Go 中使用 eBPF,我唯一建议避免的是 uretprobes,除非你非常非常清楚自己在做什么……因为几乎 100% 的情况下,它会导致你的程序崩溃。让它正常工作的唯一方法是做一些我们在 Delve 中做的那种奇怪的事情,这是一种非常复杂的小技巧。

Mat Ryer:这个技巧能不能打包成一个库呢?这个小技巧能不能一次解决所有问题?

Derek Parker这是有可能的……实际上,这个问题在 Delve 中的一个待处理的拉取请求里已经得到了解决。实现这个解决方案需要涉及很多东西,比如 Dwarf 知识(即二进制文件中的调试信息),使用 ptrace 并获得使用 ptrace 的权限,还要结合 eBPF……有很多组合在一起的东西,这些都不是典型的 Go 编程体验。所以这里确实有一些复杂的地方……但总的来说,除了 uretprobes,其他功能都可以安全地与 Go 一起使用。不过如果你使用 uretprobes,几乎肯定会导致问题。

Mat Ryer:它们通常会用来做什么?

Johnny Boursiquot:捕捉函数的返回值。

Derek Parker:对。

Mat Ryer:我明白了。所以如果你只需要读取数据,可以使用环形缓冲区之类的东西来实现。

Derek Parker:是的,从程序内部,uprobe 会触发并开始执行你的 eBPF 程序,而你的 eBPF 程序可以使用环形缓冲区或映射与用户空间通信。

Delve 同时使用了两者。它使用映射从用户空间向 eBPF 程序传递信息,然后使用环形缓冲区将 eBPF 程序生成的数据发送回 Delve。

Mat Ryer:我明白了。这真的很有趣。当我想到 Delve 时,我觉得它是一个非常底层的工具,因为我通常处理的是更大型的系统。但每次我深入研究时,我都会发现相似的层次结构,通常这些架构会更加复杂……我总是觉得这非常有趣。

Johnny Boursiquot:简单并不容易,伙计……

Mat Ryer:是的,绝对如此。

Mat Ryer:我想问一下,大家觉得 eBPF 的未来会怎样?我们是不是感觉这只是一个开始,未来会越来越令人兴奋?

Johnny Boursiquot:商业产品……这是下一个方向。商业产品。 [笑声]

Mat Ryer:这是下一步的发展吗?我们现在就可以开始创业了。我们四个。 [笑声] 就在 Go Time 上直播创业。不是 The Go Time,对吧?应该叫 Go Time。我刚才做了个像 The Facebook 那样的事。不过我觉得现在叫 The Go Time 反而更酷。

Johnny Boursiquot:The Go Time。

Mat Ryer:你懂我的意思吗?感觉我们已经绕了一圈。不过如果我们要创业,公司会是什么样子的?

Grant Seltzer Richman:我肯定会说这个生态系统正在成熟,或者说刚刚开始成熟,但还有很多用例尚未被发掘。libbpf 还没有达到 1.0 版本。我觉得现在有很多人正在进入这个社区,他们正在学习 BPF……内核这边也有很多讨论,关于 BPF 正在吞噬 Linux 的说法,甚至有人在讨论用 BPF 代码重写 Linux 内核的大部分内容,使其更加模块化。

比如调度器(scheduler),我们可以动态地将逻辑放入调度器中,改变我们调度进程的方式。当然,驱动程序也是另一个人们正在考虑的领域……但从一个更高的视角来看---我不想太过“思想领袖化”,但……

Johnny Boursiquot:请继续。请继续。

Grant Seltzer Richman:我忘了是谁在演讲中提到过这个观点,BPF 代表了一种新的软件范式,它让你能够动态改变软件与操作系统的交互方式。很难说 BPF 的未来会走向何方,因为 1)还有无数新的想法可以将 BPF 程序附加到不同的地方;2)有很多新的人才正在进入社区,带来了很多好点子,新的贡献者层出不穷……总的来说,这些想法几乎没有受到什么限制。就像问“Go 的下一个大事件是什么”,或者“你可以用 Go 写什么”一样,答案几乎是“任何东西”。不过也许 BPF 更酷一些。

Mat Ryer:好吧,这就引出了我们的常规环节……是时候进入“不受欢迎的意见”环节了。

Mat Ryer:Grant Seltzer,你有什么不受欢迎的意见要分享吗?

Grant Seltzer Richman:有的。我还想提一下,我可是这个环节的冠军……

Mat Ryer:真的吗?

Grant Seltzer Richman:我在这个节目上发表过有史以来最不受欢迎的意见。

Mat Ryer:是吗?你是说 eBPF 比 Go 更酷的时候吗? [笑声] 你打破了自己的记录。

Grant Seltzer Richman:我当时好像说的是关于棒球的。

Johnny Boursiquot:你想换个不受欢迎的意见吗?

Grant Seltzer Richman:不,我仍然认为棒球是最好的运动。但这次我不会试图超越自己。我不会说任何政治性的东西……不过我想说,我一直以来的观点是,工程团队里每个小组都应该有一个安全工程师。

Mat Ryer:真的吗?

Grant Seltzer Richman:我认为很多软件开发者,甚至是负责架构整个系统的人,在做决定时,如果能够有一个安全工程师的意见,或者是一个对安全有更多培训的开发人员的意见,对于整个组织的安全性会有非常大的帮助,而不是仅仅依赖一个在旁边的安全团队,他们只能对现有的基础设施抛出一些产品。

Johnny Boursiquot:所以在你看来,这与在产品发布前进行的一次安全审查不同?你说的是在我们构建软件时,团队中就应该有一个安全人员。

Grant Seltzer Richman:是的。

Mat Ryer:这有点像测试。以前测试几乎是独立于软件开发的一个环节,后来我们成为了测试驱动开发者,意识到编写良好测试代码是我们的责任……我们是不是正在走向一种“安全驱动开发”(Security-Driven Development,SDD)的模式?

Johnny Boursiquot:SDD。哦,我还以为你在说别的…… [笑声]

Mat Ryer:不,-驱动开发。DD。

Johnny Boursiquot:明白了。

Mat Ryer: 这真的很难做到,不知道为什么。写下来。我想我做到了。我觉得我们可以在剪辑中修复它。[笑声] 如果大家都同意的话,我很乐意继续下一个话题。

Derek Parker: 那样最理想了。

Mat Ryer: 设计系统时,安全性确实是你需要考虑的关键问题之一。你说得对,有时候你只需做一些设计决策就可以让系统更加稳健。例如,如果系统是幂等的,你可以多次重试某个操作,采取“宁可安全也不冒险”的原则,因为系统的设计方式确保不会因为重试而出问题。同样的做法也适用于安全问题。通过做出某些设计选择,你自然会让系统更加安全。所以,这确实是个有趣的话题……我们一定要在 Twitter 上测试这个观点。虽然我们也可以在 Facebook 上测试,但我想我们都知道为什么不这样做……

Grant Seltzer Richman: 哈哈。

Mat Ryer: 因为我们永远也看不到测试结果……

Derek Parker: BGP,和 BPF 不同。

Johnny Boursiquot: [笑声]

Mat Ryer: 哦,是吗?这就是我们做这个节目的原因……[笑声] 哦,不……!

Johnny Boursiquot: 这个澄清很及时,的确如此。

Mat Ryer: 我犯了个错误。好吧,非常有趣……Johnny,你怎么看?你觉得团队里有安全专家是什么感觉?

Johnny Boursiquot: 我并不反对。很难反对这个观点。

Mat Ryer: 说实话,很难反对任何关于安全的观点。你不能成为那个在房间里说“我觉得我们应该少关注安全”的人。[笑声] Derek,今天你有什么不受欢迎的观点吗?

Derek Parker: 有的。上次我没有发表什么观点,我紧张了。但这次我有一个。虽然没有 Grant 的观点那么发人深省。

Mat Ryer: 也没有那么戏剧性,毕竟你这次没紧张得说不出话来。[笑声] 这个环节的戏剧性正是来源于大家的紧张感。

Derek Parker: 最近我在写 Go 代码和 eBPF 代码之间来回切换,这让我回到了很多 C 语言的编程中。所以我的不受欢迎的观点是---蛇形命名法比驼峰命名法更好。[笑]

Johnny Boursiquot: 哇哦。

Mat Ryer: 那么,对于那些不熟悉这两种命名法的人来说,能解释一下它们的区别吗?

Derek Parker: 蛇形命名法是这样的:word_another_word_another_word,而驼峰命名法是这样的:wordAnotherWord……Go 语言通常使用驼峰命名法,而 C 或 Rust 通常使用蛇形命名法。我个人觉得蛇形命名法看起来更好,也更易读。我不知道,驼峰命名法总给人一种词语混在一起的感觉,而蛇形命名法看起来更像一个句子……我觉得它看起来更好。

Mat Ryer: 这个观点挺有意思的。那在 Twitter 上的标签(hashtag)呢?你会用蛇形命名法来写标签吗?

Derek Parker: 我通常都全用小写。我会把字符串转成小写后写标签。

Mat Ryer: 把字符串转成小写。

Derek Parker: 对。

Mat Ryer: 那你会用 eBPF 来处理这个问题吗?比如在发推之前改掉它?[笑声] 不过据说这其实是一个无障碍访问的问题,全用小写对屏幕阅读器来说不太友好。我之前在电脑上故意输入很多无意义的东西,让电脑读出来,我玩了好几个小时。

Derek Parker: 是的,是的。

Mat Ryer: 是的,基本上就是在模糊测试 say 命令。

Derek Parker: 确实,SSH 到别人的电脑上,然后用 say 命令输入一些随机的内容,乐趣无穷。[笑]

Mat Ryer: 哦,是的,确实有趣。

Derek Parker: 但通常我会保持单词简短,用一个词的标签,这样希望不会影响可读性。

Mat Ryer: 但蛇形标签会解决这个问题,不是吗?

Derek Parker: 没错。

Johnny Boursiquot: 虽然看起来有点可疑,但的确如此……

Derek Parker: [笑声]

Mat Ryer: 看起来是有点奇怪。我以前用 Ruby 编程时,标准输入(STDIN)也使用蛇形命名法,比如下划线分隔词汇……是啊,我也不知道。

Johnny Boursiquot: 俗话说,“入乡随俗。”

Grant Seltzer Richman: 有一年在 GopherCon 上有一个非常有趣的演讲,讲的是如何编写更易于访问的 Go 代码,或者说通用代码,其中的一部分就是让代码更容易被屏幕阅读器读取。当 Derek 提出他的观点时,我就在想这个问题。我觉得蛇形命名法可能比驼峰命名法更容易让屏幕阅读器读取。

Mat Ryer: 是的,可能是这样吧。不过 Derek,你的观点能走到多远?你会给你的孩子起蛇形命名的名字吗?

Johnny Boursiquot: 你还在考虑这个问题吗?[笑声]

Derek Parker: 是的,确实是这样。我最小的孩子叫 Davie_,你知道的……[笑]

Mat Ryer: 我真迫不及待想见到第一个给孩子起这种名字的工程师,比如名字中带下划线之类的。我会非常喜欢。

Derek Parker: [笑]

Mat Ryer: 这个观点不错。那么,Johnny,你接受这个观点了吗?

Johnny Boursiquot: 我做过一些 Ruby 编程,所以我对下划线的可读性非常熟悉,但既然这是 Go Time 播客,我们谈论的是 Go,我得说“不,我不喜欢这个观点。”

Derek Parker: [笑声]

Mat Ryer: 但 Derek,你在写 Go 代码时会用下划线吗?

Derek Parker: 不会……

Mat Ryer: 你真的会在 Go 代码里用下划线命名吗?

Derek Parker: 不会,不会。我还没那么怪。

Johnny Boursiquot: 他知道该怎么做。

Mat Ryer: 那如果你真的这么做了,代码会变成什么样子?会有多糟?

Derek Parker: 我觉得问题出在大写的蛇形命名法让我觉得非常别扭。它在 Go 里行不通,因为大写字母表示导出功能---比如蛇形命名中的首字母大写……这就完全不对劲了。这不对劲。

Mat Ryer: 所有的东西在成为“标准做法”前看起来都不对。

Derek Parker: 对,没错。[笑]

Mat Ryer: 这就是一种趋势。其实没有什么问题。我现在就去试试看,看看是什么样子。嗯,我感觉不太好。我感觉有点恶心。太糟糕了。对……不过这个观点确实不错。我喜欢这种观点。Johnny,你最近有不受欢迎的观点吗?

Johnny Boursiquot: 我的不受欢迎的观点就是,我永远也想不出一个不受欢迎的观点。

Mat Ryer: 是啊,我知道。因为你太受欢迎了。

Johnny Boursiquot: 每个观点最终都会变得很受欢迎,所以我厌倦了不受欢迎的观点,因为它们总是变得很受欢迎。

Mat Ryer: 这太有深意了。你不受欢迎的观点似乎是“我们不应该继续这个环节。”[笑声] 有趣的是,当我们把这些观点发到 Twitter 上时---我真的认为 Grant 是记录保持者,因为……大多数时候,人们会同意这些观点。通常,大家的论点都很有力。

Johnny Boursiquot: 现在我更关注的是有多少人持不同意见的比例。我试图弄清楚究竟有多少人倾向于某个观点。这比去说“哦,这个观点非常不受欢迎”更有趣,因为这种情况不常发生。

Mat Ryer: 是的,确实不常发生。这非常有趣。好的,我们快结束了。我想快速做一个“喊出”(shout-at)环节……这就像“喊出”(shout-out),但我第一次做的时候说错了……

Johnny Boursiquot: 是的,你是在喊着叫。

Mat Ryer: 所以现在变成了“喊出”(shout-at)……我们要“喊出”一个特定的线下活动。今天我要“喊出”的是 Meetup.com 上的 GDN 页面。网址是 meetup.com/pro/go。在那里你可以找到很多资源、本地线下活动、附近的 Gopher 社区,你可以去认识并交流……谁知道呢?你可能会在那里找到对 eBPF 感兴趣的人,然后你们可以一起讨论并加入进来。看看你能否构建一些很酷的东西。

Johnny Boursiquot: 对于那些不知道的人来说,GDN 代表 Go Developer Network(Go 开发者网络)。这是所有 Go 线下活动和事件背后的元组织,甚至包括 GoBridge 等等。它是幕后团队的幕后团队。

Mat Ryer: 是的,它有很多成员。截至目前有 117,000 名成员……你可以成为其中一员;如果你已经是其中一员,你可以让这个数字再增加一个。

Johnny Boursiquot: 是的,加入 GDN,我们会把你的会员证信息邮寄给你。开玩笑的,没有会员证。

Mat Ryer: 我刚才还很兴奋呢。我在想“我要加入这个组织。”

Johnny Boursiquot: [笑] 我们不是发放执照的组织。

Mat Ryer: 哎……这样还有什么意思?我本来想加入的。如果没有徽章……

Johnny Boursiquot: 你想要证书吗?

Mat Ryer: 一个小银色的 Gopher 徽章,你可以到处炫耀,还能享受半价优惠。

Johnny Boursiquot: 我可以私信你我的地址,你可以给我寄张支票……

Mat Ryer: 好吧。那你会给我做个 Gopher 警徽吗?

Johnny Boursiquot: 是的,我会给你画个涂鸦,然后寄给你。

Mat Ryer: 它上面会写“治安官 Mat”吗?[笑声]

Johnny Boursiquot: 你可以做治安官,Mat。你可以做治安官。

Mat Ryer: 我们应该这样做。我们应该在社区里设立等级制度。

Johnny Boursiquot: 等级制度?我们在哪里?[笑声]

Mat Ryer: 是的,是的,现在就像警察部队一样。

Derek Parker: Go 开发者部队,对吧。

Mat Ryer: 对。现在就像政府机构一样。“Mat Ryer,GDN。” 这听起来像一个新闻组织。Johnny,这是它的主页吗?你似乎对此很了解……

Johnny Boursiquot: 是的,这是入门页面。

Mat Ryer: 你怎么知道这么多?

Johnny Boursiquot: 哦……我认识一些认识一些人的人。

Mat Ryer: 听起来像是个可疑的组织。[笑声] “我认识一些认识一些人的人……” 就像,“哦,你这 GitHub 账号不错。真是可惜,如果它出了什么事……” [笑声]

好吧,今天的时间差不多了。希望你喜欢这次关于 eBPF 的深度探讨。非常技术性,也非常有趣……而且相当令人兴奋。我确实想看看 Gopher 们将用它构建什么。我认为这里有一些令人兴奋的机会。如果你用它构建了什么有趣的东西,请发推告诉我们 @GoTimeFM,我们很想听到你的故事。

非常感谢今天的嘉宾。Derek Parker,Grant Seltzer---总是很高兴和你们一起交流。你们一定要再来。当然,还有 Johnny Boursiquot……还有我。就这样吧。再见!

这可能不是我最专业的结尾,但……[笑声] 就这样吧。现在我们要播放结束曲了。

Johnny Boursiquot: 是的。

Mat Ryer: 再见……

Johnny Boursiquot: 再见。



更多参考:

libbpf

libbpf/libbpf

深入浅出 eBPF 安全项目 Tracee

bcc 之opensnoop 工具的使用

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/472853.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Linux驱动开发第2步_“物理内存”和“虚拟内存”的映射

“新字符设备的GPIO驱动”和“设备树下的GPIO驱动”都要用到寄存器地址,使用“物理内存”和“虚拟内存”映射时,非常不方便,而pinctrl和gpio子系统的GPIO驱动,非常简化。因此,要重点学习pinctrl和gpio子系统下的GPIO驱…

【0x001C】HCI_Write_Page_Scan_Activity详解

目录 一、命令概述 二、命令格式和参数说明 2.1. HCI_Write_Page_Scan_Activity命令格式 2.2. Page_Scan_Interval 2.3. Page_Scan_Window 三、响应事件及参数说明 3.1. HCI_Command_Complete事件 3.2. Status 3.3. 示例 四、命令执行流程 4.1. 命令发起阶段(主机端…

【AI图像生成网站Golang】雪花算法

AI图像生成网站 目录 一、项目介绍 二、雪花算法 三、JWT认证与令牌桶算法 四、项目架构(等待更新) 五、图床上传与图像生成API搭建(等待更新) 六、项目测试与调试(等待更新) 雪花算法 雪花算法 (Snowflake) 是一种高效、可扩展的分布式唯一ID生成算法,最早…

JMeter与大模型融合应用之JMeter日志分析服务化实战应用

JMeter与大模型融合应用之JMeter日志分析服务化 引言 在当今的互联网时代,网站和应用程序的性能直接影响到用户的体验和业务的成功。为了保证系统的稳定性和高效性,性能测试成为了软件开发过程中的一个重要环节。在这其中,Apache JMeter作为一款开源的性能测试工具,凭借其…

Docker环境搭建Cloudreve网盘服务(附shell脚本一键搭建)

Docker搭建Cloudreve Cloudreve介绍: Cloudreve 是一个基于 ThinkPHP 框架构建的开源网盘系统,旨在帮助用户以较低的成本快速搭建起既能满足个人也能满足企业需求的网盘服务。Cloudreve 支持多种存储介质,包括但不限于本地存储、阿里云OSS、…

浪浪云轻量服务器搭建vulfocus网络安全靶场

什么是网络安全靶场 网络安全靶场是一个模拟真实网络环境的训练平台,旨在为网络安全专业人员提供一个安全的环境来测试和提高他们的技能。靶场通常包括各种网络设备、操作系统、应用程序和安全工具,允许用户在其中进行攻击和防御练习。以下是网络安全靶…

对称加密算法DES的实现

一、实验目的 1、了解对称密码体制基本原理 2、掌握编程语言实现对称加密、解密 二、实验原理 DES 使用一个 56 位的密钥以及附加的 8 位奇偶校验位,产生最大 64 位的分组大小。这是一个迭代的分组密码,使用称为 Feistel 的技术,其中将加密…

【linux学习指南】VSCode部署Ubantu云服务器,与Xshell进行本地通信文件编写

文章目录 📝前言🌠 步骤🌉测试同步 🚩总结 📝前言 本文目的是讲使用Vscode连接Ubantu,与本地Xshell建立通信同步文件编写。 查看本机系统相关信息: cat /etc/lsb*DISTRIB_IDUbuntu: 表示这是 Ubuntu 发行…

实战:一文讲透模糊匹配的三种方式的区别

在 SQL 查询中,模糊查询是我们常用的工具之一。LIKE 关键字配合 % 符号,可以实现前缀匹配、后缀匹配和包含匹配等多种查询方式。然而,不同的匹配方式对查询性能会有显著影响。本文将详细探讨在 SQL 查询中,字符串前后加 % 与只在后面加 % 的性能差异及其应用场景。 一、SQL…

利用Blackbox AI让编程更轻松

引言 随着人工智能技术的发展,AI已经成为工作中不可缺少的工具之一。俗话讲“术业有专攻”,对AI来说当然也是如此。由于训练集、调教等方面的差别,不同的AI适用的工作也不尽相同。在编程辅助方面,已经有一系列比较成熟的平台&…

Vue学习记录03

响应式基础 声明响应式状态 ref() 在组合式API中,推荐使用ref()函数来声明响应式状态: import { ref } from vueconst count ref(0) ref()接收参数,并将其包裹在一个带有.value属性的ref对象中返回: const count ref(0)con…

排序排序的概念及其运用和选择排序

排序排序的概念及其运用和选择排序 7. 排序7.1 排序的概念及其运用7.2 选择排序算法——直接选择排序选择排序基本思想:直接选择排序选择排序原理参考程序 如何交换数据直接选择排序的特性总结: 7. 排序 7.1 排序的概念及其运用 排序:所谓排…

【目标检测】用YOLOv8-Segment训练语义分割数据集(保姆级教学)

前言 这篇教程会手把手带你用 YOLOv8-Segment 搭建一个属于自己的分割任务项目。从环境配置到数据集准备,再到模型训练和测试,所有步骤都有详细说明,适合初学者使用。你将学会如何安装必要的软件,标注自己的数据,并使…

爬虫开发工具与环境搭建——开发工具介绍

第二章:爬虫开发工具与环境搭建 第一节 开发工具介绍 爬虫开发需要一些合适的工具和框架来高效地抓取网页数据。在这节中,我们将介绍常用的开发工具,帮助开发者快速搭建爬虫开发环境。 1. Python与爬虫框架选择 Python因其简洁、易学的语法…

类和对象——拷贝构造函数,赋值运算符重载(C++)

1.拷⻉构造函数 如果⼀个构造函数的第⼀个参数是自身类类型的引用,且任何额外的参数都有默认值,则此构造函数也叫做拷贝构造函数,也就是说拷贝构造是⼀个特殊的构造函数。 // 拷贝构造函数//d2(d1) Date(const Date& d) {_year d._yea…

高级数据结构——hash表与布隆过滤器

文章目录 hash表与布隆过滤器1. hash函数2. 选择hash函数3. 散列冲突3.1 负载因子3.2 冲突解决3. STL中的散列表 4. 布隆过滤器4.1 背景1. 应用场景2. 常见的处理场景: 4.2 布隆过滤器构成4.3 原理4.4 应用分析4.5 要点 5. 分布式一致性hash5.1 缓存失效问题 6. 大数…

xcode-select: error: tool ‘xcodebuild‘ requires Xcode, but active developer

打开 .sh 文件所在的终端窗口,执行终端命令:sh 文件名.sh,出现如下错误: 解决办法:

java中volatile 类型变量提供什么保证?能使得一个非原子操作变成原子操作吗?

大家好,我是锋哥。今天分享关于【java中volatile 类型变量提供什么保证?能使得一个非原子操作变成原子操作吗?】面试题。希望对大家有帮助; java中volatile 类型变量提供什么保证?能使得一个非原子操作变成原子操作吗&…

candence : 通孔焊盘、插装器件封装绘制

通孔焊盘、插装器件封装绘制 以2.54mm 2x10的 排针为例绘制封装 一、 flash 热风焊盘制作 1、新建 2、选择 flash SYMBOL,并设置保存路径 3、add flash 具体参数 花焊盘参数 Inner diameter 通孔直径(1.0mm) 圆形补偿值(0.4mm)1.4mm Outer diameter 通孔直径…

VSCode设置

打开设置页 VSCode打开配置页面,有多种方式: a. 点击左上角 File(文件) -> Preferences (首选项) -> Settings(设置)。 b. 使用快捷键 Ctrl ,(Windows) 或 Cmd ,(Mac)。 c. 点击左下角 Manage(管理) -> Settings(设置)。 VSCode设置页面打…