微服务架构:Kafka的崛起

转载 2016年08月28日 23:22:32

http://www.infoq.com/cn/articles/micro-service-architecture-the-rise-of-kafka?utm_source=infoq&utm_medium=related_content_link&utm_campaign=relatedContent_presentations_clk

正如我们在以前的博客中提到的,比如说我们的Docker系列博客,我们正处于把系统迁移到微服务新世界的过程中。

促成这次架构改造的一项关键的技术就是Apache Kafka消息队列。它不仅成为了我们基础架构的关键组成部分,还为我们正在创建的系统架构提供了依据。

Kafka概览

虽然这篇文章的目的不是在宣扬Kafka比其他消息队列系统更优秀,但是本文讨论的某些部分是专门针对它的。对于外行来说,Kafka是一个开源的分布式消息队列系统。它最初是由LinkedIn研发,现在由Apache软件基金会维护。和其他的消息队列系统一样,你可以给它发送消息,同时也可以读取消息。用Kafka的说法就是“生产者”发送消息,“消费者”接收它们。

Kafka的独特性在于它同时提供简单的文件系统和桥接这两种功能。一个Kafka的代理器(broker)最基本的任务就是尽可能快地将消息写到磁盘上的日志中,并从中读取消息。消息队列中的消息在持久化之后就不会丢失了,这是整个项目的核心所在。

队列(Queue)在Kafka中被称为“主题”(topic),同一个主题共享1个或多个“分区”(partition)。每条消息都有一个“偏移”(offset)-一个代表它所在分区位置的偏移量。这使得消费者可以记录它们当前读到的位置,并向代理(broker)请求读取接下来一条(或多条)消息。多个消费者可以同时读取同一个分区的数据,每个消费者从某个位置上读取数据都是独立于其他消费者的。它们甚至可以在整个分区内随意跳跃式前进或后退。

多个Kafka代理组合到一起成为一个集群。分区是在分散在整个集群中的,这样就提供了可扩展性。它们也可以复制到集群中的多个节点上,实现了高可用性。综合复制与分区持久化特点,进而达到高可靠性。

想了解更多的细节,请阅读这里

构建微服务的系统架构

为了帮助我们理解Kafka的用途和影响力,想象一个通过REST API从外部接收数据的系统,进而用某种方式进行变换,最后将结果保存到数据库中。

我们想要把这个系统升级为微服务架构,所以首先把这个系统切分为两个服务-一个用来提供外部的REST接口(Alpha服务),另外一个用来做数据变换(Beta服务)。简单起见,Beta服务同时会负责存储变换后的数据。

由一对微服务组成的系统会比提供整体服务(往往是糟糕的)的系统要好一点,所以我们定义一个接口用于从Alpha服务将数据发送到Beta服务,用来减少耦合。和使用REST接口实现的系统相比,让我们看看使用Kafka实现这个接口将会如何影响该系统的设计和运行。

系统的可用性和性能

当数据被提交到Alpha的服务,它在响应客户端之前需要确保数据安全地存储在某个地方,或者已经失败-客户端需要知道,因为如果出现了错误它可以重新发送(或用一些其他的方式进行恢复),

使用REST接口,Alpha服务在响应客户端之前将需要一直等待Beta服务的响应,直到Beta服务将数据存储到数据库中。

这种做法存在两个问题。首先,Alpha服务现在要求Beta服务是启动状态并且可以响应请求-它的正常运行依赖于Beta服务。其次,Alpha服务要等到Beta服务的响应才能响应客户端-它的性能也依赖于Beta服务!

在这两种情况下,Alpha服务耦合于Beta服务。Beta服务失败的频率是多少?它需要停机维护的频率是多少?它的峰值性能是多少?难道真的只有在数据被安全的存储之后才可以响应,或者说提前响应就是不可行的?如果它依赖于其他服务,相应的会需要进一步延伸耦合链?像这样的系统好坏程度取决于其最薄弱(weakest)的服务。

如果我们使用Kafaka消息队列做为接口替换上面描述的,我们将会得到一个完全不同的结果,Kafka有一招:一个Kafka消息队列是持久化存储的。当数据已安全地放到队列中时,Alpha服务就可以响应请求了;我们可以确信数据将最终会存储到数据库中,因为Beta服务致力于处理队列中的消息。Alpha服务现在仅仅依赖于Kafka的正常运行和性能了-这两个指标都可能远远好于系统中的其他微服务。它是如此松耦合于Beta服务,它甚至都不需要知道它的存在!

