@Rays
2018-08-22T14:53:12.000000Z
字数 5384
阅读 1843
云技术
摘要: 事件驱动是当前的一个技术热点。开源项目Liftbridge以可扩展的类Kafka日志API扩展了NATS,加入到这一热点领域中。为了解该项目的更多细节,并了解不断变化中的系统连接技术环境,InfoQ采访了资深技术人员Tyler Treat。Treat是Liftbridge项目的创立者,也是NATS的长期贡献者。
作者: Richard Seroter
正文:
一项Gartner机构的研究表明,企业正将注意力转向事件驱动IT。研究指出了到2020年CIO必须优先考虑的三个事项。Apache Kafka作为一种被广为采用的事件流平台,其使用量的增长有力地支撑了上述声明。三家主要的云服务提供商(AWS、GCP和Azure)都提供了自己的事件流处理服务,一些业界领袖也加入了CloudEvents规范。开源项目Liftbridge通过提供类似于Kafka的可扩展日志API,实现了对NATS消息系统的扩展。
Liftbridge是由资深技术人员Tyler Treat创立的一个项目。Treat是NATS引擎的一位长期贡献者,现在NATS已成为一个由CNCF负责的项目。在宣布项目开源的博客帖子中,Treat指出该项目的目标是“填补基于日志的复杂消息系统(例如Apache Kafka和Apache Pulsar)与更为简单的云原生系统之间的空白”。为了解该项目的更多细节,并了解不断变化中的系统连接技术环境,InfoQ采访了Treat。
InfoQ:该项目意在解决哪些问题?
Tyler Treat:从根本上说,Liftbridge要解决的问题,也正是Apache Kafka等系统要解决的同一类问题。Liftbridge本质上是一个消息传递系统,它支持数据生成者与消费者的分离。和Kafka一样,Liftbridge也是一个消息日志系统。不同于RabbitMQ之类的传统消息代理,Liftbridge将消息添加到不可变的提交日志中。在传统的消息代理中,消息通常会被消费者从消息队列中取走。而使用Liftbridge,消息在消费之后会依然时会保留在日志中,并支持多个消费者从同一日志中读取消息。它几乎等同于将数据库中的预写日志功能提取出来,并以服务的形式公开提供。这使得通过系统发送的消息可以重播(replay)。
该方法已实现了大量事件源和流处理相关的实际用例。例如,我们可以通过日志聚合将所有应用和系统日志写入到Liftbridge,并以后者作为一种缓冲区,实现将日志传输给Splunk、Datadog、冷存储以及任何关注日志数据的后端。在我曾供职的一家企业中,该方法通过提供一种数据获取方式,可以同时评估多个日志记录提供者。Liftbridge和Kafka等系统提供了非常强大的数据流水线。
然而,我们构建Liftbridge的目的并非在于替代Kafka,其更主要的目标在于为NATS提供一种类似Kafka的语义。NATS是一种即发即弃(Fire-and-Forget)的高性能消息传递系统,由于它在设计上是始终处于开启状态的,并且非常简单,因此常被视为一种用于分布式系统的“拨号音”。但这样做的缺点是NATS的功能非常有限。我们继续使用上面的类比,可将Liftbridge看成是NATS的“语音邮件”。一旦有消息发布到NATS,但是对消息感兴趣的消费者是离线的,那么Liftbridge就会将消息记录到日志,确保消息依然是可传递的。这个比喻可能并不完美,希望大家能明白其中的意思。
InfoQ:该架构历经多年的构建,您能概述一下其中的关键体会吗?
Treat: 首先,我必须要向设计Kafka的Confluent人员脱帽致敬,因为我认为Kafka是此类架构的真正开创者。Liftbridge直接受Kafka的启发。它实际上借用了一些相同的概念,特别是数据复制和提交日志相关的实现。
在我的职业生涯中,曾参与了多个消息传递系统的实现。同时,我也是NATS和NATS Streaming的核心提交者之一。Liftbridge也从NATS中汲取了大量灵感。我非常感谢NATS的创建者Derek Collison及其他团队成员。其中,不少人都曾是另一种主要的消息传递系统TIBCO的前员工。
我学到的最重要的,就是简单性是一种被低估的特性。很多系统出错的原因。在于它们试图实现得过多。由于范围太过宽泛,因此系统会受到多种因素的影响,包括性能、可扩展性、可操作性等。传统的ESB就是一个很好的例子,通常它们很慢,或是不能扩展,或是非常难以操作或使用。
我学到的另一件事,就是简单性通常有助于提高性能。例如,Liftbridge和Kafka使用简单的仅添加(append-only)日志。这种做法使我们可利用顺序磁盘访问和操作系统页面缓存等功能。不同于大多数的消息代理,Liftbridge和Kafka并不追踪消费者的状态。这不仅简化了系统,而且提高了性能。
然而,竞争性目标和权衡总是存在的。如果在考虑性能的同时忽略容错性或可扩展性,很容易实现快速性能。同样,可扩展性和容错性与简单性之间存在着权衡。Kafka使用ZooKeeper处理群集和故障转移,因此它并不是一个简单系统。有别于Kafka,Liftbridge在内部使用了Raft替代了ZooKeeper的角色。另一方面,复杂性现在只存在于代码库中,而系统往往更容易操作。
通常,“简单性”最终只是将系统的复杂性推动到其它地方。使用相对简单的系统Kafka,很多复杂性被推到ZooKeeper和客户端。使用ESB时,客户端的语义可能非常简单,但这是因为复杂性已经推送到服务器端。服务器端很容易处理这种复杂性,但是在一些情况下,例如需要分布式以支持容错、维护一致性以保持数据正确、保持系统快速等,简单性统是非常难以实现的。许多消息代理无法同时满足上述领域中的一个或多个。
最后一点,容错是非常难以有效实现的。我的意思是,现有的复杂系统尤其难以添加聚类、数据复制等操作。这些问题是与架构密切相关的,必须从系统的一开始就做出仔细的考虑。熟悉我的人都知道我是John Gall的Systemantics的粉丝。有几个Systemantics原则适用于此,它们分别是“一个复杂的系统无疑是从一个可工作的简单系统发展而来的”、“一个从零开始设计的复杂系统永远不会工作,也无法通过修修补补使其工作。我们必须重新从一个简单系统开始做起”。我正在从零开始实现复制功能,并将其以补丁的形式添加到现有的复杂系统中,这项工作非常具有挑战性。就容错而言,我们不一定需要从一开始就实现容错,但需要我们具有一种可发展的愿景和设计。
InfoQ: 是否可以让部分流量继续“仅仅”使用NATS,或者是否可以将单个实例专用于基于日志的事件处理?
Treat: Liftbridge项目意在为NATS提供补充,而不是要取代NATS,或是改变NATS的行为。这是其设计的关键所在,也是Liftbridge有别于NATS Streaming的一个方面。也许对Liftbridge来说,更好的比喻是作为NATS的速记员,它恪尽职守地记录下来所有要播放的信息。这意味着。NATS的流量将会继续正常的运行,无需考虑Liftbridge在后台所做的任何记录保存。这不需要做任何特殊的配置,也无需更改任何代码。
InfoQ:您是否看到存在一些特有的场景,其中只适合使用ESB、轻量级消息代理、内存事件处理器(如NATS)或是基于日志的事件处理器?或者,您是否看到一些合并用例中使用了一到两种消息传递引擎?
Treat:有趣的是,一些较新的系统试图支持去很多上述类型乃至更多类型的用例。例如,Apache Pulsar提供了一种“统一”解决方案。它既可以提供传统的队列语义(例如,RabbitMQ所支持的语义),也可以提供类似于Kafka那样的数据流语义。我最近还看到Pulsar支持可进行流处理计算的函数,大体上类似于Apache Storm,Flink或是AWS Lambda之类的功能。NATS Streaming具有类似的功能,只是功能有限,例如提供队列语义的队列组(queue group)。
Confluent的员工会宣称Kafka能满足用户的所有需求。Kafka可能更适用于实时数据处理,但是对于微服务解耦,Kakfa需要做一些扩展。改变开发人员的思维方式至少会是一场艰苦的战斗。要让开发人员适应“发布者-订阅者”模式,需要做大量艰苦的工作。对于大多数开发人员而言,通过流处理构建复杂应用并非一种自然而然的做法。实际上,Kafka不仅仅与RabbitMQ、ActiveMQ或ESB等产生竞争,它还与数据库进行竞争,与Istio这样的服务网格竞争,与REST竞争。这是因为Confluent正试图从根本上改变开发人员构建系统的方式,而这是一个很大的挑战。
Streamlio的员工会宣称Pulsar能满足用户的所有需求。如果开发人员有可用的解决方案,那么为什么还要从根本上去重新构建系统,或是采用消息队列、流数据流水线及流处理框架? CIO喜欢这样做。
我个人采用的架构方法是使用一些相对较小的可组合组件。理想情况下,这可以通过一些合理的努力实现。我并不太喜欢近乎无所不包的系统,我认为有意思之处在于这正是导致大部分ESB失宠的部分原因,也是我与NATS产生共鸣之处。NATS是一种非常简单并精心设计的系统。
我认为存在着运行多种类型系统的用例。NATS非常棒,因为它是一种非常轻量级的系统。我们实际上已在一家企业将其用做服务网格原型,并作为守护进程运行在托管的虚拟机上。我曾谈到过,很多人在物联网中使用NATS,并将其运行在嵌入式设备上。一位曾与我交谈过的用户使用NATS来控制射击场的机器人,这颇具吸引力(也有点可怕!)。还有一个用例中,将NATS作为具有数十万个节点的集群的控制平面。Kafka非常适合大规模的数据处理,但由于使用了JVM和ZooKeeper,因此是重量级的。只要用户具有需要使用Kafka的工作负载以及可支持Kafka的资源(这也意味着,会有一项业务仅是提供Kafka服务),那么他们完全可以使用Kafka。但我认为,更传统的消息队列也有其一席之地。如果要使用消息队列,我会倾向于更多地依靠Amazon SQS或Google Cloud“发布者-订阅者”等托管服务。
InfoQ:在您(及社区)看来,在达到可用于生产环境前,Liftbridge还需满足哪些条件?
Treat:的确还需要实现一些项目。首先,Liftbridge需要支持TLS。在我看来,加密是一件首先需考虑的事情。它实际上并非十分难以实现,更重要的是该特性需要经过更严格的测试,包括负载测试和更强的故障注入测试,以消除任何性能或可靠性上的问题。在正确性方面,Liftbridge需要支持最小规模的同步副本集。该设计主要为了支持用户通过请求写入仲裁而保证数据的持久性。最后,我个人还希望能看到的一些功能,例如日志压缩(通过仅保留具有最新密钥的消息而压缩日志)、按时间戳和时间增量记录日志、改进检测和监视,以及支持在Liftbridge中嵌入运行NATS的方式。
InfoQ:要摆脱传统的ESB转而采用类似于Liftbridge的系统,用户应该怎么做?
Treat:对于使用更传统的消息传递中间件的用户,我通常会要求他们首先评估自己为什么需要队列。有些情况下队列是完全适用的,但更多情况下,用户过早地将队列引入到一个并非自身真正需要的系统中。对此,参见一个非常好的博客帖子“如何将一块巨石劈成两半?”。该帖子指出,对于短期任务,用户真正需要的是一种负载均衡器,因为队列不可避免地会以“满”或“空”这两种状态运行。如果队列以满状态运行,并且用户没有推出足够的工作,那么客户端就会产生等待,因为这是短期存活的任务。如果队列以空状态运行,那么它是以一种慢速的负载平衡器方式运行。实际上,NATS完全匹配对负载均衡器的描述,因为它并非一种队列,而是一种路由器。对于长期存活的任务,用户需要的是数据库。因为二者在客户端之外的任务管理上(例如,结果处理、故障故障等)存在着很多细微的差别。
如果你仍然踌躇不前,那么你应看到的是,从ESB迁移到Liftbridge的过程可能并不像你所想象的那样令人生畏。首先,NATS提供了一个连接器框架,简化了NATS和传统技术的桥接过程(谨记,Liftbridge只是NATS的扩展,因此数据将通过NATS)。该连接器支持用户将消息中间件中的数据直接传输给NATS(及Liftbridge)。如果用户使用了一些更复杂的ESB功能(例如,基于内容的路由),那么也可以使用连接器将这些功能映射到NATS。其次,尽管NATS并不支持ESB提供的许多功能,但它确实支持通配符订阅(wildcard subscription)。这是一种广为使用的强大功能,尤其是在AMQP中,它有助于将复杂的路由方案映射到NATS。不同于NATS Streaming,作为NATS扩展的Liftbridge完全支持通配符。