作者 |
过去一年,ARMS基于eBPF技术打造了Kubernetes监控,提供多言语无侵入的运行性能,系统性能,网络性能观测才干,验证了eBPF技术的有效性。eBPF技术和生态开展很好,未来前景广阔,作为该技术的通常者,本文目的是经过回答7个外围疑问引见eBPF技术自身,为大家解开eBPF的面纱。
eBPF是一个能够在内核运转沙箱程序的技术,提供了一种在内核事情和用户程序事情出现时安保注入代码的机制,使得非内核开发人员也可以对内核启动控制。随着内核的开展,eBPF 逐渐从最后的数据包过滤裁减到了网络、内核、安保、跟踪等,而且它的配置个性还在极速开展中,早期的 BPF 被称为经典 BPF,简称cBPF,正是这种配置裁减,使得如今的BPF被称为裁减BPF,简称eBPF。
eBPF兼具高性能和高可裁减个性,使得其成为网络打算中网络包处置的优选打算:
JIT编译器提供近乎内核本地代码的口头效率。
在内核的高低文里,可以极速地参与协定解析和路由战略。
eBPF经过kprobe,tracepoints跟踪机制兼具内核和用户的跟踪才干,这种端到端的跟踪才干可以极速启动缺点诊断,与此同时eBPF允许以愈加高效的方式显显露profiling的统计数据,而不要求像传统系统要求将少量的采样数据显显露,使得继续地实时profiling成为或者。
eBPF可以看到一切系统调用,一切网络数据包和socket网络操作,一体化联合进程高低文跟踪,网络操作级别过滤,系统调用过滤,可以更好地提供安保控制。
相比于传统的系统监控组件比如sar,只能提供静态的counters和gauges,eBPF允许可编程地灵活搜集和边缘计算聚合自定义的目的和事情,极大地优化了性能监控的效率和构想空间。
eBPF的出现实质上是为了处置内核迭代速度慢和系统需求极速变动的矛盾,在eBPF畛域罕用的一个例子是eBPF相关于Linux Kernel相似于Javascript相关于HTML,突出的是可编程性。普通来说可编程性的允许通常会带来一些新的疑问,比如内核模块其实也是为了处置这个疑问,然而他没有提供很好的边界,造成内核模块会影响内核自身的稳固性,在不同的内核版本要求做适配等。eBPF驳回以下战略,使得其成为一种安保高效地内核可编程技术:
eBPF 程序肯定被验证器校验经事先才干口头,且不能蕴含无法抵达的指令;eBPF 程序不能轻易调用内核函数,只能调用在 API 中定义的辅佐函数;eBPF 程序栈空间最多只要 512 字节,想要更大的存储,就肯定要借助映射存储。
借助即时编译器(JIT),且由于 eBPF 指令依然运转在内核中,无需向用户态复制数据,大大提高了事情处置的效率。
经过BPF Helpers,BTF,PERF MAP提供规范的接口和数据模型供开发者经常使用。
eBPF 不只裁减了寄存器的数量,引入了全新的 BPF 映射存储,还在 4.x 内核中将原本繁多的数据包过滤事情逐渐裁减到了内核态函数、用户态函数、跟踪点、性能事情(perf_events)以及安保控制等畛域。
1.经常使用 C 言语开发一个 eBPF 程序;
即插桩点触发事情时要调用的eBPF沙箱程序,该程序会在内核态运转。
2.借助 LLVM 把 eBPF 程序编译成 BPF 字节码;
eBPF 程序编译成 BPF 字节码,用于后续在eBPF虚构机内验证并运转。
3.经过 bpf 系统调用,把 BPF 字节码提交给内核;
在用户态经过bpf系统,将BPF字节码加载到内核。
4.内核验证并运转 BPF 字节码,并把相应的形态保管到 BPF 映射中;
内核验证BPF字节码安保,并且确保对应事情出现时调用正确的eBPF程序,假设有形态要求保管,则写入对应BPF映射中,比如监控数据就可以写到BPF映射中。
5.用户程序经过 BPF 映射查问 BPF 字节码的运转形态。
用户态经过查问BPF映射的内容,失掉字节码运转的形态,比如失掉抓取到的监控数据。
一个完整的 eBPF 程序,通常蕴含用户态和内核态两局部:用户态程序要求经过 BPF 系统调用跟内核启动交互,进而成功 eBPF 程序加载、事情挂载以及映射创立和降级等义务;而在内核态中,eBPF 程序也不能恣意调用内核函数,而是要求经过 BPF 辅佐函数成功所需的义务。尤其是在访问内存地址的时刻,肯定要借助 bpf_probe_read 系列函数读取内存数据,以确保内存的安保和高效访问。在 eBPF 程序要求大块存储时,咱们还要求依据运行场景,引入特定类型的 BPF 映射,并借助它向用户空间的程序提供运转形态的数据。
bpftool feature probe grep program_type
以上命令可以检查系统允许的eBPF程序类型,普通有如下类型:
eBPF program_type socket_filter availableeBPF program_type kprobe availableeBPF program_type sched_cls availableeBPF program_type sched_act availableeBPF program_type tracepoint availableeBPF program_type xdp availableeBPF program_type perf_event availableeBPF program_type cgroup_skb availableeBPF program_type cgroup_sock availableeBPF program_type lwt_in availableeBPF program_type lwt_out availableeBPF program_type lwt_xmit availableeBPF program_type sock_ops availableeBPF program_type sk_skb availableeBPF program_type cgroup_device availableeBPF program_type sk_msg availableeBPF program_type raw_tracepoint availableeBPF program_type cgroup_sock_addr availableeBPF program_type lwt_seg6local availableeBPF program_type lirc_mode2 availableeBPF program_type sk_reuseport availableeBPF program_type flow_dissector availableeBPF program_type cgroup_sysctl availableeBPF program_type raw_tracepoint_writable availableeBPF program_type cgroup_sockopt availableeBPF program_type tracing availableeBPF program_type struct_ops availableeBPF program_type ext availableeBPF program_type lsm available
详细可参考
关键是分为3大经常使用场景:
tracepoint, kprobe, perf_event等,关键用于从系统中提取跟踪消息,进而为监控、排错、性能优化等提供数据撑持。
xdp, sock_ops, cgroup_sock_addr , sk_msg等,关键用于对网络数据包启动过滤和处置,进而成功网络的观测、过滤、流量控制以及性能优化等各种丰盛的配置,这里可以丢包,重定向。
cilium基本用了一切的hook点。
lsm,用于安保,其余还有flow_dissector, lwt_in都是一些不怎样罕用的,不再赘述。
从前面可以看进去eBPF程序自身并不艰巨,艰巨的是为其寻觅适合的事情源来触发运转。关于监控和诊断畛域来说,跟踪类eBPF程序的事情源蕴含3类:内核函数(kprobe)、内核跟踪点(tracepoint)或性能事情(perf_event)。此时有2个疑问要求回答:
1.内核中都有哪些内核函数、内核跟踪点或性能事情?
sudo ls syskerneldebugtracingevents
# 查问一切内核插桩和跟踪点sudo bpftrace l# 经常使用通配符查问一切的系统调用跟踪点sudo bpftrace l # 经常使用通配符查问一切名字蕴含的跟踪点sudo bpftrace l
sudo perf list tracepoint
2.关于内核函数和内核跟踪点,在要求跟踪它们的传入参数和前往值的时刻,又该如何查问这些数据结构的定义格局呢?
sudo cat syskerneldebugtracingeventssyscallssys_enter_openatformat
详细如何经常使用以上消息,请参考bcc。
1.如何查问用户进程的跟踪点?
# 查问符号表readelf Ws usrlibx86_64linuxgnulibc# 查问USDT消息readelf n usrlibx86_64linuxgnulibc
# 查问uprobebpftrace l # 查问USDTbpftrace l
uprobe 是基于文件的。当文件中的某个函数被跟踪时,除非对进程 PID 启动了过滤,自动一切经常使用到这个文件的进程都会被插桩。
上方说的是静态编译言语,他和内核的跟踪相似,运行程序的符号消息可以寄存在 ELF 二进制文件中,也可以以独自文件的方式,放到调试文件中;而内核的符号消息除了可以寄存到内核二进制文件中之外,还会以 /proc/kallsyms 和 /sys/kernel/debug 等方式泄露到用户空间。
关于非静态编译言语来说,关键是两种:
经常使用相似编译型言语运行程序的跟踪点查问方法,查问它们在解释器层面的 uprobe 和 USDT 跟踪点,如何将解释器层面的行为和运行行为关联要求相关言语的专家来剖析。
这类言语的运行源代码会先编译为字节码,再由即时编译器(JIT)编译为机器码口头,还会有少量的优化,跟踪难度很大,同解释型编程言语相似,uprobe 和 USDT 跟踪只能用在即时编译器上,从即时编译器的跟踪点参数外面失掉最终运行程序的函数消息。找出即时编译器的跟踪点同运行程序运转之间的相关要求相关言语的专家来剖析。
可以参考BCC的运行程序跟踪,用户进程的跟踪,实质上是经过断点去口头 uprobe 处置程序。只管内核社区曾经对 BPF 做了很多的性能调优,跟踪用户态函数(特意是锁争用、内存调配之类的高频函数)还是有或者带来很大的性能开支。因此,咱们在经常使用 uprobe 时,应该尽量防止跟踪高频函数。
详细如何经常使用以上消息,请参考:
一个现实的形态是一切疑问都分明应当观察那些插桩点,然而这个要求技术人员对端到端的软件栈细节都了解十分透彻,一个愈加正当的方法是二八规律,将软件栈数据流的最外围的80%头绪抓住,保证出现疑问肯定会在这个头绪被发现即可。此时再经常使用内核栈和用户栈来检查详细的调用栈即可发现外围疑问,比如说发现了网络在丢包,然而不知道为什么丢,此时咱们知道网络丢包肯定会调用kfree_skb内核函数,那么咱们可以经过:
sudo bpftrace e
发现该函数的调用栈:
kstack kfree_skb udpv6_destroy_sock sk_common_release udp_lib_close inet_release inet6_release __sock_release sock_close __fput ____fput task_work_run exit_to_user_mode_loop exit_to_user_mode_prepare syscall_exit_to_user_mode do_syscall_64 entry_SYSCALL_64_after_hwframe
那么就可以回溯上方的函数,看看他们详细是哪一行在什么条件下调用的,就能够定位到疑问。这个方法不只可以定位疑问,也可以用于加深对内核调用的了解,比如:
可以检查一切网络相关的跟踪点及其调用栈。
eBPF在内核关键由5个模块单干:
1.BPF Verifier(验证器)
确保 eBPF 程序的安保。验证器会将待口头的指令创立为一个有向无环图(DAG),确保程序中不蕴含无法达指令;接着再模拟指令的口头环节,确保不会口头有效指令,这里经过和一般同窗了解到,这里的验证器并无法保证100%的安保,所以关于一切BPF程序,都还要求严厉的监控和评审。
将 eBPF 字节码编译老本地机器指令,以便更高效地在内核中口头。
3.多个 64 位寄存器、一个程序计数器和一个 512 字节的栈组成的存储模块
用于控制eBPF程序的运转,保管栈数据,入介入出参。
4.BPF Helpers(辅佐函数)
提供了一系列用于 eBPF 程序与内核其余模块启动交互的函数。这些函数并不是恣意一个 eBPF 程序都可以调用的,详细可用的函数集由 BPF 程序类型选择。留意,eBPF外面一切对入参,出参的修正都肯定合乎BPF规范,除了本地变量的变卦,其余变动都应当经常使用BPF Helpers成功,假设BPF Helpers不允许,则无法修正。
经过以上命令可以看到不同类型的eBPF程序可以运转哪些BPF Helpers。
5.BPF Map & context
用于提供大块的存储,这些存储可被用户空间程序用来启动访问,进而控制 eBPF 程序的运转形态。
bpftool feature probe
经过以上命令可以看到系统允许哪些类型的map。
先说下关键的系统调用bpf:
bpf cmd bpf_attr attr size
这里cmd是关键,attr是cmd的参数,size是参数大小,所以关键是看cmd有哪些
内核 bpf_cmd BPF_MAP_CREATEBPF_MAP_LOOKUP_ELEMBPF_MAP_UPDATE_ELEMBPF_MAP_DELETE_ELEMBPF_MAP_GET_NEXT_KEYBPF_PROG_LOADBPF_OBJ_PINBPF_OBJ_GETBPF_PROG_ATTACHBPF_PROG_DETACHBPF_PROG_TEST_RUNBPF_PROG_GET_NEXT_IDBPF_MAP_GET_NEXT_IDBPF_PROG_GET_FD_BY_IDBPF_MAP_GET_FD_BY_IDBPF_OBJ_GET_INFO_BY_FDBPF_PROG_QUERYBPF_RAW_TRACEPOINT_OPENBPF_BTF_LOADBPF_BTF_GET_FD_BY_IDBPF_TASK_FD_QUERYBPF_MAP_LOOKUP_AND_DELETE_ELEMBPF_MAP_FREEZEBPF_BTF_GET_NEXT_IDBPF_MAP_LOOKUP_BATCHBPF_MAP_LOOKUP_AND_DELETE_BATCHBPF_MAP_UPDATE_BATCHBPF_MAP_DELETE_BATCHBPF_LINK_CREATEBPF_LINK_UPDATEBPF_LINK_GET_FD_BY_IDBPF_LINK_GET_NEXT_IDBPF_ENABLE_STATSBPF_ITER_CREATEBPF_LINK_DETACHBPF_PROG_BIND_MAP
最外围的就是PROG,MAP相关的cmd,就是程序加载和映射处置。
1.程序加载
调用BPF_PROG_LOAD cmd,会将BPF程序加载到内核,但eBPF 程序并不像惯例的线程那样,启动后就不时运转在那里,它要求事情触发后才会口头。这些事情包括系统调用、内核跟踪点、内核函数和用户态函数的调用分开、网络事情,等等,所以要求第2个举措。
2.绑定事情
bevent fn_name
以上就是将特定的事情绑定到特定的BPF函数,实践成功原理如下:
(1)借助 bpf 系统调用,加载 BPF 程序之后,会记住前往的文件形容符;
(2)经过attach操作知道对应函数类型的事情编号;
(3)依据attach的前往值调用 perf_event_open 创立性能监控事情;
(4)经过 ioctl 的 PERF_EVENT_IOC_SET_BPF 命令,将 BPF 程序绑定到性能监控事情。
3.映射操作
经过MAP相关的cmd,控制MAP增删,而后用户态基于该MAP与内核形态启动交互。
倡导>=4.14
eBPF的生态自下而上的状况如下:
1.基础设备
允许eBPF基础才干的开展。
2.开发工具集
关键是用于加载,编译,调试eBPF程序,不同言语有不同的开发工具集:
3、eBPF运行
提供一套开发工具和脚本。
基于bcc,提供一个脚本言语。
网络优化和安保
网络安保
高性能4层负载平衡
可观测
可观测
可观测
调度bpftrace脚本
散布式环境下启动和治理eBPF程序的平台
灵活linux trace
Linux运转时安保监测
4、跟踪生态的网站
经过上方的引见,置信大家对eBPF曾经有了足够的了解,eBPF提供的只是一个框架和机制,外围还是要求用eBPF的人对软件栈的了解,找到适合的插桩点,能够和运行疑问启动关联。
1.全笼罩
内核,运行程序插桩点全笼罩。
2.无侵入
不要求修正任何被hook的代码。
3.可编程
灵活下发eBPF程序,边缘灵活口头指令,灵活聚合剖析。
本网站的文章部分内容可能来源于网络和网友发布,仅供大家学习与参考,如有侵权,请联系站长进行删除处理,不代表本网站立场,转载联系作者并注明出处:https://duobeib.com/diannaowangluoweixiu/6474.html