当然,消息队列从来就不是性能问题的灵丹妙药-它并不能神奇的改善系统的整体性能(举起手来,如果在你曾经参加的会议中有人相信的话)。然而,它确实允许你应对来自外部系统的可变负载,或者甚至是你自己系统中的微服务(例如那些必须做某种形式的批处理)。消息队列能够应对峰值负载,从而使下游服务可以平滑的速度处理。一个给定的服务的性能只需要大于系统的平均负载,而不是峰值负载。

使用REST接口时,你可以通过在每个服务中存储数据来打破依赖链并实现类似的效果。然而,为了达到这一点,在每一个服务中你都需要自己实现消息代理模块。使用现有的服务你自己不必再设计、构建和维护一套(或多套)类似的系统。

服务间松耦合

在设计系统的时候,我们发现如果Alpha服务返回的结果是转换后的数据,一些客户可能会发现它会很方便。

如果使用REST接口这将变得非常容易-Beta服务可以返回转换后的数据,Alpha服务直接透传给客户端。同时我们在两个服务之间增加了一个新的依赖关系-Alpha服务现在依赖于Beta服务的转换功能。这和上面小节中Alpha服务依赖于Beta服务存储数据是类似的情景。同样的问题出现了:如果Beta服务不能及时并且正确执行其功能,Alpha服务同样的也不能返回结果给其客户端。

和存储数据不同的是Kafka针对这个问题没有提供有效的解决方案。事实上,用Kafka接口来达到这个目的将会更复杂(但绝不是不可能)。因为消息队列是单向通信信道,从Beta服务获取转换后的数据需要相反方向的第二条信道。匹配这些异步响应结果和等待的客户端也会需要一些额外的工作。

然而,用消息队列不容易做到这个事实的给了我们一个启发,那就是我们新生的系统有些地方做的并不好,我们应该重新评估。纵观我们加诸于系统的额外功能与数据流的关系,结果表明不管它是如何实现的,是该功能引入了服务之间耦合。要想让Alpha返回转换后的数据则他必须依赖于真正做数据转换的服务,我们架构的系统不可能绕过这个事实。

这让我们停下来检查我们是否确实需要这个功能。有没有其他的方法可以提供访问转换后的结果数据并且不会引入这个问题?客户端是否需要所有转换后的数据?如果这个功能是必要,表明我们在切分微服务的时候并不是最优的,我们应该将数据转换这步放到Alpha服务中。如果不是必要的,我们只是阻止了自己添加不必要的或设计不当的功能,这些功能未来可能会影响我们系统的发展和性能。

系统的功能一旦添加上往往很难移除掉了。为了避免在系统中引入沉重的包袱,在实现之前辨别有疑问的功能(或者功能设计)是非常必要的。Kafka消息队列的自身的局限性可以指导我们设计出更好的系统。当你试图砍掉一个紧急的功能时,他们可能会感到沮丧,但是从长远来看是值得被称赞的。

提高可用性和扩展性

随着负载的增加,我们的系统应该保持高可用性,可扩展性。作为实现这一目标的一部分,我们希望能够运行多个Beta实例。如果其中一个实例宕机,其他的实例会(希望)仍然能够正常运行。可以增加更多的实例来处理增加的负载。

使用REST接口时,我们可以在Beta服务实例前面加一个负载均衡器,并且把Alpha服务从直接指向Beta服务的实例替换为指向这个负载均衡器。负载均衡器需要能够自动检测宕机的实例,从而一旦有实例宕机可以将负载转移到别的实例上。

一个Kafka消息队列默认支持可变数量的消费者(例如Beta服务),不需要额外的基础架构的支持。多个消费者可以组成一个“消费组”,只需要在连接集群的时候指定一个相同的组名。Kafka会将每个主题所有分区的数据共享传输给整个组的消费者。只要我们使用的主题有足够多的分区,我们可以持续增加Beta服务的实例,这么它们将会分担一部分负载。如果某些实例不可用,他们的分区将由剩余的实例处理。

增加更多服务

我们需要在我们的系统中添加一些新的功能(这并不重要),我们将把它放在一个新的Gamma服务中。它依赖Alpha服务的数据的方式和Beta服务依赖Alpha服务的数据的方式是一样的,并且数据是用同样的接口提供的。数据必须经过Gamma服务处理才算被整个系统完整的处理。

