我们正在用swag升级FutureStack注册,直到4月30日。条款和条件适用。 现在注册

将数据摄取管道容器化:使容器与Kafka兼容

5分钟读

在New Relic,我们在全公司范围内主动将所有的应用程序和服务移动到容器框架中。它被称为Container Fabric,是一种自产的容器编排和运行时平台。这就是为什么New Relic的移动应用程序团队一直忙于将我们的应用程序堆栈从严重依赖的传统硬件移走Capistrano部署到裸金属服务器,在容器Fabric平台上部署到Docker容器中。

当我们开始使用容器结构时,我们发现自动调度部署和我们的HTTP(S)和休息api似乎在容器中工作得很好。但是由于Java虚拟机(JVM)和内存之间的不平衡Apache卡夫卡在我们将其作为数据流平台的过程中,移动数据摄取管道是一个独特的挑战。

下面是我们如何进行一些JVM故障排除并克服这些内存失衡,从而更好地管理我们的容器化数据摄取管道。

新Relic移动数据摄取管道

在深入研究这个问题之前,我先快速解释一下数据摄取管道是如何工作的。考虑一下这个图形:

New Relic移动应用架构

通过使用针对New Relic Mobile的SDK,移动开发者可以让他们的应用程序从移动客户端发送有效负载iOS安卓)到移动路由器,它发布到Kafka集群。路由器提供Kafka生产者的功能,本质上是启动Kafka流。然后,数据有效负载被添加到Kafka主题(数据记录),并被划分为主题“分区”,以实现负载平衡和复制。

移动用户读取存储在主题中的数据。移动应用程序读取这些数据并将其发送到New Relic生态系统的各个部分(例如,用于New Relic的移动New Relic的见解)。我们将所有这些数据作为事件存储在NRDB数据库集群中。生产者和消费者应用程序运行在JVM上的Docker容器中,而容器位于更大的应用主机上。

JVM故障诊断:诊断Kafka的问题

为了充分理解容器中的Kafka和JVM之间的问题,你需要知道一些与JVM相关的关键术语:

  • : Java如何通过移动未使用的对象来为新对象分配空间来管理内存。
  • 垃圾收集: Java如何识别使用中的对象并删除未使用的对象。
  • 最大传输单元(MTU):设置网络中可以传输的最大数据包大小。

当我们使用Container Fabric部署ingest管道的测试版本时,我们注意到使用者没有正确地处理数据。JVM在一些关键的地方挣扎着。

我们的高吞吐量Kafka消费者以非常高的速率摄取数据,当新的数据进来时,JVM的堆并没有按照需要增长。使用New Relic Java代理,我们发现堆增长到最小大小(Xms),但它从未增长到最大大小(Xmx)。这导致JVM变得资源匮乏,这时它创建了一个内存不足错误(OOM)当堆耗尽空间时。

我们发现,将堆的Xms设置为与Xmx匹配,可以让堆捕获已经提交给它的资源。由于容器结构有硬性的资源限制,未充分利用我们已经提交的资源并试图诱导堆有机地增长是行不通的。

我们还看到了容器和底层主机之间的mtu问题。JVM将成功启动并获得分区的所有权,但无法传输大型数据包。我们与我们的Container Fabric团队合作,发现主机上的MTU设置与容器上的MTU设置不一样。因此,可以正确地传输小数据包(如所有权更改),但不能将大数据包从主机传输到容器。

基本上,我们没有吸收任何有效负载或客户端数据。

控制内存

当我们意识到由于堆和垃圾收集问题而导致管道失败时,我们尽可能地调整了Xms和Xmx堆大小。这使得JVM使用的内存量更灵活,并确保JVM消耗我们授予它的所有资源。这展示了我们的JVM进程的真实视图,因此我们可以调优Xmx值和内存资源,以避免OOM破坏和资源利用不足。

(注意:如果您正在处理任何类型的数据传输,您希望确保数据包能够通过您想要的大小的网络。)

一旦我们调整了这些问题,我们就能够将数据摄取管道完全从传统的硬件堆栈移到容器中。现在,我们可以设置可以部署多少个实例,并在采用我们的产品时水平扩展我们的ingest管道。

必须解决或计划jvm堆和垃圾收集问题当然不是新的Relic容器编排平台独有的工作。因此,我们分享了我们的故事,以帮助您解决自己的JVM内存问题。