关于云计算:CNI-基准测试Cilium-网络性能分析

44次阅读

共计 9541 个字符,预计需要花费 24 分钟才能阅读完成。

[](#understanding-cilium-network-performance)

原文链接:https://cilium.io/blog/2021/0…

作者:Thomas Graf

译者:罗煜、张亮,均来自 KubeSphere 团队

Thomas Graf 是 Cilium 的联结创始人,同时也是 Cilium 母公司 Isovalent 的 CTO 和联结创始人。此前 Thomas 曾先后在 Linux 内核的网络、平安和 eBPF 畛域从事了 15 年的开发工作。

注:本文已获得作者自己的翻译受权

大家好!👋

随着越来越多的要害负载被迁徙到 Kubernetes 上,网络性能基准测试正在成为抉择 Kubernetes 网络计划的重要参考。在这篇文章中,咱们将基于过来几周进行的大量基准测试的后果探讨 Cilium 的性能特点。应宽广用户的要求,咱们也将展现 Calico 的测试后果,以便进行间接比照。

除了展现测试的后果数据外,咱们还将对容器网络基准测试这一课题进行更深刻的钻研,并探讨以下几个方面的问题:

  • 吞吐量基准测试
  • 容器网络是否会减少开销
  • 打破常规:eBPF 主机路由(Host Routing)
  • 测量提早:每秒申请数
  • Cilium eBPF 和 Calico eBPF 的 CPU 火焰图比照
  • 新连贯解决速率
  • WireGuard 与 IPsec 加密开销比照
  • 测试环境

测试后果汇总

在详细分析基准测试及其数据之前,咱们先展现汇总的测试论断。如果您心愿间接理解测试细节并得出本人的论断,也能够跳过这一节的内容。

  • eBPF 起决定性作用 :Cilium 在某些方面优于 Calico 的 eBPF 数据门路(Data Path),例如在 TCP_RRTCP_CRR 基准测试中察看到的提早。此外,更重要的论断是 eBPF 显著优于 iptables。在容许应用 eBPF 绕过 iptables 的配置环境中,Cilium 和 Calico 的性能都显著优于不能绕过 iptables 的状况。

    在钻研具体细节后,咱们发现 Cilium 和 Calico 利用 eBPF 的形式并不完全相同。尽管二者的某些概念是类似的(思考到开源的性质,这也并不奇怪),CPU 火焰图显示 Cilium 利用了额定的上下文切换节俭性能。这或者能够解释 TCP_RRTCP_CRR 测试后果的差别。

    总体而言,从基准测试后果来看,eBPF 无疑是解决云原生需要挑战的最佳技术。

  • 可察看性、NetworkPolicy 和 Service:对于这个基准测试,咱们把关注的焦点放在二者的共性上,也就是网络。这使得咱们能够间接比照节点网络带来的性能差别。然而,在理论利用中也会须要用到可观测性、NetworkPolicy 和 Service,在这些方面 Cilium 和 Calico eBPF 数据门路差别微小。Cilium 反对一些 Calico eBPF 数据门路不具备的性能,但即使是 Kubernetes NetworkPolicy 之类的规范性能,Cilium 和 Calico 的实现形式也不一样。如果咱们投入更大的精力测试在这些更高级的用例中利用 eBPF,咱们可能会发现二者在这些方面的性能有显著差别。然而,限于篇幅本文将不对此作更多的探讨,更加深刻的钻研将留给下一篇文章。
  • 比照 WireGuard 和 IPsec:有些令人意外,只管 WireGuard 在咱们的测试中可能实现更高的最大吞吐量,但 IPsec 在雷同的吞吐量下 CPU 应用效率更高。这很有可能得益于 AES-NI CPU 指令集。该指令集反对卸载 IPsec 的加密工作,但 WireGuard 不能从中受害。当 AES-NI 指令集不可用时,后果就显著反转了。

    好消息是,从 Cilium 1.10 开始,Cilium 不仅反对 IPsec 还反对 WireGuard。您能够抉择其中之一来应用。

吞吐量基准测试

免责申明:

基准测试难度很大。测试后果很大水平上依赖于运行测试的硬件环境。除非是在雷同的零碎上收集的后果,否则不应间接用相对的数值进行比拟。

让咱们从最常见和最显著的 TCP 吞吐量基准测试开始,测量运行在不同节点上的容器之间的最大数据传输速率。

上图显示了单个 TCP 连贯可实现的最大吞吐量,最优的几个配置性能刚好超过了 40 Gbit/s。以上后果由 netperfTCP_STREAM 测试得出,测试环境应用了速率为 100 Gbit/s 的网口以确保网卡不会成为瓶颈。因为运行单个 netperf 过程通过单个 TCP 连贯传输数据,大部分的网络解决是由单个 CPU 外围实现的。这意味着下面的最大吞吐量受到单个外围的可用 CPU 资源限度,因而能够显示当 CPU 成为瓶颈时每个配置能够实现的吞吐量。本文前面将会进一步扩大测试,应用更多的 CPU 外围来打消 CPU 资源的限度。

应用高性能 eBPF 实现的吞吐量甚至略高于节点到节点的吞吐量。这令人十分意外。通常普遍认为,相较于节点到节点的网络,容器网络会带来额定的开销。咱们临时先把这个纳闷搁置一旁,进一步钻研之后再来剖析这个问题。

100 Gbit/s 传输速率所需的 CPU 资源

TCP_STREAM 基准测试的后果曾经暗示了哪些配置能够最无效地实现高传输速率,但咱们还是看一下运行基准测试时零碎整体的 CPU 耗费。

上图显示了达到 100 Gbit/s 吞吐量整个零碎所需的 CPU 使用率。请留神,这不同于前一个图中吞吐量对应的 CPU 耗费。在上图中,所有的 CPU 使用率都已折算为传输速率稳固在 100 Gbit/s 时的数值以便能够间接比照。上图中的条形图越短,对应的配置在 100 Gbit/s 传输速率时的效率越高。

留神 :TCP 流的性能通常受到接收端的限度,因为发送端能够同时应用 TSO 大包。这能够从上述测试中服务器侧减少的 CPU 开销中察看到。

TCP 吞吐量基准测试的意义

尽管大多数用户不太可能常常遇到上述的吞吐量程度,但这样的基准测试对特定类型的应用程序有重要意义:

  • 须要拜访大量数据的 AI/ML 应用程序
  • 数据上传 / 下载服务(备份服务、虚拟机镜像、容器镜像服务等)
  • 流媒体服务,特地是 4K+ 分辨率的流媒体

在本文前面的章节,咱们将持续深刻探讨测量提早:每秒申请数和新连贯解决速率,以更好地展现典型微服务工作负载的性能特点。

容器网络是否会减少开销

在第一个基准测试的剖析中咱们提到,与节点网络相比,容器网络会带来一些额定开销。这是为什么呢?让咱们从架构的角度来比照这两种网络模型。

上图表明容器网络也须要执行节点到节点网络的所有解决流程,并且这些流程都产生在容器的网络命名空间中(深蓝色局部)。

因为节点网络的解决工作也须要在容器网络命名空间内进行,在容器网络命名空间之外的任何工作实质上都是额定开销。上图显示了应用 Veth 设施时,Linux 路由的网络门路。如果您应用 Linux 网桥或 OVS,网络模型可能略有不同,但它们根本的开销点是雷同的。

打破常规:eBPF 主机路由(Host-Routing)

在下面的基准测试中,您兴许会纳闷 Cilium eBPF 和 Cilium eBPF 传统主机路由(Legacy Host Routing)两种配置的区别,以及为什么原生的 Cilium eBPF 数据门路会比主机路由快得多。原生的 Cilium eBPF 数据门路是一种被称为 eBPF 主机路由的优化数据门路,如下图所示:

eBPF 主机路由容许绕过主机命名空间中所有的 iptables 和下层网络栈,以及穿过 Veth 对时的一些上下文切换,以节俭资源开销。网络数据包达到网络接口设施时就被尽早捕捉,并间接传送到 Kubernetes Pod 的网络命名空间中。在流量进口侧,数据包同样穿过 Veth 对,被 eBPF 捕捉后,间接被传送到内部网络接口上。eBPF 间接查问路由表,因而这种优化齐全通明,并与零碎上运行的所有提供路由调配的服务兼容。对于如何启用该个性,请参阅调优指南中的 eBPF 主机路由。

Calico eBPF 正在将一些相似的绕过办法用于 iptables,但这与 Cilium 的原理并不完全相同,文章前面会进一步介绍。不论如何,测试后果证实绕过迟缓的内核子系统(例如 iptables)能够带来极大的性能晋升。

迫近 100 Gbit/s 的线速率(Line Rate)

在上文中,咱们剖析了只波及一个 CPU 外围的基准测试后果。接下来咱们将放开单核的限度,将 TCP 流并行化以运行多个 netperf 过程。

留神 :因为硬件有 32 个线程,咱们特意抉择了 32 个过程,以确保零碎可能平均地调配负载。

上图并没有提供非常有价值的信息,仅仅表明如果投入足够多的 CPU 资源,所有测试配置都能达到靠近 100 Gbit/s 的线速率。然而,从 CPU 资源来看,咱们依然能够发现效率上的差别。

请留神,上图中的 CPU 使用率涵盖了全副的 CPU 耗费,包含正在运行的 netperf 过程的耗费,也包含工作负载执行网络 I/O 所需的 CPU 资源。然而,它并不包含应用程序通常须要执行的任何业务逻辑所带来的 CPU 耗费。

测量提早:每秒申请数

每秒申请数与吞吐量指标简直齐全相同。它能够掂量单个 TCP 长久连贯上按程序的单字节往返的传输速率。此基准测试能够体现网络数据包的解决效率。单个网络数据包的提早越低,每秒可解决的申请就越多。吞吐量和提早的独特优化通常须要进行衡量。为了取得最大的吞吐量,较大的缓冲区是现实的抉择,然而较大的缓冲区会导致提早减少。这一景象被称为缓冲区收缩。Cilium 提供了一个称为带宽管理器(Bandwidth Manager)的性能,该性能能够主动配置偏心队列,可实现基于最早收回工夫的 Pod 速率限度,并为服务器工作负载优化 TCP 栈设置,使吞吐量和提早之间达到最佳均衡。

这个基准测试常常被忽视,但它对用户来说通常比设想的重要得多,因为它模仿了一种非常常见的微服务应用模式:应用长久化的 HTTP 或 gRPC 连贯在 Service 之间发送申请和响应。

下图显示单个 netperf 过程执行 TCP_RR 测试时,不同配置的性能体现:

在这个测试中体现更好的配置也实现了更低的均匀提早。然而,这并不足以让咱们对 P95 或 P99 提早得出结论。咱们将在将来的博客文章中探讨这些问题。

咱们进一步测试运行 32 个并行的 netperf 过程以利用所有可用的 CPU 外围。能够看到,所有配置的性能都有所晋升。然而,与吞吐量测试不同的是,在本测试中投入更多的 CPU 资源并不能补救效率上的欠缺,因为最大解决速率受提早而非可用 CPU 资源限度。即使网络带宽成为瓶颈,咱们也会看到雷同的每秒申请数值。

总体而言,后果十分鼓舞人心,Cilium 能够在咱们的测试零碎上通过 eBPF 主机路由实现近 1,000,000 申请每秒的解决速率。

Cilium eBPF 和 Calico eBPF 的 CPU 火焰图比照

总体而言,Cilium eBPF 和 Calico eBPF 的性能基本相同。这是因为它们应用了雷同的数据门路吗?并不是。并不存在预约义的 eBPF 数据门路。eBPF 是一种编程语言和运行时引擎,它容许构建数据门路个性和许多其余个性。Cilium 和 Calico eBPF 数据门路差别很大。事实上,Cilium 提供了很多 Calico eBPF 不反对的个性。但即便是在与 Linux 网络栈的交互上,两者也有显著的差别。咱们能够通过二者的 CPU 火焰图来来进一步剖析。

Cilium eBPF(接管门路)

Cilium 的 eBPF 主机路由提供了很好的免上下文切换的数据传送路径(从网卡到应用程序的套接字)。这就是为什么在下面的火焰图中整个接收端门路可能很好地匹配到一张火焰图中。火焰图也显示了 eBPF、TCP/IP 和套接字的解决块。

Calico eBPF(接管门路)

Calico eBPF 接收端看起来却不太一样。尽管有着雷同的 eBPF 解决块执行 eBPF 程序,但 Calico eBPF 接管门路穿过了额定的 Veth,这在 Cilium eBPF 数据门路接收端并不需要。

上图中的解决依然在主机的上下文中执行。上面的这火焰图显示了 Pod 中被 process_backlog 复原执行的工作。尽管这与 Cilium 场景下的工作一样(都是 TCP/IP+ 套接字数据传送),但因为穿过了 Veth 从而须要额定的上下文切换。

如果您心愿本人进行更进一步的钻研,能够点击以下链接关上交互式的火焰图 SVG 文件查看细节:

  • Cilium eBPF SVG 火焰图 – 发送端
  • Cilium eBPF SVG 火焰图 – 接收端
  • Calico eBPF SVG 火焰图 – 发送端
  • Calico eBPF SVG 火焰图 – 接收端

新连贯解决速率

连贯解决速率基准测试基于每秒申请数的基准测试,但为每个申请都建设了新的连贯。此基准测试的结果显示了应用长久连贯和为每个申请创立新连贯两种形式的性能差异。创立新 TCP 连贯须要波及零碎中的多个组件,所以这个测试是目前对整个零碎压力最大的测试。通过这个基准测试,咱们能够看到,充分利用零碎中大多数的可用资源是可能的。

这个测试展现了一个接管或发动大量 TCP 连贯的工作负载。典型的利用场景是由一个公开裸露的服务解决大量客户端申请,例如 L4 代理或服务为内部端点(例如数据抓取器)创立多个连贯。这个基准测试可能在卸载到硬件的工作起码的状况下尽可能地压测系统,从而显示出不同配置的最大性能差别。

首先,咱们运行一个 netperf 过程来进行 TCP_CRR 测试。

在单个过程下不同配置的性能差别曾经非常微小,如果应用更多的 CPU 外围差别还将进一步扩充。同时也能够显著看出,Cilium 再次可能补救网络命名空间额定开销造成的性能损失并达到和基线配置简直雷同的性能。

后续打算 :这个 CPU 资源使用率让咱们很诧异并促使咱们在接下来 1.11 的开发周期做进一步钻研。仿佛只有波及到网络命名空间的应用,发送端的资源开销总是必不可少的。这一开销在所有波及网络命名空间的配置中都存在,所以很有可能是由 Cilium 和 Calico 都波及的内核数据门路造成的。咱们会及时更新这部分钻研的停顿。

当并行运行 32 个进行 TCP_CRR 测试的 netpert 过程以利用所有 CPU 外围时,咱们察看到了一个十分有意思的景象。

基线配置的连贯解决速率显著降落。基线配置的性能并没有随着可用 CPU 资源的增多而进一步晋升,只管连贯跟踪状态表大小产生了相应变动并且咱们确认并没有产生因连贯跟踪表记录达到下限而导致的性能升高。咱们反复进行了屡次雷同的测试,后果依然雷同。当咱们手动通过 -j NOTRACK 规定绕过 iptables 连贯跟踪表时,问题立即解决了,基线配置性能复原到 200,000 连贯每秒。所以很显著,一旦连接数超过某个阈值,iptables 连贯跟踪表就会开始呈现问题。

留神 :在这个测试中,Calico eBPF 数据门路的测试后果始终不是很稳固。咱们目前还不分明起因。网络数据包的传输也不是很稳固。咱们没有将测试后果纳入思考,因为测试后果不肯定精确。咱们邀请 Calico 团队和咱们一起钻研这个问题并从新进行测试。

鉴于咱们应用的是未经批改的规范应用程序来解决申请和传输信息,每秒解决 200,000 连贯是一个十分优良的问题。不过,咱们还是看一下 CPU 的耗费。

这个基准测试结果显示了不同配置的最大性能差别。为了达到每秒解决 250,000 新连贯的指标,整个零碎必须耗费 33% 到 90% 的可用资源。

因为发送端 CPU 资源耗费始终高于接收端,咱们能够确信雷同资源下每秒能接管的连接数要大于每秒能发动的连接数。

WireGuard 与 IPsec 加密开销比照

可能所有人都会认为 WireGuard 的性能会优于 IPsec,所以咱们先测试 WireGuard 在不同的最大传输单元(MTU)下的性能。

不同的配置之间有一些差别。值得注意的是,Cilium 与 kube-proxy 的组合比独自 Cilium 的性能更好。然而,这个性能差别绝对较小并且根本能够通过优化 MTU 补救。

以下是 CPU 资源的耗费:

上述结果表明在 MTU 雷同的状况下,不同配置之间的 CPU 使用率差别很小,因此能够通过优化 MTU 配置获得最佳性能。咱们还对每秒申请数进行了测试,失去的后果也雷同。感兴趣的读者能够参阅 Cilium 文档的 CNI 性能基准测试章节。

WireGuard 与 IPsec 比照

对 Wireguard 和 IPsec 的性能进行比拟更加乏味。Cilium 反对 IPsec 曾经有一段时间了。从 1.10 开始,Cilium 也开始反对 WireGuard。在其余方面雷同的状况下,把这两个加密计划放在一起进行比照,后果肯定会十分乏味。

不出所料,WireGuard 的吞吐量更高,并且在两种 MTU 配置下,WireGuard 的最大传输速率更高。

上面持续测试当吞吐量达到 10 Gbit/s 时,WireGuard 和 IPsec 在不同的 MTU 配置下的 CPU 使用率。

尽管 WireGuard 的最大吞吐量更高,但 IPsec 在吞吐量雷同的状况下 CPU 开销更小从而更有效率,这个差别十分微小。

留神 :为了实现 IPsec 的高效率,须要应用反对 AES-NI 指令集的硬件来卸载 IPsec 的加密工作。

后续打算 :目前咱们还不分明为什么 IPsec 的高效率没有带来更高的吞吐量。应用更多的 CPU 外围也没有显著晋升性能。这很可能是因为 RSS 不能很好地跨 CPU 外围解决加密流量,因为通常用于哈希和跨 CPU 外围调配流量的 L4 信息是加密的,无奈解析。因而,从哈希的角度来看,所有的连贯都是一样的,因为在测试中只利用了两个 IP 地址。

这是否会影响提早?让我进一步钻研。提早基准测试最能精确地形容微服务工作负载的理论情况,微服务工作负载通常都会应用长久连贯来替换申请和响应。

CPU 效率与察看到的每秒申请数相符。然而,每个配置总共耗费的 CPU 资源都不是很高。相比 CPU 耗费方面的差别,提早方面的差别更为显著。

测试环境

以下是咱们应用的裸机配置。咱们搭建了两套齐全一样的相互直连的零碎。

  • CPU:AMD Ryzen 9 3950X,AM4 平台,3.5 GHz,16 核 32 线程
  • 主板 :X570 Aorus Master,反对 PCIe 4.0 x16
  • 内存 :HyperX Fury DDR4-3200 128 GB,XMP 频率 3.2 GHz
  • 网卡: Intel E810-CQDA2,双端口,每端口速率 100 Gbit/s,PCIe 4.0 x16
  • 操作系统内核: Linux 5.10 LTS(配置为 CONFIG_PREEMPT_NONE

除非特地阐明,所有测试都应用了规范的 1500 字节 MTU。尽管 MTU 的值越高,测试后果的相对数值会越好,但本文的基准测试的目标在于比拟绝对差别,而不是测试最高或最低性能的相对数值。

测试配置

应宽广用户的要求,咱们展现了 Calico 的测试后果以便进行比照。为了尽可能清晰地进行比照,咱们应用了以下配置类型进行测试:

  • 基线配置(节点到节点):此配置不应用 Kubernetes 或容器,在基准测试过程中间接在祼机上运行 netperf。通常状况下此配置的性能最优。
  • Cilium eBPF: Cilium 版本为 1.9.6 并依照调优指南进行了调优,开启了 eBPF 主机路由和 kube-proxy 替换。此配置须要操作系统内核版本为 5.10 或以上。此配置与 Calico eBPF 配置比照最具备参照性。咱们重点进行了间接路由模式的基准测试,因为这种模式下性能通常尤为重要。后续咱们也会进一步进行隧道模式的相干基准测试。
  • Cilium eBPF(传统主机路由):Cilium 版本为 1.9.6,以传统主机路由的模式运行,应用规范 kube-proxy,反对 4.9 及以下内核版本。此配置与 Calico 配置比照最具备参照性。
  • Calico eBPF:Calico 版本为 3.17.3,同时应用了开启 kube-proxy 替换、连贯跟踪绕过以及 eBPF FIB 查问的 eBPF 数据门路。此配置须要操作系统内核版本为 5.3 或以上。此配置与 Cilium eBPF 配置比照最具备参照性。
  • Calico: Calico 版本为 3.17.3,应用规范 kube-proxy,反对较低版本的操作系统内核。此配置与 Cilium eBPF(传统主机路由)配置比照最具备参照性。

复现测试后果

测试所用的全副脚本都曾经上传到 GitHub 仓库 cilium/cilium-perf-networking 中,可用于复现测试后果。

下一步

咱们在性能调优方面曾经获得了不少后果,但咱们还有许多其余的想法并将进一步优化 Cilium 各方面的性能。

  • 可察看性基准测试 :单纯的网络基准测试是必要的,然而实现可察看性所需资源的耗费才是真正辨别零碎高下的畛域。无论是对系统安全还是对故障排除来说,可察看性都是基础设施的要害个性,并且不同零碎的可视化资源耗费有很大不同。eBPF 是实现可察看性的优良工具,并且 Cilium 的 Hubble 组件也能够从中受害。在本文的基准测试中,咱们禁用了 Hubble 以便测试后果能够与 Calico 比照。在后续的文章中,咱们将对 Hubble 进行基准测试,以验证 Hubble 的 CPU 需要并将 Hubble 与其余相似的零碎比照。
  • Service 和 NetworkPolicy 基准测试 :以后的基准测试后果并不波及任何 Service 和 NetworkPolicy。咱们没有对二者进行测试以管制本文的内容范畴。咱们将进一步对应用 NetworkPolicy 的用例进行测试,除此之外还将对东西向(east-west)和南北向(north-south)的 Service 进行测试。如果您曾经等不及了,Cilium 1.8 的公布博客曾经颁布了一些基准测试后果,并且展现了 XDP 和 eBPF 对性能的显著晋升。

    目前,咱们依然对 NetworkPolicy 在 CIDR 规定方面的性能不太称心。咱们以后的架构针对大量简单的 CIDR 进行了优化,但并没有笼罩应用 LPM 来实现的一些特例。一些用户可能心愿对独自 IP 地址的大型放行和阻止列表进行基准测试。咱们会把这个用例放在优先事项中,并且提供基于哈希表的实现。

  • 内存优化 :咱们将持续优化 Cilium 的内存占用。Cilium 次要的内存占用来自于 eBPF 的 Map 调配。这些是网络解决所须要的内核级数据结构。为了提高效率,eBPF Map 的大小是事后设定的,以便依据配置所需的内存量最小。咱们目前对这方面并不是很称心,这将是咱们后续版本的重点工作。
  • 突破更多的规定:更多地绕过 iptables:咱们认为 iptables 应该齐全绕过。容器命名空间和零碎其余局部仍有优化后劲。咱们还会持续致力放慢服务网格的数据门路应用程序。目前曾经有一个利用 Envoy 的 Socket 层重定向的初步版本。请期待这个方面的停顿。
  • 想法和倡议 :如果您有其余想法和倡议,请通知咱们。例如,您心愿咱们进行哪些基准测试或改良?咱们十分心愿能失去反馈意见。您能够在 Cilium Slack 发表想法或者通过 Twitter 分割咱们。

更多信息

  • 本文的所有后果数据都能够在 Cilium 文档的 CNI 性能基准测试章节查阅。咱们会继续更新这些数据。
  • 调优指南提供了对 Cilium 进行调优的残缺教程。
  • 无关 Cilium 的更多信息,请参阅 Cilium 官网文档。
  • 无关 eBPF 的更多信息,请拜访 eBPF 官方网站。

KubeSphere 社区活动告诉

为了跟社区新老朋友们零距离交换,咱们将联结 CNCF 和其余合作伙伴,从五月到七月,在上海、杭州、深圳、成都这四个城市别离为大家带来技术的交换与碰撞。2021 年继上海站首次 Meetup 火爆全场之后,咱们将仍旧连续 KubeSphere and Friends 的主题,于 5 月 29 日杭州为大家带来 Kubernetes and Cloud Native Meetup。

咱们特地定制了 KubeSphere 全套留念周边礼品:T 恤、马克杯、留念徽章、帆布袋、口罩等。除此之外还有各种云原生硬核书籍等你来拿!

怎么样,心动了么?报名参加行将到来的杭州站即可取得定制周边纪念品!

本文由博客一文多发平台 OpenWrite 公布!

正文完
 0