如果使用REST接口,则Alpha服务将会耦合一个额外的服务,加剧前面讨论的服务间耦合的问题。随着下游服务的增加,依赖会变得原来越多。

此外,一组数据可能成功的被一个下游的服务处理,但是在另外一个服务中却处理失败。这种情况下,可能很难通知到客户端和做到自动恢复,特别是如果它们可以在状态不一致的情况下就离开。

使用Kafka接口允许新的Gamma服务和Beta服务一样简单地从同一消息队列中读取数据。只要它使用一个不同于Beta服务的消费组,两者之间不会互相干扰。由于Alpha服务不需要知道它写入数据的消息队列有什么服务在使用,我们可以持续的添加服务而不会对它造成任何影响。

数据被安全地存储在Kafka中,所以各个服务可以在瞬时故障的情况下重试,例如数据库死锁或者是网络问题。非瞬时错误,例如脏数据,和使用REST接口一样都会存在类似一些问题。检查数据合法性越早越好,例如在阿尔法服务,是减少这些问题的关键。

总结

以上的例子都是直接取自于我们在Movio推进微服务化过程中的真实案例。在这个过程中它已经证明了是一个非常宝贵的工具,催生了优秀的系统架构,并可以简单和快速的实现它。我们将继续探索使用它的新方法,并期望我们的使用会促进系统的进一步发展。

LinkedIn和Apache的团队创造了一件伟大的作品。

查看英文原文:Microservices: The rise of Kafka


相关文章推荐

Spring Cloud构建微服务架构(七)消息总线(续:Kafka)

Spring Cloud Bus除了支持RabbitMQ的自动化配置之外,还支持现在被广泛应用的Kafka。在本文中,我们将搭建一个Kafka的本地环境,并通过它来尝试使用Spring Cloud B...

深入聊聊微服务架构的身份认证问题

从单体应用架构到分布式应用架构再到微服务架构,应用的安全访问在不断的经受考验。为了适应架构的变化、需求的变化,身份认证与鉴权方案也在不断的变革。面对数十个甚至上百个微服务之间的调用,如何保证高效安全的...

Kafka环境搭建以及服务封装

一、安装前准备 1、kafka版本:kafka_2.10-0.10.1.0.tgz 2、zookeeper版本:zookeeper-3.4.3.tar.gz 3、zookeeper集群: 192.16...

Kafka详解二、如何配置Kafka集群

Kafka集群配置比较简单,为了更好的让大家理解,在这里要分别介绍下面三种配置 单节点:一个broker的集群单节点:多个broker的集群多节点:多broker集群 一、单节点单broker实例...

安装kafka rest proxy - 使得我们能通过http访问kafka

安装kafka rest proxy - 使得我们能通过http访问kafka,这对于那些没用对应kafka客户端的语言尤其有用,比如php。 The Kafka REST Proxy provi...
  • xxgwo
  • xxgwo
  • 2016年05月12日 18:22
  • 4846

Kafka本机搭建、常用命令、以及Rest模式||Kafka在zookeeper中的注册关系

Kafka简单教程

kafka数据可靠性深度解读

1 概述Kakfa起初是由LinkedIn公司开发的一个分布式的消息系统,后成为Apache的一部分,它使用Scala编写,以可水平扩展和高吞吐率而被广泛使用。目前越来越多的开源分布式处理系统如Clo...

Kafka端到端审计

概述Kafka端到端审计是指生产者生产的消息存入至broker,以及消费者从broker中消费消息这个过程之间消息个数及延迟的审计,以此可以检测是否有数据丢失,是否有数据重复以及端到端的延迟等。 目...

唯品会峰值系统架构演变

摘要:在唯品会,用户来得越早,越能买到又便宜又好的东西,所以在大促一开始会涌入大量用户,形成系统流量峰值。本文总结了唯品会419时日志平台遇到的问题和解决方案,同时根据实践经验,整理了在面对峰值前要做...
  • joeyon
  • joeyon
  • 2015年06月25日 18:06
  • 1417

Spring Cloud构建微服务架构(七)消息总线(续:Kafka)

Spring Cloud Bus除了支持RabbitMQ的自动化配置之外,还支持现在被广泛应用的Kafka。在本文中,我们将搭建一个Kafka的本地环境,并通过它来尝试使用Spring Cloud B...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:微服务架构:Kafka的崛起
举报原因:
原因补充:

(最多只允许输入30个字)